diff options
2634 files changed, 108320 insertions, 44566 deletions
@@ -514,6 +514,11 @@ S: Bessemerstraat 21 S: Amsterdam S: The Netherlands +N: NeilBrown +E: neil@brown.name +P: 4096R/566281B9 1BC6 29EB D390 D870 7B5F 497A 39EC 9EDD 5662 81B9 +D: NFSD Maintainer 2000-2007 + N: Zach Brown E: zab@zabbo.net D: maestro pci sound diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module index 9489ea8e294c..47064c2b1f79 100644 --- a/Documentation/ABI/testing/sysfs-module +++ b/Documentation/ABI/testing/sysfs-module @@ -33,3 +33,19 @@ Description: Maximum time allowed for periodic transfers per microframe (ÎĽs) Beware, non-standard modes are usually not thoroughly tested by hardware designers, and the hardware can malfunction when this setting differ from default 100. + +What: /sys/module/*/{coresize,initsize} +Date: Jan 2012 +KernelVersion:»·3.3 +Contact: Kay Sievers <kay.sievers@vrfy.org> +Description: Module size in bytes. + +What: /sys/module/*/taint +Date: Jan 2012 +KernelVersion:»·3.3 +Contact: Kay Sievers <kay.sievers@vrfy.org> +Description: Module taint flags: + P - proprietary module + O - out-of-tree module + F - force-loaded module + C - staging driver module diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index b638e50cf8f6..2f7fd4360848 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -50,7 +50,9 @@ <sect1><title>Delaying, scheduling, and timer routines</title> !Iinclude/linux/sched.h -!Ekernel/sched.c +!Ekernel/sched/core.c +!Ikernel/sched/cpupri.c +!Ikernel/sched/fair.c !Iinclude/linux/completion.h !Ekernel/timer.c </sect1> @@ -216,7 +218,6 @@ X!Isound/sound_firmware.c <chapter id="uart16x50"> <title>16x50 UART Driver</title> -!Iinclude/linux/serial_core.h !Edrivers/tty/serial/serial_core.c !Edrivers/tty/serial/8250.c </chapter> diff --git a/Documentation/DocBook/deviceiobook.tmpl b/Documentation/DocBook/deviceiobook.tmpl index c1ed6a49e598..54199a0dcf9a 100644 --- a/Documentation/DocBook/deviceiobook.tmpl +++ b/Documentation/DocBook/deviceiobook.tmpl @@ -317,7 +317,7 @@ CPU B: spin_unlock_irqrestore(&dev_lock, flags) <chapter id="pubfunctions"> <title>Public Functions Provided</title> !Iarch/x86/include/asm/io.h -!Elib/iomap.c +!Elib/pci_iomap.c </chapter> </book> diff --git a/Documentation/DocBook/media/constraints.png.b64 b/Documentation/DocBook/media/constraints.png.b64 new file mode 100644 index 000000000000..125b4a94962c --- /dev/null +++ b/Documentation/DocBook/media/constraints.png.b64 @@ -0,0 +1,59 @@ +iVBORw0KGgoAAAANSUhEUgAAAlQAAAFYCAYAAACVsmLPAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A +/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sLCBIAKVtZsMAAAAxxSURBVHja +7d3ZbqvIAkDRLsv//8v0QytXvpYZap7Wko56OAnE2AXbBSbhOI7jHwAAkr1sAgAAQQUAIKgAAAQV +AICgAgBAUAEACCoAAEEFACCoAAAQVAAAzb2jvyMEWw0AmFvh37xnhgoAQFABAPT1zvruwtNlAADV +VLxsyQwVAICgAgAQVAAAggoAQFABACCoYEohuFkugKACsmLq178DIKiAyJgSVQCCCigQU6IKQFAB +BWJKVAEIKqBgKIkqAEEFFAgkUQUgqIACYSSqAAQViKkwxjIAEFSwbUyJKgBBBWJq8GUCIKhgm5gS +VQCCCsSUqAIQVMBYoSOqAAQVLOk41lwXAIIKhoqqJyFUYhkACCpYMqpiQqjEMgAQVLBUVKWEUIll +ACCoYImoygmhEssAQFDBElHVexkACCoAAEEFACCoAAAQVAAAggoAQFABAAgqAAAEFQCAoAIAEFQA +AIIKAABBBQAgqAAABBUAgKACAOA/b5sAGjsO2wBgMWaoAAAEFQCAoAIAEFQAADtzUXohIQQbAYDi +Dh9kmYIZKgAAQQUAIKgAAAQVAICgAgAgmU/5VeSTGQDE8InxeZmhAgAQVAAAggoAQFABAAgqAAAE +FQCAoAIAEFQAAHtyY0/o4O7efe4JCzAXM1QAAIIKAEBQAQAIKgAAQQUAgKACABBUAACCCgBAUAEA +IKgAAAQVAICgAgAQVAAACCoAAEEFACCoAAAEFVBICGMsAwBBBVPHVE4QlVgGAIIKpo6ps/9utQwA +BBUsEVMpQVRiGQAIKlgqpmKCqMQyABBUsGRMzbouAAQVNHMca64LAEEFy0WVmAIQVCCqxBSAoAL6 +hI+YAhBUIKrEFICgAvqEkJgCEFQgqo4+3wuAoILto0pMAQgqICOQxBSAoAIyQklMAQgqICOYxBSA +oAIyokpMAQgqICOqxBTAvN42AYwTVQDMyQwVAICgAgAQVAAAggoAQFABAJDMp/y4FIJtwJx8ehJo +yQwVAICgAgDoyyk/HnMKhdE5RQ30YoYKAEBQAQAIKgAAQQUAIKgAABBUAACCCgBAUAEACCoAAAQV +AICgAgAQVAAAggoAAEEFACCoAAAEFQCAoAIAQFABAAgqAABBBQAgqAAAEFQAAIIKAEBQAQAIKgAA +BBUAgKACABBUAACCCgAAQQUAIKgAAAQVAICgAgBAUAEACCoAAEEFACCoAAAQVAAAggoAQFABAAgq +AACGCKoQPAs2JQAIquwCUAI2JQAIqowCOPtvbEoAEFQRBaAEbEoAEFQFCkAJ2JQAIKgKFIASsClh +szEKrDGoXkNuiOPwwim4iezYoc9+39iDfQbVq+mGEFOiCjZ7E23swR6D6tV8Q4gpUQWb7PeNPdhn +UL26bAgxJapgk/2+sQd7DKr3EDE1y96mUPT1fqgh6Ffosbsz9mDdQfXquiEY/rUKlBtLYgoqDJZB +Dmjlg8qRWlSBMSSmYLOoKhtUjtCiCowdMQUbRtXLswUgpkBU5XkXf9CmPJZ9nQJrft6Gife9XmC/ +t0mHg9tr3FcJYgrmjilgn8Fa55SfI7WYAvtnYKNBW+8+VLGn/zY6wtd4qDY1iCngx+BtdNCre1G6 +W3gPt7MXUwAwW1CJKjEFCzB2wODtH1SiSkyB/TKw+KB9DfnARJWYAvtnYKLB+m7+AJ+UgL2WTQmT +jz1jEJVf0ASD7jXck2/vY1PCQscwE+6wfkz1CaqrB6wAbEoQVcBkMdUvqH49cAVgU4KoAiaMqb5B +9bkBFIBNCaIKmDSm+geVArApYaOxZ4zCuoPq5VkDqL//F1Ow9qASVACV9/9iCtYfVIIKoOL+X0zB +HoNKUAFU2v+LKdhnUAkqgAZvqoG1B5WgAgAQVAAAggoAQFABAAgqAAAEFQCAoAIAEFQAAIIKAABB +BQAgqAAABBUAgKACAEBQAQAIKgAAQQUAIKgAABBUAACCCgBAUAEACCoAAAQVAICgAgAY3NsmIEYI +//3zONK/7u/v/nx+zdPl/1rO0++LWd6vZZ59Xe7jSfnZSq3z6jnJ2ValX09PHj9AD2aoiPJ34Lo6 +wJWKiJQD7N2BN/WAzbNtZTsCuzJDRZeD8XHkH3zPZo5CSJudeTKbdrX+lkE7QkzFbq8VHj/AGTNU +dDkY1ziw1jjY7nAA/wzKqxnIu5gSPICggoTIuDroXh1YRz3ohuCUlcgESOOUH81iZdR1fJ9+zL1Q +use1Y6nrvLsearR46rHNAQQVw6l14HtyOurJz5USVqs9LynXt8V+ShBAUMHHQfdzFuMsQGqHSW5M +PQmrVtdsjRCkOwY5gKBiGne3Okg5WJaMqbuw2uX5+P6aX4H8/f922F4AgorlgyD3hp47z3ycPfZf +p/FSb00BIKjg4kD8/cm4mFNjKfd/OpsJyb2GJ+V+UzEXSK9wAfuvqGr9s7ooHRiV2yYgDCe8xUOp +gHny2GNjVdwAOzJDRbUYSfnep8srfdCOWV6tr225ztzt3PpxiTRgdGaoAAAEFQBAX075sbS7C6dH +OJU0w8/ocQEIKjY2w0F71bAQTMBOnPIDABBUAAB9OeXHY36tCAD8ZoYKAEBQAQD05ZQfl3xSCwDu +maECABBUAACCCgBAUAEACCqgiRDczwtAUAFZMfXr3wEQVEBkTIkqAEEFFIgpUQUgqIACMSWqAAQV +UDCURBWAoAIKBJKoAhBUQIEwElUAggrEVBhjGQAIKtg2pkQVgKACMTX4MgEQVLBNTIkqAEEFYkpU +AQgqYKzQEVUAggqWdBxrrgsAQQVDRdWTECqxDAAEFSwZVTEhVGIZAAgqWCqqUkKoxDIAEFSwRFTl +hFCJZQAgqGCJqOq9DAAEFQCAoAIAEFQAAAgqAABBBQAwibdNAECqcPKLJo8fH1cNN7+U8up7jpOP +v6as//PvPr+/xPpTlsEazFABUDSmnsRTie/pvX74ZIYKgKz4+J55+fu7EMLPWZmU2auY9YsjejBD +BUDRmDk7pdZq/Vf/P2bZT7/2OI7/rU/ICSoAiHIVLS2uFyq5Dtc3kcspPwCairmQvHUghhBOT1U+ +eQx/fyfQBBUALBNrtcPmc/l/QYagAoDqYi9ib/2zPZ2l+hVw7Ms1VAAkKXXbgpIXkH9eIF7r8T15 +bEJLUAHA4wD6FQ5PPoVXc/0ll3/3db/+sCen/ABIio7PU3U5YfIdY0++78n6RzPqxfiUYYYKqh94 +rv/AzFGV8nelouLue3JC5e5XzTx57E777SUcsa+4zxeIo8HlOw/vOgBwLBlqA1drGDNUAACCCgBA +UAEATM2n/CpyQSIA7MEMFQCAoAIAEFQAAIIKAGBnLkovxI3XAGBfZqgAAAQVAEBfTvlBbXf3I3O6 +GGB6ZqgAAAQVAICgAgAQVAAAggoAAEEFACCoAAAEFQCAoAIAQFABAAgqAABBBQAgqAAAEFQAAIIK +AEBQAQAIKiBFCGMsAwBBBVPHVE4QlVgGAM29bQIoGFOf/30c7ZcBrV/zd6/Rq6/7fs1/fs3T5Z+9 +AckZO2dvaL6XeffGJ/XxpPxspdZ59ZzkbKve278BM1RQOqaeDvbSy4CW/g5WV6/RUhHRcuwYc2W2 +VY3tP/hzY4YKar5bfLIDeLIMM1WsOnaOI/9AeTZzETt2YmbTrtbfMmhH2PfFbq/Syxxk/2iGCmrF +1Kzrgplez78OpjUOsDu8qfkMyqsZyLvwSdleNZYpqGASLQe3GSpGHgNXB92r1+6or+sQvInptV+a +eF/nlB/kDv7aO14xxUpahErqOr7Hc+yF9y3Hbul13l27NPJ+aJBTgYIKRo4qMcXK46b2wTVlHb9m +3VpcXD/i85Kyb4v9lGCvZQoq2CiqxBQzvfY/ZzHOAqR2mOTG1JOwanXN1ghBunucR3INFYw4qMUU +K/sLsO9rlXKuXSoZU99jcfXxmPpp5LP7f5W+B9Ukz4GggtGiSkxBn5ja/UL0v3D5/nO1jyq1zWos +szGn/KDGTinnoliY9TV/FzZnr++U+z+dfcIw93qblPtNxVwUvcIF7N/7uZJRlbLMQS5KN0MFtQ4w +YgrWGberjs+Y21vExmqN/eDAz0M4jsifrtZ5alh5ZyWmAMbaJxfe75qhgl7veMUUwDIEFfSMKjEF +sAQXpUOrqJrk5nSwpLvT7yOMxxl+Ro9LUMFQUSWmoP348zN6XIIK7FgAWDWo/DZuAAAXpQMACCoA +gM7iT/m5BgQA4P+YoQIAEFQAAIIKAEBQAQAIKgAABBUAgKACABBUAAB7+hfHbDX87cMFJQAAAABJ +RU5ErkJggg== diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index 3bc8a61efe30..c7a4ca517859 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -163,14 +163,16 @@ get/set up to 64 properties. The actual meaning of each property is described on <section id="DTV-FREQUENCY"> <title><constant>DTV_FREQUENCY</constant></title> - <para>Central frequency of the channel, in HZ.</para> + <para>Central frequency of the channel.</para> <para>Notes:</para> - <para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz. + <para>1)For satellital delivery systems, it is measured in kHz. + For the other ones, it is measured in Hz.</para> + <para>2)For ISDB-T, the channels are usually transmitted with an offset of 143kHz. E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of the channel which is 6MHz.</para> - <para>2)As in ISDB-Tsb the channel consists of only one or three segments the + <para>3)As in ISDB-Tsb the channel consists of only one or three segments the frequency step is 429kHz, 3*429 respectively. As for ISDB-T the central frequency of the channel is expected.</para> </section> @@ -334,9 +336,10 @@ typedef enum fe_rolloff { <title>fe_delivery_system type</title> <para>Possible values: </para> <programlisting> + typedef enum fe_delivery_system { SYS_UNDEFINED, - SYS_DVBC_ANNEX_AC, + SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBT, SYS_DSS, @@ -353,6 +356,7 @@ typedef enum fe_delivery_system { SYS_DAB, SYS_DVBT2, SYS_TURBO, + SYS_DVBC_ANNEX_C, } fe_delivery_system_t; </programlisting> </section> @@ -647,6 +651,18 @@ typedef enum fe_hierarchy { many data types via a single multiplex. The API will soon support this at which point this section will be expanded.</para> </section> + <section id="DTV_ENUM_DELSYS"> + <title><constant>DTV_ENUM_DELSYS</constant></title> + <para>A Multi standard frontend needs to advertise the delivery systems provided. + Applications need to enumerate the provided delivery systems, before using + any other operation with the frontend. Prior to it's introduction, + FE_GET_INFO was used to determine a frontend type. A frontend which + provides more than a single delivery system, FE_GET_INFO doesn't help much. + Applications which intends to use a multistandard frontend must enumerate + the delivery systems associated with it, rather than trying to use + FE_GET_INFO. In the case of a legacy frontend, the result is just the same + as with FE_GET_INFO, but in a more structured format </para> + </section> </section> <section id="frontend-property-terrestrial-systems"> <title>Properties used on terrestrial delivery systems</title> @@ -721,14 +737,10 @@ typedef enum fe_hierarchy { <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem> <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem> <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem> - <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem> <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem> <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem> - <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem> - <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem> <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem> <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem> - <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem> <listitem><para><link linkend="DTV-ISDBT-LAYER-ENABLED"><constant>DTV_ISDBT_LAYER_ENABLED</constant></link></para></listitem> <listitem><para><link linkend="DTV-ISDBT-PARTIAL-RECEPTION"><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></link></para></listitem> <listitem><para><link linkend="DTV-ISDBT-SOUND-BROADCASTING"><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></link></para></listitem> @@ -767,7 +779,8 @@ typedef enum fe_hierarchy { <title>Properties used on cable delivery systems</title> <section id="dvbc-params"> <title>DVB-C delivery system</title> - <para>The DVB-C Annex-A/C is the widely used cable standard. Transmission uses QAM modulation.</para> + <para>The DVB-C Annex-A is the widely used cable standard. Transmission uses QAM modulation.</para> + <para>The DVB-C Annex-C is optimized for 6MHz, and is used in Japan. It supports a subset of the Annex A modulation types, and a roll-off of 0.13, instead of 0.15</para> <para>The following parameters are valid for DVB-C Annex A/C:</para> <itemizedlist mark='opencircle'> <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem> diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml index 61407eaba020..aeaed59d0f1f 100644 --- a/Documentation/DocBook/media/dvb/frontend.xml +++ b/Documentation/DocBook/media/dvb/frontend.xml @@ -45,8 +45,8 @@ transmission. The fontend types are given by fe_type_t type, defined as:</para> </row> <row> <entry id="FE_QAM"><constant>FE_QAM</constant></entry> - <entry>For DVB-C annex A/C standard</entry> - <entry><constant>SYS_DVBC_ANNEX_AC</constant></entry> + <entry>For DVB-C annex A standard</entry> + <entry><constant>SYS_DVBC_ANNEX_A</constant></entry> </row> <row> <entry id="FE_OFDM"><constant>FE_OFDM</constant></entry> @@ -63,6 +63,10 @@ transmission. The fontend types are given by fe_type_t type, defined as:</para> <para>Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described at the above, as they're supported via the new <link linkend="FE_GET_SET_PROPERTY">FE_GET_PROPERTY/FE_GET_SET_PROPERTY</link> ioctl's, using the <link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> parameter. </para> + +<para>The usage of this field is deprecated, as it doesn't report all supported standards, and +will provide an incomplete information for frontends that support multiple delivery systems. +Please use <link linkend="DTV_ENUM_DELSYS">DTV_ENUM_DELSYS</link> instead.</para> </section> <section id="fe-caps-t"> diff --git a/Documentation/DocBook/media/selection.png.b64 b/Documentation/DocBook/media/selection.png.b64 new file mode 100644 index 000000000000..416186558cb2 --- /dev/null +++ b/Documentation/DocBook/media/selection.png.b64 @@ -0,0 +1,206 @@ +iVBORw0KGgoAAAANSUhEUgAABIsAAAHpCAYAAAACi7yYAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A +/wD/oL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sLCBAiCLMGMtAAACAASURBVHja +7d3rkds4FgZQaMohTBY7ObRCV+fgyWJy4P6wJavVIgmSAIjHOVWu3bElPkBSAj5dgpdpmqYAAAAA +ACGEvzQBAAAAAHfCIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMDDD00A +21wul9XXTNN0aHnP749Z39o2rK0jRzssLX/pvVve9+61S69Jdey2bn/sMTx6TAAA/cIW+oVb+2tb +3p+izwioLIJsHYe9X+a979vae89ut6Pb1+txBwD0C3vZN0ERrFNZBAct/ZJxuVx2Vdg8v+/oLyEx +69j7xbq2/1u2e0u75Th2Mevf8ytVzDkDAOgXjtYv3LquVP0nQRHEUVkEBTsJve/r0hfu2hdz7e0W +27HQ4QAA9Avr7BcJiiCesAhO+GKK/YIt8SV+RscoNmippUPl1jIAQL/w3PUc7Y8JimAbYRGc9KVY +Yu6b3OsYNUTRuQAA9AvL9AtT9LsERbCdOYsAX74ZOiVbO1M6LQCAfmH7/TzohcoiqOhLK+eXV4p1 +xP4y1krF0X1bn7dXBwIA0C+ss19oagAoR1gEJ4j9osv5iPq965imKUk59eidwNc/AIB+oX7h/HpK +tzeMzm1oQJIv7Ra/eO/7sOWxtgAAtN0v1N+DdcIiyPQFlPP1JbZpTyehl19q1joQOhgAgH7hOf3C +Pct9tz36c7DMbWhQwPMXUYkOQ6517P3Sj/216axJEdfWoyMBAOgXpukX5uqv7Xm/W9JgnsoiSGxr +4FHiiyvlOu7v21pu/PqLzuuvOTHtlmIZW/bz+f1r6177ewBAv1C/8FwqjCCesAgSdwK2dAh63e+5 +fX8XuBxtt1SdkZhy6djt37vNOioAoF84Sr8wV39tzzIERvCd29Agg7knQ8T+unTk15mc64j5El17 +KsbRW75inrqR6glj79rELWsAgH5hmn7hmcckpt8HI7tMRjYAAAAA/KayCAAAAIAHYREAAAAAD8Ii +AAAAAB6ERQAAAAA8CIsAAAAAeBAWAQAAAPAgLAIAAADgQVgEAAAAwIOwCAAAAIAHYREAAAAADz80 +AQAAqVwuF40AABWbpmn1NbvDIh0BAKDGzg3n0T8EgD7sCot0BAAAmDNNUwj6iwBQlS3fzIduQ7vd +blobAMjuer1qhKZ6o4IiAGiZOYsAAMji0w+LAHC6jx0/unkaGgAAAAAPwiIAAAAAHoRFAAAAADwI +iwAAAAB4EBYBAAAA8OBpaAAAFDf3ZJa5J6htef3za5eeyDb3urWnxsQuM/V7jmxX7Dr3HIMUbfj6 ++qXjurZ977Zja1vuaVOAnqgsAgCgqKWB+rt/2/r6s7Z/z3aesf0x+1fjdgFQjsoiALpyfRng3J5+ +Fb7/2+3NL8Xv/m1pWa/veX7t/XXXN4OtuWXs+fe59c/t45H2erd/Mdu/9XX0b63q5zWkWHr9/d8+ +rtfFapOY9byz9L7X5e7ZzqVKmT2VP3ts2cc966+1MmfuGKkkAvhFZREA3XgON94FNnMhzlJQNLes +1/ffX/f62ue/fw1d3r3m9d/nlhu7/rX22rv8LW20d/voT8ztYbEBzNJrS4YMubbzzNCidLs+BzX3 +datsAjiXsAiALrwLfPYGE1uXtaVK5l2YNLes2OXurdI5svwtbaSKiFdbg5Cl18f821y1UupAZu92 +1njblwobgLG5DQ0AZqSofjkSnOSuvsmxf2fsB5SUMtT5vN2+LC82xNoziXaJNthyO11MBdHS7YUA +5CUsAmAo91u97rdGLc1jdKQi5t08QiH8uSVrTcwcSkekWv7avuTeD1hzD2TuwcOWqqIS8wa9C01G +nD/neV9fQzQAyhMWAUAma5NVA23KEeLMhUZHJ5g+e/9jXyscAqiLOYsA6MK7+XLW5gWK/fdnsYHP +2uvWJtveu969ti5/bxsJzNgTDOx5JP2z1yAmNsC4T7j8+ifXdj6vs7VjlGsdQiSAc6gsAqAbz7eY +Pf9dqmVtWd7cbWivE0LPbe/rv80tL1Vb7Vl+TBvl3g/a8nx70dIj7e9/v/b6mKer1bBfc9tZ65w8 +pdt1bh1zQdFaGwNw3GWapmnzmy6XQx1wAIAt7gHTjm4LJTuWv/uI084QYC482Pv6LfMSvXtc/Nag +pNR+xb7+yLYeXX9MG669ZunYpN7mEeeJAsZx/4y7/P7vmP6U29AAAChq6yPm9z6S3n7t34/c648J +Z97N49TKuQDQOpVFAED1VBY10rGMrCwCAMpRWQQAAADAIcIiAAAAAB48DQ0AADqSciJsAMYkLAIA +gI4IgwA4SlgEAADAZh9/X9/+/ed/t8Ovf37t3PKWXje3rq3LTP2eI9sVs961969t59r2LbX16zJi +t+Xzv1vyduE4YVHpD9SZsuDnX4COlA7HLD/Ferase2lZW7Zh6/a+vn6pDda27912rK0vVbsCAEB1 +45qFwf3H39dNIcm715fY/rWQKsV7Wj5me93Dn6VlxgZKnEdYVPLiXAgTPq7X6BBh7rWpln/kPWv7 +LigBAIDGxzUrVT+vocTS6+//thYs7A1plt73utw927kUeixt3xnhWEybzO13qe0VHtVDWFTq4nwK +cmKDni2B0NLy7/82F/4srWdPYLRneVvWUWvgNNfuAjIAALoZ10TcHhYbwNz/LiYwStpvf3PbU47t +zL0v727/WqvqijlmEEIIf2mCAh+oK0HR0UBhbflbbuVKsT1ry4vdhhRt/nm7PdZdYr0AADCCreHC +0utj/m0u3EkdcuzdzntQ09MxS7Gud23iFrQ2qCwqeXFmrjBZWv7n7XZ6WFLDNgAAAGNLGeq8Vilt +ndz53fKO7sMZc0DlPjaCpfKERTVfKBsmqy617hr2de21qeduAgAAzvM6YfKWypQS8wa9q6IpVT3z +vPyYp4pBLGERu55i1sSXytO2q2oCAAAe44MMIc5caDQ3B1KSsVzF4dC7p6KthWgqiOohLKr5A2zj +RNW511/LurY8NQ4AAEhv661OMY9RXxwDPAUP9/+OGjtsDB+ObufzOnMFOTHLnZvoWhhDLBNcl/xA +PRherIUka7dfLS333Z/a9j/VOoRIAACwc0wy86SzL/3tmadvLU12/Pra2vZryz6V3OZ3f44eMwhB +ZVGZi/jpFqi5qqAj1UJry495Gltupbdhbh1zQdFauwEAAL/72i+PkU/x+hoeRb93O/fMi1R6Iuet +xyz1emNDQRNc10NYVOoieQl0jnoNN2KWXyoo2jMH0lnbfKTdzm5nAAA4bXyzMJnyXHVLC0FA7fsV +cxveu7mCWjoG1EFYVPKDZ2GS5diAYW0ZtQYYJZ/gtrSuexs9h201txsAAFQ7vtkYMGx5/dHXHgk/ +atmvI+9PNYF0ioqvGqrG2O4yTdO0+U2XSwghhJuBNABQwPV3qL+j20LJjuXvPuL9KPnRBWCbtVvE +hCrsOq9+96Muv/87pj+lsggAAKDFAeBLsCBIaJ9jSC2ERQAAAB0QHgGpCIuI++JZmZRbmTkAAFTW +h98QHn1cPzQYFPR5+6x6+4RFRJ7IN40AAAA19dGfwp+Yx6HHPr4cQFgEAADQuNfwZy08inkEOzAu +YREAAECjYiqKdvl50bg04Ujg+Xr7Ze5bw1q63VNYlPzgXzUCAP13zNyeDJB/bJErCAKKB0WtERYB +AACcNWA9IRBy6xnDX3eColXCoowUbgLQk0kTAMQPRguFQItPOHuzDXuCoss/jieV9Ul+Hrg2TwqK +WnvioLAIAABgy6CvgiBoz/apKGL4a1dQFE1YBAAA8DywK3hrWOoAJ1U1EXR3XQuKNhEWAQAAYwwW +Gw6B9u6foAgERXsIiwAAgLYHgoUnia4tgBESwcL1UUlQ9Hn7bCo8EhYBAAB1DvJOenR860GLoAh+ +f4ZUFBS1RlgEAACUH8R5ZLx9hJyfMYKiQ4RFAABAuoGSEMj+w9mfQ4Kiw4RFAADA+iBICAS08Fkl +KEpCWAQAACMPrMwLBPTyeSYoSkZYBAAAPQ6ahEDASJ95gqKkhEUAANDaoMgtYQB/PhMFRckJiwAA +oJYBjxAIYNvnpqAoC2ERAADkHlQIgQDyf+4JipIRFgEAwN4Bg3mBAKogKEpLWAQAAK+DASEQQDME +RekJiwAAGIpbwgD6ISjKQ1gEAEAXhEAAZPl+GSwoCkFYBABA7Z10IRAAZ30HDRgUhSAsAgDgrA64 +eYEAqPl7atCgKARhEQAAR/17CSGEMP186WSHa9HNEAIB70zTNMy+Xi4XBzyRkYOiEIRFAAAs+ff8 +gYcQCICSRg+KQhAWAQCMSQgE0J25KioVR/EERb8IiwAAenJGCPS/6ctgZHp0sG+OB0AFXkMk4dF7 +gqI/hEUAAC04qxLof5O2B6B7gqKvhEUAAGcSAgFQ2HOlkSojQdE7wiIAgFxOvCUMAFgnKHpPWAQA +sJUQCIBOjFxlJCiaJywCALgTAgHAEARFy4RFAED/zAsEAKvuVUa9VxgJitYJi6DmD+uf7//+8s/6 +a969ds/yU6xn636uLWttu9e2dakdX5cRuy2Xf/K2ETBDCAQAbHBWUPS63toJi6BSS8HD9DM+eJh7 +barlH3nPme2y5h7+LC0zNlACdnaq/r5+v/Zzh0NCIADotsJIUBRPWAQ1fjg/BSKxQc+WQGhp+fd/ +mwtJltaTOzCKbZe5fSoV6giPYKXD9BQCFSMEAoCx+x+Cok2ERVCZtUBk6e9TLP/5dqrY8CfmFqy1 +7Xm+/evdenO3C5CgMyQEAoC+xibT1EV1kaBoO2ERVCp38LG0/CPhT+vt8q4dlsIrARVDdBTffB58 +hGv29X7+d3v8/+v1+ui0AgDEqiUo+rx9NhUeCYug48FcCOfPI7T3faXmQOrtWECJa/eo5xAIAKi8 +v9Dw/EU1BUWtERYByQaXe8OQ5/fVXNUEvVyruQiBAIBaCIqOERZBJ7ZOVJ17/bUParfs1+utaGu3 +oKkgIqczrpfHuf+l43NzMABgpD5IQ/MXCYqOExZBxQPCI6HDWoVOzCPhlwaNJQa8c3MFCWPo9Zov +zbUEAPRGUJSGsAgqE/M0siOBydryY546VmKw+jpwzt0ukMtZlXOuBQAgeb+m8uoiQVE6wiKo0Gsw +kmKwOjcvUEuTMadul63rjQ3STHA9SGdJCAQAUA1BUVrCIqjU0m1ksYPFtWWcFWrEPHZ+7rH1Z243 +43BLGADATD+pwuoiQVF6wiKoWMzgce01a4HMGQPZLWFXim3J3Y4G+w11boRAAABdERTlISwCoHlC +IACAgn2v6dczUmurMBIUpSMsAqDejoh5gQAAiCAoSktYBBQf4BuIIwQCACAVQVF6wiLAgJyk3BIG +AEApgqI8hEUARBECAQDwpX9Y4ZPRchgtKApBWATgS14IBAAAb40YFIUgLALolnmBAADI3ufsuLpo +1KAoBGERQHtfyEIgAADIauSgKARhEUBV3BIGAEBzfdjOqotGD4pCEBYBlPkCFQIBAED1BEW/CIsA +DhACAQCMpbYKmmmaqtmO1quLBEV/CIsA3n3ZmRcIAACGISj6SlgEDEUIBABAT16reWqpNGqJoOg7 +YRHQDbeEAQAAWwiK3hMWAdUTAgEAQGQ/9qnSqHSVUWvzFgmK5gmLgNMIgQAAgDMIipYJi4DkzAsE +AADnu1f5mMfoK0HROmEREE0IBAAAtOysoOh1vbUTFgEhBLeEAQBAr0pWGNU8b5GgKJ6wCDonBAIA +AEYnKNpGWASNEgIBAACb+vODzmEkKNpOWASVMS8QAABAGrUERZ+3z6bCI2ERFCIEAgAAanC5XLJW +F9Uyb1FNQVFrhEWQ+oOxUCgkBAIAAHaPJzIHRmcTFB0jLILaPrSFQAAAALsJio4TFkEhQiAAAKCq +MUqH1UWCojSERZD6A1coBAAAUJygKJ2/nE4AAABASqUrlgRFaaksghQfhD+1Af1QHQcAQEsERemp +LAIAAIBB1fCI+yMERXkIiwAAAIDmCYrScRsaJOYWHlrkVkoAgIHHMB08FU1QlJbKIgAAAKBZgqL0 +hEUAAABAkwRFeQiLAAAAAGaMFhSFICwCAAAAeGvEoCgEYREAAADAN6MGRSEIiwAAAGB4l8sl+TJb +fsLayEFRCCH8cEkAQJkOTo5OGAAAaY0eFIUgLAJgcCV/8VpalyAJAOB8gqJfhEUADKPmUuh32yZA +AgAoR1D0h7CIrgduBlp9DqqdM4xyHj9vv3MTACAfQdFXwiKAmcH5K4P19o9hT/vlfAQASENQ9J2w +iO4HjQZUGKyPeXxG2V/nIQCQyuVyGa5PJSh6T1iEgR0kOIcN2H2OOA8BANoiKJonLAIwYG+6vfne +Ls5BAIBlgqJlf2kCeh/oGVRyxvntvNO22gkAoE6ConUqiwAyDthDUOWRsi1xDgIAHHFWUPS63tqp +LAIoMGAXdhxrP5yDAABHCYriCYsYYuBnkIQBu/ZCmwIA4xIUbSMsAjhhwI42Ort9tTEAMApB0XbC +IoYZABoY4Vpoo120jfMQACCVWoKi1ibRFhYBGKhrD+0OANAdQdF+wiKAkwfqBusCCwAA0hIUHSMs +YqjBoAEp1Pe54LoEACAlQdFxP5xGAOebpilcLpfh9rkVKY6NUAwAID9BURrCIoBKjBQY1Rqc5Gz/ +uWULkQAA0hAUpSMsYriB4YgVHLR1rfR+ftb0eVBDW79ug/AIAGA7QVFawiJgqIH5O7UNznsOjGpo +69rb9nn7BEcAAOsERekJixhuIN77YJxjg3OD9D4/C1q93gVHAADLBEV5CIsAKhyk9xZonhV09NSG +giMAgGWConSERQCRg3QD9PaOmXMSAGAMgqJkHc0Qpin85ZQip5oHMgZZ7BmglwwhejlHS+/HSLeY +lj4nAQBqJChK2nkPIQRhEW0NisAAvbXvmslxse8AgDFcNoKiPIRFGMhCxV9+LZ+jpYMitAMAQA6j +BUUhCItoZKB4HwAZCGFwPt71v9b+joE2AQDa6sO1ZMSgKARhEUCSwTnaXfsAAPRl1KAoBGERmbSU +SEvPcY62t72CkPh20lYAANuNHBSFICyikcGOQSKtnaejEhQ5PwEAWjd6UBSCsAjAgFwbD9N22g8A +YJmg6BdhEcnlmNi6pW0G134egg7tCACQk6DoD2ERBjuAa157AgAMTVD0lbCIpFqu0FFdRM2D8NrP +z5zbJ9jQrgBAe/25lvoagqLvhEU0O5Ax0IE+OxbU8zkLANA7QdF7wiIAqiXM0MYAALkIiuYJi0im +xYmtc+4DBt+ue+0IAECdBEXLhEUYlAMAAAxstB/NBUXrhEUAVNepEAQDAJDDWUHR63prJyyiukHj +1kFi6kGlW9HgXIIiAAD9uRwERfGERQAAAEDXBEXbCIs4rMdKHNVFcM41oqoIAMDYJzVB0XbCIqqy +d6BogAkAAMCrWoKi1ibRFhYBsImqIgAA/boW+nSCov2ERVTz4VLbQNGtaAAAAG0SFB0jLKIbqhLA +9QsAQJyefxwXFB0nLIJBP0BpSy1himsCAICaCYrSEBZRxaAx1UBYdQK9XRsAANBKf/Xs8ZigKB1h +EQCnEvICAHCUoCgtYRG79Dyxdc59Bdc9AABn9ud67NMJitITFtEdVQoAAABjEBTl8cOpBZBOjl9q +eg5AhbsAAG32UWvs1wmK0lFZxKkfNLk+UFIv1+03AAAA9RIUpaWyCCCRnkNFgSkAgD7cnLOrigRF +6akswoDRvlMxt2kBAMA8QVEeKovodhB8uVwEPBTjXKvvMwAAQL9Uny6F0YKiEFQWAVT7hSxMAQCA +c40YFIWgsoiTBsSlBsGpq4umaTKAJ9t1AQAALfVHex8bjRoUhaCyCKDKL+aavngFYgAAjGbkoCgE +lUUAmwlPjlOhBwDoC+rP1Wr0oCgElUWc8IFY+kMl9fp8OYx9HZQ4/oIUAAA4h6DoF5VFACtKBoSC +IgAAatdrn1VQ9IewiKID5V4+VEx07bz3pQsAAP0QFH0lLGIIqZ+KRl9qODcERQAAtDK26o2g6Dth +EVCMwG6cL1wAAGiBoOg9E1xTbHB/9oDYRNfUSFAEAEAr/dbe+q6ConnCIoATv3BrJxQFAKBHgqJl +bkMDKGz0aiLVVAAA+m5nEhStU1nErB6fguZWNM4+/wQlAABwnrOCotf11k5lEUBmAiIAAPRjzyco +iqeyiLd6rCrKtT2qi5g7z1QSAQBAHQRF26gsAjhIIAQAgL5tvQRF26ksAjhomqYvfwAAgDrUEhS1 +Nom2yiLeDnxTqTWVvlwuBvUUuYZUHQEAUKve+6qCov2ERQAZCY4AAGihr9pbf1VQdIzb0Fj8sDjC +wBi+X18q2gAAIC9B0XHCIoYlzOIsQiMAAGrup7bcVxUUpSEsAjjxyxgAAEhDUJSOsIgsA9dWqnZU +F1HDdSc0AgBAP/UYQVFawiKASr6MAQCA7QRF6QmLACohMAIAoMY+as39VEFRHj+c+qQepLZ2a9fl +ckm6/9M0ub2t4XPj7C9C5w8AAOwjKEpHWATw5F1QUzpAEhgBAFCbe5+41n6qoCgtt6ExdFVRru12 +O1FfLpfL40+L1yUAAPRMUJSesAhgg5LBkcAIAIDa1NZHFRTlISwC2KlEaCQwAgCAc40WFIUgLBqe +W9Dybb9B/jgERgAAjDaOHKWPOmJQFIKwCCCJ0nMaAQAAeY0aFIUgLCLhQBnIdy2oLgIAoDY991FH +DopCEBa5sMk60NfGzqPWz6cc++K6AACgZqMHRSEIiwCyUG0HAMAIevshUFD0i7DIBW1QnHl/VFHg +fAIAgPoJiv744XQAyONyuQh3AIDmTdOkavqlj1fzsXKO7CMo+kplEUBjnQkBFAAApCMo+k5YNCC3 +oJXfL4N7AACgxDjm+U+r48ySBEXvCYsACnxp+zIGAIC6CIrmCYsGo6rovP0zuAfXAwD47qb0mKZk +lVFL54mgaJkJrvGFAax2MlzvAAD0QlC0TmURQAGeIAIAwNn90RJVRrX/yHhWUPS63toJiwaiMsAx +wPkEAACjEhTFExYBcAphFwDAOXJXGNXYzxMUbSMsAgAAALolKNpOWDQIv+A7Fpyv5XmLzLkEAOjH +6p+2eL7UEhS1Nom2sAgAAADojqBoP2HRAPwC4JjgXLL9AAC8U+IJaWcQFB0jLAIAAAC6ISg6TlgE +QBTzFgEA6OttcUYVuaAoDWFR59zi4diAawEAgBEIitIRFgEAABDFjzx9a7m6SFCUlrAIgFM7EAAA +cISgKD1hUcek/o4RuBYAANiitR8HBUV5CIsAAACA5gmK0hEWdcqv9I4V5JLr1ybXAgDov+Kc2UtQ +lJawCAAAAGiWoCi9H04rYpjU9iu/puAz4ZLlOpimyecNAECnfb0cBEV5qCzqkCDDMcNxBgAA0hgt +KApBWEQEv/IDJQnVAACMA2sxYlAUgrDIIItqPjgdO1wHrgcAMO6AeowaFIUgLAJoml98AAAgvZGD +ohCERRiIahuK6PXXN9VFAAD01rcbPSgKQVjk4sMxBNeENgYAIIQgKLoTFjFL5Qzgs6JvgiIAfI/A +H4KiP4RFYJCMjpT2064AAEMTFH0lLNLpx7GkUTWFlbm3xXWhPQEAchEUfScsovpBKBiU+9wYrS21 +IwBAGYKi94RFOv5UOEB2TF2baNMcbaf9AICzxzo1ERTNExYB+OJuarsEHtoMAOAoQdEyYRHNDELB +4NxniPbVVgD4nsH5cpSgaJ2wyMWGY4tjp507bR9tBADw1VlB0et6aycsAkg8QM+theq/UtsoENEm +AACxBEXxhEU0NwgFA3SfJ+/aH+0AADBHULSNsMigAMeYho5Ta4Fu6cBo1GtGWAkAME9QtJ2wiGYH +oWCA7rNl7rg4BwEACKGeoKi1SbSFRQ0PEHCsOW9wfsZxEehuP072DwD0Vxm3Dyoo2u+HUx+g/g5Q +60HR5XI5pR3v6+whaNMRBwCIJyg6RlhENwMpMCCv/3PmrPZ9Xm9rn3fOSQCAbQRFxwmLDGZpYEA8 +TZPKiMHPKddHnvOwxrZ1nQAA7CcoSkNYBFCxHqv+agiM7l6344z2Fg4B0INeftyk7XNFUJSOsAgf +6uDaPGXfagxJ5rYpxbEQCgEA5CMoSktY1BiDjXEHwn6tGe8ccp347AUAYJ2gKL2/nFYGpIDr8sx9 +9TkEAMBegqI8hEUN8cu2Ab9zwHljv9H2AADvCYrSERYBGLTbf20OANA0QVFa5iwySABci1W1hQo6 +5xwAwBaCovRUFjXC4MmAzLngHBmpTbSLcw4AIIagKA+VRQAG7FW3kYDUOQcAcKbRgqIQVBY1IcdA +yaDBOcF5A3bXn88r5xwAQBtGDIpCUFkERQZqwh0M1tO0n2vJOQcAUMqoQVEIwiIAA/YG21No5JwD +AMhp5KAoBLehVc8taAZvJc8N0h1vt/6UaWO0CQB9j13gDKMHRSGoLAJINlDn3HYfsYPqvAMASEtQ +9IuwyMACcB11dVxGCI2cgwAA6QmK/hAWVUwZZ3+Du9THdJomg0aDcRaOXS+fo85HAIC8BEVfCYsM +DnBMnX8Mc821FB65BgFokR8zaZGg6DthEaT+gvypDaBW7zqvNQRIOtUAAOcQFL0nLAJgaEtBTcog +SSAEAFAXQdE8YREAzBDwAAD0SVC0TFgEKQaU//z637lb0O7/DgAAwLkEReuERVBAzDxGAiUAAIC8 +zgqKXtdbO2ERVGItUBImAQDQRL/WE9G6O569EBTFExZBQnOBToonpKlOAgAA2EdQtI2wCAqICXEE +SgAAAOkJirYTFkEl1kKcFGFS7HIESgAAHOpzuhWNStQSFH3ePpsKj4RF0IhS1UkxyxEmAQAAtasp +KGqNsAg64nY3AACg6jFLoYozQdExwiIY7cPZ7W4AAEDHBEXHCYuAL2q63S12ewAAgPSmaWpumwVF +aQiLgM3MnwQAANRGUJSOsAjIwvxJAABj80Q0ShIUpSUsAk5j/iQA8i3Z/QAADThJREFUAOAoQVF6 +wiKgWm53AwAAlgiK8hAWAU1zuxsAABCCoCglYRHQPYESAAD0TVCUlrAIIJg/CQAAWiUoSk9YBBDB +/EkAADv6NZ6IxnM/NsO5ICjKQ1gEkOrLz+1uAADQndGCohCERQBFCZQAAGjBNE0aIYwZFIUgLAKo +jvmTAADgfKMGRSEIiwCaY/4kAKAl5i1q85iNbuSgKARhEUCX3O4GAAD7jB4UhSAsAhiW290AACjW +92ykukxQ9IuwCID3X+gV3e4Wuz0AALCXoOgPYREAu5k/CQCgL6POVyQo+kpYBEBW5k8CAKBmgqLv +hEUAnM78SQDQN09Ea+c4jUZQ9J6wCIDqmT8JAIDUBEXzhEUAdMH8SQAAB/o3g1UVCYqWCYsAGIb5 +kwAAEBStExYBwBPzJwEAI1FR9HnKemsnLAKADdzuBgDQJkFRPGERACTmdjcAePO95YloVR6TIn2j +Co67oGgbYREAnECgBABQhqBoO2ERAFTK/EkAQA4jzVNUS1D0eftsKjwSFgFAo86cP+kjXL92gP67 +OSAAQFVqCopaIywCgI6VCpQ+/r6uvkagBIB5i85t+1P6Iicdb0HRMcIiABhcqdvdBEoAQAmCouOE +RQDAonuYNH3p/Ny+do4igqCoTtbMch6B1b+XEP43OSgAEOHsuYnOqCoSFKUhLAIADoupCEoVKIV/ +VzqewiQAGJKgKB1hEQBQRLFA6d+IXzEFSgB0aKSnnH3rQwiKkhIWAQDVmAuUrtfrr05wovmTBEoA +0A9BUXrCIgCgHTEBzr+J5kcQKAGEEH7NO5OyYqX1J6KNXL2z9bwpQVCUh7AIAOhLTYGSMAkAihEU +pSMsAgDGUypQUp0EwIDOqBwTFKUlLAIAeGctxHG7GwBUQVCUnrAIAGAPt7sBwDelq4oERXkIiwAA +cnG7G9BRAGCSa2LOkx6NFhSFICwCADiXQAkAqjViUBSCsAgAoH7mTwKgcj1WFY0aFIUgLAIAaF8l +8ydNP0O4/ONwANC+kYOiEIRFAABjKBQoTT+fOtrhGvWez/9ujg80wLxFLJ0bPRk9KApBWAQAwF2p +291eO+V/X1dfI1ACoARB0S/CIgAA4qyESZfL5UtlUdLOu0AJoEo9VRUJiv4QFgEAkG7Q8E8I06OT +fYvrnEcEQSmWI0wCYPY7RFD0hbAIAIBTxYQ4KQIl1UkA6ago6puwCACA6q2FOKWqk2K2BYB2CIre +ExYBANC8UtVJscsRKNErT0Tjfh70QFA0T1gEAMAQagqUhEkA5xIULRMWAQDAfbBg/iSAWSqKxiEs +AgCADcyfBNCus4Ki1/XWTlgEAAAJud0NtjFvUf1UFKVdbwuERQAAUJjb3QDKEhRtIywCAIAKCZSo +VeonolH3se6BoGg7YREAADTK/EkAK59flQRFn7fPpsIjYREAAHTK/EnAXj1UFdUUFLVGWAQAAANz +uxvQI0HRMcIiAABgkUCJV6nnLfJEtHqOaw8ERccJiwAAgMPMnwTUQFCUhrAIAADIzvxJUKeeKroE +RekIiwAAgCq43S3xAPZpPwVk9E5QlJawCAAAaEYNt7u1GLx8/H0VGNHtvFCCovSERQAAQDdKVCe1 +WpkkMKJHgqI8hEUAAMBQSlQn1TBv0ud/t2/bkTIw8kS0Oo3choKidIRFAAAAzwO/CsKkmO2I3Zec +gRFUc90KipISFgEAAGwZlJ44b9KekCdnYNRCFYtqpQGuSUFRcsIiAACAlAPXjPMm7b29TYUR3V5v +gqIshEUAAAClB7iZAqWt74kJjKafjhdjGy0oCkFYBAAAUKV3IU6qW9y+L3PS4PDu+hgwKApBWAQA +ANCMUvMlAeMGRSEIiwAAALqR6va2PXMZnTWwtl7r7Wm9tRAWAQAADCBn1ZEgwXqtty/Coozc9QsA +AJwt5glqHwb01mu9p663NsIiAACAzsQERAb01mu9day3RsIiAACATpQKiUYc0Fuv9Y5EWJTY5+2m +EQAAgHrGKAkDolEH9NZrvaMRFgEAAHQoR0g04oDeeq13RMIiAACATuQKiEYd0Fuv9Y7qL00AAACA +Ab31Wi93wiIAAAAM6K3XenkQFgEAAGBAb73WW3C9tRMWAQAAYEBvvdZbaL0tEBYBAABgQG+91ltg +va0QFgEAAGBAb73Wm3m9LREWAQAAMEuQYL3W2856UxEWAQAA8JYBvfVabzvrTekyTdO0+U2XSwgh +hNvt5tMTAMjuer2GEELY0W2hZMfydx9xenSO9RWhFS3fLgMtKhkgffzuR11+/3dMf0plEQAAAAAP +wiIAAAAAHn5oAgAAgLG1OKcKkI/KIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwYIJrAAAAivq4 +frz9+7mJtre8/vm1SxN3z71ubl1bl5n6PUe2K3adW4/DWvsfPb5737PlmJrc/T2VRQAAABSzNHB/ +929bX3/W9u/ZzjO2/+gxOrrcrcve856alt8qlUUAAAAUsVb18zpoX3r9/d8+rh+L1Sdbq19itu91 +uXu28/73qapz9tiyjyWWneo9Z+xvb1QWAQAAkF3M7WGxAczSa3Pac9vbnu08M7RYu+3r8/b5eM3W +dj/aFjmO8xnnUQuERQAAABSzNQhZen3Mv81VK6UOZPZu52i3Qe1p99zhmYqi79yGBgAAABFShjqf +t88vy4sNsfZMon10H9fmYzozbMndHqMSFgEAANCleyBzDzS2VBWVmDfoXfVTrsqnFPv4/HevYRd9 +ERYBAABApBwhzlxodHRC59T7WGM4pIIoD2ERAAAAxWy9bWntaWdrnquL7v8dY2sIcXQ7n9d55oTd +e7Z9yzHds2+520OF1HcmuAYAACC7mKdOzT1ZbG0enVqeHrZlO1sLKO5PQXv9s8WeY5b7ONdyHtVG +ZREAAABFPM9zs6UqaOn1MQP8Ek/T2rOde+ZFamVC55T7lqo9SsxD1QuVRQAAABSz9RHzex9Jb7+O +i7l1b8utc3uqkfa8p6blt+oyTdO0+U2XSwghhNvtpgUBgOyu12sIIYQd3RZKdix/9xGnRwdcXxEA +zvbxux91+f3fMf0plUUAAAAAPJizCACA09yrxl7NVbBvef3za5cq4udeN7eurctM/Z4j2xW7ztT7 +eH/t2nGda//YZS7tz1q77DlmAL1SWQQAwCmWBvbv/m3r68/a/j3becb2x+5jDccixTLn9qXm9oc9 +Pq4fi38gRrHKopikvvQvG3vWs+fLxS8yfpEBAOb7DDH9taXX3//ter0u9pP29AvXtu91uXu2c6mP +d6RftsWWdR89FiXsOWZ7zw+ojcmaSaFIZVGqXx5S/nqzd3v37r9fZAAA1sOGd3+/9votPz6msue2 +tz3bWWvgcsaxOLq81tof4EzZK4u2/mq05XVry1/7ZWPLLw4pvlBTbXcNHQS/yAAAOfoae19/u90W +K5zvP3jN9V9S9lf2budaFXlpe6uacrRnquW11P4AZ8paWbT1V6PUy6/h1wO/yPjCBQD6kzNcWqrk +fve61z9792duOTX05e7bkONHyL3tD9CzIreh5f6CWftlo9aORMntzn1Puy9XAKBmr2HDliqSEkHK +7XYTWpx8fmh/gD9+1LhRZ06SfOQLodQEhEe+BN+VYKdc9mtbqCoCAHqVo5/zroJmy5QKqfclV9+x +tr7snvYH6NmPkXe+9nCn1Q6T0AgAiO2LbekjrD3tLKav8lwtErvuPU/KPbKdc/2qVo5diW0+crtd +D+0PkNtfNW7UvQz0tRz0zKdb7Nnu5+2v5YumxPbMlfECALz2tbY+DGTtCbO1PBxky3a21E86eiy2 +PiE4VT+9l/YHKKVIZdHR0s21JyDs/WWjhvmM/CIDAIzouX+3pSpo6fUxfbsSc2nu2c49fdaUUzds +DWy27mOq45dif1K1P0DPslYWbf3VKPXya3uKQ6rt9osMANCDrQ/7qPmhJr3u17uK8b3bnGo/j94F +0Op5BVDSZZqmafObLpdNH55rQcJrBcrWx83HLv/19ak+/Pc+Qn7rdqfc19flbA1+UuwLAGz9rt3R +baFkx/J3H/F+lD59/wPA6T5+96Muv/87pj9VZM6iFGn93mXU8uQGv8gAAAAALShSWQQAcITKokY6 +liqLAKA6eyqLfmg2AADoj2kCANhLWAQAAB0SBgGwl7BohV9kAAAAgJEIi1YIgwAAAICRCIsAAMji +Y6VCGwCo01+aAAAAAIA7lUUAACR10QQA0PZ3+TRN0+Y3XXQBAIDydnRbKNmx1EcEgC76UyqLAAAo +1vkEAOq3KyzSEQAAAADokwmuAQAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA +AA/CIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA +AA/CIgAAAAAehEUAAAAAPAiLAAAAAHgQFgEAAADwICwCAAAA4EFYBAAAAMCDsAgAAACAB2ERAAAA +AA/CIgAAAAAe/g/10lQlA3JSSwAAAABJRU5ErkJggg== diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml index afc8a0dd2601..cea6fd3ed428 100644 --- a/Documentation/DocBook/media/v4l/biblio.xml +++ b/Documentation/DocBook/media/v4l/biblio.xml @@ -178,11 +178,3 @@ in the frequency range from 87,5 to 108,0 MHz</title> </biblioentry> </bibliography> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml index a86f7a045529..c79278acfb0e 100644 --- a/Documentation/DocBook/media/v4l/common.xml +++ b/Documentation/DocBook/media/v4l/common.xml @@ -1168,6 +1168,8 @@ dheight = format.fmt.pix.height; </section> </section> + &sub-selection-api; + <section id="streaming-par"> <title>Streaming Parameters</title> @@ -1195,11 +1197,3 @@ separate parameters for input and output devices.</para> <para>These ioctls are optional, drivers need not implement them. If so, they return the &EINVAL;.</para> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index b68698f96e7f..c736380b4647 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -1082,7 +1082,7 @@ until the time in the timestamp field has arrived. I would like to follow SGI's lead, and adopt a multimedia timestamping system like their UST (Unadjusted System Time). See http://web.archive.org/web/*/http://reality.sgi.com -/cpirazzi_engr/lg/time/intro.html. +/cpirazzi_engr/lg/time/intro.html. UST uses timestamps that are 64-bit signed integers (not struct timeval's) and given in nanosecond units. The UST clock starts at zero when the system is booted and runs continuously and @@ -2376,6 +2376,23 @@ that used it. It was originally scheduled for removal in 2.6.35. <listitem> <para>V4L2_CTRL_FLAG_VOLATILE was added to signal volatile controls to userspace.</para> </listitem> + <listitem> + <para>Add selection API for extended control over cropping and +composing. Does not affect the compatibility of current drivers and +applications. See <link linkend="selection-api"> selection API </link> for +details.</para> + </listitem> + </orderedlist> + </section> + + <section> + <title>V4L2 in Linux 3.3</title> + <orderedlist> + <listitem> + <para>Added <constant>V4L2_CID_ALPHA_COMPONENT</constant> control + to the <link linkend="control">User controls class</link>. + </para> + </listitem> </orderedlist> </section> @@ -2489,6 +2506,9 @@ ioctls.</para> <listitem> <para>&VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls.</para> </listitem> + <listitem> + <para>Selection API. <xref linkend="selection-api" /></para> + </listitem> </itemizedlist> </section> @@ -2507,11 +2527,3 @@ interfaces and should not be implemented in new drivers.</para> </itemizedlist> </section> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 3bc5ee8b2c74..a1be37897ad7 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -324,12 +324,6 @@ minimum value disables backlight compensation.</entry> (usually a microscope).</entry> </row> <row> - <entry><constant>V4L2_CID_LASTP1</constant></entry> - <entry></entry> - <entry>End of the predefined control IDs (currently -<constant>V4L2_CID_ILLUMINATORS_2</constant> + 1).</entry> - </row> - <row> <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_CAPTURE</constant></entry> <entry>integer</entry> <entry>This is a read-only control that can be read by the application @@ -345,6 +339,25 @@ and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS. The value is the minimum number of OUTPUT buffers that is necessary for hardware to work.</entry> </row> + <row id="v4l2-alpha-component"> + <entry><constant>V4L2_CID_ALPHA_COMPONENT</constant></entry> + <entry>integer</entry> + <entry> Sets the alpha color component on the capture device or on + the capture buffer queue of a mem-to-mem device. When a mem-to-mem + device produces frame format that includes an alpha component + (e.g. <link linkend="rgb-formats">packed RGB image formats</link>) + and the alpha value is not defined by the mem-to-mem input data + this control lets you select the alpha component value of all + pixels. It is applicable to any pixel format that contains an alpha + component. + </entry> + </row> + <row> + <entry><constant>V4L2_CID_LASTP1</constant></entry> + <entry></entry> + <entry>End of the predefined control IDs (currently + <constant>V4L2_CID_ALPHA_COMPONENT</constant> + 1).</entry> + </row> <row> <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry> <entry></entry> @@ -3329,6 +3342,16 @@ interface and may change in the future.</para> <entry>The short circuit protection of the flash controller has been triggered.</entry> </row> + <row> + <entry><constant>V4L2_FLASH_FAULT_OVER_CURRENT</constant></entry> + <entry>Current in the LED power supply has exceeded the limit + specific to the flash controller.</entry> + </row> + <row> + <entry><constant>V4L2_FLASH_FAULT_INDICATOR</constant></entry> + <entry>The flash controller has detected a short or open + circuit condition on the indicator LED.</entry> + </row> </tbody> </entrytbl> </row> @@ -3357,11 +3380,3 @@ interface and may change in the future.</para> </section> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "common.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-capture.xml b/Documentation/DocBook/media/v4l/dev-capture.xml index 2237c661f26a..e1c5f9406d6a 100644 --- a/Documentation/DocBook/media/v4l/dev-capture.xml +++ b/Documentation/DocBook/media/v4l/dev-capture.xml @@ -108,11 +108,3 @@ linkend="mmap">memory mapping</link> or <link linkend="userp">user pointer</link>) I/O. See <xref linkend="io" /> for details.</para> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-codec.xml b/Documentation/DocBook/media/v4l/dev-codec.xml index 6e156dc45b94..dca0ecd54dc6 100644 --- a/Documentation/DocBook/media/v4l/dev-codec.xml +++ b/Documentation/DocBook/media/v4l/dev-codec.xml @@ -16,11 +16,3 @@ Applications send data to be converted to the driver through a I/O.</para> <para>[to do]</para> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-effect.xml b/Documentation/DocBook/media/v4l/dev-effect.xml index 9c243beba0e6..2350a67c0710 100644 --- a/Documentation/DocBook/media/v4l/dev-effect.xml +++ b/Documentation/DocBook/media/v4l/dev-effect.xml @@ -15,11 +15,3 @@ receive the result data either with &func-read; and &func-write; functions, or through the streaming I/O mechanism.</para> <para>[to do]</para> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-event.xml b/Documentation/DocBook/media/v4l/dev-event.xml index f14ae3fe107c..19f4becfae34 100644 --- a/Documentation/DocBook/media/v4l/dev-event.xml +++ b/Documentation/DocBook/media/v4l/dev-event.xml @@ -41,11 +41,3 @@ intermediate step leading up to that information. See the documentation for the event you want to subscribe to whether this is applicable for that event or not.</para> </listitem> </orderedlist></para> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-osd.xml b/Documentation/DocBook/media/v4l/dev-osd.xml index c9a68a2ccd33..479d9433869a 100644 --- a/Documentation/DocBook/media/v4l/dev-osd.xml +++ b/Documentation/DocBook/media/v4l/dev-osd.xml @@ -154,11 +154,3 @@ data flow. For more information see <xref linkend="crop" />.</para> however the framebuffer interface of the driver may support the <constant>FBIOBLANK</constant> ioctl.</para> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-output.xml b/Documentation/DocBook/media/v4l/dev-output.xml index 919e22c53854..9130a3dc7880 100644 --- a/Documentation/DocBook/media/v4l/dev-output.xml +++ b/Documentation/DocBook/media/v4l/dev-output.xml @@ -104,11 +104,3 @@ linkend="mmap">memory mapping</link> or <link linkend="userp">user pointer</link>) I/O. See <xref linkend="io" /> for details.</para> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-overlay.xml b/Documentation/DocBook/media/v4l/dev-overlay.xml index 92513cf79150..40d1d7681439 100644 --- a/Documentation/DocBook/media/v4l/dev-overlay.xml +++ b/Documentation/DocBook/media/v4l/dev-overlay.xml @@ -369,11 +369,3 @@ reasons. <!-- video4linux-list@redhat.com on 22 Oct 2002 subject <para>To start or stop the frame buffer overlay applications call the &VIDIOC-OVERLAY; ioctl.</para> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-radio.xml b/Documentation/DocBook/media/v4l/dev-radio.xml index 73aa90b45b34..3e6ac73b36af 100644 --- a/Documentation/DocBook/media/v4l/dev-radio.xml +++ b/Documentation/DocBook/media/v4l/dev-radio.xml @@ -47,11 +47,3 @@ depending on the selected frequency. The &VIDIOC-G-TUNER; or &VIDIOC-G-MODULATOR; ioctl reports the supported frequency range.</para> </section> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-raw-vbi.xml b/Documentation/DocBook/media/v4l/dev-raw-vbi.xml index c5a70bdfaf27..b788c72c885e 100644 --- a/Documentation/DocBook/media/v4l/dev-raw-vbi.xml +++ b/Documentation/DocBook/media/v4l/dev-raw-vbi.xml @@ -337,11 +337,3 @@ an &EBUSY; if the required hardware resources are temporarily unavailable, for example the device is already in use by another process.</para> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-rds.xml b/Documentation/DocBook/media/v4l/dev-rds.xml index 2427f54397e7..38883a419e65 100644 --- a/Documentation/DocBook/media/v4l/dev-rds.xml +++ b/Documentation/DocBook/media/v4l/dev-rds.xml @@ -29,10 +29,10 @@ returned by the &VIDIOC-QUERYCAP; ioctl. Any tuner that supports RDS will set the <constant>V4L2_TUNER_CAP_RDS</constant> flag in the <structfield>capability</structfield> field of &v4l2-tuner;. If the driver only passes RDS blocks without interpreting the data -the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be +the <constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant> flag has to be set, see <link linkend="reading-rds-data">Reading RDS data</link>. For future use the -flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> has also been +flag <constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant> has also been defined. However, a driver for a radio tuner with this capability does not yet exist, so if you are planning to write such a driver you should discuss this on the linux-media mailing list: &v4l-ml;.</para> @@ -52,9 +52,9 @@ field of &v4l2-modulator;. In order to enable the RDS transmission one must set the <constant>V4L2_TUNER_SUB_RDS</constant> bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;. If the driver only passes RDS blocks without interpreting the data -the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be set. If the +the <constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant> flag has to be set. If the tuner is capable of handling RDS entities like program identification codes and radio -text, the flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> should be set, +text, the flag <constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant> should be set, see <link linkend="writing-rds-data">Writing RDS data</link> and <link linkend="fm-tx-controls">FM Transmitter Control Reference</link>.</para> </section> @@ -194,11 +194,3 @@ as follows:</para> </tgroup> </table> </section> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml index 69e789fa7f7b..548f8ea28dee 100644 --- a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml +++ b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml @@ -697,12 +697,3 @@ Sliced VBI services</link> for a description of the line payload.</entry> </section> </section> - - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/dev-teletext.xml b/Documentation/DocBook/media/v4l/dev-teletext.xml index 414b1cfff9f4..bd21c64d70f3 100644 --- a/Documentation/DocBook/media/v4l/dev-teletext.xml +++ b/Documentation/DocBook/media/v4l/dev-teletext.xml @@ -27,11 +27,3 @@ kernel 2.6.37.</para> <para>Modern devices all use the <link linkend="raw-vbi">raw</link> or <link linkend="sliced">sliced</link> VBI API.</para> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/driver.xml b/Documentation/DocBook/media/v4l/driver.xml index 1f7eea5c4ec3..eacafe312cd2 100644 --- a/Documentation/DocBook/media/v4l/driver.xml +++ b/Documentation/DocBook/media/v4l/driver.xml @@ -198,11 +198,3 @@ devices with the videodev module.</para> <para>to do</para> </section> --> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-close.xml b/Documentation/DocBook/media/v4l/func-close.xml index dfb41cbbbec3..232920d2f3c6 100644 --- a/Documentation/DocBook/media/v4l/func-close.xml +++ b/Documentation/DocBook/media/v4l/func-close.xml @@ -60,11 +60,3 @@ descriptor.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-ioctl.xml b/Documentation/DocBook/media/v4l/func-ioctl.xml index 2de64be706f5..4394184a1a6d 100644 --- a/Documentation/DocBook/media/v4l/func-ioctl.xml +++ b/Documentation/DocBook/media/v4l/func-ioctl.xml @@ -69,11 +69,3 @@ their respective function and parameters are specified in <xref the parameter remains unmodified.</para> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-mmap.xml b/Documentation/DocBook/media/v4l/func-mmap.xml index 786732b64bbd..f31ad71bf301 100644 --- a/Documentation/DocBook/media/v4l/func-mmap.xml +++ b/Documentation/DocBook/media/v4l/func-mmap.xml @@ -181,11 +181,3 @@ complete the request.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-munmap.xml b/Documentation/DocBook/media/v4l/func-munmap.xml index e2c4190f9bb6..860d49ca54a5 100644 --- a/Documentation/DocBook/media/v4l/func-munmap.xml +++ b/Documentation/DocBook/media/v4l/func-munmap.xml @@ -74,11 +74,3 @@ mapped yet.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-open.xml b/Documentation/DocBook/media/v4l/func-open.xml index 7595d07a8c72..cf64e207c3ee 100644 --- a/Documentation/DocBook/media/v4l/func-open.xml +++ b/Documentation/DocBook/media/v4l/func-open.xml @@ -111,11 +111,3 @@ system has been reached.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-poll.xml b/Documentation/DocBook/media/v4l/func-poll.xml index ec3c718f5963..85cad8bff5ba 100644 --- a/Documentation/DocBook/media/v4l/func-poll.xml +++ b/Documentation/DocBook/media/v4l/func-poll.xml @@ -117,11 +117,3 @@ than <constant>OPEN_MAX</constant>.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-read.xml b/Documentation/DocBook/media/v4l/func-read.xml index a5089bf8873d..e218bbfbd362 100644 --- a/Documentation/DocBook/media/v4l/func-read.xml +++ b/Documentation/DocBook/media/v4l/func-read.xml @@ -179,11 +179,3 @@ type of device.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-select.xml b/Documentation/DocBook/media/v4l/func-select.xml index b6713623181f..e12a60d9bd85 100644 --- a/Documentation/DocBook/media/v4l/func-select.xml +++ b/Documentation/DocBook/media/v4l/func-select.xml @@ -128,11 +128,3 @@ zero or greater than <constant>FD_SETSIZE</constant>.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/func-write.xml b/Documentation/DocBook/media/v4l/func-write.xml index 2c09c09371c3..575207885726 100644 --- a/Documentation/DocBook/media/v4l/func-write.xml +++ b/Documentation/DocBook/media/v4l/func-write.xml @@ -126,11 +126,3 @@ type of device.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 3f47df1aa54a..b815929b5bba 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -1282,11 +1282,3 @@ line, top field first. The bottom field is transmitted first.</entry> </mediaobject> </figure> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/libv4l.xml b/Documentation/DocBook/media/v4l/libv4l.xml index 3cb10ec51929..d3b71e20003c 100644 --- a/Documentation/DocBook/media/v4l/libv4l.xml +++ b/Documentation/DocBook/media/v4l/libv4l.xml @@ -158,10 +158,3 @@ still don't use libv4l.</para> </section> </section> -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/pixfmt-grey.xml b/Documentation/DocBook/media/v4l/pixfmt-grey.xml index 3b72bc6b2de7..bee970d3f76d 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-grey.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-grey.xml @@ -60,11 +60,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-m420.xml b/Documentation/DocBook/media/v4l/pixfmt-m420.xml index ce4bc019e5c0..aadae92c5d04 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-m420.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-m420.xml @@ -137,11 +137,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12.xml index 873f67035181..84dd4fd7cb80 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-nv12.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-nv12.xml @@ -141,11 +141,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml index c9e166d9ded8..3fd3ce5df270 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml @@ -144,11 +144,3 @@ CbCr plane has as many pad bytes after its rows.</para> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml index 7a2855a526c1..2f82b1da8dfe 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml @@ -64,11 +64,3 @@ layout of macroblocks</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv16.xml b/Documentation/DocBook/media/v4l/pixfmt-nv16.xml index 26094035fc04..8ae1f8a810d0 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-nv16.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-nv16.xml @@ -164,11 +164,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv24.xml b/Documentation/DocBook/media/v4l/pixfmt-nv24.xml new file mode 100644 index 000000000000..fb255f2ca9dd --- /dev/null +++ b/Documentation/DocBook/media/v4l/pixfmt-nv24.xml @@ -0,0 +1,121 @@ + <refentry> + <refmeta> + <refentrytitle>V4L2_PIX_FMT_NV24 ('NV24'), V4L2_PIX_FMT_NV42 ('NV42')</refentrytitle> + &manvol; + </refmeta> + <refnamediv> + <refname id="V4L2-PIX-FMT-NV24"><constant>V4L2_PIX_FMT_NV24</constant></refname> + <refname id="V4L2-PIX-FMT-NV42"><constant>V4L2_PIX_FMT_NV42</constant></refname> + <refpurpose>Formats with full horizontal and vertical +chroma resolutions, also known as YUV 4:4:4. One luminance and one +chrominance plane with alternating chroma samples as opposed to +<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose> + </refnamediv> + <refsect1> + <title>Description</title> + + <para>These are two-plane versions of the YUV 4:4:4 format. The three + components are separated into two sub-images or planes. The Y plane is + first, with each Y sample stored in one byte per pixel. For + <constant>V4L2_PIX_FMT_NV24</constant>, a combined CbCr plane + immediately follows the Y plane in memory. The CbCr plane has the same + width and height, in pixels, as the Y plane (and the image). Each line + contains one CbCr pair per pixel, with each Cb and Cr sample stored in + one byte. <constant>V4L2_PIX_FMT_NV42</constant> is the same except that + the Cb and Cr samples are swapped, the CrCb plane starts with a Cr + sample.</para> + + <para>If the Y plane has pad bytes after each row, then the CbCr plane + has twice as many pad bytes after its rows.</para> + + <example> + <title><constant>V4L2_PIX_FMT_NV24</constant> 4 × 4 +pixel image</title> + + <formalpara> + <title>Byte Order.</title> + <para>Each cell is one byte. + <informaltable frame="none"> + <tgroup cols="9" align="center"> + <colspec align="left" colwidth="2*" /> + <tbody valign="top"> + <row> + <entry>start + 0:</entry> + <entry>Y'<subscript>00</subscript></entry> + <entry>Y'<subscript>01</subscript></entry> + <entry>Y'<subscript>02</subscript></entry> + <entry>Y'<subscript>03</subscript></entry> + </row> + <row> + <entry>start + 4:</entry> + <entry>Y'<subscript>10</subscript></entry> + <entry>Y'<subscript>11</subscript></entry> + <entry>Y'<subscript>12</subscript></entry> + <entry>Y'<subscript>13</subscript></entry> + </row> + <row> + <entry>start + 8:</entry> + <entry>Y'<subscript>20</subscript></entry> + <entry>Y'<subscript>21</subscript></entry> + <entry>Y'<subscript>22</subscript></entry> + <entry>Y'<subscript>23</subscript></entry> + </row> + <row> + <entry>start + 12:</entry> + <entry>Y'<subscript>30</subscript></entry> + <entry>Y'<subscript>31</subscript></entry> + <entry>Y'<subscript>32</subscript></entry> + <entry>Y'<subscript>33</subscript></entry> + </row> + <row> + <entry>start + 16:</entry> + <entry>Cb<subscript>00</subscript></entry> + <entry>Cr<subscript>00</subscript></entry> + <entry>Cb<subscript>01</subscript></entry> + <entry>Cr<subscript>01</subscript></entry> + <entry>Cb<subscript>02</subscript></entry> + <entry>Cr<subscript>02</subscript></entry> + <entry>Cb<subscript>03</subscript></entry> + <entry>Cr<subscript>03</subscript></entry> + </row> + <row> + <entry>start + 24:</entry> + <entry>Cb<subscript>10</subscript></entry> + <entry>Cr<subscript>10</subscript></entry> + <entry>Cb<subscript>11</subscript></entry> + <entry>Cr<subscript>11</subscript></entry> + <entry>Cb<subscript>12</subscript></entry> + <entry>Cr<subscript>12</subscript></entry> + <entry>Cb<subscript>13</subscript></entry> + <entry>Cr<subscript>13</subscript></entry> + </row> + <row> + <entry>start + 32:</entry> + <entry>Cb<subscript>20</subscript></entry> + <entry>Cr<subscript>20</subscript></entry> + <entry>Cb<subscript>21</subscript></entry> + <entry>Cr<subscript>21</subscript></entry> + <entry>Cb<subscript>22</subscript></entry> + <entry>Cr<subscript>22</subscript></entry> + <entry>Cb<subscript>23</subscript></entry> + <entry>Cr<subscript>23</subscript></entry> + </row> + <row> + <entry>start + 40:</entry> + <entry>Cb<subscript>30</subscript></entry> + <entry>Cr<subscript>30</subscript></entry> + <entry>Cb<subscript>31</subscript></entry> + <entry>Cr<subscript>31</subscript></entry> + <entry>Cb<subscript>32</subscript></entry> + <entry>Cr<subscript>32</subscript></entry> + <entry>Cb<subscript>33</subscript></entry> + <entry>Cr<subscript>33</subscript></entry> + </row> + </tbody> + </tgroup> + </informaltable> + </para> + </formalpara> + </example> + </refsect1> + </refentry> diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml index 4db272b8a0d3..166c8d65e4f7 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml @@ -428,8 +428,11 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para> <para>Bit 7 is the most significant bit. The value of a = alpha bits is undefined when reading from the driver, ignored when writing to the driver, except when alpha blending has been negotiated for a -<link linkend="overlay">Video Overlay</link> or <link -linkend="osd">Video Output Overlay</link>.</para> +<link linkend="overlay">Video Overlay</link> or <link linkend="osd"> +Video Output Overlay</link> or when alpha component has been configured +for a <link linkend="capture">Video Capture</link> by means of <link +linkend="v4l2-alpha-component"> <constant>V4L2_CID_ALPHA_COMPONENT +</constant> </link> control.</para> <example> <title><constant>V4L2_PIX_FMT_BGR24</constant> 4 × 4 pixel @@ -930,11 +933,3 @@ See &v4l-dvb; for access instructions.</para> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml index 3cab5d0ca75d..33fa5a47a865 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml @@ -234,11 +234,3 @@ linkend="osd">Video Output Overlay</link>.</para> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml b/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml index 519a9efbac10..6494b05d84a1 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml @@ -81,11 +81,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml b/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml index 5fe84ecc2ebe..5eaf2b42d3f7 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml @@ -65,11 +65,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml index d67a472b0880..fee65dca79c5 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml @@ -65,11 +65,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml index 0cdf13b8ac1c..19727ab4c757 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml @@ -65,11 +65,3 @@ columns and rows.</para> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml b/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml index 816c8d467c16..b1f6801a17ff 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml @@ -118,11 +118,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml b/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml index 61f12a5e68d9..82803408b389 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml @@ -118,11 +118,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-y16.xml b/Documentation/DocBook/media/v4l/pixfmt-y16.xml index d58404015078..ff4f727d5624 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-y16.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-y16.xml @@ -79,11 +79,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-y41p.xml b/Documentation/DocBook/media/v4l/pixfmt-y41p.xml index 73c8536efb05..98dcb91d2917 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-y41p.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-y41p.xml @@ -147,11 +147,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml index 8eb4a193d770..0869dce5f92c 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml @@ -131,11 +131,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml index 00e0960a9869..086dc731bf02 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml @@ -145,11 +145,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml index 42d7de5e456d..48649fac1596 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml @@ -147,11 +147,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml index f5d8f57495c8..9957863daf18 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml @@ -152,11 +152,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml index 4348bd9f0d01..4ce6463fe0a5 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml @@ -151,11 +151,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml b/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml index bdb2ffacbbcc..58384092251a 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml @@ -118,11 +118,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml b/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml index 40d17ae39dde..bfffdc76d3da 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml @@ -118,11 +118,3 @@ pixel image</title> </example> </refsect1> </refentry> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "pixfmt.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 2ff6b7776d7f..31eaae2469f9 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -714,6 +714,7 @@ information.</para> &sub-nv12m; &sub-nv12mt; &sub-nv16; + &sub-nv24; &sub-m420; </section> @@ -890,6 +891,11 @@ kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm <entry>'M310'</entry> <entry>Compressed BGGR Bayer format used by the gspca driver.</entry> </row> + <row id="V4L2-PIX-FMT-JL2005BCD"> + <entry><constant>V4L2_PIX_FMT_JL2005BCD</constant></entry> + <entry>'JL20'</entry> + <entry>JPEG compressed RGGB Bayer format used by the gspca driver.</entry> + </row> <row id="V4L2-PIX-FMT-OV511"> <entry><constant>V4L2_PIX_FMT_OV511</constant></entry> <entry>'O511'</entry> @@ -997,11 +1003,3 @@ the other bits are set to 0.</entry> </tgroup> </table> </section> - - <!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: - --> diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml new file mode 100644 index 000000000000..2f0bdb4d5551 --- /dev/null +++ b/Documentation/DocBook/media/v4l/selection-api.xml @@ -0,0 +1,321 @@ +<section id="selection-api"> + + <title>Experimental API for cropping, composing and scaling</title> + + <note> + <title>Experimental</title> + + <para>This is an <link linkend="experimental">experimental</link> +interface and may change in the future.</para> + </note> + + <section> + <title>Introduction</title> + +<para>Some video capture devices can sample a subsection of a picture and +shrink or enlarge it to an image of arbitrary size. Next, the devices can +insert the image into larger one. Some video output devices can crop part of an +input image, scale it up or down and insert it at an arbitrary scan line and +horizontal offset into a video signal. We call these abilities cropping, +scaling and composing.</para> + +<para>On a video <emphasis>capture</emphasis> device the source is a video +signal, and the cropping target determine the area actually sampled. The sink +is an image stored in a memory buffer. The composing area specifies which part +of the buffer is actually written to by the hardware. </para> + +<para>On a video <emphasis>output</emphasis> device the source is an image in a +memory buffer, and the cropping target is a part of an image to be shown on a +display. The sink is the display or the graphics screen. The application may +select the part of display where the image should be displayed. The size and +position of such a window is controlled by the compose target.</para> + +<para>Rectangles for all cropping and composing targets are defined even if the +device does supports neither cropping nor composing. Their size and position +will be fixed in such a case. If the device does not support scaling then the +cropping and composing rectangles have the same size.</para> + + </section> + + <section> + <title>Selection targets</title> + + <figure id="sel-targets-capture"> + <title>Cropping and composing targets</title> + <mediaobject> + <imageobject> + <imagedata fileref="selection.png" format="PNG" /> + </imageobject> + <textobject> + <phrase>Targets used by a cropping, composing and scaling + process</phrase> + </textobject> + </mediaobject> + </figure> + </section> + + <section> + + <title>Configuration</title> + +<para>Applications can use the <link linkend="vidioc-g-selection">selection +API</link> to select an area in a video signal or a buffer, and to query for +default settings and hardware limits.</para> + +<para>Video hardware can have various cropping, composing and scaling +limitations. It may only scale up or down, support only discrete scaling +factors, or have different scaling abilities in the horizontal and vertical +directions. Also it may not support scaling at all. At the same time the +cropping/composing rectangles may have to be aligned, and both the source and +the sink may have arbitrary upper and lower size limits. Therefore, as usual, +drivers are expected to adjust the requested parameters and return the actual +values selected. An application can control the rounding behaviour using <link +linkend="v4l2-sel-flags"> constraint flags </link>.</para> + + <section> + + <title>Configuration of video capture</title> + +<para>See figure <xref linkend="sel-targets-capture" /> for examples of the +selection targets available for a video capture device. It is recommended to +configure the cropping targets before to the composing targets.</para> + +<para>The range of coordinates of the top left corner, width and height of +areas that can be sampled is given by the <constant> V4L2_SEL_TGT_CROP_BOUNDS +</constant> target. It is recommended for the driver developers to put the +top/left corner at position <constant> (0,0) </constant>. The rectangle's +coordinates are expressed in pixels.</para> + +<para>The top left corner, width and height of the source rectangle, that is +the area actually sampled, is given by the <constant> V4L2_SEL_TGT_CROP_ACTIVE +</constant> target. It uses the same coordinate system as <constant> +V4L2_SEL_TGT_CROP_BOUNDS </constant>. The active cropping area must lie +completely inside the capture boundaries. The driver may further adjust the +requested size and/or position according to hardware limitations.</para> + +<para>Each capture device has a default source rectangle, given by the +<constant> V4L2_SEL_TGT_CROP_DEFAULT </constant> target. This rectangle shall +over what the driver writer considers the complete picture. Drivers shall set +the active crop rectangle to the default when the driver is first loaded, but +not later.</para> + +<para>The composing targets refer to a memory buffer. The limits of composing +coordinates are obtained using <constant> V4L2_SEL_TGT_COMPOSE_BOUNDS +</constant>. All coordinates are expressed in pixels. The rectangle's top/left +corner must be located at position <constant> (0,0) </constant>. The width and +height are equal to the image size set by <constant> VIDIOC_S_FMT </constant>. +</para> + +<para>The part of a buffer into which the image is inserted by the hardware is +controlled by the <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target. +The rectangle's coordinates are also expressed in the same coordinate system as +the bounds rectangle. The composing rectangle must lie completely inside bounds +rectangle. The driver must adjust the composing rectangle to fit to the +bounding limits. Moreover, the driver can perform other adjustments according +to hardware limitations. The application can control rounding behaviour using +<link linkend="v4l2-sel-flags"> constraint flags </link>.</para> + +<para>For capture devices the default composing rectangle is queried using +<constant> V4L2_SEL_TGT_COMPOSE_DEFAULT </constant>. It is usually equal to the +bounding rectangle.</para> + +<para>The part of a buffer that is modified by the hardware is given by +<constant> V4L2_SEL_TGT_COMPOSE_PADDED </constant>. It contains all pixels +defined using <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> plus all +padding data modified by hardware during insertion process. All pixels outside +this rectangle <emphasis>must not</emphasis> be changed by the hardware. The +content of pixels that lie inside the padded area but outside active area is +undefined. The application can use the padded and active rectangles to detect +where the rubbish pixels are located and remove them if needed.</para> + + </section> + + <section> + + <title>Configuration of video output</title> + +<para>For output devices targets and ioctls are used similarly to the video +capture case. The <emphasis> composing </emphasis> rectangle refers to the +insertion of an image into a video signal. The cropping rectangles refer to a +memory buffer. It is recommended to configure the composing targets before to +the cropping targets.</para> + +<para>The cropping targets refer to the memory buffer that contains an image to +be inserted into a video signal or graphical screen. The limits of cropping +coordinates are obtained using <constant> V4L2_SEL_TGT_CROP_BOUNDS </constant>. +All coordinates are expressed in pixels. The top/left corner is always point +<constant> (0,0) </constant>. The width and height is equal to the image size +specified using <constant> VIDIOC_S_FMT </constant> ioctl.</para> + +<para>The top left corner, width and height of the source rectangle, that is +the area from which image date are processed by the hardware, is given by the +<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant>. Its coordinates are expressed +in in the same coordinate system as the bounds rectangle. The active cropping +area must lie completely inside the crop boundaries and the driver may further +adjust the requested size and/or position according to hardware +limitations.</para> + +<para>For output devices the default cropping rectangle is queried using +<constant> V4L2_SEL_TGT_CROP_DEFAULT </constant>. It is usually equal to the +bounding rectangle.</para> + +<para>The part of a video signal or graphics display where the image is +inserted by the hardware is controlled by <constant> +V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target. The rectangle's coordinates +are expressed in pixels. The composing rectangle must lie completely inside the +bounds rectangle. The driver must adjust the area to fit to the bounding +limits. Moreover, the driver can perform other adjustments according to +hardware limitations. </para> + +<para>The device has a default composing rectangle, given by the <constant> +V4L2_SEL_TGT_COMPOSE_DEFAULT </constant> target. This rectangle shall cover what +the driver writer considers the complete picture. It is recommended for the +driver developers to put the top/left corner at position <constant> (0,0) +</constant>. Drivers shall set the active composing rectangle to the default +one when the driver is first loaded.</para> + +<para>The devices may introduce additional content to video signal other than +an image from memory buffers. It includes borders around an image. However, +such a padded area is driver-dependent feature not covered by this document. +Driver developers are encouraged to keep padded rectangle equal to active one. +The padded target is accessed by the <constant> V4L2_SEL_TGT_COMPOSE_PADDED +</constant> identifier. It must contain all pixels from the <constant> +V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> target.</para> + + </section> + + <section> + + <title>Scaling control.</title> + +<para>An application can detect if scaling is performed by comparing the width +and the height of rectangles obtained using <constant> V4L2_SEL_TGT_CROP_ACTIVE +</constant> and <constant> V4L2_SEL_TGT_COMPOSE_ACTIVE </constant> targets. If +these are not equal then the scaling is applied. The application can compute +the scaling ratios using these values.</para> + + </section> + + </section> + + <section> + + <title>Comparison with old cropping API.</title> + +<para>The selection API was introduced to cope with deficiencies of previous +<link linkend="crop"> API </link>, that was designed to control simple capture +devices. Later the cropping API was adopted by video output drivers. The ioctls +are used to select a part of the display were the video signal is inserted. It +should be considered as an API abuse because the described operation is +actually the composing. The selection API makes a clear distinction between +composing and cropping operations by setting the appropriate targets. The V4L2 +API lacks any support for composing to and cropping from an image inside a +memory buffer. The application could configure a capture device to fill only a +part of an image by abusing V4L2 API. Cropping a smaller image from a larger +one is achieved by setting the field <structfield> +&v4l2-pix-format;::bytesperline </structfield>. Introducing an image offsets +could be done by modifying field <structfield> &v4l2-buffer;::m:userptr +</structfield> before calling <constant> VIDIOC_QBUF </constant>. Those +operations should be avoided because they are not portable (endianness), and do +not work for macroblock and Bayer formats and mmap buffers. The selection API +deals with configuration of buffer cropping/composing in a clear, intuitive and +portable way. Next, with the selection API the concepts of the padded target +and constraints flags are introduced. Finally, <structname> &v4l2-crop; +</structname> and <structname> &v4l2-cropcap; </structname> have no reserved +fields. Therefore there is no way to extend their functionality. The new +<structname> &v4l2-selection; </structname> provides a lot of place for future +extensions. Driver developers are encouraged to implement only selection API. +The former cropping API would be simulated using the new one. </para> + + </section> + + <section> + <title>Examples</title> + <example> + <title>Resetting the cropping parameters</title> + + <para>(A video capture device is assumed; change <constant> +V4L2_BUF_TYPE_VIDEO_CAPTURE </constant> for other devices; change target to +<constant> V4L2_SEL_TGT_COMPOSE_* </constant> family to configure composing +area)</para> + + <programlisting> + + &v4l2-selection; sel = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .target = V4L2_SEL_TGT_CROP_DEFAULT, + }; + ret = ioctl(fd, &VIDIOC-G-SELECTION;, &sel); + if (ret) + exit(-1); + sel.target = V4L2_SEL_TGT_CROP_ACTIVE; + ret = ioctl(fd, &VIDIOC-S-SELECTION;, &sel); + if (ret) + exit(-1); + + </programlisting> + </example> + + <example> + <title>Simple downscaling</title> + <para>Setting a composing area on output of size of <emphasis> at most +</emphasis> half of limit placed at a center of a display.</para> + <programlisting> + + &v4l2-selection; sel = { + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, + .target = V4L2_SEL_TGT_COMPOSE_BOUNDS, + }; + struct v4l2_rect r; + + ret = ioctl(fd, &VIDIOC-G-SELECTION;, &sel); + if (ret) + exit(-1); + /* setting smaller compose rectangle */ + r.width = sel.r.width / 2; + r.height = sel.r.height / 2; + r.left = sel.r.width / 4; + r.top = sel.r.height / 4; + sel.r = r; + sel.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + sel.flags = V4L2_SEL_FLAG_LE; + ret = ioctl(fd, &VIDIOC-S-SELECTION;, &sel); + if (ret) + exit(-1); + + </programlisting> + </example> + + <example> + <title>Querying for scaling factors</title> + <para>A video output device is assumed; change <constant> +V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> for other devices</para> + <programlisting> + + &v4l2-selection; compose = { + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, + .target = V4L2_SEL_TGT_COMPOSE_ACTIVE, + }; + &v4l2-selection; crop = { + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, + .target = V4L2_SEL_TGT_CROP_ACTIVE, + }; + double hscale, vscale; + + ret = ioctl(fd, &VIDIOC-G-SELECTION;, &compose); + if (ret) + exit(-1); + ret = ioctl(fd, &VIDIOC-G-SELECTION;, &crop); + if (ret) + exit(-1); + + /* computing scaling factors */ + hscale = (double)compose.r.width / crop.r.width; + vscale = (double)compose.r.height / crop.r.height; + + </programlisting> + </example> + + </section> + +</section> diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 2ab365c10fb9..e97c512861bb 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -501,6 +501,7 @@ and discussions on the V4L mailing list.</revremark> &sub-g-output; &sub-g-parm; &sub-g-priority; + &sub-g-selection; &sub-g-sliced-vbi-cap; &sub-g-std; &sub-g-tuner; diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml index 1d31427edd1b..0be17c232d3a 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml @@ -228,11 +228,3 @@ is out of bounds.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml index 71d373b6d36a..347d142e7431 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml @@ -156,11 +156,3 @@ bounds.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml index 476fe1d2bba0..9b8efcd6e947 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml @@ -311,11 +311,3 @@ out of bounds.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml index a281d26a195f..a64d5ef103fa 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml @@ -196,11 +196,3 @@ is out of bounds.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-enumstd.xml b/Documentation/DocBook/media/v4l/vidioc-enumstd.xml index 95803fe2c8e4..3a5fc5405f96 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enumstd.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enumstd.xml @@ -381,11 +381,3 @@ is out of bounds.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml b/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml index 5146d00782e3..12b1d0503e26 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml @@ -127,11 +127,3 @@ this control belongs to.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index 5122ce87e0b8..b17a7aac6997 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml @@ -183,7 +183,12 @@ applications must set the array to zero.</entry> <entry>__u32</entry> <entry><structfield>ctrl_class</structfield></entry> <entry>The control class to which all controls belong, see -<xref linkend="ctrl-class" />.</entry> +<xref linkend="ctrl-class" />. Drivers that use a kernel framework for handling +controls will also accept a value of 0 here, meaning that the controls can +belong to any control class. Whether drivers support this can be tested by setting +<structfield>ctrl_class</structfield> to 0 and calling <constant>VIDIOC_TRY_EXT_CTRLS</constant> +with a <structfield>count</structfield> of 0. If that succeeds, then the driver +supports this feature.</entry> </row> <row> <entry>__u32</entry> @@ -194,10 +199,13 @@ also be zero.</entry> <row> <entry>__u32</entry> <entry><structfield>error_idx</structfield></entry> - <entry>Set by the driver in case of an error. It is the -index of the control causing the error or equal to 'count' when the -error is not associated with a particular control. Undefined when the -ioctl returns 0 (success).</entry> + <entry>Set by the driver in case of an error. If it is equal +to <structfield>count</structfield>, then no actual changes were made to +controls. In other words, the error was not associated with setting a particular +control. If it is another value, then only the controls up to <structfield>error_idx-1</structfield> +were modified and control <structfield>error_idx</structfield> is the one that +caused the error. The <structfield>error_idx</structfield> value is undefined +if the ioctl returned 0 (success).</entry> </row> <row> <entry>__u32</entry> @@ -312,10 +320,3 @@ to store the payload and this error code is returned.</para> </refsect1> </refentry> -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml index 055718231bc1..7c63815e7afd 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml @@ -295,7 +295,8 @@ set this field to zero.</entry> <entry>The device is capable of non-destructive overlays. When the driver clears this flag, only destructive overlays are supported. There are no drivers yet which support both destructive and -non-destructive overlays.</entry> +non-destructive overlays. Video Output Overlays are in practice always +non-destructive.</entry> </row> <row> <entry><constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry> @@ -339,8 +340,8 @@ blending makes no sense for destructive overlays.</entry> <row> <entry><constant>V4L2_FBUF_CAP_SRC_CHROMAKEY</constant></entry> <entry>0x0080</entry> - <entry>The device supports Source Chroma-keying. Framebuffer pixels -with the chroma-key colors are replaced by video pixels, which is exactly opposite of + <entry>The device supports Source Chroma-keying. Video pixels +with the chroma-key colors are replaced by framebuffer pixels, which is exactly opposite of <constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry> </row> </tbody> @@ -356,21 +357,27 @@ with the chroma-key colors are replaced by video pixels, which is exactly opposi <entry><constant>V4L2_FBUF_FLAG_PRIMARY</constant></entry> <entry>0x0001</entry> <entry>The framebuffer is the primary graphics surface. -In other words, the overlay is destructive. [?]</entry> +In other words, the overlay is destructive. This flag is typically set by any +driver that doesn't have the <constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant> +capability and it is cleared otherwise.</entry> </row> <row> <entry><constant>V4L2_FBUF_FLAG_OVERLAY</constant></entry> <entry>0x0002</entry> - <entry>The frame buffer is an overlay surface the same -size as the capture. [?]</entry> - </row> - <row> - <entry spanname="hspan">The purpose of -<constant>V4L2_FBUF_FLAG_PRIMARY</constant> and -<constant>V4L2_FBUF_FLAG_OVERLAY</constant> was never quite clear. -Most drivers seem to ignore these flags. For compatibility with the -<wordasword>bttv</wordasword> driver applications should set the -<constant>V4L2_FBUF_FLAG_OVERLAY</constant> flag.</entry> + <entry>If this flag is set for a video capture device, then the +driver will set the initial overlay size to cover the full framebuffer size, +otherwise the existing overlay size (as set by &VIDIOC-S-FMT;) will be used. + +Only one video capture driver (bttv) supports this flag. The use of this flag +for capture devices is deprecated. There is no way to detect which drivers +support this flag, so the only reliable method of setting the overlay size is +through &VIDIOC-S-FMT;. + +If this flag is set for a video output device, then the video output overlay +window is relative to the top-left corner of the framebuffer and restricted +to the size of the framebuffer. If it is cleared, then the video output +overlay window is relative to the video output display. + </entry> </row> <row> <entry><constant>V4L2_FBUF_FLAG_CHROMAKEY</constant></entry> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml index 062d72069090..66e9a5257861 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml @@ -98,8 +98,11 @@ the &v4l2-output; <structfield>modulator</structfield> field and the <entry>&v4l2-tuner-type;</entry> <entry><structfield>type</structfield></entry> <entry>The tuner type. This is the same value as in the -&v4l2-tuner; <structfield>type</structfield> field. The field is not -applicable to modulators, &ie; ignored by drivers.</entry> +&v4l2-tuner; <structfield>type</structfield> field. The type must be set +to <constant>V4L2_TUNER_RADIO</constant> for <filename>/dev/radioX</filename> +device nodes, and to <constant>V4L2_TUNER_ANALOG_TV</constant> +for all others. The field is not applicable to modulators, &ie; ignored +by drivers.</entry> </row> <row> <entry>__u32</entry> @@ -135,11 +138,3 @@ wrong.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-input.xml b/Documentation/DocBook/media/v4l/vidioc-g-input.xml index 08ae82f131f2..1d43065090dd 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-input.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-input.xml @@ -61,8 +61,8 @@ desired input in an integer and call the <constant>VIDIOC_S_INPUT</constant> ioctl with a pointer to this integer. Side effects are possible. For example inputs may support different video standards, so the driver may implicitly switch the -current standard. It is good practice to select an input before -querying or negotiating any other parameters.</para> +current standard. Because of these possible side effects applications +must select an input before querying or negotiating any other parameters.</para> <para>Information about video inputs is available using the &VIDIOC-ENUMINPUT; ioctl.</para> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml index 15ce660f0f5a..7f4ac7e41fa8 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml @@ -236,11 +236,3 @@ mode.</entry> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-output.xml b/Documentation/DocBook/media/v4l/vidioc-g-output.xml index fd45f1c13ccf..4533068ecb8a 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-output.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-output.xml @@ -61,8 +61,9 @@ desired output in an integer and call the <constant>VIDIOC_S_OUTPUT</constant> ioctl with a pointer to this integer. Side effects are possible. For example outputs may support different video standards, so the driver may implicitly switch the current -standard. It is good practice to select an output before querying or -negotiating any other parameters.</para> +standard. +standard. Because of these possible side effects applications +must select an output before querying or negotiating any other parameters.</para> <para>Information about video outputs is available using the &VIDIOC-ENUMOUTPUT; ioctl.</para> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-priority.xml b/Documentation/DocBook/media/v4l/vidioc-g-priority.xml index 8f5e3da7002f..6a81b4fe9538 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-priority.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-priority.xml @@ -133,11 +133,3 @@ priority.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml new file mode 100644 index 000000000000..a9d36e0c090e --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml @@ -0,0 +1,304 @@ +<refentry id="vidioc-g-selection"> + + <refmeta> + <refentrytitle>ioctl VIDIOC_G_SELECTION, VIDIOC_S_SELECTION</refentrytitle> + &manvol; + </refmeta> + + <refnamediv> + <refname>VIDIOC_G_SELECTION</refname> + <refname>VIDIOC_S_SELECTION</refname> + <refpurpose>Get or set one of the selection rectangles</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcprototype> + <funcdef>int <function>ioctl</function></funcdef> + <paramdef>int <parameter>fd</parameter></paramdef> + <paramdef>int <parameter>request</parameter></paramdef> + <paramdef>struct v4l2_selection *<parameter>argp</parameter></paramdef> + </funcprototype> + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Arguments</title> + + <variablelist> + <varlistentry> + <term><parameter>fd</parameter></term> + <listitem> + <para>&fd;</para> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>request</parameter></term> + <listitem> + <para>VIDIOC_G_SELECTION, VIDIOC_S_SELECTION</para> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>argp</parameter></term> + <listitem> + <para></para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>Description</title> + + <note> + <title>Experimental</title> + <para>This is an <link linkend="experimental"> experimental </link> + interface and may change in the future.</para> + </note> + + <para>The ioctls are used to query and configure selection rectangles.</para> + +<para> To query the cropping (composing) rectangle set <structfield> +&v4l2-selection;::type </structfield> to the respective buffer type. Do not +use multiplanar buffers. Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE +</constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE +</constant>. Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of +<constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>. The next step is +setting <structfield> &v4l2-selection;::target </structfield> to value +<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant> +V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>). Please refer to table <xref +linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional +targets. Fields <structfield> &v4l2-selection;::flags </structfield> and +<structfield> &v4l2-selection;::reserved </structfield> are ignored and they +must be filled with zeros. The driver fills the rest of the structure or +returns &EINVAL; if incorrect buffer type or target was used. If cropping +(composing) is not supported then the active rectangle is not mutable and it is +always equal to the bounds rectangle. Finally, structure <structfield> +&v4l2-selection;::r </structfield> is filled with the current cropping +(composing) coordinates. The coordinates are expressed in driver-dependent +units. The only exception are rectangles for images in raw formats, whose +coordinates are always expressed in pixels. </para> + +<para> To change the cropping (composing) rectangle set <structfield> +&v4l2-selection;::type </structfield> to the respective buffer type. Do not +use multiplanar buffers. Use <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE +</constant> instead of <constant> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE +</constant>. Use <constant> V4L2_BUF_TYPE_VIDEO_OUTPUT </constant> instead of +<constant> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE </constant>. The next step is +setting <structfield> &v4l2-selection;::target </structfield> to value +<constant> V4L2_SEL_TGT_CROP_ACTIVE </constant> (<constant> +V4L2_SEL_TGT_COMPOSE_ACTIVE </constant>). Please refer to table <xref +linkend="v4l2-sel-target" /> or <xref linkend="selection-api" /> for additional +targets. Set desired active area into the field <structfield> +&v4l2-selection;::r </structfield>. Field <structfield> +&v4l2-selection;::reserved </structfield> is ignored and must be filled with +zeros. The driver may adjust the rectangle coordinates. An application may +introduce constraints to control rounding behaviour. Set the field +<structfield> &v4l2-selection;::flags </structfield> to one of values: + +<itemizedlist> + <listitem> +<para><constant>0</constant> - The driver can adjust the rectangle size freely +and shall choose a crop/compose rectangle as close as possible to the requested +one.</para> + </listitem> + <listitem> +<para><constant>V4L2_SEL_FLAG_GE</constant> - The driver is not allowed to +shrink the rectangle. The original rectangle must lay inside the adjusted +one.</para> + </listitem> + <listitem> +<para><constant>V4L2_SEL_FLAG_LE</constant> - The driver is not allowed to +enlarge the rectangle. The adjusted rectangle must lay inside the original +one.</para> + </listitem> + <listitem> +<para><constant>V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE</constant> - The driver +must choose the size exactly the same as in the requested rectangle.</para> + </listitem> +</itemizedlist> + +Please refer to <xref linkend="sel-const-adjust" />. + +</para> + +<para> The driver may have to adjusts the requested dimensions against hardware +limits and other parts as the pipeline, i.e. the bounds given by the +capture/output window or TV display. The closest possible values of horizontal +and vertical offset and sizes are chosen according to following priority: + +<orderedlist> + <listitem> + <para>Satisfy constraints from <structfield>&v4l2-selection;::flags</structfield>.</para> + </listitem> + <listitem> + <para>Adjust width, height, left, and top to hardware limits and alignments.</para> + </listitem> + <listitem> + <para>Keep center of adjusted rectangle as close as possible to the original one.</para> + </listitem> + <listitem> + <para>Keep width and height as close as possible to original ones.</para> + </listitem> + <listitem> + <para>Keep horizontal and vertical offset as close as possible to original ones.</para> + </listitem> +</orderedlist> + +On success the field <structfield> &v4l2-selection;::r </structfield> contains +the adjusted rectangle. When the parameters are unsuitable the application may +modify the cropping (composing) or image parameters and repeat the cycle until +satisfactory parameters have been negotiated. If constraints flags have to be +violated at then ERANGE is returned. The error indicates that <emphasis> there +exist no rectangle </emphasis> that satisfies the constraints.</para> + + </refsect1> + + <refsect1> + <table frame="none" pgwide="1" id="v4l2-sel-target"> + <title>Selection targets.</title> + <tgroup cols="3"> + &cs-def; + <tbody valign="top"> + <row> + <entry><constant>V4L2_SEL_TGT_CROP_ACTIVE</constant></entry> + <entry>0</entry> + <entry>area that is currently cropped by hardware</entry> + </row> + <row> + <entry><constant>V4L2_SEL_TGT_CROP_DEFAULT</constant></entry> + <entry>1</entry> + <entry>suggested cropping rectangle that covers the "whole picture"</entry> + </row> + <row> + <entry><constant>V4L2_SEL_TGT_CROP_BOUNDS</constant></entry> + <entry>2</entry> + <entry>limits for the cropping rectangle</entry> + </row> + <row> + <entry><constant>V4L2_SEL_TGT_COMPOSE_ACTIVE</constant></entry> + <entry>256</entry> + <entry>area to which data are composed by hardware</entry> + </row> + <row> + <entry><constant>V4L2_SEL_TGT_COMPOSE_DEFAULT</constant></entry> + <entry>257</entry> + <entry>suggested composing rectangle that covers the "whole picture"</entry> + </row> + <row> + <entry><constant>V4L2_SEL_TGT_COMPOSE_BOUNDS</constant></entry> + <entry>258</entry> + <entry>limits for the composing rectangle</entry> + </row> + <row> + <entry><constant>V4L2_SEL_TGT_COMPOSE_PADDED</constant></entry> + <entry>259</entry> + <entry>the active area and all padding pixels that are inserted or modified by the hardware</entry> + </row> + </tbody> + </tgroup> + </table> + </refsect1> + + <refsect1> + <table frame="none" pgwide="1" id="v4l2-sel-flags"> + <title>Selection constraint flags</title> + <tgroup cols="3"> + &cs-def; + <tbody valign="top"> + <row> + <entry><constant>V4L2_SEL_FLAG_GE</constant></entry> + <entry>0x00000001</entry> + <entry>indicate that adjusted rectangle must contain a rectangle from <structfield>&v4l2-selection;::r</structfield></entry> + </row> + <row> + <entry><constant>V4L2_SEL_FLAG_LE</constant></entry> + <entry>0x00000002</entry> + <entry>indicate that adjusted rectangle must be inside a rectangle from <structfield>&v4l2-selection;::r</structfield></entry> + </row> + </tbody> + </tgroup> + </table> + </refsect1> + + <section> + <figure id="sel-const-adjust"> + <title>Size adjustments with constraint flags.</title> + <mediaobject> + <imageobject> + <imagedata fileref="constraints.png" format="PNG" /> + </imageobject> + <textobject> + <phrase>Behaviour of rectangle adjustment for different constraint + flags.</phrase> + </textobject> + </mediaobject> + </figure> + </section> + + <refsect1> + <table pgwide="1" frame="none" id="v4l2-selection"> + <title>struct <structname>v4l2_selection</structname></title> + <tgroup cols="3"> + &cs-str; + <tbody valign="top"> + <row> + <entry>__u32</entry> + <entry><structfield>type</structfield></entry> + <entry>Type of the buffer (from &v4l2-buf-type;)</entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>target</structfield></entry> + <entry>used to select between <link linkend="v4l2-sel-target"> cropping and composing rectangles </link></entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>flags</structfield></entry> + <entry>control over coordinates adjustments, refer to <link linkend="v4l2-sel-flags">selection flags</link></entry> + </row> + <row> + <entry>&v4l2-rect;</entry> + <entry><structfield>r</structfield></entry> + <entry>selection rectangle</entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>reserved[9]</structfield></entry> + <entry>Reserved fields for future use</entry> + </row> + </tbody> + </tgroup> + </table> + </refsect1> + + <refsect1> + &return-value; + <variablelist> + <varlistentry> + <term><errorcode>EINVAL</errorcode></term> + <listitem> + <para>The buffer <structfield> &v4l2-selection;::type </structfield> +or <structfield> &v4l2-selection;::target </structfield> is not supported, or +the <structfield> &v4l2-selection;::flags </structfield> are invalid.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><errorcode>ERANGE</errorcode></term> + <listitem> + <para>it is not possible to adjust a rectangle <structfield> +&v4l2-selection;::r </structfield> that satisfies all contraints from +<structfield> &v4l2-selection;::flags </structfield>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><errorcode>EBUSY</errorcode></term> + <listitem> + <para>it is not possible to apply change of selection rectangle at the moment. +Usually because streaming is in progress.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + +</refentry> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-std.xml b/Documentation/DocBook/media/v4l/vidioc-g-std.xml index 37996f25b5d4..99ff1a016220 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-std.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-std.xml @@ -88,11 +88,3 @@ standards.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml index bd98c734c06b..91ec2fb658f8 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml @@ -318,6 +318,16 @@ standard.</para><!-- FIXME what if PAL+NTSC and Bi but not SAP? --></entry> <entry>RDS capture is supported. This capability is only valid for radio tuners.</entry> </row> + <row> + <entry><constant>V4L2_TUNER_CAP_RDS_BLOCK_IO</constant></entry> + <entry>0x0100</entry> + <entry>The RDS data is passed as unparsed RDS blocks.</entry> + </row> + <row> + <entry><constant>V4L2_TUNER_CAP_RDS_CONTROLS</constant></entry> + <entry>0x0200</entry> + <entry>The RDS data is parsed by the hardware and set via controls.</entry> + </row> </tbody> </tgroup> </table> @@ -525,11 +535,3 @@ out of bounds.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml index 5c104d42d31c..6e414d7b6df7 100644 --- a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml @@ -100,11 +100,3 @@ supported, or the <structfield>index</structfield> is out of bounds.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml index 0ac0057a51c4..36660d311b51 100644 --- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml +++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml @@ -443,11 +443,3 @@ or this particular menu item is not supported by the driver.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml index c30dcc4232c0..e013da845b11 100644 --- a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml +++ b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml @@ -125,11 +125,3 @@ wrong.</para> </variablelist> </refsect1> </refentry> - -<!-- -Local Variables: -mode: sgml -sgml-parent-document: "v4l2.sgml" -indent-tabs-mode: nil -End: ---> diff --git a/Documentation/acpi/apei/einj.txt b/Documentation/acpi/apei/einj.txt index 5cc699ba5453..e7cc36397217 100644 --- a/Documentation/acpi/apei/einj.txt +++ b/Documentation/acpi/apei/einj.txt @@ -47,20 +47,53 @@ directory apei/einj. The following files are provided. - param1 This file is used to set the first error parameter value. Effect of - parameter depends on error_type specified. For memory error, this is - physical memory address. Only available if param_extension module - parameter is specified. + parameter depends on error_type specified. - param2 This file is used to set the second error parameter value. Effect of - parameter depends on error_type specified. For memory error, this is - physical memory address mask. Only available if param_extension - module parameter is specified. + parameter depends on error_type specified. + +BIOS versions based in the ACPI 4.0 specification have limited options +to control where the errors are injected. Your BIOS may support an +extension (enabled with the param_extension=1 module parameter, or +boot command line einj.param_extension=1). This allows the address +and mask for memory injections to be specified by the param1 and +param2 files in apei/einj. + +BIOS versions using the ACPI 5.0 specification have more control over +the target of the injection. For processor related errors (type 0x1, +0x2 and 0x4) the APICID of the target should be provided using the +param1 file in apei/einj. For memory errors (type 0x8, 0x10 and 0x20) +the address is set using param1 with a mask in param2 (0x0 is equivalent +to all ones). For PCI express errors (type 0x40, 0x80 and 0x100) the +segment, bus, device and function are specified using param1: + + 31 24 23 16 15 11 10 8 7 0 + +-------------------------------------------------+ + | segment | bus | device | function | reserved | + +-------------------------------------------------+ + +An ACPI 5.0 BIOS may also allow vendor specific errors to be injected. +In this case a file named vendor will contain identifying information +from the BIOS that hopefully will allow an application wishing to use +the vendor specific extension to tell that they are running on a BIOS +that supports it. All vendor extensions have the 0x80000000 bit set in +error_type. A file vendor_flags controls the interpretation of param1 +and param2 (1 = PROCESSOR, 2 = MEMORY, 4 = PCI). See your BIOS vendor +documentation for details (and expect changes to this API if vendors +creativity in using this feature expands beyond our expectations). + +Example: +# cd /sys/kernel/debug/apei/einj +# cat available_error_type # See which errors can be injected +0x00000002 Processor Uncorrectable non-fatal +0x00000008 Memory Correctable +0x00000010 Memory Uncorrectable non-fatal +# echo 0x12345000 > param1 # Set memory address for injection +# echo 0xfffffffffffff000 > param2 # Mask - anywhere in this page +# echo 0x8 > error_type # Choose correctable memory error +# echo 1 > error_inject # Inject now -Injecting parameter support is a BIOS version specific extension, that -is, it only works on some BIOS version. If you want to use it, please -make sure your BIOS version has the proper support and specify -"param_extension=y" in module parameter. For more information about EINJ, please refer to ACPI specification -version 4.0, section 17.5. +version 4.0, section 17.5 and ACPI 5.0, section 18.6. diff --git a/Documentation/coccinelle.txt b/Documentation/coccinelle.txt index 96b690348ba1..cf44eb6499b4 100644 --- a/Documentation/coccinelle.txt +++ b/Documentation/coccinelle.txt @@ -102,9 +102,15 @@ or make coccicheck COCCI=<my_SP.cocci> MODE=report - Using Coccinelle on (modified) files -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Controlling Which Files are Processed by Coccinelle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +By default the entire kernel source tree is checked. + +To apply Coccinelle to a specific directory, M= can be used. +For example, to check drivers/net/wireless/ one may write: + make coccicheck M=drivers/net/wireless/ + To apply Coccinelle on a file basis, instead of a directory basis, the following command may be used: diff --git a/Documentation/devicetree/bindings/dma/atmel-dma.txt b/Documentation/devicetree/bindings/dma/atmel-dma.txt new file mode 100644 index 000000000000..3c046ee6e8b5 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/atmel-dma.txt @@ -0,0 +1,14 @@ +* Atmel Direct Memory Access Controller (DMA) + +Required properties: +- compatible: Should be "atmel,<chip>-dma" +- reg: Should contain DMA registers location and length +- interrupts: Should contain DMA interrupt + +Examples: + +dma@ffffec00 { + compatible = "atmel,at91sam9g45-dma"; + reg = <0xffffec00 0x200>; + interrupts = <21>; +}; diff --git a/Documentation/devicetree/bindings/i2c/omap-i2c.txt b/Documentation/devicetree/bindings/i2c/omap-i2c.txt new file mode 100644 index 000000000000..56564aa4b444 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/omap-i2c.txt @@ -0,0 +1,30 @@ +I2C for OMAP platforms + +Required properties : +- compatible : Must be "ti,omap3-i2c" or "ti,omap4-i2c" +- ti,hwmods : Must be "i2c<n>", n being the instance number (1-based) +- #address-cells = <1>; +- #size-cells = <0>; + +Recommended properties : +- clock-frequency : Desired I2C bus clock frequency in Hz. Otherwise + the default 100 kHz frequency will be used. + +Optional properties: +- Child nodes conforming to i2c bus binding + +Note: Current implementation will fetch base address, irq and dma +from omap hwmod data base during device registration. +Future plan is to migrate hwmod data base contents into device tree +blob so that, all the required data will be used from device tree dts +file. + +Examples : + +i2c1: i2c@0 { + compatible = "ti,omap3-i2c"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "i2c1"; + clock-frequency = <400000>; +}; diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt new file mode 100644 index 000000000000..19f6af47a792 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt @@ -0,0 +1,78 @@ +* Freescale MC13783/MC13892 Power Management Integrated Circuit (PMIC) + +Required properties: +- compatible : Should be "fsl,mc13783" or "fsl,mc13892" + +Optional properties: +- fsl,mc13xxx-uses-adc : Indicate the ADC is being used +- fsl,mc13xxx-uses-codec : Indicate the Audio Codec is being used +- fsl,mc13xxx-uses-rtc : Indicate the RTC is being used +- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used + +Sub-nodes: +- regulators : Contain the regulator nodes. The MC13892 regulators are + bound using their names as listed below with their registers and bits + for enabling. + + vcoincell : regulator VCOINCELL (register 13, bit 23) + sw1 : regulator SW1 (register 24, bit 0) + sw2 : regulator SW2 (register 25, bit 0) + sw3 : regulator SW3 (register 26, bit 0) + sw4 : regulator SW4 (register 27, bit 0) + swbst : regulator SWBST (register 29, bit 20) + vgen1 : regulator VGEN1 (register 32, bit 0) + viohi : regulator VIOHI (register 32, bit 3) + vdig : regulator VDIG (register 32, bit 9) + vgen2 : regulator VGEN2 (register 32, bit 12) + vpll : regulator VPLL (register 32, bit 15) + vusb2 : regulator VUSB2 (register 32, bit 18) + vgen3 : regulator VGEN3 (register 33, bit 0) + vcam : regulator VCAM (register 33, bit 6) + vvideo : regulator VVIDEO (register 33, bit 12) + vaudio : regulator VAUDIO (register 33, bit 15) + vsd : regulator VSD (register 33, bit 18) + gpo1 : regulator GPO1 (register 34, bit 6) + gpo2 : regulator GPO2 (register 34, bit 8) + gpo3 : regulator GPO3 (register 34, bit 10) + gpo4 : regulator GPO4 (register 34, bit 12) + pwgt1spi : regulator PWGT1SPI (register 34, bit 15) + pwgt2spi : regulator PWGT2SPI (register 34, bit 16) + vusb : regulator VUSB (register 50, bit 3) + + The bindings details of individual regulator device can be found in: + Documentation/devicetree/bindings/regulator/regulator.txt + +Examples: + +ecspi@70010000 { /* ECSPI1 */ + fsl,spi-num-chipselects = <2>; + cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */ + <&gpio3 25 0>; /* GPIO4_25 */ + status = "okay"; + + pmic: mc13892@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mc13892"; + spi-max-frequency = <6000000>; + reg = <0>; + interrupt-parent = <&gpio0>; + interrupts = <8>; + + regulators { + sw1_reg: mc13892__sw1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1375000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: mc13892__sw2 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1850000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/mfd/twl-familly.txt b/Documentation/devicetree/bindings/mfd/twl-familly.txt new file mode 100644 index 000000000000..a66fcf946759 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/twl-familly.txt @@ -0,0 +1,47 @@ +Texas Instruments TWL family + +The TWLs are Integrated Power Management Chips. +Some version might contain much more analog function like +USB transceiver or Audio amplifier. +These chips are connected to an i2c bus. + + +Required properties: +- compatible : Must be "ti,twl4030"; + For Integrated power-management/audio CODEC device used in OMAP3 + based boards +- compatible : Must be "ti,twl6030"; + For Integrated power-management used in OMAP4 based boards +- interrupts : This i2c device has an IRQ line connected to the main SoC +- interrupt-controller : Since the twl support several interrupts internally, + it is considered as an interrupt controller cascaded to the SoC one. +- #interrupt-cells = <1>; +- interrupt-parent : The parent interrupt controller. + +Optional node: +- Child nodes contain in the twl. The twl family is made of several variants + that support a different number of features. + The children nodes will thus depend of the capability of the variant. + + +Example: +/* + * Integrated Power Management Chip + * http://www.ti.com/lit/ds/symlink/twl6030.pdf + */ +twl@48 { + compatible = "ti,twl6030"; + reg = <0x48>; + interrupts = <39>; /* IRQ_SYS_1N cascaded to gic */ + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <0>; + + twl_rtc { + compatible = "ti,twl_rtc"; + interrupts = <11>; + reg = <0>; + }; +}; diff --git a/Documentation/devicetree/bindings/resource-names.txt b/Documentation/devicetree/bindings/resource-names.txt new file mode 100644 index 000000000000..e280fef6f265 --- /dev/null +++ b/Documentation/devicetree/bindings/resource-names.txt @@ -0,0 +1,54 @@ +Some properties contain an ordered list of 1 or more datum which are +normally accessed by index. However, some devices will have multiple +values which are more naturally accessed by name. Device nodes can +include a supplemental property for assigning names to each of the list +items. The names property consists of a list of strings in the same +order as the data in the resource property. + +The following supplemental names properties are defined. + +Resource Property Supplemental Names Property +----------------- --------------------------- +reg reg-names +clocks clock-names +interrupts interrupt-names + +Usage: + +The -names property must be used in conjunction with the normal resource +property. If not it will be ignored. + +Examples: + +l4-abe { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x48000000 0x00001000>, /* MPU path */ + <1 0 0x49000000 0x00001000>; /* L3 path */ + mcasp { + compatible = "ti,mcasp"; + reg = <0 0x10 0x10>, <0 0x20 0x10>, + <1 0x10 0x10>, <1 0x20 0x10>; + reg-names = "mpu", "dat", + "dma", "dma_dat"; + interrupts = <11>, <12>; + interrupt-names = "rx", "tx"; + }; + + timer { + compatible = "ti,timer"; + reg = <0 0x40 0x10>, <1 0x40 0x10>; + reg-names = "mpu", "dma"; + }; +}; + + +usb { + compatible = "ti,usb-host"; + reg = <0x4a064000 0x800>, <0x4a064800 0x200>, + <0x4a064c00 0x200>; + reg-names = "config", "ohci", "ehci"; + interrupts = <14>, <15>; + interrupt-names = "ohci", "ehci"; +}; diff --git a/Documentation/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt index 510eab32f392..225f96d88f55 100644 --- a/Documentation/dma-buf-sharing.txt +++ b/Documentation/dma-buf-sharing.txt @@ -219,6 +219,10 @@ NOTES: If the exporter chooses not to allow an attach() operation once a map_dma_buf() API has been called, it simply returns an error. +Miscellaneous notes: +- Any exporters or users of the dma-buf buffer sharing framework must have + a 'select DMA_SHARED_BUFFER' in their respective Kconfigs. + References: [1] struct dma_buf_ops in include/linux/dma-buf.h [2] All interfaces mentioned above defined in include/linux/dma-buf.h diff --git a/Documentation/dmaengine.txt b/Documentation/dmaengine.txt index 94b7e0f96b38..bbe6cb3d1856 100644 --- a/Documentation/dmaengine.txt +++ b/Documentation/dmaengine.txt @@ -75,6 +75,10 @@ The slave DMA usage consists of following steps: slave_sg - DMA a list of scatter gather buffers from/to a peripheral dma_cyclic - Perform a cyclic DMA operation from/to a peripheral till the operation is explicitly stopped. + interleaved_dma - This is common to Slave as well as M2M clients. For slave + address of devices' fifo could be already known to the driver. + Various types of operations could be expressed by setting + appropriate values to the 'dma_interleaved_template' members. A non-NULL return of this transfer API represents a "descriptor" for the given transaction. @@ -89,6 +93,10 @@ The slave DMA usage consists of following steps: struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_data_direction direction); + struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)( + struct dma_chan *chan, struct dma_interleaved_template *xt, + unsigned long flags); + The peripheral driver is expected to have mapped the scatterlist for the DMA operation prior to calling device_prep_slave_sg, and must keep the scatterlist mapped until the DMA operation has completed. diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index e67be7afc78b..d1d4a179a382 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -27,8 +27,8 @@ use IO::Handle; "or51211", "or51132_qam", "or51132_vsb", "bluebird", "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718", "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395", - "lme2510c_s7395_old", "drxk", "drxk_terratec_h5", "tda10071", - "it9135" ); + "lme2510c_s7395_old", "drxk", "drxk_terratec_h5", + "drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137"); # Check args syntax() if (scalar(@ARGV) != 1); @@ -644,6 +644,24 @@ sub drxk { "$fwfile" } +sub drxk_hauppauge_hvr930c { + my $url = "http://www.wintvcd.co.uk/drivers/"; + my $zipfile = "HVR-9x0_5_10_325_28153_SIGNED.zip"; + my $hash = "83ab82e7e9480ec8bf1ae0155ca63c88"; + my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); + my $drvfile = "HVR-900/emOEM.sys"; + my $fwfile = "dvb-usb-hauppauge-hvr930c-drxk.fw"; + + checkstandard(); + + wgetfile($zipfile, $url . $zipfile); + verify($zipfile, $hash); + unzip($zipfile, $tmpdir); + extract("$tmpdir/$drvfile", 0x117b0, 42692, "$fwfile"); + + "$fwfile" +} + sub drxk_terratec_h5 { my $url = "http://www.linuxtv.org/downloads/firmware/"; my $hash = "19000dada8e2741162ccc50cc91fa7f1"; @@ -658,6 +676,26 @@ sub drxk_terratec_h5 { } sub it9135 { + my $sourcefile = "dvb-usb-it9135.zip"; + my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile"; + my $hash = "1e55f6c8833f1d0ae067c2bb2953e6a9"; + my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0); + my $outfile = "dvb-usb-it9135.fw"; + my $fwfile1 = "dvb-usb-it9135-01.fw"; + my $fwfile2 = "dvb-usb-it9135-02.fw"; + + checkstandard(); + + wgetfile($sourcefile, $url); + unzip($sourcefile, $tmpdir); + verify("$tmpdir/$outfile", $hash); + extract("$tmpdir/$outfile", 64, 8128, "$fwfile1"); + extract("$tmpdir/$outfile", 12866, 5817, "$fwfile2"); + + "$fwfile1 $fwfile2" +} + +sub it9137 { my $url = "http://kworld.server261.com/kworld/CD/ITE_TiVme/V1.00/"; my $zipfile = "Driver_V10.323.1.0412.100412.zip"; my $hash = "79b597dc648698ed6820845c0c9d0d37"; diff --git a/Documentation/fb/api.txt b/Documentation/fb/api.txt new file mode 100644 index 000000000000..d4ff7de85700 --- /dev/null +++ b/Documentation/fb/api.txt @@ -0,0 +1,306 @@ + The Frame Buffer Device API + --------------------------- + +Last revised: June 21, 2011 + + +0. Introduction +--------------- + +This document describes the frame buffer API used by applications to interact +with frame buffer devices. In-kernel APIs between device drivers and the frame +buffer core are not described. + +Due to a lack of documentation in the original frame buffer API, drivers +behaviours differ in subtle (and not so subtle) ways. This document describes +the recommended API implementation, but applications should be prepared to +deal with different behaviours. + + +1. Capabilities +--------------- + +Device and driver capabilities are reported in the fixed screen information +capabilities field. + +struct fb_fix_screeninfo { + ... + __u16 capabilities; /* see FB_CAP_* */ + ... +}; + +Application should use those capabilities to find out what features they can +expect from the device and driver. + +- FB_CAP_FOURCC + +The driver supports the four character code (FOURCC) based format setting API. +When supported, formats are configured using a FOURCC instead of manually +specifying color components layout. + + +2. Types and visuals +-------------------- + +Pixels are stored in memory in hardware-dependent formats. Applications need +to be aware of the pixel storage format in order to write image data to the +frame buffer memory in the format expected by the hardware. + +Formats are described by frame buffer types and visuals. Some visuals require +additional information, which are stored in the variable screen information +bits_per_pixel, grayscale, red, green, blue and transp fields. + +Visuals describe how color information is encoded and assembled to create +macropixels. Types describe how macropixels are stored in memory. The following +types and visuals are supported. + +- FB_TYPE_PACKED_PIXELS + +Macropixels are stored contiguously in a single plane. If the number of bits +per macropixel is not a multiple of 8, whether macropixels are padded to the +next multiple of 8 bits or packed together into bytes depends on the visual. + +Padding at end of lines may be present and is then reported through the fixed +screen information line_length field. + +- FB_TYPE_PLANES + +Macropixels are split across multiple planes. The number of planes is equal to +the number of bits per macropixel, with plane i'th storing i'th bit from all +macropixels. + +Planes are located contiguously in memory. + +- FB_TYPE_INTERLEAVED_PLANES + +Macropixels are split across multiple planes. The number of planes is equal to +the number of bits per macropixel, with plane i'th storing i'th bit from all +macropixels. + +Planes are interleaved in memory. The interleave factor, defined as the +distance in bytes between the beginning of two consecutive interleaved blocks +belonging to different planes, is stored in the fixed screen information +type_aux field. + +- FB_TYPE_FOURCC + +Macropixels are stored in memory as described by the format FOURCC identifier +stored in the variable screen information grayscale field. + +- FB_VISUAL_MONO01 + +Pixels are black or white and stored on a number of bits (typically one) +specified by the variable screen information bpp field. + +Black pixels are represented by all bits set to 1 and white pixels by all bits +set to 0. When the number of bits per pixel is smaller than 8, several pixels +are packed together in a byte. + +FB_VISUAL_MONO01 is currently used with FB_TYPE_PACKED_PIXELS only. + +- FB_VISUAL_MONO10 + +Pixels are black or white and stored on a number of bits (typically one) +specified by the variable screen information bpp field. + +Black pixels are represented by all bits set to 0 and white pixels by all bits +set to 1. When the number of bits per pixel is smaller than 8, several pixels +are packed together in a byte. + +FB_VISUAL_MONO01 is currently used with FB_TYPE_PACKED_PIXELS only. + +- FB_VISUAL_TRUECOLOR + +Pixels are broken into red, green and blue components, and each component +indexes a read-only lookup table for the corresponding value. Lookup tables +are device-dependent, and provide linear or non-linear ramps. + +Each component is stored in a macropixel according to the variable screen +information red, green, blue and transp fields. + +- FB_VISUAL_PSEUDOCOLOR and FB_VISUAL_STATIC_PSEUDOCOLOR + +Pixel values are encoded as indices into a colormap that stores red, green and +blue components. The colormap is read-only for FB_VISUAL_STATIC_PSEUDOCOLOR +and read-write for FB_VISUAL_PSEUDOCOLOR. + +Each pixel value is stored in the number of bits reported by the variable +screen information bits_per_pixel field. + +- FB_VISUAL_DIRECTCOLOR + +Pixels are broken into red, green and blue components, and each component +indexes a programmable lookup table for the corresponding value. + +Each component is stored in a macropixel according to the variable screen +information red, green, blue and transp fields. + +- FB_VISUAL_FOURCC + +Pixels are encoded and interpreted as described by the format FOURCC +identifier stored in the variable screen information grayscale field. + + +3. Screen information +--------------------- + +Screen information are queried by applications using the FBIOGET_FSCREENINFO +and FBIOGET_VSCREENINFO ioctls. Those ioctls take a pointer to a +fb_fix_screeninfo and fb_var_screeninfo structure respectively. + +struct fb_fix_screeninfo stores device independent unchangeable information +about the frame buffer device and the current format. Those information can't +be directly modified by applications, but can be changed by the driver when an +application modifies the format. + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + __u32 smem_len; /* Length of frame buffer mem */ + __u32 type; /* see FB_TYPE_* */ + __u32 type_aux; /* Interleave for interleaved Planes */ + __u32 visual; /* see FB_VISUAL_* */ + __u16 xpanstep; /* zero if no hardware panning */ + __u16 ypanstep; /* zero if no hardware panning */ + __u16 ywrapstep; /* zero if no hardware ywrap */ + __u32 line_length; /* length of a line in bytes */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + __u32 mmio_len; /* Length of Memory Mapped I/O */ + __u32 accel; /* Indicate to driver which */ + /* specific chip/card we have */ + __u16 capabilities; /* see FB_CAP_* */ + __u16 reserved[2]; /* Reserved for future compatibility */ +}; + +struct fb_var_screeninfo stores device independent changeable information +about a frame buffer device, its current format and video mode, as well as +other miscellaneous parameters. + +struct fb_var_screeninfo { + __u32 xres; /* visible resolution */ + __u32 yres; + __u32 xres_virtual; /* virtual resolution */ + __u32 yres_virtual; + __u32 xoffset; /* offset from virtual to visible */ + __u32 yoffset; /* resolution */ + + __u32 bits_per_pixel; /* guess what */ + __u32 grayscale; /* 0 = color, 1 = grayscale, */ + /* >1 = FOURCC */ + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + __u32 nonstd; /* != 0 Non standard pixel format */ + + __u32 activate; /* see FB_ACTIVATE_* */ + + __u32 height; /* height of picture in mm */ + __u32 width; /* width of picture in mm */ + + __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + __u32 pixclock; /* pixel clock in ps (pico seconds) */ + __u32 left_margin; /* time from sync to picture */ + __u32 right_margin; /* time from picture to sync */ + __u32 upper_margin; /* time from sync to picture */ + __u32 lower_margin; + __u32 hsync_len; /* length of horizontal sync */ + __u32 vsync_len; /* length of vertical sync */ + __u32 sync; /* see FB_SYNC_* */ + __u32 vmode; /* see FB_VMODE_* */ + __u32 rotate; /* angle we rotate counter clockwise */ + __u32 colorspace; /* colorspace for FOURCC-based modes */ + __u32 reserved[4]; /* Reserved for future compatibility */ +}; + +To modify variable information, applications call the FBIOPUT_VSCREENINFO +ioctl with a pointer to a fb_var_screeninfo structure. If the call is +successful, the driver will update the fixed screen information accordingly. + +Instead of filling the complete fb_var_screeninfo structure manually, +applications should call the FBIOGET_VSCREENINFO ioctl and modify only the +fields they care about. + + +4. Format configuration +----------------------- + +Frame buffer devices offer two ways to configure the frame buffer format: the +legacy API and the FOURCC-based API. + + +The legacy API has been the only frame buffer format configuration API for a +long time and is thus widely used by application. It is the recommended API +for applications when using RGB and grayscale formats, as well as legacy +non-standard formats. + +To select a format, applications set the fb_var_screeninfo bits_per_pixel field +to the desired frame buffer depth. Values up to 8 will usually map to +monochrome, grayscale or pseudocolor visuals, although this is not required. + +- For grayscale formats, applications set the grayscale field to one. The red, + blue, green and transp fields must be set to 0 by applications and ignored by + drivers. Drivers must fill the red, blue and green offsets to 0 and lengths + to the bits_per_pixel value. + +- For pseudocolor formats, applications set the grayscale field to zero. The + red, blue, green and transp fields must be set to 0 by applications and + ignored by drivers. Drivers must fill the red, blue and green offsets to 0 + and lengths to the bits_per_pixel value. + +- For truecolor and directcolor formats, applications set the grayscale field + to zero, and the red, blue, green and transp fields to describe the layout of + color components in memory. + +struct fb_bitfield { + __u32 offset; /* beginning of bitfield */ + __u32 length; /* length of bitfield */ + __u32 msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + + Pixel values are bits_per_pixel wide and are split in non-overlapping red, + green, blue and alpha (transparency) components. Location and size of each + component in the pixel value are described by the fb_bitfield offset and + length fields. Offset are computed from the right. + + Pixels are always stored in an integer number of bytes. If the number of + bits per pixel is not a multiple of 8, pixel values are padded to the next + multiple of 8 bits. + +Upon successful format configuration, drivers update the fb_fix_screeninfo +type, visual and line_length fields depending on the selected format. + + +The FOURCC-based API replaces format descriptions by four character codes +(FOURCC). FOURCCs are abstract identifiers that uniquely define a format +without explicitly describing it. This is the only API that supports YUV +formats. Drivers are also encouraged to implement the FOURCC-based API for RGB +and grayscale formats. + +Drivers that support the FOURCC-based API report this capability by setting +the FB_CAP_FOURCC bit in the fb_fix_screeninfo capabilities field. + +FOURCC definitions are located in the linux/videodev2.h header. However, and +despite starting with the V4L2_PIX_FMT_prefix, they are not restricted to V4L2 +and don't require usage of the V4L2 subsystem. FOURCC documentation is +available in Documentation/DocBook/v4l/pixfmt.xml. + +To select a format, applications set the grayscale field to the desired FOURCC. +For YUV formats, they should also select the appropriate colorspace by setting +the colorspace field to one of the colorspaces listed in linux/videodev2.h and +documented in Documentation/DocBook/v4l/colorspaces.xml. + +The red, green, blue and transp fields are not used with the FOURCC-based API. +For forward compatibility reasons applications must zero those fields, and +drivers must ignore them. Values other than 0 may get a meaning in future +extensions. + +Upon successful format configuration, drivers update the fb_fix_screeninfo +type, visual and line_length fields depending on the selected format. The type +and visual fields are set to FB_TYPE_FOURCC and FB_VISUAL_FOURCC respectively. diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index d49c2ec72d12..1bea46a54b1c 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -439,52 +439,6 @@ Who: Jean Delvare <khali@linux-fr.org> ---------------------------- -What: Support for driver specific ioctls in the pwc driver (everything - defined in media/pwc-ioctl.h) -When: 3.3 -Why: This stems from the v4l1 era, with v4l2 everything can be done with - standardized v4l2 API calls -Who: Hans de Goede <hdegoede@redhat.com> - ----------------------------- - -What: Driver specific sysfs API in the pwc driver -When: 3.3 -Why: Setting pan/tilt should be done with v4l2 controls, like with other - cams. The button is available as a standard input device -Who: Hans de Goede <hdegoede@redhat.com> - ----------------------------- - -What: Driver specific use of pixfmt.priv in the pwc driver -When: 3.3 -Why: The .priv field never was intended for this, setting a framerate is - support using the standardized S_PARM ioctl -Who: Hans de Goede <hdegoede@redhat.com> - ----------------------------- - -What: Software emulation of arbritary resolutions in the pwc driver -When: 3.3 -Why: The pwc driver claims to support any resolution between 160x120 - and 640x480, but emulates this by simply drawing a black border - around the image. Userspace can draw its own black border if it - really wants one. -Who: Hans de Goede <hdegoede@redhat.com> - ----------------------------- - -What: For VIDIOC_S_FREQUENCY the type field must match the device node's type. - If not, return -EINVAL. -When: 3.2 -Why: It makes no sense to switch the tuner to radio mode by calling - VIDIOC_S_FREQUENCY on a video node, or to switch the tuner to tv mode by - calling VIDIOC_S_FREQUENCY on a radio node. This is the first step of a - move to more consistent handling of tv and radio tuners. -Who: Hans Verkuil <hans.verkuil@cisco.com> - ----------------------------- - What: Opening a radio device node will no longer automatically switch the tuner mode from tv to radio. When: 3.3 diff --git a/Documentation/filesystems/ceph.txt b/Documentation/filesystems/ceph.txt index 763d8ebbbebd..d6030aa33376 100644 --- a/Documentation/filesystems/ceph.txt +++ b/Documentation/filesystems/ceph.txt @@ -119,12 +119,20 @@ Mount Options must rely on TCP's error correction to detect data corruption in the data payload. - noasyncreaddir - Disable client's use its local cache to satisfy readdir - requests. (This does not change correctness; the client uses - cached metadata only when a lease or capability ensures it is - valid.) + dcache + Use the dcache contents to perform negative lookups and + readdir when the client has the entire directory contents in + its cache. (This does not change correctness; the client uses + cached metadata only when a lease or capability ensures it is + valid.) + + nodcache + Do not use the dcache as above. This avoids a significant amount of + complex code, sacrificing performance without affecting correctness, + and is useful for tracking down bugs. + noasyncreaddir + Do not use the dcache as above for readdir. More Information ================ diff --git a/Documentation/filesystems/nfs/00-INDEX b/Documentation/filesystems/nfs/00-INDEX index a57e12411d2a..1716874a651e 100644 --- a/Documentation/filesystems/nfs/00-INDEX +++ b/Documentation/filesystems/nfs/00-INDEX @@ -2,6 +2,8 @@ - this file (nfs-related documentation). Exporting - explanation of how to make filesystems exportable. +fault_injection.txt + - information for using fault injection on the server knfsd-stats.txt - statistics which the NFS server makes available to user space. nfs.txt diff --git a/Documentation/filesystems/nfs/fault_injection.txt b/Documentation/filesystems/nfs/fault_injection.txt new file mode 100644 index 000000000000..426d166089a3 --- /dev/null +++ b/Documentation/filesystems/nfs/fault_injection.txt @@ -0,0 +1,69 @@ + +Fault Injection +=============== +Fault injection is a method for forcing errors that may not normally occur, or +may be difficult to reproduce. Forcing these errors in a controlled environment +can help the developer find and fix bugs before their code is shipped in a +production system. Injecting an error on the Linux NFS server will allow us to +observe how the client reacts and if it manages to recover its state correctly. + +NFSD_FAULT_INJECTION must be selected when configuring the kernel to use this +feature. + + +Using Fault Injection +===================== +On the client, mount the fault injection server through NFS v4.0+ and do some +work over NFS (open files, take locks, ...). + +On the server, mount the debugfs filesystem to <debug_dir> and ls +<debug_dir>/nfsd. This will show a list of files that will be used for +injecting faults on the NFS server. As root, write a number n to the file +corresponding to the action you want the server to take. The server will then +process the first n items it finds. So if you want to forget 5 locks, echo '5' +to <debug_dir>/nfsd/forget_locks. A value of 0 will tell the server to forget +all corresponding items. A log message will be created containing the number +of items forgotten (check dmesg). + +Go back to work on the client and check if the client recovered from the error +correctly. + + +Available Faults +================ +forget_clients: + The NFS server keeps a list of clients that have placed a mount call. If + this list is cleared, the server will have no knowledge of who the client + is, forcing the client to reauthenticate with the server. + +forget_openowners: + The NFS server keeps a list of what files are currently opened and who + they were opened by. Clearing this list will force the client to reopen + its files. + +forget_locks: + The NFS server keeps a list of what files are currently locked in the VFS. + Clearing this list will force the client to reclaim its locks (files are + unlocked through the VFS as they are cleared from this list). + +forget_delegations: + A delegation is used to assure the client that a file, or part of a file, + has not changed since the delegation was awarded. Clearing this list will + force the client to reaquire its delegation before accessing the file + again. + +recall_delegations: + Delegations can be recalled by the server when another client attempts to + access a file. This test will notify the client that its delegation has + been revoked, forcing the client to reaquire the delegation before using + the file again. + + +tools/nfs/inject_faults.sh script +================================= +This script has been created to ease the fault injection process. This script +will detect the mounted debugfs directory and write to the files located there +based on the arguments passed by the user. For example, running +`inject_faults.sh forget_locks 1` as root will instruct the server to forget +one lock. Running `inject_faults forget_locks` will instruct the server to +forgetall locks. diff --git a/Documentation/filesystems/squashfs.txt b/Documentation/filesystems/squashfs.txt index 7db3ebda5a4c..403c090aca39 100644 --- a/Documentation/filesystems/squashfs.txt +++ b/Documentation/filesystems/squashfs.txt @@ -93,8 +93,8 @@ byte alignment: Compressed data blocks are written to the filesystem as files are read from the source directory, and checked for duplicates. Once all file data has been -written the completed inode, directory, fragment, export and uid/gid lookup -tables are written. +written the completed inode, directory, fragment, export, uid/gid lookup and +xattr tables are written. 3.1 Compression options ----------------------- @@ -151,7 +151,7 @@ in each metadata block. Directories are sorted in alphabetical order, and at lookup the index is scanned linearly looking for the first filename alphabetically larger than the filename being looked up. At this point the location of the metadata block the filename is in has been found. -The general idea of the index is ensure only one metadata block needs to be +The general idea of the index is to ensure only one metadata block needs to be decompressed to do a lookup irrespective of the length of the directory. This scheme has the advantage that it doesn't require extra memory overhead and doesn't require much extra storage on disk. diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 6f496a586732..23b7def21ba8 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -26,6 +26,10 @@ Supported chips: Prefix: 'it8721' Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Not publicly available + * IT8728F + Prefix: 'it8728' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * SiS950 [clone of IT8705F] Prefix: 'it87' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -71,7 +75,7 @@ Description ----------- This driver implements support for the IT8705F, IT8712F, IT8716F, -IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips. +IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they @@ -105,6 +109,9 @@ The IT8726F is just bit enhanced IT8716F with additional hardware for AMD power sequencing. Therefore the chip will appear as IT8716F to userspace applications. +The IT8728F is considered compatible with the IT8721F, until a datasheet +becomes available (hopefully.) + Temperatures are measured in degrees Celsius. An alarm is triggered once when the Overtemperature Shutdown limit is crossed. @@ -121,8 +128,8 @@ alarm is triggered if the voltage has crossed a programmable minimum or maximum limit. Note that minimum in this case always means 'closest to zero'; this is important for negative voltage measurements. All voltage inputs can measure voltages between 0 and 4.08 volts, with a resolution of -0.016 volt (except IT8721F/IT8758E: 0.012 volt.) The battery voltage in8 does -not have limit registers. +0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery +voltage in8 does not have limit registers. On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside the chip (in7, in8 and optionally in3). The driver handles this transparently diff --git a/Documentation/hwmon/lm63 b/Documentation/hwmon/lm63 index b9843eab1afb..4d30d209881a 100644 --- a/Documentation/hwmon/lm63 +++ b/Documentation/hwmon/lm63 @@ -12,6 +12,11 @@ Supported chips: Addresses scanned: I2C 0x18 and 0x4e Datasheet: Publicly available at the National Semiconductor website http://www.national.com/pf/LM/LM64.html + * National Semiconductor LM96163 + Prefix: 'lm96163' + Addresses scanned: I2C 0x4c + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/pf/LM/LM96163.html Author: Jean Delvare <khali@linux-fr.org> @@ -49,16 +54,24 @@ value for measuring the speed of the fan. It can measure fan speeds down to Note that the pin used for fan monitoring is shared with an alert out function. Depending on how the board designer wanted to use the chip, fan speed monitoring will or will not be possible. The proper chip configuration -is left to the BIOS, and the driver will blindly trust it. +is left to the BIOS, and the driver will blindly trust it. Only the original +LM63 suffers from this limitation, the LM64 and LM96163 have separate pins +for fan monitoring and alert out. On the LM64, monitoring is always enabled; +on the LM96163 it can be disabled. A PWM output can be used to control the speed of the fan. The LM63 has two PWM modes: manual and automatic. Automatic mode is not fully implemented yet (you cannot define your custom PWM/temperature curve), and mode change isn't supported either. -The lm63 driver will not update its values more frequently than every -second; reading them more often will do no harm, but will return 'old' -values. +The lm63 driver will not update its values more frequently than configured with +the update_interval sysfs attribute; reading them more often will do no harm, +but will return 'old' values. Values in the automatic fan control lookup table +(attributes pwm1_auto_*) have their own independent lifetime of 5 seconds. The LM64 is effectively an LM63 with GPIO lines. The driver does not support these GPIO lines at present. + +The LM96163 is an enhanced version of LM63 with improved temperature accuracy +and better PWM resolution. For LM96163, the external temperature sensor type is +configurable as CPU embedded diode(1) or 3904 transistor(2). diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index a4aa8f600e09..1f4dd855a299 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface @@ -304,7 +304,7 @@ value (fastest fan speed) wins. temp[1-*]_type Sensor type selection. Integers 1 to 6 RW - 1: PII/Celeron Diode + 1: CPU embedded diode 2: 3904 transistor 3: thermal diode 4: thermistor diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 54078ed96b37..4840334ea97b 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -149,6 +149,7 @@ Code Seq#(hex) Include File Comments 'M' 01-03 drivers/scsi/megaraid/megaraid_sas.h 'M' 00-0F drivers/video/fsl-diu-fb.h conflict! 'N' 00-1F drivers/usb/scanner.h +'N' 40-7F drivers/block/nvme.c 'O' 00-06 mtd/ubi-user.h UBI 'P' all linux/soundcard.h conflict! 'P' 60-6F sound/sscape_ioctl.h conflict! diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index f47cdefb4d1e..ab0a984530d8 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -33,14 +33,15 @@ This document describes the Linux kernel Makefiles. === 6 Architecture Makefiles --- 6.1 Set variables to tweak the build to the architecture - --- 6.2 Add prerequisites to archprepare: - --- 6.3 List directories to visit when descending - --- 6.4 Architecture-specific boot images - --- 6.5 Building non-kbuild targets - --- 6.6 Commands useful for building a boot image - --- 6.7 Custom kbuild commands - --- 6.8 Preprocessing linker scripts - --- 6.9 Generic header files + --- 6.2 Add prerequisites to archheaders: + --- 6.3 Add prerequisites to archprepare: + --- 6.4 List directories to visit when descending + --- 6.5 Architecture-specific boot images + --- 6.6 Building non-kbuild targets + --- 6.7 Commands useful for building a boot image + --- 6.8 Custom kbuild commands + --- 6.9 Preprocessing linker scripts + --- 6.10 Generic header files === 7 Kbuild syntax for exported headers --- 7.1 header-y @@ -252,7 +253,7 @@ more details, with real examples. This will create a library lib.a based on delay.o. For kbuild to actually recognize that there is a lib.a being built, the directory shall be listed in libs-y. - See also "6.3 List directories to visit when descending". + See also "6.4 List directories to visit when descending". Use of lib-y is normally restricted to lib/ and arch/*/lib. @@ -974,7 +975,20 @@ When kbuild executes, the following steps are followed (roughly): $(KBUILD_ARFLAGS) set by the top level Makefile to "D" (deterministic mode) if this option is supported by $(AR). ---- 6.2 Add prerequisites to archprepare: +--- 6.2 Add prerequisites to archheaders: + + The archheaders: rule is used to generate header files that + may be installed into user space by "make header_install" or + "make headers_install_all". In order to support + "make headers_install_all", this target has to be able to run + on an unconfigured tree, or a tree configured for another + architecture. + + It is run before "make archprepare" when run on the + architecture itself. + + +--- 6.3 Add prerequisites to archprepare: The archprepare: rule is used to list prerequisites that need to be built before starting to descend down in the subdirectories. @@ -990,7 +1004,7 @@ When kbuild executes, the following steps are followed (roughly): generating offset header files. ---- 6.3 List directories to visit when descending +--- 6.4 List directories to visit when descending An arch Makefile cooperates with the top Makefile to define variables which specify how to build the vmlinux file. Note that there is no @@ -1019,7 +1033,7 @@ When kbuild executes, the following steps are followed (roughly): drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/ ---- 6.4 Architecture-specific boot images +--- 6.5 Architecture-specific boot images An arch Makefile specifies goals that take the vmlinux file, compress it, wrap it in bootstrapping code, and copy the resulting files @@ -1070,7 +1084,7 @@ When kbuild executes, the following steps are followed (roughly): When "make" is executed without arguments, bzImage will be built. ---- 6.5 Building non-kbuild targets +--- 6.6 Building non-kbuild targets extra-y @@ -1090,7 +1104,7 @@ When kbuild executes, the following steps are followed (roughly): shall be built, but shall not be linked as part of built-in.o. ---- 6.6 Commands useful for building a boot image +--- 6.7 Commands useful for building a boot image Kbuild provides a few macros that are useful when building a boot image. @@ -1112,7 +1126,7 @@ When kbuild executes, the following steps are followed (roughly): always be built. Assignments to $(targets) are without $(obj)/ prefix. if_changed may be used in conjunction with custom commands as - defined in 6.7 "Custom kbuild commands". + defined in 6.8 "Custom kbuild commands". Note: It is a typical mistake to forget the FORCE prerequisite. Another common pitfall is that whitespace is sometimes @@ -1171,7 +1185,7 @@ When kbuild executes, the following steps are followed (roughly): $(obj)/%.dtb: $(src)/%.dts $(call cmd,dtc) ---- 6.7 Custom kbuild commands +--- 6.8 Custom kbuild commands When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand of a command is normally displayed. @@ -1198,7 +1212,7 @@ When kbuild executes, the following steps are followed (roughly): will be displayed with "make KBUILD_VERBOSE=0". ---- 6.8 Preprocessing linker scripts +--- 6.9 Preprocessing linker scripts When the vmlinux image is built, the linker script arch/$(ARCH)/kernel/vmlinux.lds is used. @@ -1228,7 +1242,7 @@ When kbuild executes, the following steps are followed (roughly): The kbuild infrastructure for *lds file are used in several architecture-specific files. ---- 6.9 Generic header files +--- 6.10 Generic header files The directory include/asm-generic contains the header files that may be shared between individual architectures. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index eb93fd0ec734..033d4e69b43b 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1059,6 +1059,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. By default, super page will be supported if Intel IOMMU has the capability. With this option, super page will not be supported. + + intel_idle.max_cstate= [KNL,HW,ACPI,X86] + 0 disables intel_idle and fall back on acpi_idle. + 1 to 6 specify maximum depth of C-state. + intremap= [X86-64, Intel-IOMMU] on enable Interrupt Remapping (default) off disable Interrupt Remapping @@ -2475,6 +2480,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. stacktrace [FTRACE] Enabled the stack tracer on boot up. + stacktrace_filter=[function-list] + [FTRACE] Limit the functions that the stack tracer + will trace at boot up. function-list is a comma separated + list of functions. This list can be changed at run + time by the stack_trace_filter file in the debugfs + tracing directory. Note, this enables stack tracing + and the stacktrace above is not needed. + sti= [PARISC,HW] Format: <num> Set the STI (builtin display/keyboard on the HP-PARISC diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt index 51063e681ca4..b6e39739a36d 100644 --- a/Documentation/kmemleak.txt +++ b/Documentation/kmemleak.txt @@ -127,7 +127,10 @@ See the include/linux/kmemleak.h header for the functions prototype. kmemleak_init - initialize kmemleak kmemleak_alloc - notify of a memory block allocation +kmemleak_alloc_percpu - notify of a percpu memory block allocation kmemleak_free - notify of a memory block freeing +kmemleak_free_part - notify of a partial memory block freeing +kmemleak_free_percpu - notify of a percpu memory block freeing kmemleak_not_leak - mark an object as not a leak kmemleak_ignore - do not scan or report an object as leak kmemleak_scan_area - add scan areas inside a memory block diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt index 8898a95b41e5..22ae8441489f 100644 --- a/Documentation/mmc/mmc-dev-attrs.txt +++ b/Documentation/mmc/mmc-dev-attrs.txt @@ -64,3 +64,13 @@ Note on Erase Size and Preferred Erase Size: size specified by the card. "preferred_erase_size" is in bytes. + +SD/MMC/SDIO Clock Gating Attribute +================================== + +Read and write access is provided to following attribute. +This attribute appears only if CONFIG_MMC_CLKGATE is enabled. + + clkgate_delay Tune the clock gating delay with desired value in milliseconds. + +echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt index 2db28b8e662f..f08d078d43cf 100644 --- a/Documentation/mmc/mmc-dev-parts.txt +++ b/Documentation/mmc/mmc-dev-parts.txt @@ -25,3 +25,16 @@ echo 0 > /sys/block/mmcblkXbootY/force_ro To re-enable read-only access: echo 1 > /sys/block/mmcblkXbootY/force_ro + +The boot partitions can also be locked read only until the next power on, +with: + +echo 1 > /sys/block/mmcblkXbootY/ro_lock_until_next_power_on + +This is a feature of the card and not of the kernel. If the card does +not support boot partition locking, the file will not exist. If the +feature has been disabled on the card, the file will be read-only. + +The boot partitions can also be locked permanently, but this feature is +not accessible through sysfs in order to avoid accidental or malicious +bricking. diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt index 40a4c65f380a..262acf56fa79 100644 --- a/Documentation/power/basic-pm-debugging.txt +++ b/Documentation/power/basic-pm-debugging.txt @@ -15,7 +15,7 @@ test at least a couple of times in a row for confidence. [This is necessary, because some problems only show up on a second attempt at suspending and resuming the system.] Moreover, hibernating in the "reboot" and "shutdown" modes causes the PM core to skip some platform-related callbacks which on ACPI -systems might be necessary to make hibernation work. Thus, if you machine fails +systems might be necessary to make hibernation work. Thus, if your machine fails to hibernate or resume in the "reboot" mode, you should try the "platform" mode: # echo platform > /sys/power/disk diff --git a/Documentation/power/freezing-of-tasks.txt b/Documentation/power/freezing-of-tasks.txt index 6ccb68f68da6..ebd7490ef1df 100644 --- a/Documentation/power/freezing-of-tasks.txt +++ b/Documentation/power/freezing-of-tasks.txt @@ -120,10 +120,10 @@ So in practice, the 'at all' may become a 'why freeze kernel threads?' and freezing user threads I don't find really objectionable." Still, there are kernel threads that may want to be freezable. For example, if -a kernel that belongs to a device driver accesses the device directly, it in -principle needs to know when the device is suspended, so that it doesn't try to -access it at that time. However, if the kernel thread is freezable, it will be -frozen before the driver's .suspend() callback is executed and it will be +a kernel thread that belongs to a device driver accesses the device directly, it +in principle needs to know when the device is suspended, so that it doesn't try +to access it at that time. However, if the kernel thread is freezable, it will +be frozen before the driver's .suspend() callback is executed and it will be thawed after the driver's .resume() callback has run, so it won't be accessing the device while it's suspended. diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas index 64adb98b181c..57566bacb4c5 100644 --- a/Documentation/scsi/ChangeLog.megaraid_sas +++ b/Documentation/scsi/ChangeLog.megaraid_sas @@ -1,3 +1,13 @@ +Release Date : Fri. Jan 6, 2012 17:00:00 PST 2010 - + (emaild-id:megaraidlinux@lsi.com) + Adam Radford +Current Version : 00.00.06.14-rc1 +Old Version : 00.00.06.12-rc1 + 1. Fix reglockFlags for degraded raid5/6 for MR 9360/9380. + 2. Mask off flags in ioctl path to prevent memory scribble with older + MegaCLI versions. + 3. Remove poll_mode_io module paramater, sysfs node, and associated code. +------------------------------------------------------------------------------- Release Date : Wed. Oct 5, 2011 17:00:00 PST 2010 - (emaild-id:megaraidlinux@lsi.com) Adam Radford diff --git a/Documentation/scsi/LICENSE.qla4xxx b/Documentation/scsi/LICENSE.qla4xxx index 494980e40491..ab899591ecb7 100644 --- a/Documentation/scsi/LICENSE.qla4xxx +++ b/Documentation/scsi/LICENSE.qla4xxx @@ -1,32 +1,11 @@ Copyright (c) 2003-2011 QLogic Corporation -QLogic Linux iSCSI HBA Driver +QLogic Linux iSCSI Driver This program includes a device driver for Linux 3.x. You may modify and redistribute the device driver code under the GNU General Public License (a copy of which is attached hereto as Exhibit A) published by the Free Software Foundation (version 2). -REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE, -THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT -CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR -OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT, -TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN -ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN -COMBINATION WITH THIS PROGRAM. - EXHIBIT A diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 7ef9b843d529..6e21b8b52638 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -230,14 +230,9 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "#include <linux/ctype.h>\n" buf += "#include <asm/unaligned.h>\n\n" buf += "#include <target/target_core_base.h>\n" - buf += "#include <target/target_core_transport.h>\n" - buf += "#include <target/target_core_fabric_ops.h>\n" + buf += "#include <target/target_core_fabric.h>\n" buf += "#include <target/target_core_fabric_configfs.h>\n" - buf += "#include <target/target_core_fabric_lib.h>\n" - buf += "#include <target/target_core_device.h>\n" - buf += "#include <target/target_core_tpg.h>\n" buf += "#include <target/target_core_configfs.h>\n" - buf += "#include <target/target_core_base.h>\n" buf += "#include <target/configfs_macros.h>\n\n" buf += "#include \"" + fabric_mod_name + "_base.h\"\n" buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n" @@ -260,7 +255,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " /* " + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n" buf += " return ERR_PTR(-EINVAL); */\n" buf += " se_nacl_new = " + fabric_mod_name + "_alloc_fabric_acl(se_tpg);\n" - buf += " if (!(se_nacl_new))\n" + buf += " if (!se_nacl_new)\n" buf += " return ERR_PTR(-ENOMEM);\n" buf += "//#warning FIXME: Hardcoded nexus depth in " + fabric_mod_name + "_make_nodeacl()\n" buf += " nexus_depth = 1;\n" @@ -308,7 +303,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " if (strict_strtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)\n" buf += " return ERR_PTR(-EINVAL);\n\n" buf += " tpg = kzalloc(sizeof(struct " + fabric_mod_name + "_tpg), GFP_KERNEL);\n" - buf += " if (!(tpg)) {\n" + buf += " if (!tpg) {\n" buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_tpg\");\n" buf += " return ERR_PTR(-ENOMEM);\n" buf += " }\n" @@ -344,7 +339,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " /* if (" + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n" buf += " return ERR_PTR(-EINVAL); */\n\n" buf += " " + fabric_mod_port + " = kzalloc(sizeof(struct " + fabric_mod_name + "_" + fabric_mod_port + "), GFP_KERNEL);\n" - buf += " if (!(" + fabric_mod_port + ")) {\n" + buf += " if (!" + fabric_mod_port + ") {\n" buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_" + fabric_mod_port + "\");\n" buf += " return ERR_PTR(-ENOMEM);\n" buf += " }\n" @@ -352,7 +347,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): if proto_ident == "FC" or proto_ident == "SAS": buf += " " + fabric_mod_port + "->" + fabric_mod_port + "_wwpn = wwpn;\n" - buf += " /* " + fabric_mod_name + "_format_wwn(&" + fabric_mod_port + "->" + fabric_mod_port + "_name[0], " + fabric_mod_name.upper() + "__NAMELEN, wwpn); */\n\n" + buf += " /* " + fabric_mod_name + "_format_wwn(&" + fabric_mod_port + "->" + fabric_mod_port + "_name[0], " + fabric_mod_name.upper() + "_NAMELEN, wwpn); */\n\n" buf += " return &" + fabric_mod_port + "->" + fabric_mod_port + "_wwn;\n" buf += "}\n\n" buf += "static void " + fabric_mod_name + "_drop_" + fabric_mod_port + "(struct se_wwn *wwn)\n" @@ -391,8 +386,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .tpg_alloc_fabric_acl = " + fabric_mod_name + "_alloc_fabric_acl,\n" buf += " .tpg_release_fabric_acl = " + fabric_mod_name + "_release_fabric_acl,\n" buf += " .tpg_get_inst_index = " + fabric_mod_name + "_tpg_get_inst_index,\n" - buf += " .release_cmd_to_pool = " + fabric_mod_name + "_release_cmd,\n" - buf += " .release_cmd_direct = " + fabric_mod_name + "_release_cmd,\n" + buf += " .release_cmd = " + fabric_mod_name + "_release_cmd,\n" buf += " .shutdown_session = " + fabric_mod_name + "_shutdown_session,\n" buf += " .close_session = " + fabric_mod_name + "_close_session,\n" buf += " .stop_session = " + fabric_mod_name + "_stop_session,\n" @@ -405,14 +399,12 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .set_default_node_attributes = " + fabric_mod_name + "_set_default_node_attrs,\n" buf += " .get_task_tag = " + fabric_mod_name + "_get_task_tag,\n" buf += " .get_cmd_state = " + fabric_mod_name + "_get_cmd_state,\n" - buf += " .new_cmd_failure = " + fabric_mod_name + "_new_cmd_failure,\n" buf += " .queue_data_in = " + fabric_mod_name + "_queue_data_in,\n" buf += " .queue_status = " + fabric_mod_name + "_queue_status,\n" buf += " .queue_tm_rsp = " + fabric_mod_name + "_queue_tm_rsp,\n" buf += " .get_fabric_sense_len = " + fabric_mod_name + "_get_fabric_sense_len,\n" buf += " .set_fabric_sense_len = " + fabric_mod_name + "_set_fabric_sense_len,\n" buf += " .is_state_remove = " + fabric_mod_name + "_is_state_remove,\n" - buf += " .pack_lun = " + fabric_mod_name + "_pack_lun,\n" buf += " /*\n" buf += " * Setup function pointers for generic logic in target_core_fabric_configfs.c\n" buf += " */\n" @@ -439,9 +431,9 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " * Register the top level struct config_item_type with TCM core\n" buf += " */\n" buf += " fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name[4:] + "\");\n" - buf += " if (!(fabric)) {\n" + buf += " if (IS_ERR(fabric)) {\n" buf += " printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n" - buf += " return -ENOMEM;\n" + buf += " return PTR_ERR(fabric);\n" buf += " }\n" buf += " /*\n" buf += " * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n" @@ -475,9 +467,9 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n" buf += " return 0;\n" buf += "};\n\n" - buf += "static void " + fabric_mod_name + "_deregister_configfs(void)\n" + buf += "static void __exit " + fabric_mod_name + "_deregister_configfs(void)\n" buf += "{\n" - buf += " if (!(" + fabric_mod_name + "_fabric_configfs))\n" + buf += " if (!" + fabric_mod_name + "_fabric_configfs)\n" buf += " return;\n\n" buf += " target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n" buf += " " + fabric_mod_name + "_fabric_configfs = NULL;\n" @@ -492,17 +484,15 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " return ret;\n\n" buf += " return 0;\n" buf += "};\n\n" - buf += "static void " + fabric_mod_name + "_exit(void)\n" + buf += "static void __exit " + fabric_mod_name + "_exit(void)\n" buf += "{\n" buf += " " + fabric_mod_name + "_deregister_configfs();\n" buf += "};\n\n" - buf += "#ifdef MODULE\n" buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n" buf += "MODULE_LICENSE(\"GPL\");\n" buf += "module_init(" + fabric_mod_name + "_init);\n" buf += "module_exit(" + fabric_mod_name + "_exit);\n" - buf += "#endif\n" ret = p.write(buf) if ret: @@ -514,7 +504,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): def tcm_mod_scan_fabric_ops(tcm_dir): - fabric_ops_api = tcm_dir + "include/target/target_core_fabric_ops.h" + fabric_ops_api = tcm_dir + "include/target/target_core_fabric.h" print "Using tcm_mod_scan_fabric_ops: " + fabric_ops_api process_fo = 0; @@ -579,11 +569,7 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "#include <scsi/scsi_cmnd.h>\n" buf += "#include <scsi/libfc.h>\n\n" buf += "#include <target/target_core_base.h>\n" - buf += "#include <target/target_core_transport.h>\n" - buf += "#include <target/target_core_fabric_ops.h>\n" - buf += "#include <target/target_core_fabric_lib.h>\n" - buf += "#include <target/target_core_device.h>\n" - buf += "#include <target/target_core_tpg.h>\n" + buf += "#include <target/target_core_fabric.h>\n" buf += "#include <target/target_core_configfs.h>\n\n" buf += "#include \"" + fabric_mod_name + "_base.h\"\n" buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n" @@ -788,7 +774,7 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "{\n" buf += " struct " + fabric_mod_name + "_nacl *nacl;\n\n" buf += " nacl = kzalloc(sizeof(struct " + fabric_mod_name + "_nacl), GFP_KERNEL);\n" - buf += " if (!(nacl)) {\n" + buf += " if (!nacl) {\n" buf += " printk(KERN_ERR \"Unable to alocate struct " + fabric_mod_name + "_nacl\\n\");\n" buf += " return NULL;\n" buf += " }\n\n" @@ -815,7 +801,7 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "}\n\n" bufi += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *);\n" - if re.search('release_cmd_to_pool', fo): + if re.search('\*release_cmd\)\(', fo): buf += "void " + fabric_mod_name + "_release_cmd(struct se_cmd *se_cmd)\n" buf += "{\n" buf += " return;\n" @@ -899,13 +885,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "}\n\n" bufi += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *);\n" - if re.search('new_cmd_failure\)\(', fo): - buf += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *se_cmd)\n" - buf += "{\n" - buf += " return;\n" - buf += "}\n\n" - bufi += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *);\n" - if re.search('queue_data_in\)\(', fo): buf += "int " + fabric_mod_name + "_queue_data_in(struct se_cmd *se_cmd)\n" buf += "{\n" @@ -948,15 +927,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "}\n\n" bufi += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *);\n" - if re.search('pack_lun\)\(', fo): - buf += "u64 " + fabric_mod_name + "_pack_lun(unsigned int lun)\n" - buf += "{\n" - buf += " WARN_ON(lun >= 256);\n" - buf += " /* Caller wants this byte-swapped */\n" - buf += " return cpu_to_le64((lun & 0xff) << 8);\n" - buf += "}\n\n" - bufi += "u64 " + fabric_mod_name + "_pack_lun(unsigned int);\n" - ret = p.write(buf) if ret: diff --git a/Documentation/video4linux/CARDLIST.au0828 b/Documentation/video4linux/CARDLIST.au0828 index d5cb4ea287b2..7b59e953c4bf 100644 --- a/Documentation/video4linux/CARDLIST.au0828 +++ b/Documentation/video4linux/CARDLIST.au0828 @@ -1,5 +1,5 @@ 0 -> Unknown board (au0828) - 1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008] + 1 -> Hauppauge HVR950Q (au0828) [2040:7200,2040:7210,2040:7217,2040:721b,2040:721e,2040:721f,2040:7280,0fd9:0008,2040:7260,2040:7213] 2 -> Hauppauge HVR850 (au0828) [2040:7240] 3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620] 4 -> Hauppauge HVR950Q rev xxF8 (au0828) [2040:7201,2040:7211,2040:7281] diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv index 4739d5684305..b753906c7183 100644 --- a/Documentation/video4linux/CARDLIST.bttv +++ b/Documentation/video4linux/CARDLIST.bttv @@ -71,7 +71,7 @@ 70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E) 71 -> Lifeview FlyVideo 98EZ (capture only) LR51 [1851:1851] 72 -> Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM) [1554:4011] - 73 -> Sensoray 311 [6000:0311] + 73 -> Sensoray 311/611 [6000:0311,6000:0611] 74 -> RemoteVision MX (RV605) 75 -> Powercolor MTV878/ MTV878R/ MTV878F 76 -> Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) [0e11:0079] @@ -158,3 +158,4 @@ 157 -> Geovision GV-800(S) (master) [800a:763d] 158 -> Geovision GV-800(S) (slave) [800b:763d,800c:763d,800d:763d] 159 -> ProVideo PV183 [1830:1540,1831:1540,1832:1540,1833:1540,1834:1540,1835:1540,1836:1540,1837:1540] +160 -> Tongwei Video Technology TD-3116 [f200:3116] diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 8910449d23a8..23584d0c6a75 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -29,3 +29,6 @@ 28 -> LEADTEK WinFast PxTV1200 [107d:6f22] 29 -> GoTView X5 3D Hybrid [5654:2390] 30 -> NetUP Dual DVB-T/C-CI RF [1b55:e2e4] + 31 -> Leadtek Winfast PxDVR3200 H XC4000 [107d:6f39] + 32 -> MPX-885 + 33 -> Mygica X8507 [14f1:8502] diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index d9c0f119196d..eee18e6962b6 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -85,3 +85,5 @@ 84 -> Samsung SMT 7020 DVB-S [18ac:dc00,18ac:dccd] 85 -> Twinhan VP-1027 DVB-S [1822:0023] 86 -> TeVii S464 DVB-S/S2 [d464:9022] + 87 -> Leadtek WinFast DTV2000 H PLUS [107d:6f42] + 88 -> Leadtek WinFast DTV1800 H (XC4000) [107d:6f38] diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 4a7b3df6d8bd..e7be3ac49ead 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -11,7 +11,7 @@ 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500] 11 -> Terratec Hybrid XS (em2880) 12 -> Kworld PVR TV 2800 RF (em2820/em2840) - 13 -> Terratec Prodigy XS (em2880) [0ccd:0047] + 13 -> Terratec Prodigy XS (em2880) 14 -> SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) 15 -> V-Gear PocketTV (em2800) 16 -> Hauppauge WinTV HVR 950 (em2883) [2040:6513,2040:6517,2040:651b] @@ -40,7 +40,7 @@ 39 -> KWorld PVRTV 300U (em2861) [eb1a:e300] 40 -> Plextor ConvertX PX-TV100U (em2861) [093b:a005] 41 -> Kworld 350 U DVB-T (em2870) [eb1a:e350] - 42 -> Kworld 355 U DVB-T (em2870) [eb1a:e355,eb1a:e357] + 42 -> Kworld 355 U DVB-T (em2870) [eb1a:e355,eb1a:e357,eb1a:e359] 43 -> Terratec Cinergy T XS (em2870) [0ccd:0043] 44 -> Terratec Cinergy T XS (MT2060) (em2870) 45 -> Pinnacle PCTV DVB-T (em2870) @@ -64,7 +64,7 @@ 64 -> Easy Cap Capture DC-60 (em2860) 65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515] 66 -> Empire dual TV (em2880) - 67 -> Terratec Grabby (em2860) [0ccd:0096] + 67 -> Terratec Grabby (em2860) [0ccd:0096,0ccd:10AF] 68 -> Terratec AV350 (em2860) [0ccd:0084] 69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313] 70 -> Evga inDtube (em2882) @@ -76,3 +76,7 @@ 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340] 77 -> EM2874 Leadership ISDBT (em2874) 78 -> PCTV nanoStick T2 290e (em28174) + 79 -> Terratec Cinergy H5 (em2884) [0ccd:10a2,0ccd:10ad] + 80 -> PCTV DVB-S2 Stick (460e) (em28174) + 81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605] + 82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2] diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 7efae9bd73ed..e7ef38a19859 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -186,3 +186,4 @@ 185 -> MagicPro ProHDTV Pro2 DMB-TH/Hybrid [17de:d136] 186 -> Beholder BeholdTV 501 [5ace:5010] 187 -> Beholder BeholdTV 503 FM [5ace:5030] +188 -> Sensoray 811/911 [6000:0811,6000:0911] diff --git a/Documentation/video4linux/CARDLIST.saa7164 b/Documentation/video4linux/CARDLIST.saa7164 index 152bd7b781ca..2205e8d55537 100644 --- a/Documentation/video4linux/CARDLIST.saa7164 +++ b/Documentation/video4linux/CARDLIST.saa7164 @@ -7,3 +7,5 @@ 6 -> Hauppauge WinTV-HVR2200 [0070:8901] 7 -> Hauppauge WinTV-HVR2250 [0070:8891,0070:8851] 8 -> Hauppauge WinTV-HVR2250 [0070:88A1] + 9 -> Hauppauge WinTV-HVR2200 [0070:8940] + 10 -> Hauppauge WinTV-HVR2200 [0070:8953] diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index b15e29f31121..f2060f0dc02c 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -189,6 +189,7 @@ ov519 05a9:0511 Video Blaster WebCam 3/WebCam Plus, D-Link USB Digital Video Ca ov519 05a9:0518 Creative WebCam ov519 05a9:0519 OV519 Microphone ov519 05a9:0530 OmniVision +ov534_9 05a9:1550 OmniVision VEHO Filmscanner ov519 05a9:2800 OmniVision SuperCAM ov519 05a9:4519 Webcam Classic ov534_9 05a9:8065 OmniVision test kit ov538+ov9712 @@ -278,6 +279,7 @@ pac7302 093a:2628 Genius iLook 300 pac7302 093a:2629 Genious iSlim 300 pac7302 093a:262a Webcam 300k pac7302 093a:262c Philips SPC 230 NC +jl2005bcd 0979:0227 Various brands, 19 known cameras supported jeilinj 0979:0280 Sakar 57379 jeilinj 0979:0280 Sportscam DV15 zc3xx 0ac8:0302 Z-star Vimicro zc0302 diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 26aa0573933e..e2492a9d1027 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -666,27 +666,6 @@ a control of this type whenever the first control belonging to a new control class is added. -Differences from the Spec -========================= - -There are a few places where the framework acts slightly differently from the -V4L2 Specification. Those differences are described in this section. We will -have to see whether we need to adjust the spec or not. - -1) It is no longer required to have all controls contained in a -v4l2_ext_control array be from the same control class. The framework will be -able to handle any type of control in the array. You need to set ctrl_class -to 0 in order to enable this. If ctrl_class is non-zero, then it will still -check that all controls belong to that control class. - -If you set ctrl_class to 0 and count to 0, then it will only return an error -if there are no controls at all. - -2) Clarified the way error_idx works. For get and set it will be equal to -count if nothing was done yet. If it is less than count then only the controls -up to error_idx-1 were successfully applied. - - Proposals for Extensions ======================== diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index f8dcabf7852c..659b2ba12a4f 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -612,6 +612,12 @@ You can set a pointer to a mutex_lock in struct video_device. Usually this will be either a top-level mutex or a mutex per device node. If you want finer-grained locking then you have to set it to NULL and do you own locking. +It is up to the driver developer to decide which method to use. However, if +your driver has high-latency operations (for example, changing the exposure +of a USB webcam might take a long time), then you might be better off with +doing your own locking if you want to allow the user to do other things with +the device while waiting for the high-latency command to finish. + If a lock is specified then all file operations will be serialized on that lock. If you use videobuf then you must pass the same lock to the videobuf queue initialize function: if videobuf has to wait for a frame to arrive, then @@ -619,6 +625,11 @@ it will temporarily unlock the lock and relock it afterwards. If your driver also waits in the code, then you should do the same to allow other processes to access the device node while the first process is waiting for something. +In the case of videobuf2 you will need to implement the wait_prepare and +wait_finish callbacks to unlock/lock if applicable. In particular, if you use +the lock in struct video_device then you must unlock/lock this mutex in +wait_prepare and wait_finish. + The implementation of a hotplug disconnect should also take the lock before calling v4l2_device_disconnect. diff --git a/MAINTAINERS b/MAINTAINERS index bcb668c0af71..48418c8475f0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -745,6 +745,7 @@ M: Barry Song <baohua.song@csr.com> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-prima2/ +F: drivers/dma/sirf-dma* ARM/EBSA110 MACHINE SUPPORT M: Russell King <linux@arm.linux.org.uk> @@ -2246,6 +2247,17 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm.git S: Supported F: fs/dlm/ +DMA BUFFER SHARING FRAMEWORK +M: Sumit Semwal <sumit.semwal@linaro.org> +S: Maintained +L: linux-media@vger.kernel.org +L: dri-devel@lists.freedesktop.org +L: linaro-mm-sig@lists.linaro.org +F: drivers/base/dma-buf* +F: include/linux/dma-buf* +F: Documentation/dma-buf-sharing.txt +T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git + DMA GENERIC OFFLOAD ENGINE SUBSYSTEM M: Vinod Koul <vinod.koul@intel.com> M: Dan Williams <dan.j.williams@intel.com> @@ -2830,6 +2842,14 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/fujitsu-laptop.c +FUJITSU M-5MO LS CAMERA ISP DRIVER +M: Kyungmin Park <kyungmin.park@samsung.com> +M: Heungjun Kim <riverful.kim@samsung.com> +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/video/m5mols/ +F: include/media/m5mols.h + FUSE: FILESYSTEM IN USERSPACE M: Miklos Szeredi <miklos@szeredi.hu> L: fuse-devel@lists.sourceforge.net @@ -3202,6 +3222,7 @@ F: drivers/i2c/busses/i2c-stub.c I2C SUBSYSTEM M: "Jean Delvare (PC drivers, core)" <khali@linux-fr.org> M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org> +M: "Wolfram Sang (embedded platforms)" <w.sang@pengutronix.de> L: linux-i2c@vger.kernel.org W: http://i2c.wiki.kernel.org/ T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/ @@ -3783,7 +3804,6 @@ S: Odd Fixes KERNEL NFSD, SUNRPC, AND LOCKD SERVERS M: "J. Bruce Fields" <bfields@fieldses.org> -M: Neil Brown <neilb@suse.de> L: linux-nfs@vger.kernel.org W: http://nfs.sourceforge.net/ S: Supported @@ -4692,6 +4712,8 @@ Q: http://patchwork.kernel.org/project/linux-omap/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git S: Maintained F: arch/arm/*omap*/ +F: drivers/i2c/busses/i2c-omap.c +F: include/linux/i2c-omap.h OMAP CLOCK FRAMEWORK SUPPORT M: Paul Walmsley <paul@pwsan.com> @@ -5674,6 +5696,12 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported F: sound/soc/samsung +SAMSUNG FRAMEBUFFER DRIVER +M: Jingoo Han <jg1.han@samsung.com> +L: linux-fbdev@vger.kernel.org +S: Maintained +F: drivers/video/s3c-fb.c + SERIAL DRIVERS M: Alan Cox <alan@linux.intel.com> L: linux-serial@vger.kernel.org @@ -5837,7 +5865,7 @@ F: drivers/mmc/host/sdhci-spear.c SECURITY SUBSYSTEM M: James Morris <jmorris@namei.org> L: linux-security-module@vger.kernel.org (suggested Cc:) -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git W: http://security.wiki.kernel.org/ S: Supported F: security/ @@ -5963,6 +5991,7 @@ L: davinci-linux-open-source@linux.davincidsp.com (subscribers-only) Q: http://patchwork.kernel.org/project/linux-davinci/list/ S: Supported F: arch/arm/mach-davinci +F: drivers/i2c/busses/i2c-davinci.c SIS 190 ETHERNET DRIVER M: Francois Romieu <romieu@fr.zoreil.com> @@ -7181,7 +7210,7 @@ S: Maintained F: drivers/net/vmxnet3/ VMware PVSCSI driver -M: Alok Kataria <akataria@vmware.com> +M: Arvind Kumar <arvindkumar@vmware.com> M: VMware PV-Drivers <pv-drivers@vmware.com> L: linux-scsi@vger.kernel.org S: Maintained @@ -1,7 +1,7 @@ VERSION = 3 -PATCHLEVEL = 2 +PATCHLEVEL = 3 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Saber-toothed Squirrel # *DOCUMENTATION* @@ -312,7 +312,7 @@ endif # If the user is running make -s (silent mode), suppress echoing of # commands -ifneq ($(findstring s,$(MAKEFLAGS)),) +ifneq ($(filter s% -s%,$(MAKEFLAGS)),) quiet=silent_ endif @@ -442,7 +442,7 @@ asm-generic: no-dot-config-targets := clean mrproper distclean \ cscope gtags TAGS tags help %docs check% coccicheck \ - include/linux/version.h headers_% \ + include/linux/version.h headers_% archheaders \ kernelversion %src-pkg config-targets := 0 @@ -979,7 +979,7 @@ prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \ include/config/auto.conf $(cmd_crmodverdir) -archprepare: prepare1 scripts_basic +archprepare: archheaders prepare1 scripts_basic prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. @@ -1046,8 +1046,11 @@ hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj # If we do an all arch process set dst to asm-$(hdr-arch) hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm) +PHONY += archheaders +archheaders: + PHONY += __headers -__headers: include/linux/version.h scripts_basic asm-generic FORCE +__headers: include/linux/version.h scripts_basic asm-generic archheaders FORCE $(Q)$(MAKE) $(build)=scripts build_unifdef PHONY += headers_install_all diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 40319d91bb7f..1683bfb9166f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -160,7 +160,6 @@ machine-$(CONFIG_ARCH_MSM) := msm machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0 machine-$(CONFIG_ARCH_IMX_V4_V5) := imx machine-$(CONFIG_ARCH_IMX_V6_V7) := imx -machine-$(CONFIG_ARCH_MX5) := mx5 machine-$(CONFIG_ARCH_MXS) := mxs machine-$(CONFIG_ARCH_NETX) := netx machine-$(CONFIG_ARCH_NOMADIK) := nomadik diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 5df26a9976a2..fc871e719aae 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -59,9 +59,11 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE endif +targets += $(dtb-y) + # Rule to build device tree blobs -$(obj)/%.dtb: $(src)/dts/%.dts - $(call cmd,dtc) +$(obj)/%.dtb: $(src)/dts/%.dts FORCE + $(call if_changed_dep,dtc) $(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y)) diff --git a/arch/arm/configs/mx5_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index d0d8dfece37e..3a4fb2e5fc68 100644 --- a/arch/arm/configs/mx5_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -3,6 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_KERNEL_LZO=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y CONFIG_RELAY=y CONFIG_EXPERT=y # CONFIG_SLUB_DEBUG is not set @@ -14,20 +15,31 @@ CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_LBDAF is not set # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_MXC=y -CONFIG_ARCH_MX5=y -CONFIG_MACH_MX51_BABBAGE=y +CONFIG_MACH_MX31LILLY=y +CONFIG_MACH_MX31LITE=y +CONFIG_MACH_PCM037=y +CONFIG_MACH_PCM037_EET=y +CONFIG_MACH_MX31_3DS=y +CONFIG_MACH_MX31MOBOARD=y +CONFIG_MACH_QONG=y +CONFIG_MACH_ARMADILLO5X0=y +CONFIG_MACH_KZM_ARM11_01=y +CONFIG_MACH_PCM043=y +CONFIG_MACH_MX35_3DS=y +CONFIG_MACH_EUKREA_CPUIMX35=y +CONFIG_MACH_VPR200=y +CONFIG_MACH_IMX51_DT=y CONFIG_MACH_MX51_3DS=y CONFIG_MACH_EUKREA_CPUIMX51=y CONFIG_MACH_EUKREA_CPUIMX51SD=y CONFIG_MACH_MX51_EFIKAMX=y CONFIG_MACH_MX51_EFIKASB=y -CONFIG_MACH_MX53_EVK=y -CONFIG_MACH_MX53_SMD=y -CONFIG_MACH_MX53_LOCO=y -CONFIG_MACH_MX53_ARD=y +CONFIG_MACH_IMX53_DT=y +CONFIG_SOC_IMX6Q=y CONFIG_MXC_PWM=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y CONFIG_VMSPLIT_2G=y CONFIG_PREEMPT_VOLUNTARY=y CONFIG_AEABI=y @@ -49,7 +61,7 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set -# CONFIG_IPV6 is not set +CONFIG_IPV6=y # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y @@ -68,24 +80,20 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_ATA=y CONFIG_PATA_IMX=y CONFIG_NETDEVICES=y -CONFIG_MII=m -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_QSEMI_PHY=y -CONFIG_LXT_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_SMSC_PHY=y -CONFIG_BROADCOM_PHY=y -CONFIG_ICPLUS_PHY=y -CONFIG_REALTEK_PHY=y -CONFIG_NATIONAL_PHY=y -CONFIG_STE10XP=y -CONFIG_LSI_ET1011C_PHY=y -CONFIG_MICREL_PHY=y -CONFIG_NET_ETHERNET=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_FARADAY is not set +CONFIG_FEC=y +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +# CONFIG_NET_VENDOR_STMICRO is not set # CONFIG_WLAN is not set # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_EVDEV=y @@ -124,7 +132,6 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MXC=y CONFIG_USB_STORAGE=y CONFIG_MMC=y -CONFIG_MMC_BLOCK=m CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y @@ -133,6 +140,8 @@ CONFIG_LEDS_CLASS=y CONFIG_RTC_CLASS=y CONFIG_RTC_INTF_DEV_UIE_EMUL=y CONFIG_RTC_MXC=y +CONFIG_DMADEVICES=y +CONFIG_IMX_SDMA=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y diff --git a/arch/arm/configs/mx3_defconfig b/arch/arm/configs/mx3_defconfig deleted file mode 100644 index cb0717fbb03d..000000000000 --- a/arch/arm/configs/mx3_defconfig +++ /dev/null @@ -1,144 +0,0 @@ -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EXPERT=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_MODVERSIONS=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_ARCH_MXC=y -CONFIG_MACH_MX31ADS_WM1133_EV1=y -CONFIG_MACH_MX31LILLY=y -CONFIG_MACH_MX31LITE=y -CONFIG_MACH_PCM037=y -CONFIG_MACH_PCM037_EET=y -CONFIG_MACH_MX31_3DS=y -CONFIG_MACH_MX31MOBOARD=y -CONFIG_MACH_QONG=y -CONFIG_MACH_ARMADILLO5X0=y -CONFIG_MACH_KZM_ARM11_01=y -CONFIG_MACH_PCM043=y -CONFIG_MACH_MX35_3DS=y -CONFIG_MACH_EUKREA_CPUIMX35=y -CONFIG_MXC_IRQ_PRIOR=y -CONFIG_MXC_PWM=y -CONFIG_ARM_ERRATA_411920=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_PREEMPT=y -CONFIG_AEABI=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="noinitrd console=ttymxc0,115200 root=/dev/mtdblock2 rw ip=off" -CONFIG_VFP=y -CONFIG_PM_DEBUG=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_FW_LOADER=m -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_MXC=y -CONFIG_MTD_UBI=y -# CONFIG_BLK_DEV is not set -CONFIG_MISC_DEVICES=y -CONFIG_EEPROM_AT24=y -CONFIG_NETDEVICES=y -CONFIG_SMSC_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_SMSC911X=y -CONFIG_DNET=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_KEYBOARD_ATKBD is not set -CONFIG_KEYBOARD_IMX=y -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -CONFIG_SERIAL_8250=m -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_IMX=y -CONFIG_SERIAL_IMX_CONSOLE=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_IMX=y -CONFIG_SPI=y -CONFIG_W1=y -CONFIG_W1_MASTER_MXC=y -CONFIG_W1_SLAVE_THERM=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_IMX2_WDT=y -CONFIG_MFD_WM8350_I2C=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_WM8350=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_VIDEO_DEV=y -# CONFIG_RC_CORE is not set -# CONFIG_MEDIA_TUNER_CUSTOMISE is not set -CONFIG_SOC_CAMERA=y -CONFIG_SOC_CAMERA_MT9M001=y -CONFIG_SOC_CAMERA_MT9M111=y -CONFIG_SOC_CAMERA_MT9T031=y -CONFIG_SOC_CAMERA_MT9V022=y -CONFIG_SOC_CAMERA_TW9910=y -CONFIG_SOC_CAMERA_OV772X=y -CONFIG_VIDEO_MX3=y -# CONFIG_RADIO_ADAPTERS is not set -CONFIG_FB=y -CONFIG_SOUND=y -CONFIG_SND=y -# CONFIG_SND_ARM is not set -# CONFIG_SND_SPI is not set -CONFIG_SND_SOC=y -CONFIG_SND_IMX_SOC=y -CONFIG_SND_MXC_SOC_WM1133_EV1=y -CONFIG_SND_SOC_PHYCORE_AC97=y -CONFIG_SND_SOC_EUKREA_TLV320=y -CONFIG_USB=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_MXC=y -CONFIG_USB_GADGET=m -CONFIG_USB_FSL_USB2=m -CONFIG_USB_G_SERIAL=m -CONFIG_USB_ULPI=y -CONFIG_MMC=y -CONFIG_MMC_MXC=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_MXC=y -CONFIG_DMADEVICES=y -# CONFIG_DNOTIFY is not set -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_UBIFS_FS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -# CONFIG_ENABLE_WARN_DEPRECATED is not set -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/arch/arm/include/asm/gpio.h b/arch/arm/include/asm/gpio.h index 7151753b0989..c402e9b31f4c 100644 --- a/arch/arm/include/asm/gpio.h +++ b/arch/arm/include/asm/gpio.h @@ -2,7 +2,7 @@ #define _ARCH_ARM_GPIO_H #if CONFIG_ARCH_NR_GPIO > 0 -#define ARCH_NR_GPIO CONFIG_ARCH_NR_GPIO +#define ARCH_NR_GPIOS CONFIG_ARCH_NR_GPIO #endif /* not all ARM platforms necessarily support this API ... */ diff --git a/arch/arm/include/asm/hwcap.h b/arch/arm/include/asm/hwcap.h index c93a22a8b924..917626128a1d 100644 --- a/arch/arm/include/asm/hwcap.h +++ b/arch/arm/include/asm/hwcap.h @@ -25,7 +25,8 @@ #define HWCAP_IDIVT (1 << 18) #define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) -#if defined(__KERNEL__) && !defined(__ASSEMBLY__) +#if defined(__KERNEL__) +#if !defined(__ASSEMBLY__) /* * This yields a mask that user programs can use to figure out what * instruction set this cpu supports. @@ -33,5 +34,6 @@ #define ELF_HWCAP (elf_hwcap) extern unsigned int elf_hwcap; #endif +#endif #endif diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index feec86768f9c..f82ec22eeb11 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -24,7 +24,6 @@ #define MAX_INSN_SIZE 2 #define MAX_STACK_SIZE 64 /* 32 would probably be OK */ -#define regs_return_value(regs) ((regs)->ARM_r0) #define flush_insn_slot(p) do { } while (0) #define kretprobe_blacklist_size 0 diff --git a/arch/arm/include/asm/memblock.h b/arch/arm/include/asm/memblock.h index b8da2e415e4e..00ca5f92648e 100644 --- a/arch/arm/include/asm/memblock.h +++ b/arch/arm/include/asm/memblock.h @@ -6,4 +6,6 @@ struct machine_desc; extern void arm_memblock_init(struct meminfo *, struct machine_desc *); +phys_addr_t arm_memblock_steal(phys_addr_t size, phys_addr_t align); + #endif diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 96187ff58c24..451808ba1211 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -189,6 +189,11 @@ static inline int valid_user_regs(struct pt_regs *regs) return 0; } +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->ARM_r0; +} + #define instruction_pointer(regs) (regs)->ARM_pc #ifdef CONFIG_SMP diff --git a/arch/arm/include/asm/swab.h b/arch/arm/include/asm/swab.h index 32ee164a2f6b..b859d82e30ca 100644 --- a/arch/arm/include/asm/swab.h +++ b/arch/arm/include/asm/swab.h @@ -22,7 +22,8 @@ # define __SWAB_64_THRU_32__ #endif -#if defined(__KERNEL__) && __LINUX_ARM_ARCH__ >= 6 +#if defined(__KERNEL__) +#if __LINUX_ARM_ARCH__ >= 6 static inline __attribute_const__ __u32 __arch_swahb32(__u32 x) { @@ -39,8 +40,10 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x) } #define __arch_swab32 __arch_swab32 -#else +#endif +#endif +#if !defined(__KERNEL__) || __LINUX_ARM_ARCH__ < 6 static inline __attribute_const__ __u32 __arch_swab32(__u32 x) { __u32 t; diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 0f30c3a78fc1..d4c24d412a8d 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -129,6 +129,7 @@ extern void vfp_flush_hwstate(struct thread_info *); /* * thread information flags: * TIF_SYSCALL_TRACE - syscall trace active + * TIF_SYSCAL_AUDIT - syscall auditing active * TIF_SIGPENDING - signal pending * TIF_NEED_RESCHED - rescheduling necessary * TIF_NOTIFY_RESUME - callback before returning to user @@ -139,6 +140,7 @@ extern void vfp_flush_hwstate(struct thread_info *); #define TIF_NEED_RESCHED 1 #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ #define TIF_SYSCALL_TRACE 8 +#define TIF_SYSCALL_AUDIT 9 #define TIF_POLLING_NRFLAG 16 #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ @@ -149,11 +151,15 @@ extern void vfp_flush_hwstate(struct thread_info *); #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_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_SECCOMP (1 << TIF_SECCOMP) +/* Checks for any syscall work in entry-common.S */ +#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT) + /* * Change these and you break ASM code in entry-common.S */ diff --git a/arch/arm/include/asm/unified.h b/arch/arm/include/asm/unified.h index bc631161e9c6..f5989f46b4d2 100644 --- a/arch/arm/include/asm/unified.h +++ b/arch/arm/include/asm/unified.h @@ -37,8 +37,8 @@ #define THUMB(x...) x #ifdef __ASSEMBLY__ #define W(instr) instr.w -#endif #define BSYM(sym) sym + 1 +#endif #else /* !CONFIG_THUMB2_KERNEL */ @@ -49,8 +49,8 @@ #define THUMB(x...) #ifdef __ASSEMBLY__ #define W(instr) instr -#endif #define BSYM(sym) sym +#endif #endif /* CONFIG_THUMB2_KERNEL */ diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 4a1123783806..512cd1473454 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -427,7 +427,8 @@ /* * The following syscalls are obsolete and no longer available for EABI. */ -#if defined(__ARM_EABI__) && !defined(__KERNEL__) +#if !defined(__KERNEL__) +#if defined(__ARM_EABI__) #undef __NR_time #undef __NR_umount #undef __NR_stime @@ -441,6 +442,7 @@ #undef __NR_syscall #undef __NR_ipc #endif +#endif #ifdef __KERNEL__ diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index b2a27b6b0046..520889cf1b5b 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -87,7 +87,7 @@ ENTRY(ret_from_fork) get_thread_info tsk ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? + tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls? beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1] @@ -443,7 +443,7 @@ ENTRY(vector_swi) 1: #endif - tst r10, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? + tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls? bne __sys_trace cmp scno, #NR_syscalls @ check upper syscall limit diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 14e277d2ff91..6d5791144066 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -99,6 +99,14 @@ ENTRY(stext) THUMB( it eq ) @ force fixup-able long branch encoding beq __error_p @ yes, error 'p' +#ifdef CONFIG_ARM_LPAE + mrc p15, 0, r3, c0, c1, 4 @ read ID_MMFR0 + and r3, r3, #0xf @ extract VMSA support + cmp r3, #5 @ long-descriptor translation table format? + THUMB( it lo ) @ force fixup-able long branch encoding + blo __error_p @ only classic page table format +#endif + #ifndef CONFIG_XIP_KERNEL adr r3, 2f ldmia r3, {r4, r8} diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 483727ad6892..e1d5e1929fbd 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -906,11 +906,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) { unsigned long ip; - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return scno; - if (!(current->ptrace & PT_PTRACED)) - return scno; - /* * Save IP. IP is used to denote syscall entry/exit: * IP = 0 -> entry, = 1 -> exit @@ -918,6 +913,17 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) ip = regs->ARM_ip; regs->ARM_ip = why; + if (!ip) + audit_syscall_exit(regs); + else + audit_syscall_entry(AUDIT_ARCH_ARMEB, scno, regs->ARM_r0, + regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return scno; + if (!(current->ptrace & PT_PTRACED)) + return scno; + current_thread_info()->syscall = scno; /* the 0x80 provides a way for the tracing parent to distinguish diff --git a/arch/arm/mach-ep93xx/include/mach/dma.h b/arch/arm/mach-ep93xx/include/mach/dma.h index 46d4d876e6fb..e82c642fa53c 100644 --- a/arch/arm/mach-ep93xx/include/mach/dma.h +++ b/arch/arm/mach-ep93xx/include/mach/dma.h @@ -37,7 +37,7 @@ */ struct ep93xx_dma_data { int port; - enum dma_data_direction direction; + enum dma_transfer_direction direction; const char *name; }; @@ -80,14 +80,14 @@ static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan) * channel supports given DMA direction. Only M2P channels have such * limitation, for M2M channels the direction is configurable. */ -static inline enum dma_data_direction +static inline enum dma_transfer_direction ep93xx_dma_chan_direction(struct dma_chan *chan) { if (!ep93xx_dma_chan_is_m2p(chan)) return DMA_NONE; /* even channels are for TX, odd for RX */ - return (chan->chan_id % 2 == 0) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; } #endif /* __ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-exynos/headsmp.S b/arch/arm/mach-exynos/headsmp.S index 3cdeb3647542..5364d4bfa8bc 100644 --- a/arch/arm/mach-exynos/headsmp.S +++ b/arch/arm/mach-exynos/headsmp.S @@ -36,6 +36,8 @@ pen: ldr r7, [r6] * should now contain the SVC stack for this core */ b secondary_startup +ENDPROC(exynos4_secondary_startup) + .align 2 1: .long . .long pen_release diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 2b11e046d391..0679b8ad2d1e 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -597,7 +597,8 @@ static struct s3c_fb_pd_win origen_fb_win0 = { static struct s3c_fb_platdata origen_lcd_pdata __initdata = { .win[0] = &origen_fb_win0, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC | + VIDCON1_INV_VCLK, .setup_gpio = exynos4_fimd0_gpio_setup_24bpp, }; diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 60bc45e3e709..683aec786b78 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -24,7 +24,6 @@ #include <asm/cacheflush.h> #include <asm/hardware/gic.h> #include <asm/smp_scu.h> -#include <asm/unified.h> #include <mach/hardware.h> #include <mach/regs-clock.h> @@ -137,7 +136,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) while (time_before(jiffies, timeout)) { smp_rmb(); - __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)), + __raw_writel(virt_to_phys(exynos4_secondary_startup), CPU1_BOOT_REG); gic_raise_softirq(cpumask_of(cpu), 1); @@ -192,6 +191,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) * until it receives a soft interrupt, and then the * secondary CPU branches to this address. */ - __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)), + __raw_writel(virt_to_phys(exynos4_secondary_startup), CPU1_BOOT_REG); } diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 804c4a55f803..7afbe1e55beb 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -25,7 +25,6 @@ #include <linux/smp.h> #include <asm/cacheflush.h> -#include <asm/unified.h> #include <asm/smp_scu.h> #include <asm/hardware/arm_timer.h> #include <asm/hardware/timer-sp.h> @@ -76,7 +75,7 @@ void highbank_set_cpu_jump(int cpu, void *jump_addr) #ifdef CONFIG_SMP cpu = cpu_logical_map(cpu); #endif - writel(BSYM(virt_to_phys(jump_addr)), HB_JUMP_TABLE_VIRT(cpu)); + writel(virt_to_phys(jump_addr), HB_JUMP_TABLE_VIRT(cpu)); __cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16); outer_clean_range(HB_JUMP_TABLE_PHYS(cpu), HB_JUMP_TABLE_PHYS(cpu) + 15); diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 0e6de366c648..09f357bcecde 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -22,6 +22,18 @@ config ARCH_MX25 config MACH_MX27 bool +config ARCH_MX5 + bool + +config ARCH_MX50 + bool + +config ARCH_MX51 + bool + +config ARCH_MX53 + bool + config SOC_IMX1 bool select ARCH_MX1 @@ -73,6 +85,32 @@ config SOC_IMX35 select MXC_AVIC select SMP_ON_UP if SMP +config SOC_IMX5 + select CPU_V7 + select ARM_L1_CACHE_SHIFT_6 + select MXC_TZIC + select ARCH_MXC_IOMUX_V3 + select ARCH_MXC_AUDMUX_V2 + select ARCH_HAS_CPUFREQ + select ARCH_MX5 + bool + +config SOC_IMX50 + bool + select SOC_IMX5 + select ARCH_MX50 + +config SOC_IMX51 + bool + select SOC_IMX5 + select ARCH_MX5 + select ARCH_MX51 + +config SOC_IMX53 + bool + select SOC_IMX5 + select ARCH_MX5 + select ARCH_MX53 if ARCH_IMX_V4_V5 @@ -592,6 +630,207 @@ config MACH_VPR200 Include support for VPR200 platform. This includes specific configurations for the board and its peripherals. +comment "i.MX5 platforms:" + +config MACH_MX50_RDP + bool "Support MX50 reference design platform" + depends on BROKEN + select SOC_IMX50 + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + help + Include support for MX50 reference design platform (RDP) board. This + includes specific configurations for the board and its peripherals. + +comment "i.MX51 machines:" + +config MACH_IMX51_DT + bool "Support i.MX51 platforms from device tree" + select SOC_IMX51 + select USE_OF + select MACH_MX51_BABBAGE + help + Include support for Freescale i.MX51 based platforms + using the device tree for discovery + +config MACH_MX51_BABBAGE + bool "Support MX51 BABBAGE platforms" + select SOC_IMX51 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + help + Include support for MX51 Babbage platform, also known as MX51EVK in + u-boot. This includes specific configurations for the board and its + peripherals. + +config MACH_MX51_3DS + bool "Support MX51PDK (3DS)" + select SOC_IMX51 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_DEBUG_BOARD + help + Include support for MX51PDK (3DS) platform. This includes specific + configurations for the board and its peripherals. + +config MACH_EUKREA_CPUIMX51 + bool "Support Eukrea CPUIMX51 module" + select SOC_IMX51 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SPI_IMX + help + Include support for Eukrea CPUIMX51 platform. This includes + specific configurations for the module and its peripherals. + +choice + prompt "Baseboard" + depends on MACH_EUKREA_CPUIMX51 + default MACH_EUKREA_MBIMX51_BASEBOARD + +config MACH_EUKREA_MBIMX51_BASEBOARD + prompt "Eukrea MBIMX51 development board" + bool + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select LEDS_GPIO_REGISTER + help + This adds board specific devices that can be found on Eukrea's + MBIMX51 evaluation board. + +endchoice + +config MACH_EUKREA_CPUIMX51SD + bool "Support Eukrea CPUIMX51SD module" + select SOC_IMX51 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SPI_IMX + help + Include support for Eukrea CPUIMX51SD platform. This includes + specific configurations for the module and its peripherals. + +choice + prompt "Baseboard" + depends on MACH_EUKREA_CPUIMX51SD + default MACH_EUKREA_MBIMXSD51_BASEBOARD + +config MACH_EUKREA_MBIMXSD51_BASEBOARD + prompt "Eukrea MBIMXSD development board" + bool + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select LEDS_GPIO_REGISTER + help + This adds board specific devices that can be found on Eukrea's + MBIMXSD evaluation board. + +endchoice + +config MX51_EFIKA_COMMON + bool + select SOC_IMX51 + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_PATA_IMX + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_ULPI if USB_ULPI + +config MACH_MX51_EFIKAMX + bool "Support MX51 Genesi Efika MX nettop" + select LEDS_GPIO_REGISTER + select MX51_EFIKA_COMMON + help + Include support for Genesi Efika MX nettop. This includes specific + configurations for the board and its peripherals. + +config MACH_MX51_EFIKASB + bool "Support MX51 Genesi Efika Smartbook" + select LEDS_GPIO_REGISTER + select MX51_EFIKA_COMMON + help + Include support for Genesi Efika Smartbook. This includes specific + configurations for the board and its peripherals. + +comment "i.MX53 machines:" + +config MACH_IMX53_DT + bool "Support i.MX53 platforms from device tree" + select SOC_IMX53 + select USE_OF + select MACH_MX53_ARD + select MACH_MX53_EVK + select MACH_MX53_LOCO + select MACH_MX53_SMD + help + Include support for Freescale i.MX53 based platforms + using the device tree for discovery + +config MACH_MX53_EVK + bool "Support MX53 EVK platforms" + select SOC_IMX53 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select LEDS_GPIO_REGISTER + help + Include support for MX53 EVK platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_SMD + bool "Support MX53 SMD platforms" + select SOC_IMX53 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + help + Include support for MX53 SMD platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_LOCO + bool "Support MX53 LOCO platforms" + select SOC_IMX53 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_GPIO_KEYS + select LEDS_GPIO_REGISTER + help + Include support for MX53 LOCO platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_ARD + bool "Support MX53 ARD platforms" + select SOC_IMX53 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_GPIO_KEYS + help + Include support for MX53 ARD platform. This includes specific + configurations for the board and its peripherals. + comment "i.MX6 family:" config SOC_IMX6Q diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index f5920c24f7d7..55db9c488f2b 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -11,6 +11,8 @@ obj-$(CONFIG_SOC_IMX27) += clock-imx27.o mm-imx27.o ehci-imx27.o obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o +obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o + # Support for CMOS sensor interface obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o @@ -75,3 +77,22 @@ obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o ifeq ($(CONFIG_PM),y) obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o endif + +# i.MX5 based machines +obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o +obj-$(CONFIG_MACH_MX51_3DS) += mach-mx51_3ds.o +obj-$(CONFIG_MACH_MX53_EVK) += mach-mx53_evk.o +obj-$(CONFIG_MACH_MX53_SMD) += mach-mx53_smd.o +obj-$(CONFIG_MACH_MX53_LOCO) += mach-mx53_loco.o +obj-$(CONFIG_MACH_MX53_ARD) += mach-mx53_ard.o +obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += mach-cpuimx51.o +obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o +obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += mach-cpuimx51sd.o +obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd-baseboard.o +obj-$(CONFIG_MX51_EFIKA_COMMON) += mx51_efika.o +obj-$(CONFIG_MACH_MX51_EFIKAMX) += mach-mx51_efikamx.o +obj-$(CONFIG_MACH_MX51_EFIKASB) += mach-mx51_efikasb.o +obj-$(CONFIG_MACH_MX50_RDP) += mach-mx50_rdp.o + +obj-$(CONFIG_MACH_IMX51_DT) += imx51-dt.o +obj-$(CONFIG_MACH_IMX53_DT) += imx53-dt.o diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot index 5f4d06af4912..6dfdbcc83afd 100644 --- a/arch/arm/mach-imx/Makefile.boot +++ b/arch/arm/mach-imx/Makefile.boot @@ -22,6 +22,18 @@ zreladdr-$(CONFIG_SOC_IMX35) += 0x80008000 params_phys-$(CONFIG_SOC_IMX35) := 0x80000100 initrd_phys-$(CONFIG_SOC_IMX35) := 0x80800000 +zreladdr-$(CONFIG_SOC_IMX50) += 0x70008000 +params_phys-$(CONFIG_SOC_IMX50) := 0x70000100 +initrd_phys-$(CONFIG_SOC_IMX50) := 0x70800000 + +zreladdr-$(CONFIG_SOC_IMX51) += 0x90008000 +params_phys-$(CONFIG_SOC_IMX51) := 0x90000100 +initrd_phys-$(CONFIG_SOC_IMX51) := 0x90800000 + +zreladdr-$(CONFIG_SOC_IMX53) += 0x70008000 +params_phys-$(CONFIG_SOC_IMX53) := 0x70000100 +initrd_phys-$(CONFIG_SOC_IMX53) := 0x70800000 + zreladdr-$(CONFIG_SOC_IMX6Q) += 0x10008000 params_phys-$(CONFIG_SOC_IMX6Q) := 0x10000100 initrd_phys-$(CONFIG_SOC_IMX6Q) := 0x10800000 diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-imx/clock-mx51-mx53.c index 4cb276977190..08470504a088 100644 --- a/arch/arm/mach-mx5/clock-mx51-mx53.c +++ b/arch/arm/mach-imx/clock-mx51-mx53.c @@ -23,7 +23,7 @@ #include <mach/common.h> #include <mach/clock.h> -#include "crm_regs.h" +#include "crm-regs-imx5.h" /* External clock values passed-in by the board code */ static unsigned long external_high_reference, external_low_reference; diff --git a/arch/arm/mach-mx5/cpu.c b/arch/arm/mach-imx/cpu-imx5.c index 5e2e7a843860..5e2e7a843860 100644 --- a/arch/arm/mach-mx5/cpu.c +++ b/arch/arm/mach-imx/cpu-imx5.c diff --git a/arch/arm/mach-mx5/cpu_op-mx51.c b/arch/arm/mach-imx/cpu_op-mx51.c index 9d34c3d4c024..9d34c3d4c024 100644 --- a/arch/arm/mach-mx5/cpu_op-mx51.c +++ b/arch/arm/mach-imx/cpu_op-mx51.c diff --git a/arch/arm/mach-mx5/cpu_op-mx51.h b/arch/arm/mach-imx/cpu_op-mx51.h index 97477fecb469..97477fecb469 100644 --- a/arch/arm/mach-mx5/cpu_op-mx51.h +++ b/arch/arm/mach-imx/cpu_op-mx51.h diff --git a/arch/arm/mach-mx5/crm_regs.h b/arch/arm/mach-imx/crm-regs-imx5.h index 5e11ba7daee2..5e11ba7daee2 100644 --- a/arch/arm/mach-mx5/crm_regs.h +++ b/arch/arm/mach-imx/crm-regs-imx5.h diff --git a/arch/arm/mach-mx5/devices-imx50.h b/arch/arm/mach-imx/devices-imx50.h index 7216667eaafc..7216667eaafc 100644 --- a/arch/arm/mach-mx5/devices-imx50.h +++ b/arch/arm/mach-imx/devices-imx50.h diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-imx/devices-imx51.h index af488bc0e225..af488bc0e225 100644 --- a/arch/arm/mach-mx5/devices-imx51.h +++ b/arch/arm/mach-imx/devices-imx51.h diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-imx/devices-imx53.h index 6e1e5d1f8c3a..6e1e5d1f8c3a 100644 --- a/arch/arm/mach-mx5/devices-imx53.h +++ b/arch/arm/mach-imx/devices-imx53.h diff --git a/arch/arm/mach-mx5/efika.h b/arch/arm/mach-imx/efika.h index 014aa985faae..014aa985faae 100644 --- a/arch/arm/mach-mx5/efika.h +++ b/arch/arm/mach-imx/efika.h diff --git a/arch/arm/mach-mx5/ehci.c b/arch/arm/mach-imx/ehci-imx5.c index c17fa131728b..c17fa131728b 100644 --- a/arch/arm/mach-mx5/ehci.c +++ b/arch/arm/mach-imx/ehci-imx5.c diff --git a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx51-baseboard.c index a6a3ab8f1b1c..a6a3ab8f1b1c 100644 --- a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimx51-baseboard.c diff --git a/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c index d817fc80b986..d817fc80b986 100644 --- a/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c +++ b/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c diff --git a/arch/arm/mach-mx5/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c index e6bad17b908c..e6bad17b908c 100644 --- a/arch/arm/mach-mx5/imx51-dt.c +++ b/arch/arm/mach-imx/imx51-dt.c diff --git a/arch/arm/mach-mx5/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c index 05ebb3e68679..05ebb3e68679 100644 --- a/arch/arm/mach-mx5/imx53-dt.c +++ b/arch/arm/mach-imx/imx53-dt.c diff --git a/arch/arm/mach-mx5/board-cpuimx51.c b/arch/arm/mach-imx/mach-cpuimx51.c index 944025da8333..944025da8333 100644 --- a/arch/arm/mach-mx5/board-cpuimx51.c +++ b/arch/arm/mach-imx/mach-cpuimx51.c diff --git a/arch/arm/mach-mx5/board-cpuimx51sd.c b/arch/arm/mach-imx/mach-cpuimx51sd.c index 9fbe923c8b08..9fbe923c8b08 100644 --- a/arch/arm/mach-mx5/board-cpuimx51sd.c +++ b/arch/arm/mach-imx/mach-cpuimx51sd.c diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c index 89c33258639f..4d1aab154400 100644 --- a/arch/arm/mach-imx/mach-mx31_3ds.c +++ b/arch/arm/mach-imx/mach-mx31_3ds.c @@ -36,6 +36,7 @@ #include <asm/mach/time.h> #include <asm/memory.h> #include <asm/mach/map.h> +#include <asm/memblock.h> #include <mach/common.h> #include <mach/iomux-mx3.h> #include <mach/3ds_debugboard.h> @@ -754,10 +755,8 @@ static struct sys_timer mx31_3ds_timer = { static void __init mx31_3ds_reserve(void) { /* reserve MX31_3DS_CAMERA_BUF_SIZE bytes for mx3-camera */ - mx3_camera_base = memblock_alloc(MX31_3DS_CAMERA_BUF_SIZE, + mx3_camera_base = arm_memblock_steal(MX31_3DS_CAMERA_BUF_SIZE, MX31_3DS_CAMERA_BUF_SIZE); - memblock_free(mx3_camera_base, MX31_3DS_CAMERA_BUF_SIZE); - memblock_remove(mx3_camera_base, MX31_3DS_CAMERA_BUF_SIZE); } MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)") diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index b95981dacb2b..f225262b5c38 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -41,6 +41,7 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <asm/mach/map.h> +#include <asm/memblock.h> #include <mach/board-mx31moboard.h> #include <mach/common.h> #include <mach/hardware.h> @@ -584,10 +585,8 @@ struct sys_timer mx31moboard_timer = { static void __init mx31moboard_reserve(void) { /* reserve 4 MiB for mx3-camera */ - mx3_camera_base = memblock_alloc(MX3_CAMERA_BUF_SIZE, + mx3_camera_base = arm_memblock_steal(MX3_CAMERA_BUF_SIZE, MX3_CAMERA_BUF_SIZE); - memblock_free(mx3_camera_base, MX3_CAMERA_BUF_SIZE); - memblock_remove(mx3_camera_base, MX3_CAMERA_BUF_SIZE); } MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard") diff --git a/arch/arm/mach-mx5/board-mx50_rdp.c b/arch/arm/mach-imx/mach-mx50_rdp.c index 42b66e8d9615..42b66e8d9615 100644 --- a/arch/arm/mach-mx5/board-mx50_rdp.c +++ b/arch/arm/mach-imx/mach-mx50_rdp.c diff --git a/arch/arm/mach-mx5/board-mx51_3ds.c b/arch/arm/mach-imx/mach-mx51_3ds.c index 83eab4176ca4..83eab4176ca4 100644 --- a/arch/arm/mach-mx5/board-mx51_3ds.c +++ b/arch/arm/mach-imx/mach-mx51_3ds.c diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-imx/mach-mx51_babbage.c index e4b822e9f719..e4b822e9f719 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-imx/mach-mx51_babbage.c diff --git a/arch/arm/mach-mx5/board-mx51_efikamx.c b/arch/arm/mach-imx/mach-mx51_efikamx.c index 3a5ed2dd885a..3a5ed2dd885a 100644 --- a/arch/arm/mach-mx5/board-mx51_efikamx.c +++ b/arch/arm/mach-imx/mach-mx51_efikamx.c diff --git a/arch/arm/mach-mx5/board-mx51_efikasb.c b/arch/arm/mach-imx/mach-mx51_efikasb.c index ea5f65b0381a..ea5f65b0381a 100644 --- a/arch/arm/mach-mx5/board-mx51_efikasb.c +++ b/arch/arm/mach-imx/mach-mx51_efikasb.c diff --git a/arch/arm/mach-mx5/board-mx53_ard.c b/arch/arm/mach-imx/mach-mx53_ard.c index 5f224f1c3eb6..08dfb7628d2d 100644 --- a/arch/arm/mach-mx5/board-mx53_ard.c +++ b/arch/arm/mach-imx/mach-mx53_ard.c @@ -32,7 +32,6 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> -#include "crm_regs.h" #include "devices-imx53.h" #define ARD_ETHERNET_INT_B IMX_GPIO_NR(2, 31) diff --git a/arch/arm/mach-mx5/board-mx53_evk.c b/arch/arm/mach-imx/mach-mx53_evk.c index d6ce137896d6..5a72188b9cdb 100644 --- a/arch/arm/mach-mx5/board-mx53_evk.c +++ b/arch/arm/mach-imx/mach-mx53_evk.c @@ -37,7 +37,6 @@ #define EVK_ECSPI1_CS1 IMX_GPIO_NR(3, 19) #define MX53EVK_LED IMX_GPIO_NR(7, 7) -#include "crm_regs.h" #include "devices-imx53.h" static iomux_v3_cfg_t mx53_evk_pads[] = { diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-imx/mach-mx53_loco.c index fd8b524e1c58..37f67cac15a4 100644 --- a/arch/arm/mach-mx5/board-mx53_loco.c +++ b/arch/arm/mach-imx/mach-mx53_loco.c @@ -32,7 +32,6 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> -#include "crm_regs.h" #include "devices-imx53.h" #define MX53_LOCO_POWER IMX_GPIO_NR(1, 8) diff --git a/arch/arm/mach-mx5/board-mx53_smd.c b/arch/arm/mach-imx/mach-mx53_smd.c index 22c53c9b18aa..8e972c5c3e13 100644 --- a/arch/arm/mach-mx5/board-mx53_smd.c +++ b/arch/arm/mach-imx/mach-mx53_smd.c @@ -31,7 +31,6 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> -#include "crm_regs.h" #include "devices-imx53.h" #define SMD_FEC_PHY_RST IMX_GPIO_NR(7, 6) diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c index d7e151669ed3..e48854b9d990 100644 --- a/arch/arm/mach-imx/mach-pcm037.c +++ b/arch/arm/mach-imx/mach-pcm037.c @@ -39,6 +39,7 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <asm/mach/map.h> +#include <asm/memblock.h> #include <mach/common.h> #include <mach/hardware.h> #include <mach/iomux-mx3.h> @@ -680,10 +681,8 @@ struct sys_timer pcm037_timer = { static void __init pcm037_reserve(void) { /* reserve 4 MiB for mx3-camera */ - mx3_camera_base = memblock_alloc(MX3_CAMERA_BUF_SIZE, + mx3_camera_base = arm_memblock_steal(MX3_CAMERA_BUF_SIZE, MX3_CAMERA_BUF_SIZE); - memblock_free(mx3_camera_base, MX3_CAMERA_BUF_SIZE); - memblock_remove(mx3_camera_base, MX3_CAMERA_BUF_SIZE); } MACHINE_START(PCM037, "Phytec Phycore pcm037") diff --git a/arch/arm/mach-mx5/mm.c b/arch/arm/mach-imx/mm-imx5.c index bc17dfea3817..bc17dfea3817 100644 --- a/arch/arm/mach-mx5/mm.c +++ b/arch/arm/mach-imx/mm-imx5.c diff --git a/arch/arm/mach-mx5/mx51_efika.c b/arch/arm/mach-imx/mx51_efika.c index ec6ca91b299b..ec6ca91b299b 100644 --- a/arch/arm/mach-mx5/mx51_efika.c +++ b/arch/arm/mach-imx/mx51_efika.c diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-imx/pm-imx5.c index 5eebfaad1226..6dc093448057 100644 --- a/arch/arm/mach-mx5/system.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -1,8 +1,6 @@ /* - * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. - */ - -/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: @@ -10,14 +8,22 @@ * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ -#include <linux/platform_device.h> +#include <linux/suspend.h> +#include <linux/clk.h> #include <linux/io.h> -#include <mach/hardware.h> +#include <linux/err.h> +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> #include <mach/common.h> -#include "crm_regs.h" +#include <mach/hardware.h> +#include "crm-regs-imx5.h" + +static struct clk *gpc_dvfs_clk; -/* set cpu low power mode before WFI instruction. This function is called - * mx5 because it can be used for mx50, mx51, and mx53.*/ +/* + * set cpu low power mode before WFI instruction. This function is called + * mx5 because it can be used for mx50, mx51, and mx53. + */ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) { u32 plat_lpc, arm_srpgcr, ccm_clpcr; @@ -80,3 +86,68 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); } } + +static int mx5_suspend_prepare(void) +{ + return clk_enable(gpc_dvfs_clk); +} + +static int mx5_suspend_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_MEM: + mx5_cpu_lp_set(STOP_POWER_OFF); + break; + case PM_SUSPEND_STANDBY: + mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); + break; + default: + return -EINVAL; + } + + if (state == PM_SUSPEND_MEM) { + local_flush_tlb_all(); + flush_cache_all(); + + /*clear the EMPGC0/1 bits */ + __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); + } + cpu_do_idle(); + return 0; +} + +static void mx5_suspend_finish(void) +{ + clk_disable(gpc_dvfs_clk); +} + +static int mx5_pm_valid(suspend_state_t state) +{ + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); +} + +static const struct platform_suspend_ops mx5_suspend_ops = { + .valid = mx5_pm_valid, + .prepare = mx5_suspend_prepare, + .enter = mx5_suspend_enter, + .finish = mx5_suspend_finish, +}; + +static int __init mx5_pm_init(void) +{ + if (!cpu_is_mx51() && !cpu_is_mx53()) + return 0; + + if (gpc_dvfs_clk == NULL) + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); + + if (!IS_ERR(gpc_dvfs_clk)) { + if (cpu_is_mx51()) + suspend_set_ops(&mx5_suspend_ops); + } else + return -EPERM; + + return 0; +} +device_initcall(mx5_pm_init); diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index 4bde04f99e38..29bd1243781e 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -15,7 +15,6 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/smp.h> -#include <asm/unified.h> #define SRC_SCR 0x000 #define SRC_GPR1 0x020 @@ -43,7 +42,7 @@ void imx_enable_cpu(int cpu, bool enable) void imx_set_cpu_jump(int cpu, void *jump_addr) { cpu = cpu_logical_map(cpu); - writel_relaxed(BSYM(virt_to_phys(jump_addr)), + writel_relaxed(virt_to_phys(jump_addr), src_base + SRC_GPR1 + cpu * 8); } diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S index 0c631a9f8647..bcd5af223dea 100644 --- a/arch/arm/mach-msm/headsmp.S +++ b/arch/arm/mach-msm/headsmp.S @@ -34,6 +34,7 @@ pen: ldr r7, [r6] * should now contain the SVC stack for this core */ b secondary_startup +ENDPROC(msm_secondary_startup) .align 1: .long . diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c index a9103bc6615f..bd66ed04d6dc 100644 --- a/arch/arm/mach-msm/vreg.c +++ b/arch/arm/mach-msm/vreg.c @@ -19,6 +19,7 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/debugfs.h> +#include <linux/module.h> #include <linux/string.h> #include <mach/vreg.h> diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig deleted file mode 100644 index af0c212e3c7b..000000000000 --- a/arch/arm/mach-mx5/Kconfig +++ /dev/null @@ -1,244 +0,0 @@ -if ARCH_MX5 - -# ARCH_MX5/50/53 are left to mark places where prevent multi-soc in single -# image. So for most time, SOC_IMX50/51/53 should be used. - -config ARCH_MX51 - bool - -config ARCH_MX50 - bool - -config ARCH_MX53 - bool - -config SOC_IMX50 - bool - select CPU_V7 - select ARM_L1_CACHE_SHIFT_6 - select MXC_TZIC - select ARCH_MXC_IOMUX_V3 - select ARCH_MXC_AUDMUX_V2 - select ARCH_HAS_CPUFREQ - select ARCH_MX50 - -config SOC_IMX51 - bool - select CPU_V7 - select ARM_L1_CACHE_SHIFT_6 - select MXC_TZIC - select ARCH_MXC_IOMUX_V3 - select ARCH_MXC_AUDMUX_V2 - select ARCH_HAS_CPUFREQ - select ARCH_MX51 - -config SOC_IMX53 - bool - select CPU_V7 - select ARM_L1_CACHE_SHIFT_6 - select MXC_TZIC - select ARCH_MXC_IOMUX_V3 - select ARCH_MX53 - -#comment "i.MX50 machines:" - -config MACH_MX50_RDP - bool "Support MX50 reference design platform" - depends on BROKEN - select SOC_IMX50 - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select IMX_HAVE_PLATFORM_SPI_IMX - help - Include support for MX50 reference design platform (RDP) board. This - includes specific configurations for the board and its peripherals. - -comment "i.MX51 machines:" - -config MACH_IMX51_DT - bool "Support i.MX51 platforms from device tree" - select SOC_IMX51 - select USE_OF - select MACH_MX51_BABBAGE - help - Include support for Freescale i.MX51 based platforms - using the device tree for discovery - -config MACH_MX51_BABBAGE - bool "Support MX51 BABBAGE platforms" - select SOC_IMX51 - select IMX_HAVE_PLATFORM_FSL_USB2_UDC - select IMX_HAVE_PLATFORM_IMX2_WDT - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_MXC_EHCI - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select IMX_HAVE_PLATFORM_SPI_IMX - help - Include support for MX51 Babbage platform, also known as MX51EVK in - u-boot. This includes specific configurations for the board and its - peripherals. - -config MACH_MX51_3DS - bool "Support MX51PDK (3DS)" - select SOC_IMX51 - select IMX_HAVE_PLATFORM_IMX2_WDT - select IMX_HAVE_PLATFORM_IMX_KEYPAD - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select IMX_HAVE_PLATFORM_SPI_IMX - select MXC_DEBUG_BOARD - help - Include support for MX51PDK (3DS) platform. This includes specific - configurations for the board and its peripherals. - -config MACH_EUKREA_CPUIMX51 - bool "Support Eukrea CPUIMX51 module" - select SOC_IMX51 - select IMX_HAVE_PLATFORM_FSL_USB2_UDC - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_MXC_EHCI - select IMX_HAVE_PLATFORM_MXC_NAND - select IMX_HAVE_PLATFORM_SPI_IMX - help - Include support for Eukrea CPUIMX51 platform. This includes - specific configurations for the module and its peripherals. - -choice - prompt "Baseboard" - depends on MACH_EUKREA_CPUIMX51 - default MACH_EUKREA_MBIMX51_BASEBOARD - -config MACH_EUKREA_MBIMX51_BASEBOARD - prompt "Eukrea MBIMX51 development board" - bool - select IMX_HAVE_PLATFORM_IMX_KEYPAD - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select LEDS_GPIO_REGISTER - help - This adds board specific devices that can be found on Eukrea's - MBIMX51 evaluation board. - -endchoice - -config MACH_EUKREA_CPUIMX51SD - bool "Support Eukrea CPUIMX51SD module" - select SOC_IMX51 - select IMX_HAVE_PLATFORM_FSL_USB2_UDC - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_MXC_EHCI - select IMX_HAVE_PLATFORM_MXC_NAND - select IMX_HAVE_PLATFORM_SPI_IMX - help - Include support for Eukrea CPUIMX51SD platform. This includes - specific configurations for the module and its peripherals. - -choice - prompt "Baseboard" - depends on MACH_EUKREA_CPUIMX51SD - default MACH_EUKREA_MBIMXSD51_BASEBOARD - -config MACH_EUKREA_MBIMXSD51_BASEBOARD - prompt "Eukrea MBIMXSD development board" - bool - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select LEDS_GPIO_REGISTER - help - This adds board specific devices that can be found on Eukrea's - MBIMXSD evaluation board. - -endchoice - -config MX51_EFIKA_COMMON - bool - select SOC_IMX51 - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_MXC_EHCI - select IMX_HAVE_PLATFORM_PATA_IMX - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select IMX_HAVE_PLATFORM_SPI_IMX - select MXC_ULPI if USB_ULPI - -config MACH_MX51_EFIKAMX - bool "Support MX51 Genesi Efika MX nettop" - select LEDS_GPIO_REGISTER - select MX51_EFIKA_COMMON - help - Include support for Genesi Efika MX nettop. This includes specific - configurations for the board and its peripherals. - -config MACH_MX51_EFIKASB - bool "Support MX51 Genesi Efika Smartbook" - select LEDS_GPIO_REGISTER - select MX51_EFIKA_COMMON - help - Include support for Genesi Efika Smartbook. This includes specific - configurations for the board and its peripherals. - -comment "i.MX53 machines:" - -config MACH_IMX53_DT - bool "Support i.MX53 platforms from device tree" - select SOC_IMX53 - select USE_OF - select MACH_MX53_ARD - select MACH_MX53_EVK - select MACH_MX53_LOCO - select MACH_MX53_SMD - help - Include support for Freescale i.MX53 based platforms - using the device tree for discovery - -config MACH_MX53_EVK - bool "Support MX53 EVK platforms" - select SOC_IMX53 - select IMX_HAVE_PLATFORM_IMX2_WDT - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select IMX_HAVE_PLATFORM_SPI_IMX - select LEDS_GPIO_REGISTER - help - Include support for MX53 EVK platform. This includes specific - configurations for the board and its peripherals. - -config MACH_MX53_SMD - bool "Support MX53 SMD platforms" - select SOC_IMX53 - select IMX_HAVE_PLATFORM_IMX2_WDT - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - help - Include support for MX53 SMD platform. This includes specific - configurations for the board and its peripherals. - -config MACH_MX53_LOCO - bool "Support MX53 LOCO platforms" - select SOC_IMX53 - select IMX_HAVE_PLATFORM_IMX2_WDT - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select IMX_HAVE_PLATFORM_GPIO_KEYS - select LEDS_GPIO_REGISTER - help - Include support for MX53 LOCO platform. This includes specific - configurations for the board and its peripherals. - -config MACH_MX53_ARD - bool "Support MX53 ARD platforms" - select SOC_IMX53 - select IMX_HAVE_PLATFORM_IMX2_WDT - select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_IMX_UART - select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX - select IMX_HAVE_PLATFORM_GPIO_KEYS - help - Include support for MX53 ARD platform. This includes specific - configurations for the board and its peripherals. - -endif diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile deleted file mode 100644 index 0fc60807fa2b..000000000000 --- a/arch/arm/mach-mx5/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# -# Makefile for the linux kernel. -# - -# Object file lists. -obj-y := cpu.o mm.o clock-mx51-mx53.o ehci.o system.o - -obj-$(CONFIG_PM) += pm-imx5.o -obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o -obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o -obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o -obj-$(CONFIG_MACH_MX53_EVK) += board-mx53_evk.o -obj-$(CONFIG_MACH_MX53_SMD) += board-mx53_smd.o -obj-$(CONFIG_MACH_MX53_LOCO) += board-mx53_loco.o -obj-$(CONFIG_MACH_MX53_ARD) += board-mx53_ard.o -obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o -obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o -obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += board-cpuimx51sd.o -obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd-baseboard.o -obj-$(CONFIG_MX51_EFIKA_COMMON) += mx51_efika.o -obj-$(CONFIG_MACH_MX51_EFIKAMX) += board-mx51_efikamx.o -obj-$(CONFIG_MACH_MX51_EFIKASB) += board-mx51_efikasb.o -obj-$(CONFIG_MACH_MX50_RDP) += board-mx50_rdp.o - -obj-$(CONFIG_MACH_IMX51_DT) += imx51-dt.o -obj-$(CONFIG_MACH_IMX53_DT) += imx53-dt.o diff --git a/arch/arm/mach-mx5/Makefile.boot b/arch/arm/mach-mx5/Makefile.boot deleted file mode 100644 index ca207ca305ec..000000000000 --- a/arch/arm/mach-mx5/Makefile.boot +++ /dev/null @@ -1,9 +0,0 @@ - zreladdr-$(CONFIG_ARCH_MX50) += 0x70008000 -params_phys-$(CONFIG_ARCH_MX50) := 0x70000100 -initrd_phys-$(CONFIG_ARCH_MX50) := 0x70800000 - zreladdr-$(CONFIG_ARCH_MX51) += 0x90008000 -params_phys-$(CONFIG_ARCH_MX51) := 0x90000100 -initrd_phys-$(CONFIG_ARCH_MX51) := 0x90800000 - zreladdr-$(CONFIG_ARCH_MX53) += 0x70008000 -params_phys-$(CONFIG_ARCH_MX53) := 0x70000100 -initrd_phys-$(CONFIG_ARCH_MX53) := 0x70800000 diff --git a/arch/arm/mach-mx5/pm-imx5.c b/arch/arm/mach-mx5/pm-imx5.c deleted file mode 100644 index 98052fc852c7..000000000000 --- a/arch/arm/mach-mx5/pm-imx5.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ -#include <linux/suspend.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/err.h> -#include <asm/cacheflush.h> -#include <asm/tlbflush.h> -#include <mach/common.h> -#include <mach/hardware.h> -#include "crm_regs.h" - -static struct clk *gpc_dvfs_clk; - -static int mx5_suspend_prepare(void) -{ - return clk_enable(gpc_dvfs_clk); -} - -static int mx5_suspend_enter(suspend_state_t state) -{ - switch (state) { - case PM_SUSPEND_MEM: - mx5_cpu_lp_set(STOP_POWER_OFF); - break; - case PM_SUSPEND_STANDBY: - mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); - break; - default: - return -EINVAL; - } - - if (state == PM_SUSPEND_MEM) { - local_flush_tlb_all(); - flush_cache_all(); - - /*clear the EMPGC0/1 bits */ - __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); - __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); - } - cpu_do_idle(); - return 0; -} - -static void mx5_suspend_finish(void) -{ - clk_disable(gpc_dvfs_clk); -} - -static int mx5_pm_valid(suspend_state_t state) -{ - return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); -} - -static const struct platform_suspend_ops mx5_suspend_ops = { - .valid = mx5_pm_valid, - .prepare = mx5_suspend_prepare, - .enter = mx5_suspend_enter, - .finish = mx5_suspend_finish, -}; - -static int __init mx5_pm_init(void) -{ - if (gpc_dvfs_clk == NULL) - gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); - - if (!IS_ERR(gpc_dvfs_clk)) { - if (cpu_is_mx51()) - suspend_set_ops(&mx5_suspend_ops); - } else - return -EPERM; - - return 0; -} -device_initcall(mx5_pm_init); diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 904bd1dfcd2e..a8ba7b96dcd1 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -366,8 +366,8 @@ config OMAP3_SDRC_AC_TIMING going on could result in system crashes; config OMAP4_ERRATA_I688 - bool "OMAP4 errata: Async Bridge Corruption" - depends on ARCH_OMAP4 + bool "OMAP4 errata: Async Bridge Corruption (BROKEN)" + depends on ARCH_OMAP4 && BROKEN select ARCH_HAS_BARRIERS help If a data is stalled inside asynchronous bridge because of back diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 2ceb75d21eb2..39fba9df17fb 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -602,20 +602,6 @@ static void __init omap_sfh7741prox_init(void) __func__, OMAP4_SFH7741_ENABLE_GPIO, error); } -static void sdp4430_hdmi_mux_init(void) -{ - /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ - omap_mux_init_signal("hdmi_hpd", - OMAP_PIN_INPUT_PULLUP); - omap_mux_init_signal("hdmi_cec", - OMAP_PIN_INPUT_PULLUP); - /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ - omap_mux_init_signal("hdmi_ddc_scl", - OMAP_PIN_INPUT_PULLUP); - omap_mux_init_signal("hdmi_ddc_sda", - OMAP_PIN_INPUT_PULLUP); -} - static struct gpio sdp4430_hdmi_gpios[] = { { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, @@ -833,9 +819,16 @@ static void omap_4430sdp_display_init(void) pr_err("%s: Could not get display_sel GPIO\n", __func__); sdp4430_lcd_init(); - sdp4430_hdmi_mux_init(); sdp4430_picodlp_init(); omap_display_init(&sdp4430_dss_data); + /* + * OMAP4460SDP/Blaze and OMAP4430 ES2.3 SDP/Blaze boards and + * later have external pull up on the HDMI I2C lines + */ + if (cpu_is_omap446x() || omap_rev() > OMAP4430_REV_ES2_2) + omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP); + else + omap_hdmi_init(0); } #ifdef CONFIG_OMAP_MUX diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index e96a2e7ad36f..30ad40db2cf3 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -412,21 +412,6 @@ int __init omap4_panda_dvi_init(void) return r; } - -static void omap4_panda_hdmi_mux_init(void) -{ - /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ - omap_mux_init_signal("hdmi_hpd", - OMAP_PIN_INPUT_PULLUP); - omap_mux_init_signal("hdmi_cec", - OMAP_PIN_INPUT_PULLUP); - /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ - omap_mux_init_signal("hdmi_ddc_scl", - OMAP_PIN_INPUT_PULLUP); - omap_mux_init_signal("hdmi_ddc_sda", - OMAP_PIN_INPUT_PULLUP); -} - static struct gpio panda_hdmi_gpios[] = { { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, @@ -478,8 +463,16 @@ void omap4_panda_display_init(void) if (r) pr_err("error initializing panda DVI\n"); - omap4_panda_hdmi_mux_init(); omap_display_init(&omap4_panda_dss_data); + + /* + * OMAP4460SDP/Blaze and OMAP4430 ES2.3 SDP/Blaze boards and + * later have external pull up on the HDMI I2C lines + */ + if (cpu_is_omap446x() || omap_rev() > OMAP4430_REV_ES2_2) + omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP); + else + omap_hdmi_init(0); } static void __init omap4_panda_init(void) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 46dfd1ae8f71..0b510ad01a00 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -28,7 +28,6 @@ #include <plat/board.h> #include <plat/mcbsp.h> #include <plat/mmc.h> -#include <plat/iommu.h> #include <plat/dma.h> #include <plat/omap_hwmod.h> #include <plat/omap_device.h> @@ -128,6 +127,10 @@ static struct platform_device omap2cam_device = { }; #endif +#if defined(CONFIG_IOMMU_API) + +#include <plat/iommu.h> + static struct resource omap3isp_resources[] = { { .start = OMAP3430_ISP_BASE, @@ -224,6 +227,15 @@ int omap3_init_camera(struct isp_platform_data *pdata) return platform_device_register(&omap3isp_device); } +#else /* !CONFIG_IOMMU_API */ + +int omap3_init_camera(struct isp_platform_data *pdata) +{ + return 0; +} + +#endif + static inline void omap_init_camera(void) { #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE) diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index bc6cf863a563..3c446d1a1781 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -30,6 +30,7 @@ #include <plat/omap-pm.h> #include "common.h" +#include "mux.h" #include "control.h" #include "display.h" @@ -97,6 +98,36 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = { { "dss_hdmi", "omapdss_hdmi", -1 }, }; +static void omap4_hdmi_mux_pads(enum omap_hdmi_flags flags) +{ + u32 reg; + u16 control_i2c_1; + + /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ + omap_mux_init_signal("hdmi_hpd", + OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("hdmi_cec", + OMAP_PIN_INPUT_PULLUP); + /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ + omap_mux_init_signal("hdmi_ddc_scl", + OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("hdmi_ddc_sda", + OMAP_PIN_INPUT_PULLUP); + + /* + * CONTROL_I2C_1: HDMI_DDC_SDA_PULLUPRESX (bit 28) and + * HDMI_DDC_SCL_PULLUPRESX (bit 24) are set to disable + * internal pull up resistor. + */ + if (flags & OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP) { + control_i2c_1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1; + reg = omap4_ctrl_pad_readl(control_i2c_1); + reg |= (OMAP4_HDMI_DDC_SDA_PULLUPRESX_MASK | + OMAP4_HDMI_DDC_SCL_PULLUPRESX_MASK); + omap4_ctrl_pad_writel(reg, control_i2c_1); + } +} + static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes) { u32 enable_mask, enable_shift; @@ -130,6 +161,14 @@ static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes) return 0; } +int omap_hdmi_init(enum omap_hdmi_flags flags) +{ + if (cpu_is_omap44xx()) + omap4_hdmi_mux_pads(flags); + + return 0; +} + static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask) { if (cpu_is_omap44xx()) diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c index 69f3c72d959b..d8f8ef40290f 100644 --- a/arch/arm/mach-omap2/omap-secure.c +++ b/arch/arm/mach-omap2/omap-secure.c @@ -16,6 +16,7 @@ #include <linux/memblock.h> #include <asm/cacheflush.h> +#include <asm/memblock.h> #include <mach/omap-secure.h> @@ -57,20 +58,10 @@ u32 omap_secure_dispatcher(u32 idx, u32 flag, u32 nargs, u32 arg1, u32 arg2, /* Allocate the memory to save secure ram */ int __init omap_secure_ram_reserve_memblock(void) { - phys_addr_t paddr; u32 size = OMAP_SECURE_RAM_STORAGE; size = ALIGN(size, SZ_1M); - paddr = memblock_alloc(size, SZ_1M); - if (!paddr) { - pr_err("%s: failed to reserve %x bytes\n", - __func__, size); - return -ENOMEM; - } - memblock_free(paddr, size); - memblock_remove(paddr, size); - - omap_secure_memblock_base = paddr; + omap_secure_memblock_base = arm_memblock_steal(size, SZ_1M); return 0; } diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index bc16c818c6b7..40a8fbc07e4b 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -20,6 +20,7 @@ #include <asm/hardware/gic.h> #include <asm/hardware/cache-l2x0.h> #include <asm/mach/map.h> +#include <asm/memblock.h> #include <plat/irqs.h> #include <plat/sram.h> @@ -61,13 +62,8 @@ static int __init omap_barriers_init(void) return -ENODEV; size = ALIGN(PAGE_SIZE, SZ_1M); - paddr = memblock_alloc(size, SZ_1M); - if (!paddr) { - pr_err("%s: failed to reserve 4 Kbytes\n", __func__); - return -ENOMEM; - } - memblock_free(paddr, size); - memblock_remove(paddr, size); + paddr = arm_memblock_steal(size, SZ_1M); + dram_io_desc[0].virtual = OMAP4_DRAM_BARRIER_VA; dram_io_desc[0].pfn = __phys_to_pfn(paddr); dram_io_desc[0].length = size; diff --git a/arch/arm/mach-picoxcell/time.c b/arch/arm/mach-picoxcell/time.c index 6c89cf8ab22e..2ecba6743b8e 100644 --- a/arch/arm/mach-picoxcell/time.c +++ b/arch/arm/mach-picoxcell/time.c @@ -67,7 +67,7 @@ static void picoxcell_add_clocksource(struct device_node *source_timer) static void __iomem *sched_io_base; -unsigned u32 notrace picoxcell_read_sched_clock(void) +static u32 picoxcell_read_sched_clock(void) { return __raw_readl(sched_io_base); } diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index e83c654a58d0..17c878ddbc70 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -17,7 +17,6 @@ #include <asm/hardware/gic.h> #include <asm/mach-types.h> #include <asm/smp_scu.h> -#include <asm/unified.h> #include <mach/board-eb.h> #include <mach/board-pb11mp.h> @@ -75,6 +74,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) * until it receives a soft interrupt, and then the * secondary CPU branches to this address. */ - __raw_writel(BSYM(virt_to_phys(versatile_secondary_startup)), + __raw_writel(virt_to_phys(versatile_secondary_startup), __io_address(REALVIEW_SYS_FLAGSSET)); } diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 0069561464f9..e62962117763 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -117,17 +117,14 @@ static void __init realview_eb_map_io(void) static struct pl061_platform_data gpio0_plat_data = { .gpio_base = 0, - .irq_base = -1, }; static struct pl061_platform_data gpio1_plat_data = { .gpio_base = 8, - .irq_base = -1, }; static struct pl061_platform_data gpio2_plat_data = { .gpio_base = 16, - .irq_base = -1, }; static struct pl022_ssp_controller ssp0_plat_data = { diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index 8fe395568a47..e4abe94fb11a 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -113,17 +113,14 @@ static void __init realview_pb1176_map_io(void) static struct pl061_platform_data gpio0_plat_data = { .gpio_base = 0, - .irq_base = -1, }; static struct pl061_platform_data gpio1_plat_data = { .gpio_base = 8, - .irq_base = -1, }; static struct pl061_platform_data gpio2_plat_data = { .gpio_base = 16, - .irq_base = -1, }; static struct pl022_ssp_controller ssp0_plat_data = { diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index 34a26011bb89..127a3fd42ab1 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -112,17 +112,14 @@ static void __init realview_pb11mp_map_io(void) static struct pl061_platform_data gpio0_plat_data = { .gpio_base = 0, - .irq_base = -1, }; static struct pl061_platform_data gpio1_plat_data = { .gpio_base = 8, - .irq_base = -1, }; static struct pl061_platform_data gpio2_plat_data = { .gpio_base = 16, - .irq_base = -1, }; static struct pl022_ssp_controller ssp0_plat_data = { diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index d26a6def1d65..25b2e59296f8 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -102,17 +102,14 @@ static void __init realview_pba8_map_io(void) static struct pl061_platform_data gpio0_plat_data = { .gpio_base = 0, - .irq_base = -1, }; static struct pl061_platform_data gpio1_plat_data = { .gpio_base = 8, - .irq_base = -1, }; static struct pl061_platform_data gpio2_plat_data = { .gpio_base = 16, - .irq_base = -1, }; static struct pl022_ssp_controller ssp0_plat_data = { diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index a250fb4124bf..ac715645b860 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c @@ -124,17 +124,14 @@ static void __init realview_pbx_map_io(void) static struct pl061_platform_data gpio0_plat_data = { .gpio_base = 0, - .irq_base = -1, }; static struct pl061_platform_data gpio1_plat_data = { .gpio_base = 8, - .irq_base = -1, }; static struct pl061_platform_data gpio2_plat_data = { .gpio_base = 16, - .irq_base = -1, }; static struct pl022_ssp_controller ssp0_plat_data = { diff --git a/arch/arm/mach-s3c64xx/include/mach/crag6410.h b/arch/arm/mach-s3c64xx/include/mach/crag6410.h index 5d55ab018b6b..4cb2f951f1e9 100644 --- a/arch/arm/mach-s3c64xx/include/mach/crag6410.h +++ b/arch/arm/mach-s3c64xx/include/mach/crag6410.h @@ -21,5 +21,6 @@ #define CODEC_GPIO_BASE (GPIO_BOARD_START + 8) #define GLENFARCLAS_PMIC_GPIO_BASE (GPIO_BOARD_START + 32) #define BANFF_PMIC_GPIO_BASE (GPIO_BOARD_START + 64) +#define MMGPIO_GPIO_BASE (GPIO_BOARD_START + 96) #endif diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 1cc91d794c97..8077f650eb0e 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -260,6 +260,7 @@ static struct platform_device crag6410_dm9k_device = { static struct resource crag6410_mmgpio_resource[] = { [0] = { + .name = "dat", .start = S3C64XX_PA_XM0CSN4 + 1, .end = S3C64XX_PA_XM0CSN4 + 1, .flags = IORESOURCE_MEM, @@ -272,7 +273,7 @@ static struct platform_device crag6410_mmgpio = { .resource = crag6410_mmgpio_resource, .num_resources = ARRAY_SIZE(crag6410_mmgpio_resource), .dev.platform_data = &(struct bgpio_pdata) { - .base = -1, + .base = MMGPIO_GPIO_BASE, }, }; @@ -328,7 +329,6 @@ static struct platform_device wallvdd_device = { static struct platform_device *crag6410_devices[] __initdata = { &s3c_device_hsmmc0, - &s3c_device_hsmmc1, &s3c_device_hsmmc2, &s3c_device_i2c0, &s3c_device_i2c1, @@ -355,7 +355,7 @@ static struct platform_device *crag6410_devices[] __initdata = { static struct pca953x_platform_data crag6410_pca_data = { .gpio_base = PCA935X_GPIO_BASE, - .irq_base = 0, + .irq_base = -1, }; /* VDDARM is controlled by DVS1 connected to GPK(0) */ @@ -683,12 +683,6 @@ static struct s3c_sdhci_platdata crag6410_hsmmc2_pdata = { .cd_type = S3C_SDHCI_CD_PERMANENT, }; -static struct s3c_sdhci_platdata crag6410_hsmmc1_pdata = { - .max_width = 4, - .cd_type = S3C_SDHCI_CD_GPIO, - .ext_cd_gpio = S3C64XX_GPF(11), -}; - static void crag6410_cfg_sdhci0(struct platform_device *dev, int width) { /* Set all the necessary GPG pins to special-function 2 */ @@ -723,7 +717,6 @@ static void __init crag6410_machine_init(void) gpio_direction_output(S3C64XX_GPF(10), 1); s3c_sdhci0_set_platdata(&crag6410_hsmmc0_pdata); - s3c_sdhci1_set_platdata(&crag6410_hsmmc1_pdata); s3c_sdhci2_set_platdata(&crag6410_hsmmc2_pdata); s3c_i2c0_set_platdata(&i2c0_pdata); diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index 055dac90e0e2..7d3e81b9dd06 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -346,23 +346,10 @@ int __init s3c64xx_pm_init(void) static __init int s3c64xx_pm_initcall(void) { - u32 val; - pm_cpu_prep = s3c64xx_pm_prepare; pm_cpu_sleep = s3c64xx_cpu_suspend; pm_uart_udivslot = 1; - /* - * Unconditionally disable power domains that contain only - * blocks which have no mainline driver support. - */ - val = __raw_readl(S3C64XX_NORMAL_CFG); - val &= ~(S3C64XX_NORMALCFG_DOMAIN_G_ON | - S3C64XX_NORMALCFG_DOMAIN_V_ON | - S3C64XX_NORMALCFG_DOMAIN_I_ON | - S3C64XX_NORMALCFG_DOMAIN_P_ON); - __raw_writel(val, S3C64XX_NORMAL_CFG); - #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK gpio_request(S3C64XX_GPN(12), "DEBUG_LED0"); gpio_request(S3C64XX_GPN(13), "DEBUG_LED1"); diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 6b93e200bcac..ebafe8aa8956 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -202,6 +202,7 @@ static struct irda_platform_data assabet_irda_data = { static struct mcp_plat_data assabet_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, + .codec = "ucb1x00", }; static void __init assabet_init(void) @@ -252,6 +253,17 @@ static void __init assabet_init(void) sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources, ARRAY_SIZE(assabet_flash_resources)); sa11x0_register_irda(&assabet_irda_data); + + /* + * Setup the PPC unit correctly. + */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + + ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); sa11x0_register_mcp(&assabet_mcp_data); } @@ -268,7 +280,7 @@ static void __init map_sa1100_gpio_regs( void ) int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO); pmd_t *pmd; - pmd = pmd_offset(pgd_offset_k(virt), virt); + pmd = pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt); *pmd = __pmd(phys | prot); flush_pmd_entry(pmd); } diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 11bb6d0b9be3..d12d0f48b1dc 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -124,12 +124,23 @@ static void __init cerf_map_io(void) static struct mcp_plat_data cerf_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, + .codec = "ucb1x00", }; static void __init cerf_init(void) { platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices)); sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1); + + /* + * Setup the PPC unit correctly. + */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + sa11x0_register_mcp(&cerf_mcp_data); } diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index b9060e236def..c483912d08af 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -27,6 +27,7 @@ #include <linux/timer.h> #include <linux/gpio.h> #include <linux/pda_power.h> +#include <linux/mfd/ucb1x00.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -85,10 +86,15 @@ static struct scoop_pcmcia_config collie_pcmcia_config = { .num_devs = 1, }; +static struct ucb1x00_plat_data collie_ucb1x00_data = { + .gpio_base = COLLIE_TC35143_GPIO_BASE, +}; + static struct mcp_plat_data collie_mcp_data = { .mccr0 = MCCR0_ADM | MCCR0_ExtClk, .sclk_rate = 9216000, - .gpio_base = COLLIE_TC35143_GPIO_BASE, + .codec = "ucb1x00", + .codec_pdata = &collie_ucb1x00_data, }; /* @@ -351,6 +357,16 @@ static void __init collie_init(void) sa11x0_register_mtd(&collie_flash_data, collie_flash_resources, ARRAY_SIZE(collie_flash_resources)); + + /* + * Setup the PPC unit correctly. + */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + sa11x0_register_mcp(&collie_mcp_data); sharpsl_save_param(); diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 480d2ea46b00..e3a28ca2a7b7 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -217,10 +217,15 @@ static struct platform_device sa11x0uart3_device = { static struct resource sa11x0mcp_resources[] = { [0] = { .start = __PREG(Ser4MCCR0), - .end = __PREG(Ser4MCCR0) + 0xffff, + .end = __PREG(Ser4MCCR0) + 0x1C - 1, .flags = IORESOURCE_MEM, }, [1] = { + .start = __PREG(Ser4MCCR1), + .end = __PREG(Ser4MCCR1) + 0x4 - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { .start = IRQ_Ser4MCP, .end = IRQ_Ser4MCP, .flags = IORESOURCE_IRQ, diff --git a/arch/arm/mach-sa1100/include/mach/gpio.h b/arch/arm/mach-sa1100/include/mach/gpio.h index 703631887c94..a38fc4f54241 100644 --- a/arch/arm/mach-sa1100/include/mach/gpio.h +++ b/arch/arm/mach-sa1100/include/mach/gpio.h @@ -51,7 +51,4 @@ static inline void gpio_set_value(unsigned gpio, int value) #define gpio_cansleep __gpio_cansleep -#define gpio_to_irq(gpio) ((gpio < 11) ? (IRQ_GPIO0 + gpio) : \ - (IRQ_GPIO11 - 11 + gpio)) - #endif diff --git a/arch/arm/mach-sa1100/include/mach/mcp.h b/arch/arm/mach-sa1100/include/mach/mcp.h index ed1a331508a7..586cec898b35 100644 --- a/arch/arm/mach-sa1100/include/mach/mcp.h +++ b/arch/arm/mach-sa1100/include/mach/mcp.h @@ -17,6 +17,8 @@ struct mcp_plat_data { u32 mccr1; unsigned int sclk_rate; int gpio_base; + const char *codec; + void *codec_pdata; }; #endif diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index af4e2761f3db..d117ceab6215 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -24,10 +24,20 @@ static struct mcp_plat_data lart_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, + .codec = "ucb1x00", }; static void __init lart_init(void) { + /* + * Setup the PPC unit correctly. + */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + sa11x0_register_mcp(&lart_mcp_data); } diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c index 318b2b766a0b..748d34435b3f 100644 --- a/arch/arm/mach-sa1100/shannon.c +++ b/arch/arm/mach-sa1100/shannon.c @@ -55,11 +55,22 @@ static struct resource shannon_flash_resource = { static struct mcp_plat_data shannon_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, + .codec = "ucb1x00", }; static void __init shannon_init(void) { sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1); + + /* + * Setup the PPC unit correctly. + */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + sa11x0_register_mcp(&shannon_mcp_data); } diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index e17c04d6e324..458ececefa58 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -14,6 +14,7 @@ #include <linux/mtd/partitions.h> #include <linux/io.h> #include <linux/gpio.h> +#include <linux/mfd/ucb1x00.h> #include <asm/irq.h> #include <mach/hardware.h> @@ -187,10 +188,15 @@ static struct resource simpad_flash_resources [] = { } }; +static struct ucb1x00_plat_data simpad_ucb1x00_data = { + .gpio_base = SIMPAD_UCB1X00_GPIO_BASE, +}; + static struct mcp_plat_data simpad_mcp_data = { .mccr0 = MCCR0_ADM, .sclk_rate = 11981000, - .gpio_base = SIMPAD_UCB1X00_GPIO_BASE, + .codec = "ucb1300", + .codec_pdata = &simpad_ucb1x00_data, }; @@ -378,6 +384,16 @@ static int __init simpad_init(void) sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources, ARRAY_SIZE(simpad_flash_resources)); + + /* + * Setup the PPC unit correctly. + */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + sa11x0_register_mcp(&simpad_mcp_data); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index a4e6ca04e319..eff8a96c75ee 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -271,7 +271,7 @@ static struct sh_mobile_lcdc_info lcdc0_info = { .flags = LCDC_FLAGS_DWPOL, .lcd_size_cfg.width = 44, .lcd_size_cfg.height = 79, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .lcd_cfg = lcdc0_modes, .num_cfg = ARRAY_SIZE(lcdc0_modes), .board_cfg = { @@ -321,12 +321,46 @@ static struct resource mipidsi0_resources[] = { }, }; +#define DSI0PHYCR 0xe615006c +static int sh_mipi_set_dot_clock(struct platform_device *pdev, + void __iomem *base, + int enable) +{ + struct clk *pck; + int ret; + + pck = clk_get(&pdev->dev, "dsip_clk"); + if (IS_ERR(pck)) { + ret = PTR_ERR(pck); + goto sh_mipi_set_dot_clock_pck_err; + } + + if (enable) { + clk_set_rate(pck, clk_round_rate(pck, 24000000)); + __raw_writel(0x2a809010, DSI0PHYCR); + clk_enable(pck); + } else { + clk_disable(pck); + } + + ret = 0; + + clk_put(pck); + +sh_mipi_set_dot_clock_pck_err: + return ret; +} + static struct sh_mipi_dsi_info mipidsi0_info = { .data_format = MIPI_RGB888, .lcd_chan = &lcdc0_info.ch[0], + .lane = 2, .vsynw_offset = 20, .clksrc = 1, - .flags = SH_MIPI_DSI_HSABM, + .flags = SH_MIPI_DSI_HSABM | + SH_MIPI_DSI_SYNC_PULSES_MODE | + SH_MIPI_DSI_HSbyteCLK, + .set_dot_clock = sh_mipi_set_dot_clock, }; static struct platform_device mipidsi0_device = { @@ -472,8 +506,6 @@ static void __init ag5evm_map_io(void) shmobile_setup_console(); } -#define DSI0PHYCR 0xe615006c - static void __init ag5evm_init(void) { sh73a0_pinmux_init(); @@ -554,9 +586,6 @@ static void __init ag5evm_init(void) gpio_direction_output(GPIO_PORT235, 0); lcd_backlight_reset(); - /* MIPI-DSI clock setup */ - __raw_writel(0x2a809010, DSI0PHYCR); - /* enable SDHI0 on CN15 [SD I/F] */ gpio_request(GPIO_FN_SDHICD0, NULL); gpio_request(GPIO_FN_SDHIWP0, NULL); diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index d2e7b73aa9b6..aab0a349f759 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -491,7 +491,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .meram_dev = &meram_info, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .lcd_cfg = ap4evb_lcdc_modes, .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes), .meram_cfg = &lcd_meram_cfg, @@ -564,6 +564,30 @@ static struct platform_device keysc_device = { }; /* MIPI-DSI */ +#define PHYCTRL 0x0070 +static int sh_mipi_set_dot_clock(struct platform_device *pdev, + void __iomem *base, + int enable) +{ + struct clk *pck = clk_get(&pdev->dev, "dsip_clk"); + void __iomem *phy = base + PHYCTRL; + + if (IS_ERR(pck)) + return PTR_ERR(pck); + + if (enable) { + clk_set_rate(pck, clk_round_rate(pck, 24000000)); + iowrite32(ioread32(phy) | (0xb << 8), phy); + clk_enable(pck); + } else { + clk_disable(pck); + } + + clk_put(pck); + + return 0; +} + static struct resource mipidsi0_resources[] = { [0] = { .start = 0xffc60000, @@ -580,7 +604,11 @@ static struct resource mipidsi0_resources[] = { static struct sh_mipi_dsi_info mipidsi0_info = { .data_format = MIPI_RGB888, .lcd_chan = &lcdc_info.ch[0], + .lane = 2, .vsynw_offset = 17, + .flags = SH_MIPI_DSI_SYNC_PULSES_MODE | + SH_MIPI_DSI_HSbyteCLK, + .set_dot_clock = sh_mipi_set_dot_clock, }; static struct platform_device mipidsi0_device = { @@ -798,7 +826,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = { .meram_dev = &meram_info, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = RGB24, .clock_divider = 1, .flags = LCDC_FLAGS_DWPOL, diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index cbc5934ae03f..9b42fbd10f8e 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -388,7 +388,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .clock_source = LCDC_CLK_BUS, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .lcd_cfg = mackerel_lcdc_modes, .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes), .interface_type = RGB24, @@ -451,7 +451,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = RGB24, .clock_divider = 1, .flags = LCDC_FLAGS_DWPOL, diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index e349c22a0d71..293456d8dcfd 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -612,8 +612,8 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]), CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), - CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), - CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 34944d01bf1e..afbead6a6e17 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -427,8 +427,8 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]), CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), - CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), - CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */ diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c index 77b8fc12fc2f..fcf8b1761aef 100644 --- a/arch/arm/mach-shmobile/pm-sh7372.c +++ b/arch/arm/mach-shmobile/pm-sh7372.c @@ -276,7 +276,7 @@ static int sh7372_a3sp_suspend(void) * Serial consoles make use of SCIF hardware located in A3SP, * keep such power domain on if "no_console_suspend" is set. */ - return console_suspend_enabled ? -EBUSY : 0; + return console_suspend_enabled ? 0 : -EBUSY; } struct sh7372_pm_domain sh7372_a3sp = { diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 1ea89be63e29..6fcf304d3cdf 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -445,31 +445,39 @@ static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = { }, }; +#define SH7372_CHCLR 0x220 + static const struct sh_dmae_channel sh7372_dmae_channels[] = { { .offset = 0, .dmars = 0, .dmars_bit = 0, + .chclr_offset = SH7372_CHCLR + 0, }, { .offset = 0x10, .dmars = 0, .dmars_bit = 8, + .chclr_offset = SH7372_CHCLR + 0x10, }, { .offset = 0x20, .dmars = 4, .dmars_bit = 0, + .chclr_offset = SH7372_CHCLR + 0x20, }, { .offset = 0x30, .dmars = 4, .dmars_bit = 8, + .chclr_offset = SH7372_CHCLR + 0x30, }, { .offset = 0x50, .dmars = 8, .dmars_bit = 0, + .chclr_offset = SH7372_CHCLR + 0x50, }, { .offset = 0x60, .dmars = 8, .dmars_bit = 8, + .chclr_offset = SH7372_CHCLR + 0x60, } }; @@ -487,6 +495,7 @@ static struct sh_dmae_pdata dma_platform_data = { .ts_shift = ts_shift, .ts_shift_num = ARRAY_SIZE(ts_shift), .dmaor_init = DMAOR_DME, + .chclr_present = 1, }; /* Resource order important! */ @@ -494,7 +503,7 @@ static struct resource sh7372_dmae0_resources[] = { { /* Channel registers and DMAOR */ .start = 0xfe008020, - .end = 0xfe00808f, + .end = 0xfe00828f, .flags = IORESOURCE_MEM, }, { @@ -522,7 +531,7 @@ static struct resource sh7372_dmae1_resources[] = { { /* Channel registers and DMAOR */ .start = 0xfe018020, - .end = 0xfe01808f, + .end = 0xfe01828f, .flags = IORESOURCE_MEM, }, { @@ -550,7 +559,7 @@ static struct resource sh7372_dmae2_resources[] = { { /* Channel registers and DMAOR */ .start = 0xfe028020, - .end = 0xfe02808f, + .end = 0xfe02828f, .flags = IORESOURCE_MEM, }, { diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 9361a5290177..5c00712907d1 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -19,11 +19,11 @@ #include <linux/amba/pl022.h> #include <linux/amba/serial.h> #include <linux/spi/spi.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/regulator/ab8500.h> #include <linux/mfd/tc3589x.h> #include <linux/mfd/tps6105x.h> -#include <linux/mfd/ab8500/gpio.h> +#include <linux/mfd/abx500/ab8500-gpio.h> #include <linux/leds-lp5521.h> #include <linux/input.h> #include <linux/smsc911x.h> diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c index fe1569b67c91..9de9e9c4dbbb 100644 --- a/arch/arm/mach-ux500/board-u5500.c +++ b/arch/arm/mach-ux500/board-u5500.c @@ -10,7 +10,7 @@ #include <linux/amba/bus.h> #include <linux/irq.h> #include <linux/i2c.h> -#include <linux/mfd/ab5500/ab5500.h> +#include <linux/mfd/abx500/ab5500.h> #include <asm/hardware/gic.h> #include <asm/mach/arch.h> diff --git a/arch/arm/mach-ux500/headsmp.S b/arch/arm/mach-ux500/headsmp.S index 64fa451edcfd..08da5589bcd8 100644 --- a/arch/arm/mach-ux500/headsmp.S +++ b/arch/arm/mach-ux500/headsmp.S @@ -32,6 +32,8 @@ pen: ldr r7, [r6] * should now contain the SVC stack for this core */ b secondary_startup +ENDPROC(u8500_secondary_startup) + .align 2 1: .long . .long pen_release diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h index 47969909836c..d2d4131435a6 100644 --- a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h +++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h @@ -9,7 +9,7 @@ #define __MACH_IRQS_BOARD_MOP500_H /* Number of AB8500 irqs is taken from header file */ -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START #define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \ diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 2b5f7ac001a3..124ffb169093 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -13,8 +13,6 @@ #include <linux/smp.h> #include <linux/io.h> -#include <asm/unified.h> - #include <mach/motherboard.h> #define V2M_PA_CS7 0x10000000 @@ -46,6 +44,6 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus) * secondary CPU branches to this address. */ writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR)); - writel(BSYM(virt_to_phys(versatile_secondary_startup)), + writel(virt_to_phys(versatile_secondary_startup), MMIO_P2V(V2M_SYS_FLAGSSET)); } diff --git a/arch/arm/mach-w90x900/clksel.c b/arch/arm/mach-w90x900/clksel.c index 3de4a5211c3b..06d867dce551 100644 --- a/arch/arm/mach-w90x900/clksel.c +++ b/arch/arm/mach-w90x900/clksel.c @@ -48,7 +48,7 @@ static void clock_source_select(const char *dev_id, unsigned int clkval) offset = ATAOFFSET; else if (strcmp(dev_id, "nuc900-lcd") == 0) offset = LCDOFFSET; - else if (strcmp(dev_id, "nuc900-audio") == 0) + else if (strcmp(dev_id, "nuc900-ac97") == 0) offset = AUDOFFSET; else offset = CPUOFFSET; diff --git a/arch/arm/mach-w90x900/cpu.c b/arch/arm/mach-w90x900/cpu.c index 604e1db266e8..9a0661992909 100644 --- a/arch/arm/mach-w90x900/cpu.c +++ b/arch/arm/mach-w90x900/cpu.c @@ -79,7 +79,7 @@ static DEFINE_CLK(timer4, 23); static struct clk_lookup nuc900_clkregs[] = { DEF_CLKLOOK(&clk_lcd, "nuc900-lcd", NULL), - DEF_CLKLOOK(&clk_audio, "nuc900-audio", NULL), + DEF_CLKLOOK(&clk_audio, "nuc900-ac97", NULL), DEF_CLKLOOK(&clk_fmi, "nuc900-fmi", NULL), DEF_CLKLOOK(&clk_ms, "nuc900-fmi", "MS"), DEF_CLKLOOK(&clk_sd, "nuc900-fmi", "SD"), diff --git a/arch/arm/mach-w90x900/dev.c b/arch/arm/mach-w90x900/dev.c index 5b0c38abacc1..78110befb7a9 100644 --- a/arch/arm/mach-w90x900/dev.c +++ b/arch/arm/mach-w90x900/dev.c @@ -501,8 +501,8 @@ static struct resource nuc900_ac97_resource[] = { }; -struct platform_device nuc900_device_audio = { - .name = "nuc900-audio", +struct platform_device nuc900_device_ac97 = { + .name = "nuc900-ac97", .id = -1, .num_resources = ARRAY_SIZE(nuc900_ac97_resource), .resource = nuc900_ac97_resource, @@ -523,7 +523,7 @@ static struct platform_device *nuc900_public_dev[] __initdata = { &nuc900_device_emc, &nuc900_device_spi, &nuc900_device_wdt, - &nuc900_device_audio, + &nuc900_device_ac97, }; /* Provide adding specific CPU platform devices API */ diff --git a/arch/arm/mach-w90x900/mfp.c b/arch/arm/mach-w90x900/mfp.c index 9dd74612bb87..c58d142b8a46 100644 --- a/arch/arm/mach-w90x900/mfp.c +++ b/arch/arm/mach-w90x900/mfp.c @@ -155,7 +155,7 @@ void mfp_set_groupg(struct device *dev, const char *subname) } else if (strcmp(dev_id, "nuc900-i2c1") == 0) { mfpen &= ~(GPIOG2TO3); mfpen |= ENI2C1;/*enable i2c1*/ - } else if (strcmp(dev_id, "nuc900-audio") == 0) { + } else if (strcmp(dev_id, "nuc900-ac97") == 0) { mfpen &= ~(GPIOG22TO23); mfpen |= ENAC97;/*enable AC97*/ } else if (strcmp(dev_id, "nuc900-mmc-port1") == 0) { diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index e34ea8adc1f9..6ec1226fc62d 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -22,6 +22,7 @@ #include <linux/memblock.h> #include <asm/mach-types.h> +#include <asm/memblock.h> #include <asm/prom.h> #include <asm/sections.h> #include <asm/setup.h> @@ -307,6 +308,21 @@ static void arm_memory_present(void) } #endif +static bool arm_memblock_steal_permitted = true; + +phys_addr_t arm_memblock_steal(phys_addr_t size, phys_addr_t align) +{ + phys_addr_t phys; + + BUG_ON(!arm_memblock_steal_permitted); + + phys = memblock_alloc(size, align); + memblock_free(phys, size); + memblock_remove(phys, size); + + return phys; +} + void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) { int i; @@ -349,6 +365,7 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) if (mdesc->reserve) mdesc->reserve(); + arm_memblock_steal_permitted = false; memblock_allow_resize(); memblock_dump_all(); } diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index b30708e28c1d..dcebb1230f7f 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -17,26 +17,17 @@ config ARCH_IMX_V4_V5 and ARMv5 SoCs config ARCH_IMX_V6_V7 - bool "i.MX3, i.MX6" + bool "i.MX3, i.MX5, i.MX6" select AUTO_ZRELADDR if !ZBOOT_ROM select ARM_PATCH_PHYS_VIRT select MIGHT_HAVE_CACHE_L2X0 help - This enables support for systems based on the Freescale i.MX3 and i.MX6 - family. - -config ARCH_MX5 - bool "i.MX50, i.MX51, i.MX53" - select AUTO_ZRELADDR if !ZBOOT_ROM - select ARM_PATCH_PHYS_VIRT - help - This enables support for machines using Freescale's i.MX50 and i.MX53 - processors. + This enables support for systems based on the Freescale i.MX3, i.MX5 + and i.MX6 family. endchoice source "arch/arm/mach-imx/Kconfig" -source "arch/arm/mach-mx5/Kconfig" endmenu diff --git a/arch/arm/plat-mxc/include/mach/mx3fb.h b/arch/arm/plat-mxc/include/mach/mx3fb.h index ac24c5c4bc83..fdbe60001542 100644 --- a/arch/arm/plat-mxc/include/mach/mx3fb.h +++ b/arch/arm/plat-mxc/include/mach/mx3fb.h @@ -22,6 +22,20 @@ #define FB_SYNC_SWAP_RGB 0x04000000 #define FB_SYNC_CLK_SEL_EN 0x02000000 +/* + * Specify the way your display is connected. The IPU can arbitrarily + * map the internal colors to the external data lines. We only support + * the following mappings at the moment. + */ +enum disp_data_mapping { + /* blue -> d[0..5], green -> d[6..11], red -> d[12..17] */ + IPU_DISP_DATA_MAPPING_RGB666, + /* blue -> d[0..4], green -> d[5..10], red -> d[11..15] */ + IPU_DISP_DATA_MAPPING_RGB565, + /* blue -> d[0..7], green -> d[8..15], red -> d[16..23] */ + IPU_DISP_DATA_MAPPING_RGB888, +}; + /** * struct mx3fb_platform_data - mx3fb platform data * @@ -33,6 +47,7 @@ struct mx3fb_platform_data { const char *name; const struct fb_videomode *mode; int num_modes; + enum disp_data_mapping disp_data_fmt; }; #endif diff --git a/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/arch/arm/plat-nomadik/include/plat/ste_dma40.h index 685c78716d95..fd0ee84c45d1 100644 --- a/arch/arm/plat-nomadik/include/plat/ste_dma40.h +++ b/arch/arm/plat-nomadik/include/plat/ste_dma40.h @@ -113,7 +113,8 @@ struct stedma40_half_channel_info { * @dst_dev_type: Dst device type * @src_info: Parameters for dst half channel * @dst_info: Parameters for dst half channel - * + * @use_fixed_channel: if true, use physical channel specified by phy_channel + * @phy_channel: physical channel to use, only if use_fixed_channel is true * * This structure has to be filled by the client drivers. * It is recommended to do all dma configurations for clients in the machine. @@ -129,6 +130,9 @@ struct stedma40_chan_cfg { int dst_dev_type; struct stedma40_half_channel_info src_info; struct stedma40_half_channel_info dst_info; + + bool use_fixed_channel; + int phy_channel; }; /** @@ -153,6 +157,7 @@ struct stedma40_platform_data { struct stedma40_chan_cfg *memcpy_conf_phy; struct stedma40_chan_cfg *memcpy_conf_log; int disabled_channels[STEDMA40_MAX_PHYS]; + bool use_esram_lcla; }; #ifdef CONFIG_STE_DMA40 @@ -187,7 +192,7 @@ static inline struct dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan, dma_addr_t addr, unsigned int size, - enum dma_data_direction direction, + enum dma_transfer_direction direction, unsigned long flags) { struct scatterlist sg; @@ -209,7 +214,7 @@ static inline struct dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan, dma_addr_t addr, unsigned int size, - enum dma_data_direction direction, + enum dma_transfer_direction direction, unsigned long flags) { return NULL; diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 19719329a47b..60278f47c0bd 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -20,6 +20,7 @@ #include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/mach/map.h> +#include <asm/memblock.h> #include <plat/tc.h> #include <plat/board.h> @@ -164,14 +165,12 @@ void __init omap_dsp_reserve_sdram_memblock(void) if (!size) return; - paddr = memblock_alloc(size, SZ_1M); + paddr = arm_memblock_steal(size, SZ_1M); if (!paddr) { pr_err("%s: failed to reserve %x bytes\n", __func__, size); return; } - memblock_free(paddr, size); - memblock_remove(paddr, size); omap_dsp_phys_mempool_base = paddr; } diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c index 1121df13e15f..21f1fda8b661 100644 --- a/arch/arm/plat-s3c24xx/cpu.c +++ b/arch/arm/plat-s3c24xx/cpu.c @@ -38,8 +38,6 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <mach/system-reset.h> - #include <mach/regs-gpio.h> #include <plat/regs-serial.h> diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c index 2cded872f22b..0747c77a2fd5 100644 --- a/arch/arm/plat-samsung/dma-ops.c +++ b/arch/arm/plat-samsung/dma-ops.c @@ -37,14 +37,14 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch, (void *)dma_ch; chan = dma_request_channel(mask, pl330_filter, filter_param); - if (info->direction == DMA_FROM_DEVICE) { + if (info->direction == DMA_DEV_TO_MEM) { memset(&slave_config, 0, sizeof(struct dma_slave_config)); slave_config.direction = info->direction; slave_config.src_addr = info->fifo; slave_config.src_addr_width = info->width; slave_config.src_maxburst = 1; dmaengine_slave_config(chan, &slave_config); - } else if (info->direction == DMA_TO_DEVICE) { + } else if (info->direction == DMA_MEM_TO_DEV) { memset(&slave_config, 0, sizeof(struct dma_slave_config)); slave_config.direction = info->direction; slave_config.dst_addr = info->fifo; diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h index 22eafc310bd7..71a6827c7706 100644 --- a/arch/arm/plat-samsung/include/plat/dma-ops.h +++ b/arch/arm/plat-samsung/include/plat/dma-ops.h @@ -14,10 +14,11 @@ #define __SAMSUNG_DMA_OPS_H_ __FILE__ #include <linux/dmaengine.h> +#include <mach/dma.h> struct samsung_dma_prep_info { enum dma_transaction_type cap; - enum dma_data_direction direction; + enum dma_transfer_direction direction; dma_addr_t buf; unsigned long period; unsigned long len; @@ -27,7 +28,7 @@ struct samsung_dma_prep_info { struct samsung_dma_info { enum dma_transaction_type cap; - enum dma_data_direction direction; + enum dma_transfer_direction direction; enum dma_slave_buswidth width; dma_addr_t fifo; struct s3c2410_dma_client *client; diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h index b9061128abde..7b02143ccd9a 100644 --- a/arch/arm/plat-samsung/include/plat/dma.h +++ b/arch/arm/plat-samsung/include/plat/dma.h @@ -10,6 +10,9 @@ * published by the Free Software Foundation. */ +#ifndef __PLAT_DMA_H +#define __PLAT_DMA_H + #include <linux/dma-mapping.h> enum s3c2410_dma_buffresult { @@ -122,5 +125,6 @@ extern int s3c2410_dma_getposition(enum dma_ch channel, extern int s3c2410_dma_set_opfn(enum dma_ch, s3c2410_dma_opfn_t rtn); extern int s3c2410_dma_set_buffdone_fn(enum dma_ch, s3c2410_dma_cbfn_t rtn); - #include <plat/dma-ops.h> + +#endif diff --git a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h index aea68b60ef98..fa95e9a00972 100644 --- a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h +++ b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h @@ -11,6 +11,8 @@ #ifndef __S3C64XX_PLAT_SPI_H #define __S3C64XX_PLAT_SPI_H +struct platform_device; + /** * struct s3c64xx_spi_csinfo - ChipSelect description * @fb_delay: Slave specific feedback delay. diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h index 656dc00d30ed..f82f888b91a9 100644 --- a/arch/arm/plat-samsung/include/plat/sdhci.h +++ b/arch/arm/plat-samsung/include/plat/sdhci.h @@ -63,6 +63,7 @@ enum clk_types { struct s3c_sdhci_platdata { unsigned int max_width; unsigned int host_caps; + unsigned int pm_caps; enum cd_types cd_type; enum clk_types clk_type; diff --git a/arch/arm/plat-samsung/platformdata.c b/arch/arm/plat-samsung/platformdata.c index ceb9fa3a80c0..0f707184eae0 100644 --- a/arch/arm/plat-samsung/platformdata.c +++ b/arch/arm/plat-samsung/platformdata.c @@ -53,6 +53,8 @@ void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd, set->cfg_gpio = pd->cfg_gpio; if (pd->host_caps) set->host_caps |= pd->host_caps; + if (pd->pm_caps) + set->pm_caps |= pd->pm_caps; if (pd->clk_type) set->clk_type = pd->clk_type; } diff --git a/arch/arm/plat-versatile/headsmp.S b/arch/arm/plat-versatile/headsmp.S index d397a1fb2f54..dd703ef09b8d 100644 --- a/arch/arm/plat-versatile/headsmp.S +++ b/arch/arm/plat-versatile/headsmp.S @@ -38,3 +38,4 @@ pen: ldr r7, [r6] .align 1: .long . .long pen_release +ENDPROC(versatile_secondary_startup) diff --git a/arch/frv/include/asm/param.h b/arch/frv/include/asm/param.h index 6859dd503ed3..a52dca9a9566 100644 --- a/arch/frv/include/asm/param.h +++ b/arch/frv/include/asm/param.h @@ -1,22 +1,8 @@ #ifndef _ASM_PARAM_H #define _ASM_PARAM_H -#ifdef __KERNEL__ -#define HZ CONFIG_HZ /* Internal kernel timer frequency */ -#define USER_HZ 100 /* .. some user interfaces are in "ticks" */ -#define CLOCKS_PER_SEC (USER_HZ) /* like times() */ -#endif - -#ifndef HZ -#define HZ 100 -#endif - #define EXEC_PAGESIZE 16384 -#ifndef NOGROUP -#define NOGROUP (-1) -#endif - -#define MAXHOSTNAMELEN 64 /* max length of hostname */ +#include <asm-generic/param.h> #endif /* _ASM_PARAM_H */ diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c index 22078486d35d..6192f7188654 100644 --- a/arch/ia64/hp/common/aml_nfw.c +++ b/arch/ia64/hp/common/aml_nfw.c @@ -31,7 +31,7 @@ MODULE_AUTHOR("Bjorn Helgaas <bjorn.helgaas@hp.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ACPI opregion handler for native firmware calls"); -static int force_register; +static bool force_register; module_param_named(force, force_register, bool, 0); MODULE_PARM_DESC(force, "Install opregion handler even without HPQ5001 device"); diff --git a/arch/ia64/include/asm/intrinsics.h b/arch/ia64/include/asm/intrinsics.h index 111ed5222892..e4076b511829 100644 --- a/arch/ia64/include/asm/intrinsics.h +++ b/arch/ia64/include/asm/intrinsics.h @@ -201,16 +201,21 @@ extern long ia64_cmpxchg_called_with_bad_pointer (void); #endif #ifndef __ASSEMBLY__ -#if defined(CONFIG_PARAVIRT) && defined(__KERNEL__) -#ifdef ASM_SUPPORTED -# define IA64_INTRINSIC_API(name) paravirt_ ## name -#else -# define IA64_INTRINSIC_API(name) pv_cpu_ops.name -#endif -#define IA64_INTRINSIC_MACRO(name) paravirt_ ## name -#else + #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 +# ifdef ASM_SUPPORTED +# define IA64_INTRINSIC_API(name) paravirt_ ## name +# else +# define IA64_INTRINSIC_API(name) pv_cpu_ops.name +# endif +#define IA64_INTRINSIC_MACRO(name) paravirt_ ## name +#endif #endif /************************************************/ diff --git a/arch/ia64/include/asm/ptrace.h b/arch/ia64/include/asm/ptrace.h index f5cb27614e35..68c98f5b3ca6 100644 --- a/arch/ia64/include/asm/ptrace.h +++ b/arch/ia64/include/asm/ptrace.h @@ -246,7 +246,18 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs) return regs->ar_bspstore; } -#define regs_return_value(regs) ((regs)->r8) +static inline int is_syscall_success(struct pt_regs *regs) +{ + return regs->r10 != -1; +} + +static inline long regs_return_value(struct pt_regs *regs) +{ + if (is_syscall_success(regs)) + return regs->r8; + else + return -regs->r8; +} /* Conserve space in histogram by encoding slot bits in address * bits 2 and 3 rather than bits 0 and 1. diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index 7617248f0d11..7a3bd2524944 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -323,11 +323,12 @@ #define __NR_sendmmsg 1331 #define __NR_process_vm_readv 1332 #define __NR_process_vm_writev 1333 +#define __NR_accept4 1334 #ifdef __KERNEL__ -#define NR_syscalls 310 /* length of syscall table */ +#define NR_syscalls 311 /* length of syscall table */ /* * The following defines stop scripts/checksyscalls.sh from complaining about diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index bfb4d01e0e51..5207035dc061 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -429,22 +429,24 @@ static u32 __devinitdata pxm_flag[PXM_FLAG_LEN]; static struct acpi_table_slit __initdata *slit_table; cpumask_t early_cpu_possible_map = CPU_MASK_NONE; -static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) +static int __init +get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) { int pxm; pxm = pa->proximity_domain_lo; - if (ia64_platform_is("sn2")) + if (ia64_platform_is("sn2") || acpi_srat_revision >= 2) pxm += pa->proximity_domain_hi[0] << 8; return pxm; } -static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) +static int __init +get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) { int pxm; pxm = ma->proximity_domain; - if (!ia64_platform_is("sn2")) + if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1) pxm &= 0xff; return pxm; diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 5b31d46aff67..1ccbe12a4d84 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1779,6 +1779,7 @@ sys_call_table: data8 sys_sendmmsg data8 sys_process_vm_readv data8 sys_process_vm_writev + data8 sys_accept4 .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */ diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 8848f43d819e..dad91661ddf9 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1246,15 +1246,8 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, if (test_thread_flag(TIF_RESTORE_RSE)) ia64_sync_krbs(); - if (unlikely(current->audit_context)) { - long syscall; - int arch; - syscall = regs.r15; - arch = AUDIT_ARCH_IA64; - - audit_syscall_entry(arch, syscall, arg0, arg1, arg2, arg3); - } + audit_syscall_entry(AUDIT_ARCH_IA64, regs.r15, arg0, arg1, arg2, arg3); return 0; } @@ -1268,14 +1261,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3, { int step; - if (unlikely(current->audit_context)) { - int success = AUDITSC_RESULT(regs.r10); - long result = regs.r8; - - if (success != AUDITSC_SUCCESS) - result = -result; - audit_syscall_exit(success, result); - } + audit_syscall_exit(®s); step = test_thread_flag(TIF_SINGLESTEP); if (step || test_thread_flag(TIF_SYSCALL_TRACE)) diff --git a/arch/m32r/include/asm/param.h b/arch/m32r/include/asm/param.h index 94c770196048..fa207bdf96e7 100644 --- a/arch/m32r/include/asm/param.h +++ b/arch/m32r/include/asm/param.h @@ -1,23 +1,7 @@ #ifndef _ASM_M32R_PARAM_H #define _ASM_M32R_PARAM_H -#ifdef __KERNEL__ -# define HZ CONFIG_HZ /* Internal kernel timer frequency */ -# define USER_HZ 100 /* .. some user interfaces are in "ticks" */ -# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ -#endif - -#ifndef HZ -#define HZ 100 -#endif - -#define EXEC_PAGESIZE 4096 - -#ifndef NOGROUP -#define NOGROUP (-1) -#endif - -#define MAXHOSTNAMELEN 64 /* max length of hostname */ +#include <asm-generic/param.h> #endif /* _ASM_M32R_PARAM_H */ diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 4c4e58ef0cb6..0c796cf81586 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -53,6 +53,6 @@ $(obj)/simpleImage.%: vmlinux FORCE DTC_FLAGS := -p 1024 $(obj)/%.dtb: $(src)/dts/%.dts FORCE - $(call cmd,dtc) + $(call if_changed_dep,dtc) clean-files += *.dtb simpleImage.*.unstrip linux.bin.ub diff --git a/arch/microblaze/include/asm/ptrace.h b/arch/microblaze/include/asm/ptrace.h index 816bee64b196..94e92c805859 100644 --- a/arch/microblaze/include/asm/ptrace.h +++ b/arch/microblaze/include/asm/ptrace.h @@ -61,6 +61,11 @@ struct pt_regs { #define instruction_pointer(regs) ((regs)->pc) #define profile_pc(regs) instruction_pointer(regs) +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->r3; +} + #else /* __KERNEL__ */ /* pt_regs offsets used by gdbserver etc in ptrace syscalls */ diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index 043cb58f9c44..6eb2aa927d89 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c @@ -147,10 +147,8 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) */ ret = -1L; - if (unlikely(current->audit_context)) - audit_syscall_entry(EM_MICROBLAZE, regs->r12, - regs->r5, regs->r6, - regs->r7, regs->r8); + audit_syscall_entry(EM_MICROBLAZE, regs->r12, regs->r5, regs->r6, + regs->r7, regs->r8); return ret ?: regs->r12; } @@ -159,8 +157,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) { int step; - if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3); + audit_syscall_exit(regs); step = test_thread_flag(TIF_SINGLESTEP); if (step || test_thread_flag(TIF_SYSCALL_TRACE)) diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 604cd9dd1333..d4fc1a971779 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -26,6 +26,7 @@ #include <linux/cache.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> +#include <linux/cpu.h> #include <asm/cacheflush.h> #include <asm/entry.h> #include <asm/cpuinfo.h> @@ -226,5 +227,23 @@ static int __init setup_bus_notifier(void) return 0; } - arch_initcall(setup_bus_notifier); + +static DEFINE_PER_CPU(struct cpu, cpu_devices); + +static int __init topology_init(void) +{ + int i, ret; + + for_each_present_cpu(i) { + struct cpu *c = &per_cpu(cpu_devices, i); + + ret = register_cpu(c, i); + if (ret) + printk(KERN_WARNING "topology_init: register_cpu %d " + "failed (%d)\n", i, ret); + } + + return 0; +} +subsys_initcall(topology_init); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 29d92187ff30..c4c1312473fb 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -719,7 +719,6 @@ config CAVIUM_OCTEON_SIMULATOR select DMA_COHERENT select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN - select SYS_SUPPORTS_HIGHMEM select SYS_SUPPORTS_HOTPLUG_CPU select SYS_HAS_CPU_CAVIUM_OCTEON select HOLES_IN_ZONE @@ -735,7 +734,6 @@ config CAVIUM_OCTEON_REFERENCE_BOARD select DMA_COHERENT select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN - select SYS_SUPPORTS_HIGHMEM select SYS_SUPPORTS_HOTPLUG_CPU select SYS_HAS_EARLY_PRINTK select SYS_HAS_CPU_CAVIUM_OCTEON @@ -764,7 +762,6 @@ config NLM_XLR_BOARD depends on EXPERIMENTAL select BOOT_ELF32 select NLM_COMMON - select NLM_XLR select SYS_HAS_CPU_XLR select SYS_SUPPORTS_SMP select HW_HAS_PCI @@ -779,6 +776,7 @@ config NLM_XLR_BOARD select CEVT_R4K select CSRC_R4K select IRQ_CPU + select ARCH_SUPPORTS_MSI select ZONE_DMA if 64BIT select SYNC_R4K select SYS_HAS_EARLY_PRINTK @@ -786,6 +784,33 @@ config NLM_XLR_BOARD Support for systems based on Netlogic XLR and XLS processors. Say Y here if you have a XLR or XLS based board. +config NLM_XLP_BOARD + bool "Netlogic XLP based systems" + depends on EXPERIMENTAL + select BOOT_ELF32 + select NLM_COMMON + select SYS_HAS_CPU_XLP + select SYS_SUPPORTS_SMP + select HW_HAS_PCI + select SWAP_IO_SPACE + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select 64BIT_PHYS_ADDR + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_HIGHMEM + select DMA_COHERENT + select NR_CPUS_DEFAULT_32 + select CEVT_R4K + select CSRC_R4K + select IRQ_CPU + select ZONE_DMA if 64BIT + select SYNC_R4K + select SYS_HAS_EARLY_PRINTK + help + This board is based on Netlogic XLP Processor. + Say Y here if you have a XLP based board. + endchoice source "arch/mips/alchemy/Kconfig" @@ -1416,51 +1441,36 @@ config CPU_CAVIUM_OCTEON config CPU_BMIPS3300 bool "BMIPS3300" depends on SYS_HAS_CPU_BMIPS3300 - select DMA_NONCOHERENT - select IRQ_CPU - select SWAP_IO_SPACE - select SYS_SUPPORTS_32BIT_KERNEL - select WEAK_ORDERING + select CPU_BMIPS help Broadcom BMIPS3300 processors. config CPU_BMIPS4350 bool "BMIPS4350" depends on SYS_HAS_CPU_BMIPS4350 - select CPU_SUPPORTS_32BIT_KERNEL - select DMA_NONCOHERENT - select IRQ_CPU - select SWAP_IO_SPACE + select CPU_BMIPS select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU - select WEAK_ORDERING help Broadcom BMIPS4350 ("VIPER") processors. config CPU_BMIPS4380 bool "BMIPS4380" depends on SYS_HAS_CPU_BMIPS4380 - select CPU_SUPPORTS_32BIT_KERNEL - select DMA_NONCOHERENT - select IRQ_CPU - select SWAP_IO_SPACE + select CPU_BMIPS select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU - select WEAK_ORDERING help Broadcom BMIPS4380 processors. config CPU_BMIPS5000 bool "BMIPS5000" depends on SYS_HAS_CPU_BMIPS5000 - select CPU_SUPPORTS_32BIT_KERNEL + select CPU_BMIPS select CPU_SUPPORTS_HIGHMEM - select DMA_NONCOHERENT - select IRQ_CPU - select SWAP_IO_SPACE + select MIPS_CPU_SCACHE select SYS_SUPPORTS_SMP select SYS_SUPPORTS_HOTPLUG_CPU - select WEAK_ORDERING help Broadcom BMIPS5000 processors. @@ -1475,6 +1485,19 @@ config CPU_XLR select CPU_SUPPORTS_HUGEPAGES help Netlogic Microsystems XLR/XLS processors. + +config CPU_XLP + bool "Netlogic XLP SoC" + depends on SYS_HAS_CPU_XLP + select CPU_SUPPORTS_32BIT_KERNEL + select CPU_SUPPORTS_64BIT_KERNEL + select CPU_SUPPORTS_HIGHMEM + select CPU_HAS_LLSC + select WEAK_ORDERING + select WEAK_REORDERING_BEYOND_LLSC + select CPU_HAS_PREFETCH + help + Netlogic Microsystems XLP processors. endchoice if CPU_LOONGSON2F @@ -1521,6 +1544,15 @@ config CPU_LOONGSON2 select CPU_SUPPORTS_64BIT_KERNEL select CPU_SUPPORTS_HIGHMEM +config CPU_BMIPS + bool + select CPU_MIPS32 + select CPU_SUPPORTS_32BIT_KERNEL + select DMA_NONCOHERENT + select IRQ_CPU + select SWAP_IO_SPACE + select WEAK_ORDERING + config SYS_HAS_CPU_LOONGSON2E bool @@ -1608,6 +1640,9 @@ config SYS_HAS_CPU_BMIPS5000 config SYS_HAS_CPU_XLR bool +config SYS_HAS_CPU_XLP + bool + # # CPU may reorder R->R, R->W, W->R, W->W # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC @@ -1995,6 +2030,9 @@ config CPU_HAS_SMARTMIPS config CPU_HAS_WB bool +config XKS01 + bool + # # Vectored interrupt mode is an R2 feature # diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 0be318609fc6..4fedf5a51d96 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -157,6 +157,7 @@ ifeq (,$(findstring march=octeon, $(cflags-$(CONFIG_CPU_CAVIUM_OCTEON)))) cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon endif cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1 +cflags-$(CONFIG_CPU_BMIPS) += -march=mips32 -Wa,-mips32 -Wa,--trap cflags-$(CONFIG_CPU_R4000_WORKAROUNDS) += $(call cc-option,-mfix-r4000,) cflags-$(CONFIG_CPU_R4400_WORKAROUNDS) += $(call cc-option,-mfix-r4400,) diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig index 2a68be6a1b97..0faaab24376e 100644 --- a/arch/mips/alchemy/Kconfig +++ b/arch/mips/alchemy/Kconfig @@ -2,6 +2,10 @@ config ALCHEMY_GPIOINT_AU1000 bool +# au1300-style GPIO/INT controller +config ALCHEMY_GPIOINT_AU1300 + bool + # select this in your board config if you don't want to use the gpio # namespace as documented in the manuals. In this case however you need # to create the necessary gpio_* functions in your board code/headers! @@ -22,43 +26,29 @@ config MIPS_MTX1 select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK -config MIPS_BOSPORUS - bool "Alchemy Bosporus board" - select ALCHEMY_GPIOINT_AU1000 - select DMA_NONCOHERENT - select SYS_SUPPORTS_LITTLE_ENDIAN - select SYS_HAS_EARLY_PRINTK - config MIPS_DB1000 - bool "Alchemy DB1000 board" + bool "Alchemy DB1000/DB1500/DB1100 boards" select ALCHEMY_GPIOINT_AU1000 select DMA_NONCOHERENT select HW_HAS_PCI - select SYS_SUPPORTS_LITTLE_ENDIAN - select SYS_HAS_EARLY_PRINTK - -config MIPS_DB1100 - bool "Alchemy DB1100 board" - select ALCHEMY_GPIOINT_AU1000 - select DMA_NONCOHERENT + select MIPS_DISABLE_OBSOLETE_IDE + select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK config MIPS_DB1200 - bool "Alchemy DB1200 board" + bool "Alchemy DB1200/PB1200 board" select ALCHEMY_GPIOINT_AU1000 select DMA_COHERENT select MIPS_DISABLE_OBSOLETE_IDE select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK -config MIPS_DB1500 - bool "Alchemy DB1500 board" - select ALCHEMY_GPIOINT_AU1000 - select DMA_NONCOHERENT - select HW_HAS_PCI +config MIPS_DB1300 + bool "NetLogic DB1300 board" + select ALCHEMY_GPIOINT_AU1300 + select DMA_COHERENT select MIPS_DISABLE_OBSOLETE_IDE - select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK @@ -66,27 +56,11 @@ config MIPS_DB1550 bool "Alchemy DB1550 board" select ALCHEMY_GPIOINT_AU1000 select HW_HAS_PCI - select DMA_NONCOHERENT + select DMA_COHERENT select MIPS_DISABLE_OBSOLETE_IDE select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK -config MIPS_MIRAGE - bool "Alchemy Mirage board" - select DMA_NONCOHERENT - select ALCHEMY_GPIOINT_AU1000 - select SYS_SUPPORTS_LITTLE_ENDIAN - select SYS_HAS_EARLY_PRINTK - -config MIPS_PB1000 - bool "Alchemy PB1000 board" - select ALCHEMY_GPIOINT_AU1000 - select DMA_NONCOHERENT - select HW_HAS_PCI - select SWAP_IO_SPACE - select SYS_SUPPORTS_LITTLE_ENDIAN - select SYS_HAS_EARLY_PRINTK - config MIPS_PB1100 bool "Alchemy PB1100 board" select ALCHEMY_GPIOINT_AU1000 @@ -96,14 +70,6 @@ config MIPS_PB1100 select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_HAS_EARLY_PRINTK -config MIPS_PB1200 - bool "Alchemy PB1200 board" - select ALCHEMY_GPIOINT_AU1000 - select DMA_NONCOHERENT - select MIPS_DISABLE_OBSOLETE_IDE - select SYS_SUPPORTS_LITTLE_ENDIAN - select SYS_HAS_EARLY_PRINTK - config MIPS_PB1500 bool "Alchemy PB1500 board" select ALCHEMY_GPIOINT_AU1000 diff --git a/arch/mips/alchemy/Makefile b/arch/mips/alchemy/Makefile new file mode 100644 index 000000000000..aac3b179bbc0 --- /dev/null +++ b/arch/mips/alchemy/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MIPS_GPR) += board-gpr.o +obj-$(CONFIG_MIPS_MTX1) += board-mtx1.o +obj-$(CONFIG_MIPS_XXS1500) += board-xxs1500.o diff --git a/arch/mips/alchemy/Platform b/arch/mips/alchemy/Platform index 96e9e41f1b2a..7956274de15f 100644 --- a/arch/mips/alchemy/Platform +++ b/arch/mips/alchemy/Platform @@ -5,62 +5,31 @@ platform-$(CONFIG_MIPS_ALCHEMY) += alchemy/common/ # -# AMD Alchemy Pb1000 eval board -# -platform-$(CONFIG_MIPS_PB1000) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_PB1000) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00 -load-$(CONFIG_MIPS_PB1000) += 0xffffffff80100000 - -# # AMD Alchemy Pb1100 eval board # platform-$(CONFIG_MIPS_PB1100) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_PB1100) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00 load-$(CONFIG_MIPS_PB1100) += 0xffffffff80100000 # # AMD Alchemy Pb1500 eval board # platform-$(CONFIG_MIPS_PB1500) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_PB1500) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00 load-$(CONFIG_MIPS_PB1500) += 0xffffffff80100000 # # AMD Alchemy Pb1550 eval board # platform-$(CONFIG_MIPS_PB1550) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_PB1550) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00 load-$(CONFIG_MIPS_PB1550) += 0xffffffff80100000 # -# AMD Alchemy Pb1200 eval board -# -platform-$(CONFIG_MIPS_PB1200) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_PB1200) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00 -load-$(CONFIG_MIPS_PB1200) += 0xffffffff80100000 - -# -# AMD Alchemy Db1000 eval board +# AMD Alchemy Db1000/Db1500/Db1100 eval boards # platform-$(CONFIG_MIPS_DB1000) += alchemy/devboards/ cflags-$(CONFIG_MIPS_DB1000) += -I$(srctree)/arch/mips/include/asm/mach-db1x00 load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000 # -# AMD Alchemy Db1100 eval board -# -platform-$(CONFIG_MIPS_DB1100) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_DB1100) += -I$(srctree)/arch/mips/include/asm/mach-db1x00 -load-$(CONFIG_MIPS_DB1100) += 0xffffffff80100000 - -# -# AMD Alchemy Db1500 eval board -# -platform-$(CONFIG_MIPS_DB1500) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_DB1500) += -I$(srctree)/arch/mips/include/asm/mach-db1x00 -load-$(CONFIG_MIPS_DB1500) += 0xffffffff80100000 - -# # AMD Alchemy Db1550 eval board # platform-$(CONFIG_MIPS_DB1550) += alchemy/devboards/ @@ -68,42 +37,35 @@ cflags-$(CONFIG_MIPS_DB1550) += -I$(srctree)/arch/mips/include/asm/mach-db1x00 load-$(CONFIG_MIPS_DB1550) += 0xffffffff80100000 # -# AMD Alchemy Db1200 eval board +# AMD Alchemy Db1200/Pb1200 eval boards # platform-$(CONFIG_MIPS_DB1200) += alchemy/devboards/ cflags-$(CONFIG_MIPS_DB1200) += -I$(srctree)/arch/mips/include/asm/mach-db1x00 load-$(CONFIG_MIPS_DB1200) += 0xffffffff80100000 # -# AMD Alchemy Bosporus eval board -# -platform-$(CONFIG_MIPS_BOSPORUS) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_BOSPORUS) += -I$(srctree)/arch/mips/include/asm/mach-db1x00 -load-$(CONFIG_MIPS_BOSPORUS) += 0xffffffff80100000 - -# -# AMD Alchemy Mirage eval board +# NetLogic DBAu1300 development platform # -platform-$(CONFIG_MIPS_MIRAGE) += alchemy/devboards/ -cflags-$(CONFIG_MIPS_MIRAGE) += -I$(srctree)/arch/mips/include/asm/mach-db1x00 -load-$(CONFIG_MIPS_MIRAGE) += 0xffffffff80100000 +platform-$(CONFIG_MIPS_DB1300) += alchemy/devboards/ +cflags-$(CONFIG_MIPS_DB1300) += -I$(srctree)/arch/mips/include/asm/mach-db1x00 +load-$(CONFIG_MIPS_DB1300) += 0xffffffff80100000 # -# 4G-Systems eval board +# 4G-Systems MTX-1 "MeshCube" wireless router # -platform-$(CONFIG_MIPS_MTX1) += alchemy/mtx-1/ +platform-$(CONFIG_MIPS_MTX1) += alchemy/ load-$(CONFIG_MIPS_MTX1) += 0xffffffff80100000 # # MyCable eval board # -platform-$(CONFIG_MIPS_XXS1500) += alchemy/xxs1500/ +platform-$(CONFIG_MIPS_XXS1500) += alchemy/ load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000 # # Trapeze ITS GRP board # -platform-$(CONFIG_MIPS_GPR) += alchemy/gpr/ +platform-$(CONFIG_MIPS_GPR) += alchemy/ load-$(CONFIG_MIPS_GPR) += 0xffffffff80100000 # boards can specify their own <gpio.h> in one of their include dirs. diff --git a/arch/mips/alchemy/gpr/platform.c b/arch/mips/alchemy/board-gpr.c index 982ce85db60d..ba3259086b9d 100644 --- a/arch/mips/alchemy/gpr/platform.c +++ b/arch/mips/alchemy/board-gpr.c @@ -1,5 +1,5 @@ /* - * GPR board platform device registration + * GPR board platform device registration (Au1550) * * Copyright (C) 2010 Wolfgang Grandegger <wg@denx.de> * @@ -18,16 +18,89 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/mtd/partitions.h> #include <linux/mtd/physmap.h> #include <linux/leds.h> #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/i2c-gpio.h> - +#include <asm/bootinfo.h> +#include <asm/reboot.h> #include <asm/mach-au1x00/au1000.h> +#include <prom.h> + +const char *get_system_type(void) +{ + return "GPR"; +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = fw_arg0; + prom_argv = (char **)fw_arg1; + prom_envp = (char **)fw_arg2; + + prom_init_cmdline(); + + memsize_str = prom_getenv("memsize"); + if (!memsize_str) + memsize = 0x04000000; + else + strict_strtoul(memsize_str, 0, &memsize); + add_memory_region(0, memsize, BOOT_MEM_RAM); +} + +void prom_putchar(unsigned char c) +{ + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); +} + +static void gpr_reset(char *c) +{ + /* switch System-LED to orange (red# and green# on) */ + alchemy_gpio_direction_output(4, 0); + alchemy_gpio_direction_output(5, 0); + + /* trigger watchdog to reset board in 200ms */ + printk(KERN_EMERG "Triggering watchdog soft reset...\n"); + raw_local_irq_disable(); + alchemy_gpio_direction_output(1, 0); + udelay(1); + alchemy_gpio_set_value(1, 1); + while (1) + cpu_wait(); +} + +static void gpr_power_off(void) +{ + while (1) + cpu_wait(); +} + +void __init board_setup(void) +{ + printk(KERN_INFO "Trapeze ITS GPR board\n"); + + pm_power_off = gpr_power_off; + _machine_halt = gpr_power_off; + _machine_restart = gpr_reset; + + /* Enable UART1/3 */ + alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); + alchemy_uart_enable(AU1000_UART1_PHYS_ADDR); + + /* Take away Reset of UMTS-card */ + alchemy_gpio_direction_output(215, 1); +} /* * Watchdog @@ -152,7 +225,7 @@ static struct i2c_gpio_platform_data gpr_i2c_data = { .scl_is_open_drain = 1, .udelay = 2, /* ~100 kHz */ .timeout = HZ, - }; +}; static struct platform_device gpr_i2c_device = { .name = "i2c-gpio", @@ -184,7 +257,7 @@ static int gpr_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) else if ((slot == 0) && (pin == 2)) return AU1550_PCI_INTB; - return -1; + return 0xff; } static struct alchemy_pci_platdata gpr_pci_pd = { diff --git a/arch/mips/alchemy/mtx-1/platform.c b/arch/mips/alchemy/board-mtx1.c index cc47b6868ca3..295f1a95f745 100644 --- a/arch/mips/alchemy/mtx-1/platform.c +++ b/arch/mips/alchemy/board-mtx1.c @@ -1,5 +1,5 @@ /* - * MTX-1 platform devices registration + * MTX-1 platform devices registration (Au1500) * * Copyright (C) 2007-2009, Florian Fainelli <florian@openwrt.org> * @@ -19,6 +19,8 @@ */ #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/leds.h> #include <linux/gpio.h> @@ -27,8 +29,85 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/physmap.h> #include <mtd/mtd-abi.h> - +#include <asm/bootinfo.h> +#include <asm/reboot.h> +#include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1xxx_eth.h> +#include <prom.h> + +const char *get_system_type(void) +{ + return "MTX-1"; +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = fw_arg0; + prom_argv = (char **)fw_arg1; + prom_envp = (char **)fw_arg2; + + prom_init_cmdline(); + + memsize_str = prom_getenv("memsize"); + if (!memsize_str) + memsize = 0x04000000; + else + strict_strtoul(memsize_str, 0, &memsize); + add_memory_region(0, memsize, BOOT_MEM_RAM); +} + +void prom_putchar(unsigned char c) +{ + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); +} + +static void mtx1_reset(char *c) +{ + /* Jump to the reset vector */ + __asm__ __volatile__("jr\t%0" : : "r"(0xbfc00000)); +} + +static void mtx1_power_off(void) +{ + while (1) + asm volatile ( + " .set mips32 \n" + " wait \n" + " .set mips0 \n"); +} + +void __init board_setup(void) +{ +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + /* Enable USB power switch */ + alchemy_gpio_direction_output(204, 0); +#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ + + /* Initialize sys_pinfunc */ + au_writel(SYS_PF_NI2, SYS_PINFUNC); + + /* Initialize GPIO */ + au_writel(~0, KSEG1ADDR(AU1000_SYS_PHYS_ADDR) + SYS_TRIOUTCLR); + alchemy_gpio_direction_output(0, 0); /* Disable M66EN (PCI 66MHz) */ + alchemy_gpio_direction_output(3, 1); /* Disable PCI CLKRUN# */ + alchemy_gpio_direction_output(1, 1); /* Enable EXT_IO3 */ + alchemy_gpio_direction_output(5, 0); /* Disable eth PHY TX_ER */ + + /* Enable LED and set it to green */ + alchemy_gpio_direction_output(211, 1); /* green on */ + alchemy_gpio_direction_output(212, 0); /* red off */ + + pm_power_off = mtx1_power_off; + _machine_halt = mtx1_power_off; + _machine_restart = mtx1_reset; + + printk(KERN_INFO "4G Systems MTX-1 Board\n"); +} + +/******************************************************************************/ static struct gpio_keys_button mtx1_gpio_button[] = { { @@ -195,7 +274,6 @@ static struct platform_device mtx1_pci_host = { .resource = alchemy_pci_host_res, }; - static struct __initdata platform_device * mtx1_devs[] = { &mtx1_pci_host, &mtx1_gpio_leds, @@ -206,13 +284,19 @@ static struct __initdata platform_device * mtx1_devs[] = { static struct au1000_eth_platform_data mtx1_au1000_eth0_pdata = { .phy_search_highest_addr = 1, - .phy1_search_mac0 = 1, + .phy1_search_mac0 = 1, }; static int __init mtx1_register_devices(void) { int rc; + irq_set_irq_type(AU1500_GPIO204_INT, IRQ_TYPE_LEVEL_HIGH); + irq_set_irq_type(AU1500_GPIO201_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO202_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO203_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO205_INT, IRQ_TYPE_LEVEL_LOW); + au1xxx_override_eth_cfg(0, &mtx1_au1000_eth0_pdata); rc = gpio_request(mtx1_gpio_button[0].gpio, @@ -226,5 +310,4 @@ static int __init mtx1_register_devices(void) out: return platform_add_devices(mtx1_devs, ARRAY_SIZE(mtx1_devs)); } - arch_initcall(mtx1_register_devices); diff --git a/arch/mips/alchemy/board-xxs1500.c b/arch/mips/alchemy/board-xxs1500.c new file mode 100644 index 000000000000..bd5513650293 --- /dev/null +++ b/arch/mips/alchemy/board-xxs1500.c @@ -0,0 +1,154 @@ +/* + * BRIEF MODULE DESCRIPTION + * MyCable XXS1500 board support + * + * Copyright 2003, 2008 MontaVista Software Inc. + * Author: MontaVista Software, Inc. <source@mvista.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. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <asm/bootinfo.h> +#include <asm/reboot.h> +#include <asm/mach-au1x00/au1000.h> +#include <prom.h> + +const char *get_system_type(void) +{ + return "XXS1500"; +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = fw_arg0; + prom_argv = (char **)fw_arg1; + prom_envp = (char **)fw_arg2; + + prom_init_cmdline(); + + memsize_str = prom_getenv("memsize"); + if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize)) + memsize = 0x04000000; + + add_memory_region(0, memsize, BOOT_MEM_RAM); +} + +void prom_putchar(unsigned char c) +{ + alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); +} + +static void xxs1500_reset(char *c) +{ + /* Jump to the reset vector */ + __asm__ __volatile__("jr\t%0" : : "r"(0xbfc00000)); +} + +static void xxs1500_power_off(void) +{ + while (1) + asm volatile ( + " .set mips32 \n" + " wait \n" + " .set mips0 \n"); +} + +void __init board_setup(void) +{ + u32 pin_func; + + pm_power_off = xxs1500_power_off; + _machine_halt = xxs1500_power_off; + _machine_restart = xxs1500_reset; + + alchemy_gpio1_input_enable(); + alchemy_gpio2_enable(); + + /* Set multiple use pins (UART3/GPIO) to UART (it's used as UART too) */ + pin_func = au_readl(SYS_PINFUNC) & ~SYS_PF_UR3; + pin_func |= SYS_PF_UR3; + au_writel(pin_func, SYS_PINFUNC); + + /* Enable UART */ + alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); + /* Enable DTR (MCR bit 0) = USB power up */ + __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18)); + wmb(); +} + +/******************************************************************************/ + +static struct resource xxs1500_pcmcia_res[] = { + { + .name = "pcmcia-io", + .flags = IORESOURCE_MEM, + .start = AU1000_PCMCIA_IO_PHYS_ADDR, + .end = AU1000_PCMCIA_IO_PHYS_ADDR + 0x000400000 - 1, + }, + { + .name = "pcmcia-attr", + .flags = IORESOURCE_MEM, + .start = AU1000_PCMCIA_ATTR_PHYS_ADDR, + .end = AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + }, + { + .name = "pcmcia-mem", + .flags = IORESOURCE_MEM, + .start = AU1000_PCMCIA_MEM_PHYS_ADDR, + .end = AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + }, +}; + +static struct platform_device xxs1500_pcmcia_dev = { + .name = "xxs1500_pcmcia", + .id = -1, + .num_resources = ARRAY_SIZE(xxs1500_pcmcia_res), + .resource = xxs1500_pcmcia_res, +}; + +static struct platform_device *xxs1500_devs[] __initdata = { + &xxs1500_pcmcia_dev, +}; + +static int __init xxs1500_dev_init(void) +{ + irq_set_irq_type(AU1500_GPIO204_INT, IRQ_TYPE_LEVEL_HIGH); + irq_set_irq_type(AU1500_GPIO201_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO202_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO203_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO205_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO207_INT, IRQ_TYPE_LEVEL_LOW); + + irq_set_irq_type(AU1500_GPIO0_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO1_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO2_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO3_INT, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(AU1500_GPIO4_INT, IRQ_TYPE_LEVEL_LOW); /* CF irq */ + irq_set_irq_type(AU1500_GPIO5_INT, IRQ_TYPE_LEVEL_LOW); + + return platform_add_devices(xxs1500_devs, + ARRAY_SIZE(xxs1500_devs)); +} +device_initcall(xxs1500_dev_init); diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index 811ece7b22e3..407ebc00e661 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile @@ -6,9 +6,7 @@ # obj-y += prom.o time.o clocks.o platform.o power.o setup.o \ - sleeper.o dma.o dbdma.o - -obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += irq.o + sleeper.o dma.o dbdma.o vss.o irq.o # optional gpiolib support ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c index 0e63ee487d6d..cf02d7dc2df0 100644 --- a/arch/mips/alchemy/common/dbdma.c +++ b/arch/mips/alchemy/common/dbdma.c @@ -148,6 +148,50 @@ static dbdev_tab_t au1200_dbdev_tab[] __initdata = { { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, }; +static dbdev_tab_t au1300_dbdev_tab[] __initdata = { + { AU1300_DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x10100004, 0, 0 }, + { AU1300_DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x10100000, 0, 0 }, + { AU1300_DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x10101004, 0, 0 }, + { AU1300_DSCR_CMD0_UART1_RX, DEV_FLAGS_IN, 0, 8, 0x10101000, 0, 0 }, + { AU1300_DSCR_CMD0_UART2_TX, DEV_FLAGS_OUT, 0, 8, 0x10102004, 0, 0 }, + { AU1300_DSCR_CMD0_UART2_RX, DEV_FLAGS_IN, 0, 8, 0x10102000, 0, 0 }, + { AU1300_DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x10103004, 0, 0 }, + { AU1300_DSCR_CMD0_UART3_RX, DEV_FLAGS_IN, 0, 8, 0x10103000, 0, 0 }, + + { AU1300_DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 }, + { AU1300_DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 }, + { AU1300_DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 8, 8, 0x10601000, 0, 0 }, + { AU1300_DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 8, 8, 0x10601004, 0, 0 }, + + { AU1300_DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 }, + { AU1300_DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 }, + + { AU1300_DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 16, 0x10a0001c, 0, 0 }, + { AU1300_DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 16, 0x10a0001c, 0, 0 }, + { AU1300_DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 16, 0x10a0101c, 0, 0 }, + { AU1300_DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 16, 0x10a0101c, 0, 0 }, + { AU1300_DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 16, 0x10a0201c, 0, 0 }, + { AU1300_DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN, 0, 16, 0x10a0201c, 0, 0 }, + { AU1300_DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 16, 0x10a0301c, 0, 0 }, + { AU1300_DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN, 0, 16, 0x10a0301c, 0, 0 }, + + { AU1300_DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + { AU1300_DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + + { AU1300_DSCR_CMD0_SDMS_TX2, DEV_FLAGS_OUT, 4, 8, 0x10602000, 0, 0 }, + { AU1300_DSCR_CMD0_SDMS_RX2, DEV_FLAGS_IN, 4, 8, 0x10602004, 0, 0 }, + + { AU1300_DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + + { AU1300_DSCR_CMD0_UDMA, DEV_FLAGS_ANYUSE, 0, 32, 0x14001810, 0, 0 }, + + { AU1300_DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, + { AU1300_DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, + + { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +}; + /* 32 predefined plus 32 custom */ #define DBDEV_TAB_SIZE 64 @@ -1019,8 +1063,7 @@ static int __init dbdma_setup(unsigned int irq, dbdev_tab_t *idtable) dbdma_gptr->ddma_inten = 0xffff; au_sync(); - ret = request_irq(irq, dbdma_interrupt, IRQF_DISABLED, "dbdma", - (void *)dbdma_gptr); + ret = request_irq(irq, dbdma_interrupt, 0, "dbdma", (void *)dbdma_gptr); if (ret) printk(KERN_ERR "Cannot grab DBDMA interrupt!\n"); else { @@ -1038,6 +1081,8 @@ static int __init alchemy_dbdma_init(void) return dbdma_setup(AU1550_DDMA_INT, au1550_dbdev_tab); case ALCHEMY_CPU_AU1200: return dbdma_setup(AU1200_DDMA_INT, au1200_dbdev_tab); + case ALCHEMY_CPU_AU1300: + return dbdma_setup(AU1300_DDMA_INT, au1300_dbdev_tab); } return 0; } diff --git a/arch/mips/alchemy/common/gpiolib.c b/arch/mips/alchemy/common/gpiolib.c index 91fb4d9e30fd..f1b50f0c01db 100644 --- a/arch/mips/alchemy/common/gpiolib.c +++ b/arch/mips/alchemy/common/gpiolib.c @@ -27,6 +27,7 @@ * CONFIG_ALCHEMY_GPIO_INDIRECT=n, otherwise compilation will fail! * au1000 SoC have only one GPIO block : GPIO1 * Au1100, Au15x0, Au12x0 have a second one : GPIO2 + * Au1300 is totally different: 1 block with up to 128 GPIOs */ #include <linux/init.h> @@ -35,6 +36,7 @@ #include <linux/types.h> #include <linux/gpio.h> #include <asm/mach-au1x00/gpio-au1000.h> +#include <asm/mach-au1x00/gpio-au1300.h> static int gpio2_get(struct gpio_chip *chip, unsigned offset) { @@ -115,6 +117,43 @@ struct gpio_chip alchemy_gpio_chip[] = { }, }; +static int alchemy_gpic_get(struct gpio_chip *chip, unsigned int off) +{ + return au1300_gpio_get_value(off + AU1300_GPIO_BASE); +} + +static void alchemy_gpic_set(struct gpio_chip *chip, unsigned int off, int v) +{ + au1300_gpio_set_value(off + AU1300_GPIO_BASE, v); +} + +static int alchemy_gpic_dir_input(struct gpio_chip *chip, unsigned int off) +{ + return au1300_gpio_direction_input(off + AU1300_GPIO_BASE); +} + +static int alchemy_gpic_dir_output(struct gpio_chip *chip, unsigned int off, + int v) +{ + return au1300_gpio_direction_output(off + AU1300_GPIO_BASE, v); +} + +static int alchemy_gpic_gpio_to_irq(struct gpio_chip *chip, unsigned int off) +{ + return au1300_gpio_to_irq(off + AU1300_GPIO_BASE); +} + +static struct gpio_chip au1300_gpiochip = { + .label = "alchemy-gpic", + .direction_input = alchemy_gpic_dir_input, + .direction_output = alchemy_gpic_dir_output, + .get = alchemy_gpic_get, + .set = alchemy_gpic_set, + .to_irq = alchemy_gpic_gpio_to_irq, + .base = AU1300_GPIO_BASE, + .ngpio = AU1300_GPIO_NUM, +}; + static int __init alchemy_gpiochip_init(void) { int ret = 0; @@ -127,6 +166,9 @@ static int __init alchemy_gpiochip_init(void) ret = gpiochip_add(&alchemy_gpio_chip[0]); ret |= gpiochip_add(&alchemy_gpio_chip[1]); break; + case ALCHEMY_CPU_AU1300: + ret = gpiochip_add(&au1300_gpiochip); + break; } return ret; } diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 8b60ba0675e2..94fbcd19eb9c 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -25,19 +25,15 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/bitops.h> +#include <linux/export.h> #include <linux/init.h> #include <linux/interrupt.h> -#include <linux/irq.h> #include <linux/slab.h> #include <linux/syscore_ops.h> #include <asm/irq_cpu.h> -#include <asm/mipsregs.h> #include <asm/mach-au1x00/au1000.h> -#ifdef CONFIG_MIPS_PB1000 -#include <asm/mach-pb1x00/pb1000.h> -#endif +#include <asm/mach-au1x00/gpio-au1300.h> /* Interrupt Controller register offsets */ #define IC_CFG0RD 0x40 @@ -69,7 +65,17 @@ #define IC_FALLINGCLR 0x7C #define IC_TESTBIT 0x80 -static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type); +/* per-processor fixed function irqs */ +struct alchemy_irqmap { + int irq; /* linux IRQ number */ + int type; /* IRQ_TYPE_ */ + int prio; /* irq priority, 0 highest, 3 lowest */ + int internal; /* GPIC: internal source (no ext. pin)? */ +}; + +static int au1x_ic_settype(struct irq_data *d, unsigned int type); +static int au1300_gpic_settype(struct irq_data *d, unsigned int type); + /* NOTE on interrupt priorities: The original writers of this code said: * @@ -77,176 +83,207 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type); * the USB devices-side packet complete interrupt (USB_DEV_REQ_INT) * needs the highest priority. */ - -/* per-processor fixed function irqs */ -struct au1xxx_irqmap { - int im_irq; - int im_type; - int im_request; /* set 1 to get higher priority */ +struct alchemy_irqmap au1000_irqmap[] __initdata = { + { AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, + { AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, + { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1000_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { -1, }, }; -struct au1xxx_irqmap au1000_irqmap[] __initdata = { - { AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, - { AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 }, - { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1000_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, +struct alchemy_irqmap au1500_irqmap[] __initdata = { + { AU1500_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1500_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1500_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1500_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1500_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, + { AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, + { AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1500_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1500_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1500_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, { -1, }, }; -struct au1xxx_irqmap au1500_irqmap[] __initdata = { - { AU1500_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1500_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1500_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1500_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1500_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, - { AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 }, - { AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1500_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1500_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1500_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, +struct alchemy_irqmap au1100_irqmap[] __initdata = { + { AU1100_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_SD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, + { AU1100_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, + { AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1100_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1100_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1100_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, { -1, }, }; -struct au1xxx_irqmap au1100_irqmap[] __initdata = { - { AU1100_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_SD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, - { AU1100_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 }, - { AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1100_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1100_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1100_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, +struct alchemy_irqmap au1550_irqmap[] __initdata = { + { AU1550_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1550_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1550_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_CRYPTO_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1550_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1550_PCI_RST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1550_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, + { AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, + { AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, + { AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1550_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, { -1, }, }; -struct au1xxx_irqmap au1550_irqmap[] __initdata = { - { AU1550_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1550_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1550_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_CRYPTO_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1550_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1550_PCI_RST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1550_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, - { AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 }, - { AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, - { AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1550_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, +struct alchemy_irqmap au1200_irqmap[] __initdata = { + { AU1200_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_SWT_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_SD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_MAE_BE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_MAE_FE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_AES_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_CAMERA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, + { AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, + { AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, + { AU1200_MAE_BOTH_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, { -1, }, }; -struct au1xxx_irqmap au1200_irqmap[] __initdata = { - { AU1200_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_SWT_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_SD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_MAE_BE_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_MAE_FE_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_AES_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_CAMERA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, - { AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 }, - { AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { AU1200_MAE_BOTH_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, - { -1, }, +static struct alchemy_irqmap au1300_irqmap[] __initdata = { + /* multifunction: gpio pin or device */ + { AU1300_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_SD1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_SD2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + { AU1300_NAND_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, + /* au1300 internal */ + { AU1300_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_MMU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_MPU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_GPU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_UDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, + { AU1300_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, + { AU1300_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, + { AU1300_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, + { AU1300_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, + { AU1300_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, + { AU1300_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, + { AU1300_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 1, }, + { AU1300_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_SD0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_USB_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_BSA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_MPE_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, + { AU1300_ITE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_AES_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { AU1300_CIM_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, + { -1, }, /* terminator */ }; +/******************************************************************************/ static void au1x_ic0_unmask(struct irq_data *d) { @@ -265,14 +302,6 @@ static void au1x_ic1_unmask(struct irq_data *d) __raw_writel(1 << bit, base + IC_MASKSET); __raw_writel(1 << bit, base + IC_WAKESET); - -/* very hacky. does the pb1000 cpld auto-disable this int? - * nowhere in the current kernel sources is it disabled. --mlau - */ -#if defined(CONFIG_MIPS_PB1000) - if (d->irq == AU1000_GPIO15_INT) - __raw_writel(0x4000, (void __iomem *)PB1000_MDR); /* enable int */ -#endif wmb(); } @@ -470,40 +499,219 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) return ret; } -asmlinkage void plat_irq_dispatch(void) +/******************************************************************************/ + +/* + * au1300_gpic_chgcfg - change PIN configuration. + * @gpio: pin to change (0-based GPIO number from datasheet). + * @clr: clear all bits set in 'clr'. + * @set: set these bits. + * + * modifies a pins' configuration register, bits set in @clr will + * be cleared in the register, bits in @set will be set. + */ +static inline void au1300_gpic_chgcfg(unsigned int gpio, + unsigned long clr, + unsigned long set) +{ + void __iomem *r = AU1300_GPIC_ADDR; + unsigned long l; + + r += gpio * 4; /* offset into pin config array */ + l = __raw_readl(r + AU1300_GPIC_PINCFG); + l &= ~clr; + l |= set; + __raw_writel(l, r + AU1300_GPIC_PINCFG); + wmb(); +} + +/* + * au1300_pinfunc_to_gpio - assign a pin as GPIO input (GPIO ctrl). + * @pin: pin (0-based GPIO number from datasheet). + * + * Assigns a GPIO pin to the GPIO controller, so its level can either + * be read or set through the generic GPIO functions. + * If you need a GPOUT, use au1300_gpio_set_value(pin, 0/1). + * REVISIT: is this function really necessary? + */ +void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio) +{ + au1300_gpio_direction_input(gpio + AU1300_GPIO_BASE); +} +EXPORT_SYMBOL_GPL(au1300_pinfunc_to_gpio); + +/* + * au1300_pinfunc_to_dev - assign a pin to the device function. + * @pin: pin (0-based GPIO number from datasheet). + * + * Assigns a GPIO pin to its associated device function; the pin will be + * driven by the device and not through GPIO functions. + */ +void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio) +{ + void __iomem *r = AU1300_GPIC_ADDR; + unsigned long bit; + + r += GPIC_GPIO_BANKOFF(gpio); + bit = GPIC_GPIO_TO_BIT(gpio); + __raw_writel(bit, r + AU1300_GPIC_DEVSEL); + wmb(); +} +EXPORT_SYMBOL_GPL(au1300_pinfunc_to_dev); + +/* + * au1300_set_irq_priority - set internal priority of IRQ. + * @irq: irq to set priority (linux irq number). + * @p: priority (0 = highest, 3 = lowest). + */ +void au1300_set_irq_priority(unsigned int irq, int p) { - unsigned int pending = read_c0_status() & read_c0_cause(); - unsigned long s, off; - - if (pending & CAUSEF_IP7) { - off = MIPS_CPU_IRQ_BASE + 7; - goto handle; - } else if (pending & CAUSEF_IP2) { - s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ0INT; - off = AU1000_INTC0_INT_BASE; - } else if (pending & CAUSEF_IP3) { - s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ1INT; - off = AU1000_INTC0_INT_BASE; - } else if (pending & CAUSEF_IP4) { - s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ0INT; - off = AU1000_INTC1_INT_BASE; - } else if (pending & CAUSEF_IP5) { - s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ1INT; - off = AU1000_INTC1_INT_BASE; - } else - goto spurious; - - s = __raw_readl((void __iomem *)s); - if (unlikely(!s)) { -spurious: - spurious_interrupt(); - return; + irq -= ALCHEMY_GPIC_INT_BASE; + au1300_gpic_chgcfg(irq, GPIC_CFG_IL_MASK, GPIC_CFG_IL_SET(p)); +} +EXPORT_SYMBOL_GPL(au1300_set_irq_priority); + +/* + * au1300_set_dbdma_gpio - assign a gpio to one of the DBDMA triggers. + * @dchan: dbdma trigger select (0, 1). + * @gpio: pin to assign as trigger. + * + * DBDMA controller has 2 external trigger sources; this function + * assigns a GPIO to the selected trigger. + */ +void au1300_set_dbdma_gpio(int dchan, unsigned int gpio) +{ + unsigned long r; + + if ((dchan >= 0) && (dchan <= 1)) { + r = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL); + r &= ~(0xff << (8 * dchan)); + r |= (gpio & 0x7f) << (8 * dchan); + __raw_writel(r, AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL); + wmb(); } - off += __ffs(s); -handle: - do_IRQ(off); } +static inline void gpic_pin_set_idlewake(unsigned int gpio, int allow) +{ + au1300_gpic_chgcfg(gpio, GPIC_CFG_IDLEWAKE, + allow ? GPIC_CFG_IDLEWAKE : 0); +} + +static void au1300_gpic_mask(struct irq_data *d) +{ + void __iomem *r = AU1300_GPIC_ADDR; + unsigned long bit, irq = d->irq; + + irq -= ALCHEMY_GPIC_INT_BASE; + r += GPIC_GPIO_BANKOFF(irq); + bit = GPIC_GPIO_TO_BIT(irq); + __raw_writel(bit, r + AU1300_GPIC_IDIS); + wmb(); + + gpic_pin_set_idlewake(irq, 0); +} + +static void au1300_gpic_unmask(struct irq_data *d) +{ + void __iomem *r = AU1300_GPIC_ADDR; + unsigned long bit, irq = d->irq; + + irq -= ALCHEMY_GPIC_INT_BASE; + + gpic_pin_set_idlewake(irq, 1); + + r += GPIC_GPIO_BANKOFF(irq); + bit = GPIC_GPIO_TO_BIT(irq); + __raw_writel(bit, r + AU1300_GPIC_IEN); + wmb(); +} + +static void au1300_gpic_maskack(struct irq_data *d) +{ + void __iomem *r = AU1300_GPIC_ADDR; + unsigned long bit, irq = d->irq; + + irq -= ALCHEMY_GPIC_INT_BASE; + r += GPIC_GPIO_BANKOFF(irq); + bit = GPIC_GPIO_TO_BIT(irq); + __raw_writel(bit, r + AU1300_GPIC_IPEND); /* ack */ + __raw_writel(bit, r + AU1300_GPIC_IDIS); /* mask */ + wmb(); + + gpic_pin_set_idlewake(irq, 0); +} + +static void au1300_gpic_ack(struct irq_data *d) +{ + void __iomem *r = AU1300_GPIC_ADDR; + unsigned long bit, irq = d->irq; + + irq -= ALCHEMY_GPIC_INT_BASE; + r += GPIC_GPIO_BANKOFF(irq); + bit = GPIC_GPIO_TO_BIT(irq); + __raw_writel(bit, r + AU1300_GPIC_IPEND); /* ack */ + wmb(); +} + +static struct irq_chip au1300_gpic = { + .name = "GPIOINT", + .irq_ack = au1300_gpic_ack, + .irq_mask = au1300_gpic_mask, + .irq_mask_ack = au1300_gpic_maskack, + .irq_unmask = au1300_gpic_unmask, + .irq_set_type = au1300_gpic_settype, +}; + +static int au1300_gpic_settype(struct irq_data *d, unsigned int type) +{ + unsigned long s; + unsigned char *name = NULL; + irq_flow_handler_t hdl = NULL; + + switch (type) { + case IRQ_TYPE_LEVEL_HIGH: + s = GPIC_CFG_IC_LEVEL_HIGH; + name = "high"; + hdl = handle_level_irq; + break; + case IRQ_TYPE_LEVEL_LOW: + s = GPIC_CFG_IC_LEVEL_LOW; + name = "low"; + hdl = handle_level_irq; + break; + case IRQ_TYPE_EDGE_RISING: + s = GPIC_CFG_IC_EDGE_RISE; + name = "posedge"; + hdl = handle_edge_irq; + break; + case IRQ_TYPE_EDGE_FALLING: + s = GPIC_CFG_IC_EDGE_FALL; + name = "negedge"; + hdl = handle_edge_irq; + break; + case IRQ_TYPE_EDGE_BOTH: + s = GPIC_CFG_IC_EDGE_BOTH; + name = "bothedge"; + hdl = handle_edge_irq; + break; + case IRQ_TYPE_NONE: + s = GPIC_CFG_IC_OFF; + name = "disabled"; + hdl = handle_level_irq; + break; + default: + return -EINVAL; + } + + __irq_set_chip_handler_name_locked(d->irq, &au1300_gpic, hdl, name); + + au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s); + + return 0; +} + +/******************************************************************************/ static inline void ic_init(void __iomem *base) { @@ -521,13 +729,159 @@ static inline void ic_init(void __iomem *base) wmb(); } -static void __init au1000_init_irq(struct au1xxx_irqmap *map) +static unsigned long alchemy_gpic_pmdata[ALCHEMY_GPIC_INT_NUM + 6]; + +static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d) +{ + d[0] = __raw_readl(base + IC_CFG0RD); + d[1] = __raw_readl(base + IC_CFG1RD); + d[2] = __raw_readl(base + IC_CFG2RD); + d[3] = __raw_readl(base + IC_SRCRD); + d[4] = __raw_readl(base + IC_ASSIGNRD); + d[5] = __raw_readl(base + IC_WAKERD); + d[6] = __raw_readl(base + IC_MASKRD); + ic_init(base); /* shut it up too while at it */ +} + +static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d) +{ + ic_init(base); + + __raw_writel(d[0], base + IC_CFG0SET); + __raw_writel(d[1], base + IC_CFG1SET); + __raw_writel(d[2], base + IC_CFG2SET); + __raw_writel(d[3], base + IC_SRCSET); + __raw_writel(d[4], base + IC_ASSIGNSET); + __raw_writel(d[5], base + IC_WAKESET); + wmb(); + + __raw_writel(d[6], base + IC_MASKSET); + wmb(); +} + +static int alchemy_ic_suspend(void) +{ + alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), + alchemy_gpic_pmdata); + alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), + &alchemy_gpic_pmdata[7]); + return 0; +} + +static void alchemy_ic_resume(void) +{ + alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), + &alchemy_gpic_pmdata[7]); + alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), + alchemy_gpic_pmdata); +} + +static int alchemy_gpic_suspend(void) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); + int i; + + /* save 4 interrupt mask status registers */ + alchemy_gpic_pmdata[0] = __raw_readl(base + AU1300_GPIC_IEN + 0x0); + alchemy_gpic_pmdata[1] = __raw_readl(base + AU1300_GPIC_IEN + 0x4); + alchemy_gpic_pmdata[2] = __raw_readl(base + AU1300_GPIC_IEN + 0x8); + alchemy_gpic_pmdata[3] = __raw_readl(base + AU1300_GPIC_IEN + 0xc); + + /* save misc register(s) */ + alchemy_gpic_pmdata[4] = __raw_readl(base + AU1300_GPIC_DMASEL); + + /* molto silenzioso */ + __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0); + __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4); + __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8); + __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc); + wmb(); + + /* save pin/int-type configuration */ + base += AU1300_GPIC_PINCFG; + for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++) + alchemy_gpic_pmdata[i + 5] = __raw_readl(base + (i << 2)); + + wmb(); + + return 0; +} + +static void alchemy_gpic_resume(void) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); + int i; + + /* disable all first */ + __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0); + __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4); + __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8); + __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc); + wmb(); + + /* restore pin/int-type configurations */ + base += AU1300_GPIC_PINCFG; + for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++) + __raw_writel(alchemy_gpic_pmdata[i + 5], base + (i << 2)); + wmb(); + + /* restore misc register(s) */ + base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); + __raw_writel(alchemy_gpic_pmdata[4], base + AU1300_GPIC_DMASEL); + wmb(); + + /* finally restore masks */ + __raw_writel(alchemy_gpic_pmdata[0], base + AU1300_GPIC_IEN + 0x0); + __raw_writel(alchemy_gpic_pmdata[1], base + AU1300_GPIC_IEN + 0x4); + __raw_writel(alchemy_gpic_pmdata[2], base + AU1300_GPIC_IEN + 0x8); + __raw_writel(alchemy_gpic_pmdata[3], base + AU1300_GPIC_IEN + 0xc); + wmb(); +} + +static struct syscore_ops alchemy_ic_pmops = { + .suspend = alchemy_ic_suspend, + .resume = alchemy_ic_resume, +}; + +static struct syscore_ops alchemy_gpic_pmops = { + .suspend = alchemy_gpic_suspend, + .resume = alchemy_gpic_resume, +}; + +/******************************************************************************/ + +/* create chained handlers for the 4 IC requests to the MIPS IRQ ctrl */ +#define DISP(name, base, addr) \ +static void au1000_##name##_dispatch(unsigned int irq, struct irq_desc *d) \ +{ \ + unsigned long r = __raw_readl((void __iomem *)KSEG1ADDR(addr)); \ + if (likely(r)) \ + generic_handle_irq(base + __ffs(r)); \ + else \ + spurious_interrupt(); \ +} + +DISP(ic0r0, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ0INT) +DISP(ic0r1, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ1INT) +DISP(ic1r0, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ0INT) +DISP(ic1r1, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ1INT) + +static void alchemy_gpic_dispatch(unsigned int irq, struct irq_desc *d) +{ + int i = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_PRIENC); + generic_handle_irq(ALCHEMY_GPIC_INT_BASE + i); +} + +/******************************************************************************/ + +static void __init au1000_init_irq(struct alchemy_irqmap *map) { unsigned int bit, irq_nr; void __iomem *base; ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR)); ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR)); + register_syscore_ops(&alchemy_ic_pmops); mips_cpu_irq_init(); /* register all 64 possible IC0+IC1 irq sources as type "none". @@ -544,8 +898,8 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map) /* * Initialize IC0, which is fixed per processor. */ - while (map->im_irq != -1) { - irq_nr = map->im_irq; + while (map->irq != -1) { + irq_nr = map->irq; if (irq_nr >= AU1000_INTC1_INT_BASE) { bit = irq_nr - AU1000_INTC1_INT_BASE; @@ -554,16 +908,61 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map) bit = irq_nr - AU1000_INTC0_INT_BASE; base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); } - if (map->im_request) + if (map->prio == 0) __raw_writel(1 << bit, base + IC_ASSIGNSET); - au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type); + au1x_ic_settype(irq_get_irq_data(irq_nr), map->type); ++map; } - set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, au1000_ic0r0_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, au1000_ic0r1_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, au1000_ic1r0_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, au1000_ic1r1_dispatch); +} + +static void __init alchemy_gpic_init_irq(const struct alchemy_irqmap *dints) +{ + int i; + void __iomem *bank_base; + + register_syscore_ops(&alchemy_gpic_pmops); + mips_cpu_irq_init(); + + /* disable & ack all possible interrupt sources */ + for (i = 0; i < 4; i++) { + bank_base = AU1300_GPIC_ADDR + (i * 4); + __raw_writel(~0UL, bank_base + AU1300_GPIC_IDIS); + wmb(); + __raw_writel(~0UL, bank_base + AU1300_GPIC_IPEND); + wmb(); + } + + /* register an irq_chip for them, with 2nd highest priority */ + for (i = ALCHEMY_GPIC_INT_BASE; i <= ALCHEMY_GPIC_INT_LAST; i++) { + au1300_set_irq_priority(i, 1); + au1300_gpic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); + } + + /* setup known on-chip sources */ + while ((i = dints->irq) != -1) { + au1300_gpic_settype(irq_get_irq_data(i), dints->type); + au1300_set_irq_priority(i, dints->prio); + + if (dints->internal) + au1300_pinfunc_to_dev(i - ALCHEMY_GPIC_INT_BASE); + + dints++; + } + + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, alchemy_gpic_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, alchemy_gpic_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, alchemy_gpic_dispatch); + irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, alchemy_gpic_dispatch); } +/******************************************************************************/ + void __init arch_init_irq(void) { switch (alchemy_get_cputype()) { @@ -582,65 +981,17 @@ void __init arch_init_irq(void) case ALCHEMY_CPU_AU1200: au1000_init_irq(au1200_irqmap); break; + case ALCHEMY_CPU_AU1300: + alchemy_gpic_init_irq(au1300_irqmap); + break; + default: + pr_err("unknown Alchemy IRQ core\n"); + break; } } - -static unsigned long alchemy_ic_pmdata[7 * 2]; - -static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d) -{ - d[0] = __raw_readl(base + IC_CFG0RD); - d[1] = __raw_readl(base + IC_CFG1RD); - d[2] = __raw_readl(base + IC_CFG2RD); - d[3] = __raw_readl(base + IC_SRCRD); - d[4] = __raw_readl(base + IC_ASSIGNRD); - d[5] = __raw_readl(base + IC_WAKERD); - d[6] = __raw_readl(base + IC_MASKRD); - ic_init(base); /* shut it up too while at it */ -} - -static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d) -{ - ic_init(base); - - __raw_writel(d[0], base + IC_CFG0SET); - __raw_writel(d[1], base + IC_CFG1SET); - __raw_writel(d[2], base + IC_CFG2SET); - __raw_writel(d[3], base + IC_SRCSET); - __raw_writel(d[4], base + IC_ASSIGNSET); - __raw_writel(d[5], base + IC_WAKESET); - wmb(); - - __raw_writel(d[6], base + IC_MASKSET); - wmb(); -} - -static int alchemy_ic_suspend(void) -{ - alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), - alchemy_ic_pmdata); - alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), - &alchemy_ic_pmdata[7]); - return 0; -} - -static void alchemy_ic_resume(void) -{ - alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), - &alchemy_ic_pmdata[7]); - alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), - alchemy_ic_pmdata); -} - -static struct syscore_ops alchemy_ic_syscore_ops = { - .suspend = alchemy_ic_suspend, - .resume = alchemy_ic_resume, -}; - -static int __init alchemy_ic_pm_init(void) +asmlinkage void plat_irq_dispatch(void) { - register_syscore_ops(&alchemy_ic_syscore_ops); - return 0; + unsigned long r = (read_c0_status() & read_c0_cause()) >> 8; + do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(r & 0xff)); } -device_initcall(alchemy_ic_pm_init); diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index c8e5d72a5826..95cb9113b12c 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -82,6 +82,12 @@ static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = { PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT), PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT), }, + [ALCHEMY_CPU_AU1300] = { + PORT(AU1300_UART0_PHYS_ADDR, AU1300_UART0_INT), + PORT(AU1300_UART1_PHYS_ADDR, AU1300_UART1_INT), + PORT(AU1300_UART2_PHYS_ADDR, AU1300_UART2_INT), + PORT(AU1300_UART3_PHYS_ADDR, AU1300_UART3_INT), + }, }; static struct platform_device au1xx0_uart_device = { @@ -122,10 +128,12 @@ static unsigned long alchemy_ohci_data[][2] __initdata = { [ALCHEMY_CPU_AU1100] = { AU1000_USB_OHCI_PHYS_ADDR, AU1100_USB_HOST_INT }, [ALCHEMY_CPU_AU1550] = { AU1550_USB_OHCI_PHYS_ADDR, AU1550_USB_HOST_INT }, [ALCHEMY_CPU_AU1200] = { AU1200_USB_OHCI_PHYS_ADDR, AU1200_USB_INT }, + [ALCHEMY_CPU_AU1300] = { AU1300_USB_OHCI0_PHYS_ADDR, AU1300_USB_INT }, }; static unsigned long alchemy_ehci_data[][2] __initdata = { [ALCHEMY_CPU_AU1200] = { AU1200_USB_EHCI_PHYS_ADDR, AU1200_USB_INT }, + [ALCHEMY_CPU_AU1300] = { AU1300_USB_EHCI_PHYS_ADDR, AU1300_USB_INT }, }; static int __init _new_usbres(struct resource **r, struct platform_device **d) @@ -169,8 +177,8 @@ static void __init alchemy_setup_usb(int ctype) printk(KERN_INFO "Alchemy USB: cannot add OHCI0\n"); - /* setup EHCI0: Au1200 */ - if (ctype == ALCHEMY_CPU_AU1200) { + /* setup EHCI0: Au1200/Au1300 */ + if ((ctype == ALCHEMY_CPU_AU1200) || (ctype == ALCHEMY_CPU_AU1300)) { if (_new_usbres(&res, &pdev)) return; @@ -187,6 +195,25 @@ static void __init alchemy_setup_usb(int ctype) if (platform_device_register(pdev)) printk(KERN_INFO "Alchemy USB: cannot add EHCI0\n"); } + + /* Au1300: OHCI1 */ + if (ctype == ALCHEMY_CPU_AU1300) { + if (_new_usbres(&res, &pdev)) + return; + + res[0].start = AU1300_USB_OHCI1_PHYS_ADDR; + res[0].end = res[0].start + 0x100 - 1; + res[0].flags = IORESOURCE_MEM; + res[1].start = AU1300_USB_INT; + res[1].end = res[1].start; + res[1].flags = IORESOURCE_IRQ; + pdev->name = "au1xxx-ohci"; + pdev->id = 1; + pdev->dev.dma_mask = &alchemy_ohci_dmamask; + + if (platform_device_register(pdev)) + printk(KERN_INFO "Alchemy USB: cannot add OHCI1\n"); + } } /* Macro to help defining the Ethernet MAC resources */ diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c index bdd6651e9a4f..0c7fce2a3c12 100644 --- a/arch/mips/alchemy/common/power.c +++ b/arch/mips/alchemy/common/power.c @@ -126,6 +126,9 @@ void au_sleep(void) case ALCHEMY_CPU_AU1200: alchemy_sleep_au1550(); break; + case ALCHEMY_CPU_AU1300: + alchemy_sleep_au1300(); + break; } restore_core_regs(); diff --git a/arch/mips/alchemy/common/sleeper.S b/arch/mips/alchemy/common/sleeper.S index 77f3c743b716..c7bcc7e5c822 100644 --- a/arch/mips/alchemy/common/sleeper.S +++ b/arch/mips/alchemy/common/sleeper.S @@ -153,6 +153,79 @@ LEAF(alchemy_sleep_au1550) END(alchemy_sleep_au1550) +/* sleepcode for Au1300 memory controller type */ +LEAF(alchemy_sleep_au1300) + + SETUP_SLEEP + + /* cache following instructions, as memory gets put to sleep */ + la t0, 2f + la t1, 4f + subu t2, t1, t0 + + .set mips3 + +1: cache 0x14, 0(t0) + subu t2, t2, 32 + bgez t2, 1b + addu t0, t0, 32 + + .set mips0 + +2: lui a0, 0xb400 /* mem_xxx */ + + /* disable all ports in mem_sdportcfga */ + sw zero, 0x868(a0) /* mem_sdportcfga */ + sync + + /* disable ODT */ + li t0, 0x03010000 + sw t0, 0x08d8(a0) /* mem_sdcmd0 */ + sw t0, 0x08dc(a0) /* mem_sdcmd1 */ + sync + + /* precharge */ + li t0, 0x23000400 + sw t0, 0x08dc(a0) /* mem_sdcmd1 */ + sw t0, 0x08d8(a0) /* mem_sdcmd0 */ + sync + + /* auto refresh */ + sw zero, 0x08c8(a0) /* mem_sdautoref */ + sync + + /* block access to the DDR */ + lw t0, 0x0848(a0) /* mem_sdconfigb */ + li t1, (1 << 7 | 0x3F) + or t0, t0, t1 + sw t0, 0x0848(a0) /* mem_sdconfigb */ + sync + + /* issue the Self Refresh command */ + li t0, 0x10000000 + sw t0, 0x08dc(a0) /* mem_sdcmd1 */ + sw t0, 0x08d8(a0) /* mem_sdcmd0 */ + sync + + /* wait for sdram to enter self-refresh mode */ + lui t0, 0x0300 +3: lw t1, 0x0850(a0) /* mem_sdstat */ + and t2, t1, t0 + bne t2, t0, 3b + nop + + /* disable SDRAM clocks */ + li t0, ~(3<<28) + lw t1, 0x0840(a0) /* mem_sdconfiga */ + and t1, t1, t0 /* clear CE[1:0] */ + sw t1, 0x0840(a0) /* mem_sdconfiga */ + sync + + DO_SLEEP +4: + +END(alchemy_sleep_au1300) + /* This is where we return upon wakeup. * Reload all of the registers and return. diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c index d5da6adbf634..7da4d0081487 100644 --- a/arch/mips/alchemy/common/time.c +++ b/arch/mips/alchemy/common/time.c @@ -92,7 +92,7 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = { static struct irqaction au1x_rtcmatch2_irqaction = { .handler = au1x_rtcmatch2_irq, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .name = "timer", .dev_id = &au1x_rtcmatch2_clockdev, }; @@ -178,6 +178,7 @@ static int alchemy_m2inttab[] __initdata = { AU1100_RTC_MATCH2_INT, AU1550_RTC_MATCH2_INT, AU1200_RTC_MATCH2_INT, + AU1300_RTC_MATCH2_INT, }; void __init plat_time_init(void) diff --git a/arch/mips/alchemy/common/vss.c b/arch/mips/alchemy/common/vss.c new file mode 100644 index 000000000000..d23b1444d365 --- /dev/null +++ b/arch/mips/alchemy/common/vss.c @@ -0,0 +1,84 @@ +/* + * Au1300 media block power gating (VSS) + * + * This is a stop-gap solution until I have the clock framework integration + * ready. This stuff here really must be handled transparently when clocks + * for various media blocks are enabled/disabled. + */ + +#include <linux/module.h> +#include <linux/spinlock.h> +#include <asm/mach-au1x00/au1000.h> + +#define VSS_GATE 0x00 /* gate wait timers */ +#define VSS_CLKRST 0x04 /* clock/block control */ +#define VSS_FTR 0x08 /* footers */ + +#define VSS_ADDR(blk) (KSEG1ADDR(AU1300_VSS_PHYS_ADDR) + (blk * 0x0c)) + +static DEFINE_SPINLOCK(au1300_vss_lock); + +/* enable a block as outlined in the databook */ +static inline void __enable_block(int block) +{ + void __iomem *base = (void __iomem *)VSS_ADDR(block); + + __raw_writel(3, base + VSS_CLKRST); /* enable clock, assert reset */ + wmb(); + + __raw_writel(0x01fffffe, base + VSS_GATE); /* maximum setup time */ + wmb(); + + /* enable footers in sequence */ + __raw_writel(0x01, base + VSS_FTR); + wmb(); + __raw_writel(0x03, base + VSS_FTR); + wmb(); + __raw_writel(0x07, base + VSS_FTR); + wmb(); + __raw_writel(0x0f, base + VSS_FTR); + wmb(); + + __raw_writel(0x01ffffff, base + VSS_GATE); /* start FSM too */ + wmb(); + + __raw_writel(2, base + VSS_CLKRST); /* deassert reset */ + wmb(); + + __raw_writel(0x1f, base + VSS_FTR); /* enable isolation cells */ + wmb(); +} + +/* disable a block as outlined in the databook */ +static inline void __disable_block(int block) +{ + void __iomem *base = (void __iomem *)VSS_ADDR(block); + + __raw_writel(0x0f, base + VSS_FTR); /* disable isolation cells */ + wmb(); + __raw_writel(0, base + VSS_GATE); /* disable FSM */ + wmb(); + __raw_writel(3, base + VSS_CLKRST); /* assert reset */ + wmb(); + __raw_writel(1, base + VSS_CLKRST); /* disable clock */ + wmb(); + __raw_writel(0, base + VSS_FTR); /* disable all footers */ + wmb(); +} + +void au1300_vss_block_control(int block, int enable) +{ + unsigned long flags; + + if (alchemy_get_cputype() != ALCHEMY_CPU_AU1300) + return; + + /* only one block at a time */ + spin_lock_irqsave(&au1300_vss_lock, flags); + if (enable) + __enable_block(block); + else + __disable_block(block); + spin_unlock_irqrestore(&au1300_vss_lock, flags); +} +EXPORT_SYMBOL_GPL(au1300_vss_block_control); diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile index 826449c817c3..3c37fb303364 100644 --- a/arch/mips/alchemy/devboards/Makefile +++ b/arch/mips/alchemy/devboards/Makefile @@ -4,15 +4,10 @@ obj-y += prom.o bcsr.o platform.o obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_MIPS_PB1000) += pb1000/ -obj-$(CONFIG_MIPS_PB1100) += pb1100/ -obj-$(CONFIG_MIPS_PB1200) += pb1200/ -obj-$(CONFIG_MIPS_PB1500) += pb1500/ -obj-$(CONFIG_MIPS_PB1550) += pb1550/ -obj-$(CONFIG_MIPS_DB1000) += db1x00/ -obj-$(CONFIG_MIPS_DB1100) += db1x00/ -obj-$(CONFIG_MIPS_DB1200) += db1200/ -obj-$(CONFIG_MIPS_DB1500) += db1x00/ -obj-$(CONFIG_MIPS_DB1550) += db1x00/ -obj-$(CONFIG_MIPS_BOSPORUS) += db1x00/ -obj-$(CONFIG_MIPS_MIRAGE) += db1x00/ +obj-$(CONFIG_MIPS_PB1100) += pb1100.o +obj-$(CONFIG_MIPS_PB1500) += pb1500.o +obj-$(CONFIG_MIPS_PB1550) += pb1550.o +obj-$(CONFIG_MIPS_DB1000) += db1000.o +obj-$(CONFIG_MIPS_DB1200) += db1200.o +obj-$(CONFIG_MIPS_DB1300) += db1300.o +obj-$(CONFIG_MIPS_DB1550) += db1550.o diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c index 463d2c4d9441..1e83ce2e1147 100644 --- a/arch/mips/alchemy/devboards/bcsr.c +++ b/arch/mips/alchemy/devboards/bcsr.c @@ -97,14 +97,9 @@ static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) enable_irq(irq); } -/* NOTE: both the enable and mask bits must be cleared, otherwise the - * CPLD generates tons of spurious interrupts (at least on my DB1200). - * -- mlau - */ static void bcsr_irq_mask(struct irq_data *d) { unsigned short v = 1 << (d->irq - bcsr_csc_base); - __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR); __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR); wmb(); } @@ -112,7 +107,6 @@ static void bcsr_irq_mask(struct irq_data *d) static void bcsr_irq_maskack(struct irq_data *d) { unsigned short v = 1 << (d->irq - bcsr_csc_base); - __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR); __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR); __raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT); /* ack */ wmb(); @@ -121,7 +115,6 @@ static void bcsr_irq_maskack(struct irq_data *d) static void bcsr_irq_unmask(struct irq_data *d) { unsigned short v = 1 << (d->irq - bcsr_csc_base); - __raw_writew(v, bcsr_virt + BCSR_REG_INTSET); __raw_writew(v, bcsr_virt + BCSR_REG_MASKSET); wmb(); } @@ -137,9 +130,9 @@ void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq) { unsigned int irq; - /* mask & disable & ack all */ - __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTCLR); + /* mask & enable & ack all */ __raw_writew(0xffff, bcsr_virt + BCSR_REG_MASKCLR); + __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSET); __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSTAT); wmb(); diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c new file mode 100644 index 000000000000..1b81dbf6b804 --- /dev/null +++ b/arch/mips/alchemy/devboards/db1000.c @@ -0,0 +1,565 @@ +/* + * DBAu1000/1500/1100 board support + * + * Copyright 2000, 2008 MontaVista Software Inc. + * Author: MontaVista Software, Inc. <source@mvista.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. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/dma-mapping.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/leds.h> +#include <linux/mmc/host.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_gpio.h> +#include <linux/spi/ads7846.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1000_dma.h> +#include <asm/mach-au1x00/au1100_mmc.h> +#include <asm/mach-db1x00/bcsr.h> +#include <asm/reboot.h> +#include <prom.h> +#include "platform.h" + +#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT) + +struct pci_dev; + +static const char *board_type_str(void) +{ + switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) { + case BCSR_WHOAMI_DB1000: + return "DB1000"; + case BCSR_WHOAMI_DB1500: + return "DB1500"; + case BCSR_WHOAMI_DB1100: + return "DB1100"; + default: + return "(unknown)"; + } +} + +const char *get_system_type(void) +{ + return board_type_str(); +} + +void __init board_setup(void) +{ + /* initialize board register space */ + bcsr_init(DB1000_BCSR_PHYS_ADDR, + DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS); + + printk(KERN_INFO "AMD Alchemy %s Board\n", board_type_str()); +} + + +static int db1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) +{ + if ((slot < 12) || (slot > 13) || pin == 0) + return -1; + if (slot == 12) + return (pin == 1) ? AU1500_PCI_INTA : 0xff; + if (slot == 13) { + switch (pin) { + case 1: return AU1500_PCI_INTA; + case 2: return AU1500_PCI_INTB; + case 3: return AU1500_PCI_INTC; + case 4: return AU1500_PCI_INTD; + } + } + return -1; +} + +static struct resource alchemy_pci_host_res[] = { + [0] = { + .start = AU1500_PCI_PHYS_ADDR, + .end = AU1500_PCI_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct alchemy_pci_platdata db1500_pci_pd = { + .board_map_irq = db1500_map_pci_irq, +}; + +static struct platform_device db1500_pci_host_dev = { + .dev.platform_data = &db1500_pci_pd, + .name = "alchemy-pci", + .id = 0, + .num_resources = ARRAY_SIZE(alchemy_pci_host_res), + .resource = alchemy_pci_host_res, +}; + +static int __init db1500_pci_init(void) +{ + if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) == BCSR_WHOAMI_DB1500) + return platform_device_register(&db1500_pci_host_dev); + return 0; +} +/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */ +arch_initcall(db1500_pci_init); + + +static struct resource au1100_lcd_resources[] = { + [0] = { + .start = AU1100_LCD_PHYS_ADDR, + .end = AU1100_LCD_PHYS_ADDR + 0x800 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1100_LCD_INT, + .end = AU1100_LCD_INT, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32); + +static struct platform_device au1100_lcd_device = { + .name = "au1100-lcd", + .id = 0, + .dev = { + .dma_mask = &au1100_lcd_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(au1100_lcd_resources), + .resource = au1100_lcd_resources, +}; + +static struct resource alchemy_ac97c_res[] = { + [0] = { + .start = AU1000_AC97_PHYS_ADDR, + .end = AU1000_AC97_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DMA_ID_AC97C_TX, + .end = DMA_ID_AC97C_TX, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = DMA_ID_AC97C_RX, + .end = DMA_ID_AC97C_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device alchemy_ac97c_dev = { + .name = "alchemy-ac97c", + .id = -1, + .resource = alchemy_ac97c_res, + .num_resources = ARRAY_SIZE(alchemy_ac97c_res), +}; + +static struct platform_device alchemy_ac97c_dma_dev = { + .name = "alchemy-pcm-dma", + .id = 0, +}; + +static struct platform_device db1x00_codec_dev = { + .name = "ac97-codec", + .id = -1, +}; + +static struct platform_device db1x00_audio_dev = { + .name = "db1000-audio", +}; + +/******************************************************************************/ + +static irqreturn_t db1100_mmc_cd(int irq, void *ptr) +{ + void (*mmc_cd)(struct mmc_host *, unsigned long); + /* link against CONFIG_MMC=m */ + mmc_cd = symbol_get(mmc_detect_change); + mmc_cd(ptr, msecs_to_jiffies(500)); + symbol_put(mmc_detect_change); + + return IRQ_HANDLED; +} + +static int db1100_mmc_cd_setup(void *mmc_host, int en) +{ + int ret = 0; + + if (en) { + irq_set_irq_type(AU1100_GPIO19_INT, IRQ_TYPE_EDGE_BOTH); + ret = request_irq(AU1100_GPIO19_INT, db1100_mmc_cd, 0, + "sd0_cd", mmc_host); + } else + free_irq(AU1100_GPIO19_INT, mmc_host); + return ret; +} + +static int db1100_mmc1_cd_setup(void *mmc_host, int en) +{ + int ret = 0; + + if (en) { + irq_set_irq_type(AU1100_GPIO20_INT, IRQ_TYPE_EDGE_BOTH); + ret = request_irq(AU1100_GPIO20_INT, db1100_mmc_cd, 0, + "sd1_cd", mmc_host); + } else + free_irq(AU1100_GPIO20_INT, mmc_host); + return ret; +} + +static int db1100_mmc_card_readonly(void *mmc_host) +{ + /* testing suggests that this bit is inverted */ + return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 0 : 1; +} + +static int db1100_mmc_card_inserted(void *mmc_host) +{ + return !alchemy_gpio_get_value(19); +} + +static void db1100_mmc_set_power(void *mmc_host, int state) +{ + if (state) { + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR); + msleep(400); /* stabilization time */ + } else + bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0); +} + +static void db1100_mmcled_set(struct led_classdev *led, enum led_brightness b) +{ + if (b != LED_OFF) + bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0); + else + bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0); +} + +static struct led_classdev db1100_mmc_led = { + .brightness_set = db1100_mmcled_set, +}; + +static int db1100_mmc1_card_readonly(void *mmc_host) +{ + return (bcsr_read(BCSR_BOARD) & BCSR_BOARD_SD1WP) ? 1 : 0; +} + +static int db1100_mmc1_card_inserted(void *mmc_host) +{ + return !alchemy_gpio_get_value(20); +} + +static void db1100_mmc1_set_power(void *mmc_host, int state) +{ + if (state) { + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR); + msleep(400); /* stabilization time */ + } else + bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0); +} + +static void db1100_mmc1led_set(struct led_classdev *led, enum led_brightness b) +{ + if (b != LED_OFF) + bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0); + else + bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1); +} + +static struct led_classdev db1100_mmc1_led = { + .brightness_set = db1100_mmc1led_set, +}; + +static struct au1xmmc_platform_data db1100_mmc_platdata[2] = { + [0] = { + .cd_setup = db1100_mmc_cd_setup, + .set_power = db1100_mmc_set_power, + .card_inserted = db1100_mmc_card_inserted, + .card_readonly = db1100_mmc_card_readonly, + .led = &db1100_mmc_led, + }, + [1] = { + .cd_setup = db1100_mmc1_cd_setup, + .set_power = db1100_mmc1_set_power, + .card_inserted = db1100_mmc1_card_inserted, + .card_readonly = db1100_mmc1_card_readonly, + .led = &db1100_mmc1_led, + }, +}; + +static struct resource au1100_mmc0_resources[] = { + [0] = { + .start = AU1100_SD0_PHYS_ADDR, + .end = AU1100_SD0_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1100_SD_INT, + .end = AU1100_SD_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = DMA_ID_SD0_TX, + .end = DMA_ID_SD0_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = DMA_ID_SD0_RX, + .end = DMA_ID_SD0_RX, + .flags = IORESOURCE_DMA, + } +}; + +static u64 au1xxx_mmc_dmamask = DMA_BIT_MASK(32); + +static struct platform_device db1100_mmc0_dev = { + .name = "au1xxx-mmc", + .id = 0, + .dev = { + .dma_mask = &au1xxx_mmc_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &db1100_mmc_platdata[0], + }, + .num_resources = ARRAY_SIZE(au1100_mmc0_resources), + .resource = au1100_mmc0_resources, +}; + +static struct resource au1100_mmc1_res[] = { + [0] = { + .start = AU1100_SD1_PHYS_ADDR, + .end = AU1100_SD1_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1100_SD_INT, + .end = AU1100_SD_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = DMA_ID_SD1_TX, + .end = DMA_ID_SD1_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = DMA_ID_SD1_RX, + .end = DMA_ID_SD1_RX, + .flags = IORESOURCE_DMA, + } +}; + +static struct platform_device db1100_mmc1_dev = { + .name = "au1xxx-mmc", + .id = 1, + .dev = { + .dma_mask = &au1xxx_mmc_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &db1100_mmc_platdata[1], + }, + .num_resources = ARRAY_SIZE(au1100_mmc1_res), + .resource = au1100_mmc1_res, +}; + +/******************************************************************************/ + +static void db1000_irda_set_phy_mode(int mode) +{ + unsigned short mask = BCSR_RESETS_IRDA_MODE_MASK | BCSR_RESETS_FIR_SEL; + + switch (mode) { + case AU1000_IRDA_PHY_MODE_OFF: + bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_OFF); + break; + case AU1000_IRDA_PHY_MODE_SIR: + bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL); + break; + case AU1000_IRDA_PHY_MODE_FIR: + bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL | + BCSR_RESETS_FIR_SEL); + break; + } +} + +static struct au1k_irda_platform_data db1000_irda_platdata = { + .set_phy_mode = db1000_irda_set_phy_mode, +}; + +static struct resource au1000_irda_res[] = { + [0] = { + .start = AU1000_IRDA_PHYS_ADDR, + .end = AU1000_IRDA_PHYS_ADDR + 0x0fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1000_IRDA_TX_INT, + .end = AU1000_IRDA_TX_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1000_IRDA_RX_INT, + .end = AU1000_IRDA_RX_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device db1000_irda_dev = { + .name = "au1000-irda", + .id = -1, + .dev = { + .platform_data = &db1000_irda_platdata, + }, + .resource = au1000_irda_res, + .num_resources = ARRAY_SIZE(au1000_irda_res), +}; + +/******************************************************************************/ + +static struct ads7846_platform_data db1100_touch_pd = { + .model = 7846, + .vref_mv = 3300, + .gpio_pendown = 21, +}; + +static struct spi_gpio_platform_data db1100_spictl_pd = { + .sck = 209, + .mosi = 208, + .miso = 207, + .num_chipselect = 1, +}; + +static struct spi_board_info db1100_spi_info[] __initdata = { + [0] = { + .modalias = "ads7846", + .max_speed_hz = 3250000, + .bus_num = 0, + .chip_select = 0, + .mode = 0, + .irq = AU1100_GPIO21_INT, + .platform_data = &db1100_touch_pd, + .controller_data = (void *)210, /* for spi_gpio: CS# GPIO210 */ + }, +}; + +static struct platform_device db1100_spi_dev = { + .name = "spi_gpio", + .id = 0, + .dev = { + .platform_data = &db1100_spictl_pd, + }, +}; + + +static struct platform_device *db1x00_devs[] = { + &db1x00_codec_dev, + &alchemy_ac97c_dma_dev, + &alchemy_ac97c_dev, + &db1x00_audio_dev, +}; + +static struct platform_device *db1000_devs[] = { + &db1000_irda_dev, +}; + +static struct platform_device *db1100_devs[] = { + &au1100_lcd_device, + &db1100_mmc0_dev, + &db1100_mmc1_dev, + &db1000_irda_dev, + &db1100_spi_dev, +}; + +static int __init db1000_dev_init(void) +{ + int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)); + int c0, c1, d0, d1, s0, s1; + unsigned long pfc; + + if (board == BCSR_WHOAMI_DB1500) { + c0 = AU1500_GPIO2_INT; + c1 = AU1500_GPIO5_INT; + d0 = AU1500_GPIO0_INT; + d1 = AU1500_GPIO3_INT; + s0 = AU1500_GPIO1_INT; + s1 = AU1500_GPIO4_INT; + } else if (board == BCSR_WHOAMI_DB1100) { + c0 = AU1100_GPIO2_INT; + c1 = AU1100_GPIO5_INT; + d0 = AU1100_GPIO0_INT; + d1 = AU1100_GPIO3_INT; + s0 = AU1100_GPIO1_INT; + s1 = AU1100_GPIO4_INT; + + gpio_direction_input(19); /* sd0 cd# */ + gpio_direction_input(20); /* sd1 cd# */ + gpio_direction_input(21); /* touch pendown# */ + gpio_direction_input(207); /* SPI MISO */ + gpio_direction_output(208, 0); /* SPI MOSI */ + gpio_direction_output(209, 1); /* SPI SCK */ + gpio_direction_output(210, 1); /* SPI CS# */ + + /* spi_gpio on SSI0 pins */ + pfc = __raw_readl((void __iomem *)SYS_PINFUNC); + pfc |= (1 << 0); /* SSI0 pins as GPIOs */ + __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); + wmb(); + + spi_register_board_info(db1100_spi_info, + ARRAY_SIZE(db1100_spi_info)); + + platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs)); + } else if (board == BCSR_WHOAMI_DB1000) { + c0 = AU1000_GPIO2_INT; + c1 = AU1000_GPIO5_INT; + d0 = AU1000_GPIO0_INT; + d1 = AU1000_GPIO3_INT; + s0 = AU1000_GPIO1_INT; + s1 = AU1000_GPIO4_INT; + platform_add_devices(db1000_devs, ARRAY_SIZE(db1000_devs)); + } else + return 0; /* unknown board, no further dev setup to do */ + + irq_set_irq_type(d0, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(d1, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(c0, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(c1, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(s0, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(s1, IRQ_TYPE_LEVEL_LOW); + + db1x_register_pcmcia_socket( + AU1000_PCMCIA_ATTR_PHYS_ADDR, + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + AU1000_PCMCIA_MEM_PHYS_ADDR, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + AU1000_PCMCIA_IO_PHYS_ADDR, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + c0, d0, /*s0*/0, 0, 0); + + db1x_register_pcmcia_socket( + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000, + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1, + c1, d1, /*s1*/0, 0, 1); + + platform_add_devices(db1x00_devs, ARRAY_SIZE(db1x00_devs)); + db1x_register_norflash(32 << 20, 4 /* 32bit */, F_SWAPPED); + return 0; +} +device_initcall(db1000_dev_init); diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200.c index c61867c93c4a..a83302b96c01 100644 --- a/arch/mips/alchemy/devboards/db1200/platform.c +++ b/arch/mips/alchemy/devboards/db1200.c @@ -1,7 +1,7 @@ /* - * DBAu1200 board platform device registration + * DBAu1200/PBAu1200 board platform device registration * - * Copyright (C) 2008-2009 Manuel Lauss + * Copyright (C) 2008-2011 Manuel Lauss * * 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 @@ -22,6 +22,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/leds.h> #include <linux/mmc/host.h> @@ -33,18 +34,116 @@ #include <linux/spi/spi.h> #include <linux/spi/flash.h> #include <linux/smc91x.h> - +#include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1100_mmc.h> #include <asm/mach-au1x00/au1xxx_dbdma.h> +#include <asm/mach-au1x00/au1200fb.h> #include <asm/mach-au1x00/au1550_spi.h> #include <asm/mach-db1x00/bcsr.h> #include <asm/mach-db1x00/db1200.h> -#include "../platform.h" +#include "platform.h" + +static const char *board_type_str(void) +{ + switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) { + case BCSR_WHOAMI_PB1200_DDR1: + case BCSR_WHOAMI_PB1200_DDR2: + return "PB1200"; + case BCSR_WHOAMI_DB1200: + return "DB1200"; + default: + return "(unknown)"; + } +} + +const char *get_system_type(void) +{ + return board_type_str(); +} + +static int __init detect_board(void) +{ + int bid; + + /* try the DB1200 first */ + bcsr_init(DB1200_BCSR_PHYS_ADDR, + DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS); + if (BCSR_WHOAMI_DB1200 == BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) { + unsigned short t = bcsr_read(BCSR_HEXLEDS); + bcsr_write(BCSR_HEXLEDS, ~t); + if (bcsr_read(BCSR_HEXLEDS) != t) { + bcsr_write(BCSR_HEXLEDS, t); + return 0; + } + } + + /* okay, try the PB1200 then */ + bcsr_init(PB1200_BCSR_PHYS_ADDR, + PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS); + bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)); + if ((bid == BCSR_WHOAMI_PB1200_DDR1) || + (bid == BCSR_WHOAMI_PB1200_DDR2)) { + unsigned short t = bcsr_read(BCSR_HEXLEDS); + bcsr_write(BCSR_HEXLEDS, ~t); + if (bcsr_read(BCSR_HEXLEDS) != t) { + bcsr_write(BCSR_HEXLEDS, t); + return 0; + } + } + + return 1; /* it's neither */ +} + +void __init board_setup(void) +{ + unsigned long freq0, clksrc, div, pfc; + unsigned short whoami; + + if (detect_board()) { + printk(KERN_ERR "NOT running on a DB1200/PB1200 board!\n"); + return; + } + + whoami = bcsr_read(BCSR_WHOAMI); + printk(KERN_INFO "Alchemy/AMD/RMI %s Board, CPLD Rev %d" + " Board-ID %d Daughtercard ID %d\n", board_type_str(), + (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf); + + /* SMBus/SPI on PSC0, Audio on PSC1 */ + pfc = __raw_readl((void __iomem *)SYS_PINFUNC); + pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B); + pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3); + pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */ + __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); + wmb(); + + /* Clock configurations: PSC0: ~50MHz via Clkgen0, derived from + * CPU clock; all other clock generators off/unused. + */ + div = (get_au1x00_speed() + 25000000) / 50000000; + if (div & 1) + div++; + div = ((div >> 1) - 1) & 0xff; + + freq0 = div << SYS_FC_FRDIV0_BIT; + __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); + wmb(); + freq0 |= SYS_FC_FE0; /* enable F0 */ + __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); + wmb(); + + /* psc0_intclk comes 1:1 from F0 */ + clksrc = SYS_CS_MUX_FQ0 << SYS_CS_ME0_BIT; + __raw_writel(clksrc, (void __iomem *)SYS_CLKSRC); + wmb(); +} + +/******************************************************************************/ static struct mtd_partition db1200_spiflash_parts[] = { { - .name = "DB1200 SPI flash", + .name = "spi_flash", .offset = 0, .size = MTDPART_SIZ_FULL, }, @@ -78,18 +177,9 @@ static struct spi_board_info db1200_spi_devs[] __initdata = { }; static struct i2c_board_info db1200_i2c_devs[] __initdata = { - { - /* AT24C04-10 I2C eeprom */ - I2C_BOARD_INFO("24c04", 0x52), - }, - { - /* Philips NE1619 temp/voltage sensor (adm1025 drv) */ - I2C_BOARD_INFO("ne1619", 0x2d), - }, - { - /* I2S audio codec WM8731 */ - I2C_BOARD_INFO("wm8731", 0x1b), - }, + { I2C_BOARD_INFO("24c04", 0x52), }, /* AT24C04-10 I2C eeprom */ + { I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */ + { I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec WM8731 */ }; /**********************************************************************/ @@ -206,7 +296,7 @@ static struct platform_device db1200_eth_dev = { static struct resource db1200_ide_res[] = { [0] = { .start = DB1200_IDE_PHYS_ADDR, - .end = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1, + .end = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -221,13 +311,13 @@ static struct resource db1200_ide_res[] = { }, }; -static u64 ide_dmamask = DMA_BIT_MASK(32); +static u64 au1200_ide_dmamask = DMA_BIT_MASK(32); static struct platform_device db1200_ide_dev = { .name = "au1200-ide", .id = 0, .dev = { - .dma_mask = &ide_dmamask, + .dma_mask = &au1200_ide_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), }, .num_resources = ARRAY_SIZE(db1200_ide_res), @@ -236,13 +326,6 @@ static struct platform_device db1200_ide_dev = { /**********************************************************************/ -static struct platform_device db1200_rtc_dev = { - .name = "rtc-au1xxx", - .id = -1, -}; - -/**********************************************************************/ - /* SD carddetects: they're supposed to be edge-triggered, but ack * doesn't seem to work (CPLD Rev 2). Instead, the screaming one * is disabled and its counterpart enabled. The 500ms timeout is @@ -276,12 +359,12 @@ static int db1200_mmc_cd_setup(void *mmc_host, int en) if (en) { ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd, - IRQF_DISABLED, "sd_insert", mmc_host); + 0, "sd_insert", mmc_host); if (ret) goto out; ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd, - IRQF_DISABLED, "sd_eject", mmc_host); + 0, "sd_eject", mmc_host); if (ret) { free_irq(DB1200_SD0_INSERT_INT, mmc_host); goto out; @@ -333,12 +416,109 @@ static struct led_classdev db1200_mmc_led = { .brightness_set = db1200_mmcled_set, }; -static struct au1xmmc_platform_data db1200mmc_platdata = { - .cd_setup = db1200_mmc_cd_setup, - .set_power = db1200_mmc_set_power, - .card_inserted = db1200_mmc_card_inserted, - .card_readonly = db1200_mmc_card_readonly, - .led = &db1200_mmc_led, +/* -- */ + +static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr) +{ + void(*mmc_cd)(struct mmc_host *, unsigned long); + + if (irq == PB1200_SD1_INSERT_INT) { + disable_irq_nosync(PB1200_SD1_INSERT_INT); + enable_irq(PB1200_SD1_EJECT_INT); + } else { + disable_irq_nosync(PB1200_SD1_EJECT_INT); + enable_irq(PB1200_SD1_INSERT_INT); + } + + /* link against CONFIG_MMC=m */ + mmc_cd = symbol_get(mmc_detect_change); + if (mmc_cd) { + mmc_cd(ptr, msecs_to_jiffies(500)); + symbol_put(mmc_detect_change); + } + + return IRQ_HANDLED; +} + +static int pb1200_mmc1_cd_setup(void *mmc_host, int en) +{ + int ret; + + if (en) { + ret = request_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 0, + "sd1_insert", mmc_host); + if (ret) + goto out; + + ret = request_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 0, + "sd1_eject", mmc_host); + if (ret) { + free_irq(PB1200_SD1_INSERT_INT, mmc_host); + goto out; + } + + if (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) + enable_irq(PB1200_SD1_EJECT_INT); + else + enable_irq(PB1200_SD1_INSERT_INT); + + } else { + free_irq(PB1200_SD1_INSERT_INT, mmc_host); + free_irq(PB1200_SD1_EJECT_INT, mmc_host); + } + ret = 0; +out: + return ret; +} + +static void pb1200_mmc1led_set(struct led_classdev *led, + enum led_brightness brightness) +{ + if (brightness != LED_OFF) + bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0); + else + bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1); +} + +static struct led_classdev pb1200_mmc1_led = { + .brightness_set = pb1200_mmc1led_set, +}; + +static void pb1200_mmc1_set_power(void *mmc_host, int state) +{ + if (state) { + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR); + msleep(400); /* stabilization time */ + } else + bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0); +} + +static int pb1200_mmc1_card_readonly(void *mmc_host) +{ + return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0; +} + +static int pb1200_mmc1_card_inserted(void *mmc_host) +{ + return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0; +} + + +static struct au1xmmc_platform_data db1200_mmc_platdata[2] = { + [0] = { + .cd_setup = db1200_mmc_cd_setup, + .set_power = db1200_mmc_set_power, + .card_inserted = db1200_mmc_card_inserted, + .card_readonly = db1200_mmc_card_readonly, + .led = &db1200_mmc_led, + }, + [1] = { + .cd_setup = pb1200_mmc1_cd_setup, + .set_power = pb1200_mmc1_set_power, + .card_inserted = pb1200_mmc1_card_inserted, + .card_readonly = pb1200_mmc1_card_readonly, + .led = &pb1200_mmc1_led, + }, }; static struct resource au1200_mmc0_resources[] = { @@ -372,14 +552,76 @@ static struct platform_device db1200_mmc0_dev = { .dev = { .dma_mask = &au1xxx_mmc_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &db1200mmc_platdata, + .platform_data = &db1200_mmc_platdata[0], }, .num_resources = ARRAY_SIZE(au1200_mmc0_resources), .resource = au1200_mmc0_resources, }; +static struct resource au1200_mmc1_res[] = { + [0] = { + .start = AU1100_SD1_PHYS_ADDR, + .end = AU1100_SD1_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1200_SD_INT, + .end = AU1200_SD_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1200_DSCR_CMD0_SDMS_TX1, + .end = AU1200_DSCR_CMD0_SDMS_TX1, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1200_DSCR_CMD0_SDMS_RX1, + .end = AU1200_DSCR_CMD0_SDMS_RX1, + .flags = IORESOURCE_DMA, + } +}; + +static struct platform_device pb1200_mmc1_dev = { + .name = "au1xxx-mmc", + .id = 1, + .dev = { + .dma_mask = &au1xxx_mmc_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &db1200_mmc_platdata[1], + }, + .num_resources = ARRAY_SIZE(au1200_mmc1_res), + .resource = au1200_mmc1_res, +}; + /**********************************************************************/ +static int db1200fb_panel_index(void) +{ + return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f; +} + +static int db1200fb_panel_init(void) +{ + /* Apply power */ + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | + BCSR_BOARD_LCDBL); + return 0; +} + +static int db1200fb_panel_shutdown(void) +{ + /* Remove power */ + bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | + BCSR_BOARD_LCDBL, 0); + return 0; +} + +static struct au1200fb_platdata db1200fb_pd = { + .panel_index = db1200fb_panel_index, + .panel_init = db1200fb_panel_init, + .panel_shutdown = db1200fb_panel_shutdown, +}; + static struct resource au1200_lcd_res[] = { [0] = { .start = AU1200_LCD_PHYS_ADDR, @@ -401,6 +643,7 @@ static struct platform_device au1200_lcd_dev = { .dev = { .dma_mask = &au1200_lcd_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &db1200fb_pd, }, .num_resources = ARRAY_SIZE(au1200_lcd_res), .resource = au1200_lcd_res, @@ -519,7 +762,6 @@ static struct platform_device *db1200_devs[] __initdata = { &db1200_mmc0_dev, &au1200_lcd_dev, &db1200_eth_dev, - &db1200_rtc_dev, &db1200_nand_dev, &db1200_audiodma_dev, &db1200_audio_dev, @@ -527,11 +769,62 @@ static struct platform_device *db1200_devs[] __initdata = { &db1200_sound_dev, }; +static struct platform_device *pb1200_devs[] __initdata = { + &pb1200_mmc1_dev, +}; + +/* Some peripheral base addresses differ on the PB1200 */ +static int __init pb1200_res_fixup(void) +{ + /* CPLD Revs earlier than 4 cause problems */ + if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) { + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "PB1200 must be at CPLD rev 4. Please have\n"); + printk(KERN_ERR "the board updated to latest revisions.\n"); + printk(KERN_ERR "This software will not work reliably\n"); + printk(KERN_ERR "on anything older than CPLD rev 4.!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + return 1; + } + + db1200_nand_res[0].start = PB1200_NAND_PHYS_ADDR; + db1200_nand_res[0].end = PB1200_NAND_PHYS_ADDR + 0xff; + db1200_ide_res[0].start = PB1200_IDE_PHYS_ADDR; + db1200_ide_res[0].end = PB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1; + db1200_eth_res[0].start = PB1200_ETH_PHYS_ADDR; + db1200_eth_res[0].end = PB1200_ETH_PHYS_ADDR + 0xff; + return 0; +} + static int __init db1200_dev_init(void) { unsigned long pfc; unsigned short sw; - int swapped; + int swapped, bid; + + bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)); + if ((bid == BCSR_WHOAMI_PB1200_DDR1) || + (bid == BCSR_WHOAMI_PB1200_DDR2)) { + if (pb1200_res_fixup()) + return -ENODEV; + } + + /* GPIO7 is low-level triggered CPLD cascade */ + irq_set_irq_type(AU1200_GPIO7_INT, IRQ_TYPE_LEVEL_LOW); + bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT); + + /* insert/eject pairs: one of both is always screaming. To avoid + * issues they must not be automatically enabled when initially + * requested. + */ + irq_set_status_flags(DB1200_SD0_INSERT_INT, IRQ_NOAUTOEN); + irq_set_status_flags(DB1200_SD0_EJECT_INT, IRQ_NOAUTOEN); + irq_set_status_flags(DB1200_PC0_INSERT_INT, IRQ_NOAUTOEN); + irq_set_status_flags(DB1200_PC0_EJECT_INT, IRQ_NOAUTOEN); + irq_set_status_flags(DB1200_PC1_INSERT_INT, IRQ_NOAUTOEN); + irq_set_status_flags(DB1200_PC1_EJECT_INT, IRQ_NOAUTOEN); i2c_register_board_info(0, db1200_i2c_devs, ARRAY_SIZE(db1200_i2c_devs)); @@ -540,6 +833,7 @@ static int __init db1200_dev_init(void) /* SWITCHES: S6.8 I2C/SPI selector (OFF=I2C ON=SPI) * S6.7 AC97/I2S selector (OFF=AC97 ON=I2S) + * or S12 on the PB1200. */ /* NOTE: GPIO215 controls OTG VBUS supply. In SPI mode however @@ -554,7 +848,7 @@ static int __init db1200_dev_init(void) gpio_request(215, "otg-vbus"); gpio_direction_output(215, 1); - printk(KERN_INFO "DB1200 device configuration:\n"); + printk(KERN_INFO "%s device configuration:\n", board_type_str()); sw = bcsr_read(BCSR_SWITCHES); if (sw & BCSR_SWITCHES_DIP_8) { @@ -595,7 +889,7 @@ static int __init db1200_dev_init(void) /* Audio PSC clock is supplied externally. (FIXME: platdata!!) */ __raw_writel(PSC_SEL_CLK_SERCLK, - (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); + (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); wmb(); db1x_register_pcmcia_socket( @@ -621,28 +915,13 @@ static int __init db1200_dev_init(void) swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT; db1x_register_norflash(64 << 20, 2, swapped); - return platform_add_devices(db1200_devs, ARRAY_SIZE(db1200_devs)); -} -device_initcall(db1200_dev_init); - -/* au1200fb calls these: STERBT EINEN TRAGISCHEN TOD!!! */ -int board_au1200fb_panel(void) -{ - return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f; -} + platform_add_devices(db1200_devs, ARRAY_SIZE(db1200_devs)); -int board_au1200fb_panel_init(void) -{ - /* Apply power */ - bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | - BCSR_BOARD_LCDBL); - return 0; -} + /* PB1200 is a DB1200 with a 2nd MMC and Camera connector */ + if ((bid == BCSR_WHOAMI_PB1200_DDR1) || + (bid == BCSR_WHOAMI_PB1200_DDR2)) + platform_add_devices(pb1200_devs, ARRAY_SIZE(pb1200_devs)); -int board_au1200fb_panel_shutdown(void) -{ - /* Remove power */ - bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | - BCSR_BOARD_LCDBL, 0); return 0; } +device_initcall(db1200_dev_init); diff --git a/arch/mips/alchemy/devboards/db1200/Makefile b/arch/mips/alchemy/devboards/db1200/Makefile deleted file mode 100644 index 17840a5e2738..000000000000 --- a/arch/mips/alchemy/devboards/db1200/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += setup.o platform.o diff --git a/arch/mips/alchemy/devboards/db1200/setup.c b/arch/mips/alchemy/devboards/db1200/setup.c deleted file mode 100644 index 4a8980027ecf..000000000000 --- a/arch/mips/alchemy/devboards/db1200/setup.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Alchemy/AMD/RMI DB1200 board setup. - * - * Licensed under the terms outlined in the file COPYING in the root of - * this source archive. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-db1x00/bcsr.h> -#include <asm/mach-db1x00/db1200.h> - -const char *get_system_type(void) -{ - return "Alchemy Db1200"; -} - -void __init board_setup(void) -{ - unsigned long freq0, clksrc, div, pfc; - unsigned short whoami; - - bcsr_init(DB1200_BCSR_PHYS_ADDR, - DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS); - - whoami = bcsr_read(BCSR_WHOAMI); - printk(KERN_INFO "Alchemy/AMD/RMI DB1200 Board, CPLD Rev %d" - " Board-ID %d Daughtercard ID %d\n", - (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf); - - /* SMBus/SPI on PSC0, Audio on PSC1 */ - pfc = __raw_readl((void __iomem *)SYS_PINFUNC); - pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B); - pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3); - pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */ - __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); - wmb(); - - /* Clock configurations: PSC0: ~50MHz via Clkgen0, derived from - * CPU clock; all other clock generators off/unused. - */ - div = (get_au1x00_speed() + 25000000) / 50000000; - if (div & 1) - div++; - div = ((div >> 1) - 1) & 0xff; - - freq0 = div << SYS_FC_FRDIV0_BIT; - __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); - wmb(); - freq0 |= SYS_FC_FE0; /* enable F0 */ - __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); - wmb(); - - /* psc0_intclk comes 1:1 from F0 */ - clksrc = SYS_CS_MUX_FQ0 << SYS_CS_ME0_BIT; - __raw_writel(clksrc, (void __iomem *)SYS_CLKSRC); - wmb(); -} - -static int __init db1200_arch_init(void) -{ - /* GPIO7 is low-level triggered CPLD cascade */ - irq_set_irq_type(AU1200_GPIO7_INT, IRQF_TRIGGER_LOW); - bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT); - - /* insert/eject pairs: one of both is always screaming. To avoid - * issues they must not be automatically enabled when initially - * requested. - */ - irq_set_status_flags(DB1200_SD0_INSERT_INT, IRQ_NOAUTOEN); - irq_set_status_flags(DB1200_SD0_EJECT_INT, IRQ_NOAUTOEN); - irq_set_status_flags(DB1200_PC0_INSERT_INT, IRQ_NOAUTOEN); - irq_set_status_flags(DB1200_PC0_EJECT_INT, IRQ_NOAUTOEN); - irq_set_status_flags(DB1200_PC1_INSERT_INT, IRQ_NOAUTOEN); - irq_set_status_flags(DB1200_PC1_EJECT_INT, IRQ_NOAUTOEN); - return 0; -} -arch_initcall(db1200_arch_init); diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c new file mode 100644 index 000000000000..0893f2af0d01 --- /dev/null +++ b/arch/mips/alchemy/devboards/db1300.c @@ -0,0 +1,785 @@ +/* + * DBAu1300 init and platform device setup. + * + * (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com> + */ + +#include <linux/dma-mapping.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/init.h> +#include <linux/input.h> /* KEY_* codes */ +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/ata_platform.h> +#include <linux/mmc/host.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> +#include <linux/smsc911x.h> + +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1100_mmc.h> +#include <asm/mach-au1x00/au1200fb.h> +#include <asm/mach-au1x00/au1xxx_dbdma.h> +#include <asm/mach-au1x00/au1xxx_psc.h> +#include <asm/mach-db1x00/db1300.h> +#include <asm/mach-db1x00/bcsr.h> +#include <asm/mach-au1x00/prom.h> + +#include "platform.h" + +static struct i2c_board_info db1300_i2c_devs[] __initdata = { + { I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec */ + { I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */ +}; + +/* multifunction pins to assign to GPIO controller */ +static int db1300_gpio_pins[] __initdata = { + AU1300_PIN_LCDPWM0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_WAKE1, + AU1300_PIN_WAKE2, AU1300_PIN_WAKE3, AU1300_PIN_FG3AUX, + AU1300_PIN_EXTCLK1, + -1, /* terminator */ +}; + +/* multifunction pins to assign to device functions */ +static int db1300_dev_pins[] __initdata = { + /* wake-from-str pins 0-3 */ + AU1300_PIN_WAKE0, + /* external clock sources for PSC0 */ + AU1300_PIN_EXTCLK0, + /* 8bit MMC interface on SD0: 6-9 */ + AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6, + AU1300_PIN_SD0DAT7, + /* UART1 pins: 11-18 */ + AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR, + AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR, + AU1300_PIN_U1RX, AU1300_PIN_U1TX, + /* UART0 pins: 19-24 */ + AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR, + AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR, + /* UART2: 25-26 */ + AU1300_PIN_U2RX, AU1300_PIN_U2TX, + /* UART3: 27-28 */ + AU1300_PIN_U3RX, AU1300_PIN_U3TX, + /* LCD controller PWMs, ext pixclock: 30-31 */ + AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN, + /* SD1 interface: 32-37 */ + AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2, + AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK, + /* SD2 interface: 38-43 */ + AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2, + AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK, + /* PSC0/1 clocks: 44-45 */ + AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK, + /* PSCs: 46-49/50-53/54-57/58-61 */ + AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0, + AU1300_PIN_PSC0D1, + AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0, + AU1300_PIN_PSC1D1, + AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2D0, + AU1300_PIN_PSC2D1, + AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0, + AU1300_PIN_PSC3D1, + /* PCMCIA interface: 62-70 */ + AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16, + AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT, + AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW, + /* camera interface H/V sync inputs: 71-72 */ + AU1300_PIN_CIMLS, AU1300_PIN_CIMFS, + /* PSC2/3 clocks: 73-74 */ + AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK, + -1, /* terminator */ +}; + +static void __init db1300_gpio_config(void) +{ + int *i; + + i = &db1300_dev_pins[0]; + while (*i != -1) + au1300_pinfunc_to_dev(*i++); + + i = &db1300_gpio_pins[0]; + while (*i != -1) + au1300_gpio_direction_input(*i++);/* implies pin_to_gpio */ + + au1300_set_dbdma_gpio(1, AU1300_PIN_FG3AUX); +} + +char *get_system_type(void) +{ + return "DB1300"; +} + +/**********************************************************************/ + +static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + unsigned long ioaddr = (unsigned long)this->IO_ADDR_W; + + ioaddr &= 0xffffff00; + + if (ctrl & NAND_CLE) { + ioaddr += MEM_STNAND_CMD; + } else if (ctrl & NAND_ALE) { + ioaddr += MEM_STNAND_ADDR; + } else { + /* assume we want to r/w real data by default */ + ioaddr += MEM_STNAND_DATA; + } + this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr; + if (cmd != NAND_CMD_NONE) { + __raw_writeb(cmd, this->IO_ADDR_W); + wmb(); + } +} + +static int au1300_nand_device_ready(struct mtd_info *mtd) +{ + return __raw_readl((void __iomem *)MEM_STSTAT) & 1; +} + +static const char *db1300_part_probes[] = { "cmdlinepart", NULL }; + +static struct mtd_partition db1300_nand_parts[] = { + { + .name = "NAND FS 0", + .offset = 0, + .size = 8 * 1024 * 1024, + }, + { + .name = "NAND FS 1", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL + }, +}; + +struct platform_nand_data db1300_nand_platdata = { + .chip = { + .nr_chips = 1, + .chip_offset = 0, + .nr_partitions = ARRAY_SIZE(db1300_nand_parts), + .partitions = db1300_nand_parts, + .chip_delay = 20, + .part_probe_types = db1300_part_probes, + }, + .ctrl = { + .dev_ready = au1300_nand_device_ready, + .cmd_ctrl = au1300_nand_cmd_ctrl, + }, +}; + +static struct resource db1300_nand_res[] = { + [0] = { + .start = DB1300_NAND_PHYS_ADDR, + .end = DB1300_NAND_PHYS_ADDR + 0xff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device db1300_nand_dev = { + .name = "gen_nand", + .num_resources = ARRAY_SIZE(db1300_nand_res), + .resource = db1300_nand_res, + .id = -1, + .dev = { + .platform_data = &db1300_nand_platdata, + } +}; + +/**********************************************************************/ + +static struct resource db1300_eth_res[] = { + [0] = { + .start = DB1300_ETH_PHYS_ADDR, + .end = DB1300_ETH_PHYS_END, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DB1300_ETH_INT, + .end = DB1300_ETH_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct smsc911x_platform_config db1300_eth_config = { + .phy_interface = PHY_INTERFACE_MODE_MII, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_32BIT, +}; + +static struct platform_device db1300_eth_dev = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(db1300_eth_res), + .resource = db1300_eth_res, + .dev = { + .platform_data = &db1300_eth_config, + }, +}; + +/**********************************************************************/ + +static struct resource au1300_psc1_res[] = { + [0] = { + .start = AU1300_PSC1_PHYS_ADDR, + .end = AU1300_PSC1_PHYS_ADDR + 0x0fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1300_PSC1_INT, + .end = AU1300_PSC1_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1300_DSCR_CMD0_PSC1_TX, + .end = AU1300_DSCR_CMD0_PSC1_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1300_DSCR_CMD0_PSC1_RX, + .end = AU1300_DSCR_CMD0_PSC1_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1300_ac97_dev = { + .name = "au1xpsc_ac97", + .id = 1, /* PSC ID. match with AC97 codec ID! */ + .num_resources = ARRAY_SIZE(au1300_psc1_res), + .resource = au1300_psc1_res, +}; + +/**********************************************************************/ + +static struct resource au1300_psc2_res[] = { + [0] = { + .start = AU1300_PSC2_PHYS_ADDR, + .end = AU1300_PSC2_PHYS_ADDR + 0x0fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1300_PSC2_INT, + .end = AU1300_PSC2_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1300_DSCR_CMD0_PSC2_TX, + .end = AU1300_DSCR_CMD0_PSC2_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1300_DSCR_CMD0_PSC2_RX, + .end = AU1300_DSCR_CMD0_PSC2_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1300_i2s_dev = { + .name = "au1xpsc_i2s", + .id = 2, /* PSC ID */ + .num_resources = ARRAY_SIZE(au1300_psc2_res), + .resource = au1300_psc2_res, +}; + +/**********************************************************************/ + +static struct resource au1300_psc3_res[] = { + [0] = { + .start = AU1300_PSC3_PHYS_ADDR, + .end = AU1300_PSC3_PHYS_ADDR + 0x0fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1300_PSC3_INT, + .end = AU1300_PSC3_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1300_DSCR_CMD0_PSC3_TX, + .end = AU1300_DSCR_CMD0_PSC3_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1300_DSCR_CMD0_PSC3_RX, + .end = AU1300_DSCR_CMD0_PSC3_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1300_i2c_dev = { + .name = "au1xpsc_smbus", + .id = 0, /* bus number */ + .num_resources = ARRAY_SIZE(au1300_psc3_res), + .resource = au1300_psc3_res, +}; + +/**********************************************************************/ + +/* proper key assignments when facing the LCD panel. For key assignments + * according to the schematics swap up with down and left with right. + * I chose to use it to emulate the arrow keys of a keyboard. + */ +static struct gpio_keys_button db1300_5waysw_arrowkeys[] = { + { + .code = KEY_DOWN, + .gpio = AU1300_PIN_LCDPWM0, + .type = EV_KEY, + .debounce_interval = 1, + .active_low = 1, + .desc = "5waysw-down", + }, + { + .code = KEY_UP, + .gpio = AU1300_PIN_PSC2SYNC1, + .type = EV_KEY, + .debounce_interval = 1, + .active_low = 1, + .desc = "5waysw-up", + }, + { + .code = KEY_RIGHT, + .gpio = AU1300_PIN_WAKE3, + .type = EV_KEY, + .debounce_interval = 1, + .active_low = 1, + .desc = "5waysw-right", + }, + { + .code = KEY_LEFT, + .gpio = AU1300_PIN_WAKE2, + .type = EV_KEY, + .debounce_interval = 1, + .active_low = 1, + .desc = "5waysw-left", + }, + { + .code = KEY_ENTER, + .gpio = AU1300_PIN_WAKE1, + .type = EV_KEY, + .debounce_interval = 1, + .active_low = 1, + .desc = "5waysw-push", + }, +}; + +static struct gpio_keys_platform_data db1300_5waysw_data = { + .buttons = db1300_5waysw_arrowkeys, + .nbuttons = ARRAY_SIZE(db1300_5waysw_arrowkeys), + .rep = 1, + .name = "db1300-5wayswitch", +}; + +static struct platform_device db1300_5waysw_dev = { + .name = "gpio-keys", + .dev = { + .platform_data = &db1300_5waysw_data, + }, +}; + +/**********************************************************************/ + +static struct pata_platform_info db1300_ide_info = { + .ioport_shift = DB1300_IDE_REG_SHIFT, +}; + +#define IDE_ALT_START (14 << DB1300_IDE_REG_SHIFT) +static struct resource db1300_ide_res[] = { + [0] = { + .start = DB1300_IDE_PHYS_ADDR, + .end = DB1300_IDE_PHYS_ADDR + IDE_ALT_START - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DB1300_IDE_PHYS_ADDR + IDE_ALT_START, + .end = DB1300_IDE_PHYS_ADDR + DB1300_IDE_PHYS_LEN - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = DB1300_IDE_INT, + .end = DB1300_IDE_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device db1300_ide_dev = { + .dev = { + .platform_data = &db1300_ide_info, + }, + .name = "pata_platform", + .resource = db1300_ide_res, + .num_resources = ARRAY_SIZE(db1300_ide_res), +}; + +/**********************************************************************/ + +static irqreturn_t db1300_mmc_cd(int irq, void *ptr) +{ + void(*mmc_cd)(struct mmc_host *, unsigned long); + + /* disable the one currently screaming. No other way to shut it up */ + if (irq == DB1300_SD1_INSERT_INT) { + disable_irq_nosync(DB1300_SD1_INSERT_INT); + enable_irq(DB1300_SD1_EJECT_INT); + } else { + disable_irq_nosync(DB1300_SD1_EJECT_INT); + enable_irq(DB1300_SD1_INSERT_INT); + } + + /* link against CONFIG_MMC=m. We can only be called once MMC core has + * initialized the controller, so symbol_get() should always succeed. + */ + mmc_cd = symbol_get(mmc_detect_change); + mmc_cd(ptr, msecs_to_jiffies(500)); + symbol_put(mmc_detect_change); + + return IRQ_HANDLED; +} + +static int db1300_mmc_card_readonly(void *mmc_host) +{ + /* it uses SD1 interface, but the DB1200's SD0 bit in the CPLD */ + return bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP; +} + +static int db1300_mmc_card_inserted(void *mmc_host) +{ + return bcsr_read(BCSR_SIGSTAT) & (1 << 12); /* insertion irq signal */ +} + +static int db1300_mmc_cd_setup(void *mmc_host, int en) +{ + int ret; + + if (en) { + ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0, + "sd_insert", mmc_host); + if (ret) + goto out; + + ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0, + "sd_eject", mmc_host); + if (ret) { + free_irq(DB1300_SD1_INSERT_INT, mmc_host); + goto out; + } + + if (db1300_mmc_card_inserted(mmc_host)) + enable_irq(DB1300_SD1_EJECT_INT); + else + enable_irq(DB1300_SD1_INSERT_INT); + + } else { + free_irq(DB1300_SD1_INSERT_INT, mmc_host); + free_irq(DB1300_SD1_EJECT_INT, mmc_host); + } + ret = 0; +out: + return ret; +} + +static void db1300_mmcled_set(struct led_classdev *led, + enum led_brightness brightness) +{ + if (brightness != LED_OFF) + bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0); + else + bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0); +} + +static struct led_classdev db1300_mmc_led = { + .brightness_set = db1300_mmcled_set, +}; + +struct au1xmmc_platform_data db1300_sd1_platdata = { + .cd_setup = db1300_mmc_cd_setup, + .card_inserted = db1300_mmc_card_inserted, + .card_readonly = db1300_mmc_card_readonly, + .led = &db1300_mmc_led, +}; + +static struct resource au1300_sd1_res[] = { + [0] = { + .start = AU1300_SD1_PHYS_ADDR, + .end = AU1300_SD1_PHYS_ADDR, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1300_SD1_INT, + .end = AU1300_SD1_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1300_DSCR_CMD0_SDMS_TX1, + .end = AU1300_DSCR_CMD0_SDMS_TX1, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1300_DSCR_CMD0_SDMS_RX1, + .end = AU1300_DSCR_CMD0_SDMS_RX1, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1300_sd1_dev = { + .dev = { + .platform_data = &db1300_sd1_platdata, + }, + .name = "au1xxx-mmc", + .id = 1, + .resource = au1300_sd1_res, + .num_resources = ARRAY_SIZE(au1300_sd1_res), +}; + +/**********************************************************************/ + +static int db1300_movinand_inserted(void *mmc_host) +{ + return 0; /* disable for now, it doesn't work yet */ +} + +static int db1300_movinand_readonly(void *mmc_host) +{ + return 0; +} + +static void db1300_movinand_led_set(struct led_classdev *led, + enum led_brightness brightness) +{ + if (brightness != LED_OFF) + bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0); + else + bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1); +} + +static struct led_classdev db1300_movinand_led = { + .brightness_set = db1300_movinand_led_set, +}; + +struct au1xmmc_platform_data db1300_sd0_platdata = { + .card_inserted = db1300_movinand_inserted, + .card_readonly = db1300_movinand_readonly, + .led = &db1300_movinand_led, + .mask_host_caps = MMC_CAP_NEEDS_POLL, +}; + +static struct resource au1300_sd0_res[] = { + [0] = { + .start = AU1100_SD0_PHYS_ADDR, + .end = AU1100_SD0_PHYS_ADDR, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1300_SD0_INT, + .end = AU1300_SD0_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1300_DSCR_CMD0_SDMS_TX0, + .end = AU1300_DSCR_CMD0_SDMS_TX0, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1300_DSCR_CMD0_SDMS_RX0, + .end = AU1300_DSCR_CMD0_SDMS_RX0, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1300_sd0_dev = { + .dev = { + .platform_data = &db1300_sd0_platdata, + }, + .name = "au1xxx-mmc", + .id = 0, + .resource = au1300_sd0_res, + .num_resources = ARRAY_SIZE(au1300_sd0_res), +}; + +/**********************************************************************/ + +static struct platform_device db1300_wm9715_dev = { + .name = "wm9712-codec", + .id = 1, /* ID of PSC for AC97 audio, see asoc glue! */ +}; + +static struct platform_device db1300_ac97dma_dev = { + .name = "au1xpsc-pcm", + .id = 1, /* PSC ID */ +}; + +static struct platform_device db1300_i2sdma_dev = { + .name = "au1xpsc-pcm", + .id = 2, /* PSC ID */ +}; + +static struct platform_device db1300_sndac97_dev = { + .name = "db1300-ac97", +}; + +static struct platform_device db1300_sndi2s_dev = { + .name = "db1300-i2s", +}; + +/**********************************************************************/ + +static int db1300fb_panel_index(void) +{ + return 9; /* DB1300_800x480 */ +} + +static int db1300fb_panel_init(void) +{ + /* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */ + bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD, + BCSR_BOARD_LCDBL); + return 0; +} + +static int db1300fb_panel_shutdown(void) +{ + /* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */ + bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL, + BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD); + return 0; +} + +static struct au1200fb_platdata db1300fb_pd = { + .panel_index = db1300fb_panel_index, + .panel_init = db1300fb_panel_init, + .panel_shutdown = db1300fb_panel_shutdown, +}; + +static struct resource au1300_lcd_res[] = { + [0] = { + .start = AU1200_LCD_PHYS_ADDR, + .end = AU1200_LCD_PHYS_ADDR + 0x800 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1300_LCD_INT, + .end = AU1300_LCD_INT, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 au1300_lcd_dmamask = DMA_BIT_MASK(32); + +static struct platform_device db1300_lcd_dev = { + .name = "au1200-lcd", + .id = 0, + .dev = { + .dma_mask = &au1300_lcd_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &db1300fb_pd, + }, + .num_resources = ARRAY_SIZE(au1300_lcd_res), + .resource = au1300_lcd_res, +}; + +/**********************************************************************/ + +static struct platform_device *db1300_dev[] __initdata = { + &db1300_eth_dev, + &db1300_i2c_dev, + &db1300_5waysw_dev, + &db1300_nand_dev, + &db1300_ide_dev, + &db1300_sd0_dev, + &db1300_sd1_dev, + &db1300_lcd_dev, + &db1300_ac97_dev, + &db1300_i2s_dev, + &db1300_wm9715_dev, + &db1300_ac97dma_dev, + &db1300_i2sdma_dev, + &db1300_sndac97_dev, + &db1300_sndi2s_dev, +}; + +static int __init db1300_device_init(void) +{ + int swapped, cpldirq; + + /* setup CPLD IRQ muxer */ + cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1); + irq_set_irq_type(cpldirq, IRQ_TYPE_LEVEL_HIGH); + bcsr_init_irq(DB1300_FIRST_INT, DB1300_LAST_INT, cpldirq); + + /* insert/eject IRQs: one always triggers so don't enable them + * when doing request_irq() on them. DB1200 has this bug too. + */ + irq_set_status_flags(DB1300_SD1_INSERT_INT, IRQ_NOAUTOEN); + irq_set_status_flags(DB1300_SD1_EJECT_INT, IRQ_NOAUTOEN); + irq_set_status_flags(DB1300_CF_INSERT_INT, IRQ_NOAUTOEN); + irq_set_status_flags(DB1300_CF_EJECT_INT, IRQ_NOAUTOEN); + + /* + * setup board + */ + prom_get_ethernet_addr(&db1300_eth_config.mac[0]); + + i2c_register_board_info(0, db1300_i2c_devs, + ARRAY_SIZE(db1300_i2c_devs)); + + /* Audio PSC clock is supplied by codecs (PSC1, 2) */ + __raw_writel(PSC_SEL_CLK_SERCLK, + (void __iomem *)KSEG1ADDR(AU1300_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); + wmb(); + __raw_writel(PSC_SEL_CLK_SERCLK, + (void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET); + wmb(); + /* I2C uses internal 48MHz EXTCLK1 */ + __raw_writel(PSC_SEL_CLK_INTCLK, + (void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET); + wmb(); + + /* enable power to USB ports */ + bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_USBHPWR | BCSR_RESETS_OTGPWR); + + /* although it is socket #0, it uses the CPLD bits which previous boards + * have used for socket #1. + */ + db1x_register_pcmcia_socket( + AU1000_PCMCIA_ATTR_PHYS_ADDR, + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x00400000 - 1, + AU1000_PCMCIA_MEM_PHYS_ADDR, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x00400000 - 1, + AU1000_PCMCIA_IO_PHYS_ADDR, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x00010000 - 1, + DB1300_CF_INT, DB1300_CF_INSERT_INT, 0, DB1300_CF_EJECT_INT, 1); + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT; + db1x_register_norflash(64 << 20, 2, swapped); + + return platform_add_devices(db1300_dev, ARRAY_SIZE(db1300_dev)); +} +device_initcall(db1300_device_init); + + +void __init board_setup(void) +{ + unsigned short whoami; + + db1300_gpio_config(); + bcsr_init(DB1300_BCSR_PHYS_ADDR, + DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS); + + whoami = bcsr_read(BCSR_WHOAMI); + printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t" + "BoardID %d CPLD Rev %d DaughtercardID %d\n", + BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami), + BCSR_WHOAMI_DCID(whoami)); + + /* enable UARTs, YAMON only enables #2 */ + alchemy_uart_enable(AU1300_UART0_PHYS_ADDR); + alchemy_uart_enable(AU1300_UART1_PHYS_ADDR); + alchemy_uart_enable(AU1300_UART3_PHYS_ADDR); +} diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c new file mode 100644 index 000000000000..6815d0783cd8 --- /dev/null +++ b/arch/mips/alchemy/devboards/db1550.c @@ -0,0 +1,498 @@ +/* + * Alchemy Db1550 board support + * + * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com> + */ + +#include <linux/dma-mapping.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1xxx_eth.h> +#include <asm/mach-au1x00/au1xxx_dbdma.h> +#include <asm/mach-au1x00/au1xxx_psc.h> +#include <asm/mach-au1x00/au1550_spi.h> +#include <asm/mach-db1x00/bcsr.h> +#include <prom.h> +#include "platform.h" + + +const char *get_system_type(void) +{ + return "DB1550"; +} + +static void __init db1550_hw_setup(void) +{ + void __iomem *base; + + alchemy_gpio_direction_output(203, 0); /* red led on */ + + /* complete SPI setup: link psc0_intclk to a 48MHz source, + * and assign GPIO16 to PSC0_SYNC1 (SPI cs# line) + */ + base = (void __iomem *)SYS_CLKSRC; + __raw_writel(__raw_readl(base) | 0x000001e0, base); + base = (void __iomem *)SYS_PINFUNC; + __raw_writel(__raw_readl(base) | 1, base); + wmb(); + + /* reset the AC97 codec now, the reset time in the psc-ac97 driver + * is apparently too short although it's ridiculous as it is. + */ + base = (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR); + __raw_writel(PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE, + base + PSC_SEL_OFFSET); + __raw_writel(PSC_CTRL_DISABLE, base + PSC_CTRL_OFFSET); + wmb(); + __raw_writel(PSC_AC97RST_RST, base + PSC_AC97RST_OFFSET); + wmb(); + + alchemy_gpio_direction_output(202, 0); /* green led on */ +} + +void __init board_setup(void) +{ + unsigned short whoami; + + bcsr_init(DB1550_BCSR_PHYS_ADDR, + DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS); + + whoami = bcsr_read(BCSR_WHOAMI); + printk(KERN_INFO "Alchemy/AMD DB1550 Board, CPLD Rev %d" + " Board-ID %d Daughtercard ID %d\n", + (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf); + + db1550_hw_setup(); +} + +/*****************************************************************************/ + +static struct mtd_partition db1550_spiflash_parts[] = { + { + .name = "spi_flash", + .offset = 0, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data db1550_spiflash_data = { + .name = "s25fl010", + .parts = db1550_spiflash_parts, + .nr_parts = ARRAY_SIZE(db1550_spiflash_parts), + .type = "m25p10", +}; + +static struct spi_board_info db1550_spi_devs[] __initdata = { + { + /* TI TMP121AIDBVR temp sensor */ + .modalias = "tmp121", + .max_speed_hz = 2400000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + }, + { + /* Spansion S25FL001D0FMA SPI flash */ + .modalias = "m25p80", + .max_speed_hz = 2400000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + .platform_data = &db1550_spiflash_data, + }, +}; + +static struct i2c_board_info db1550_i2c_devs[] __initdata = { + { I2C_BOARD_INFO("24c04", 0x52),}, /* AT24C04-10 I2C eeprom */ + { I2C_BOARD_INFO("ne1619", 0x2d),}, /* adm1025-compat hwmon */ + { I2C_BOARD_INFO("wm8731", 0x1b),}, /* I2S audio codec WM8731 */ +}; + +/**********************************************************************/ + +static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + unsigned long ioaddr = (unsigned long)this->IO_ADDR_W; + + ioaddr &= 0xffffff00; + + if (ctrl & NAND_CLE) { + ioaddr += MEM_STNAND_CMD; + } else if (ctrl & NAND_ALE) { + ioaddr += MEM_STNAND_ADDR; + } else { + /* assume we want to r/w real data by default */ + ioaddr += MEM_STNAND_DATA; + } + this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr; + if (cmd != NAND_CMD_NONE) { + __raw_writeb(cmd, this->IO_ADDR_W); + wmb(); + } +} + +static int au1550_nand_device_ready(struct mtd_info *mtd) +{ + return __raw_readl((void __iomem *)MEM_STSTAT) & 1; +} + +static const char *db1550_part_probes[] = { "cmdlinepart", NULL }; + +static struct mtd_partition db1550_nand_parts[] = { + { + .name = "NAND FS 0", + .offset = 0, + .size = 8 * 1024 * 1024, + }, + { + .name = "NAND FS 1", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL + }, +}; + +struct platform_nand_data db1550_nand_platdata = { + .chip = { + .nr_chips = 1, + .chip_offset = 0, + .nr_partitions = ARRAY_SIZE(db1550_nand_parts), + .partitions = db1550_nand_parts, + .chip_delay = 20, + .part_probe_types = db1550_part_probes, + }, + .ctrl = { + .dev_ready = au1550_nand_device_ready, + .cmd_ctrl = au1550_nand_cmd_ctrl, + }, +}; + +static struct resource db1550_nand_res[] = { + [0] = { + .start = 0x20000000, + .end = 0x200000ff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device db1550_nand_dev = { + .name = "gen_nand", + .num_resources = ARRAY_SIZE(db1550_nand_res), + .resource = db1550_nand_res, + .id = -1, + .dev = { + .platform_data = &db1550_nand_platdata, + } +}; + +/**********************************************************************/ + +static struct resource au1550_psc0_res[] = { + [0] = { + .start = AU1550_PSC0_PHYS_ADDR, + .end = AU1550_PSC0_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1550_PSC0_INT, + .end = AU1550_PSC0_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1550_DSCR_CMD0_PSC0_TX, + .end = AU1550_DSCR_CMD0_PSC0_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1550_DSCR_CMD0_PSC0_RX, + .end = AU1550_DSCR_CMD0_PSC0_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static void db1550_spi_cs_en(struct au1550_spi_info *spi, int cs, int pol) +{ + if (cs) + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SPISEL); + else + bcsr_mod(BCSR_BOARD, BCSR_BOARD_SPISEL, 0); +} + +static struct au1550_spi_info db1550_spi_platdata = { + .mainclk_hz = 48000000, /* PSC0 clock: max. 2.4MHz SPI clk */ + .num_chipselect = 2, + .activate_cs = db1550_spi_cs_en, +}; + +static u64 spi_dmamask = DMA_BIT_MASK(32); + +static struct platform_device db1550_spi_dev = { + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &db1550_spi_platdata, + }, + .name = "au1550-spi", + .id = 0, /* bus number */ + .num_resources = ARRAY_SIZE(au1550_psc0_res), + .resource = au1550_psc0_res, +}; + +/**********************************************************************/ + +static struct resource au1550_psc1_res[] = { + [0] = { + .start = AU1550_PSC1_PHYS_ADDR, + .end = AU1550_PSC1_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1550_PSC1_INT, + .end = AU1550_PSC1_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1550_DSCR_CMD0_PSC1_TX, + .end = AU1550_DSCR_CMD0_PSC1_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1550_DSCR_CMD0_PSC1_RX, + .end = AU1550_DSCR_CMD0_PSC1_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1550_ac97_dev = { + .name = "au1xpsc_ac97", + .id = 1, /* PSC ID */ + .num_resources = ARRAY_SIZE(au1550_psc1_res), + .resource = au1550_psc1_res, +}; + + +static struct resource au1550_psc2_res[] = { + [0] = { + .start = AU1550_PSC2_PHYS_ADDR, + .end = AU1550_PSC2_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1550_PSC2_INT, + .end = AU1550_PSC2_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1550_DSCR_CMD0_PSC2_TX, + .end = AU1550_DSCR_CMD0_PSC2_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1550_DSCR_CMD0_PSC2_RX, + .end = AU1550_DSCR_CMD0_PSC2_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1550_i2c_dev = { + .name = "au1xpsc_smbus", + .id = 0, /* bus number */ + .num_resources = ARRAY_SIZE(au1550_psc2_res), + .resource = au1550_psc2_res, +}; + +/**********************************************************************/ + +static struct resource au1550_psc3_res[] = { + [0] = { + .start = AU1550_PSC3_PHYS_ADDR, + .end = AU1550_PSC3_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1550_PSC3_INT, + .end = AU1550_PSC3_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = AU1550_DSCR_CMD0_PSC3_TX, + .end = AU1550_DSCR_CMD0_PSC3_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = AU1550_DSCR_CMD0_PSC3_RX, + .end = AU1550_DSCR_CMD0_PSC3_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1550_i2s_dev = { + .name = "au1xpsc_i2s", + .id = 3, /* PSC ID */ + .num_resources = ARRAY_SIZE(au1550_psc3_res), + .resource = au1550_psc3_res, +}; + +/**********************************************************************/ + +static struct platform_device db1550_stac_dev = { + .name = "ac97-codec", + .id = 1, /* on PSC1 */ +}; + +static struct platform_device db1550_ac97dma_dev = { + .name = "au1xpsc-pcm", + .id = 1, /* on PSC3 */ +}; + +static struct platform_device db1550_i2sdma_dev = { + .name = "au1xpsc-pcm", + .id = 3, /* on PSC3 */ +}; + +static struct platform_device db1550_sndac97_dev = { + .name = "db1550-ac97", +}; + +static struct platform_device db1550_sndi2s_dev = { + .name = "db1550-i2s", +}; + +/**********************************************************************/ + +static int db1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) +{ + if ((slot < 11) || (slot > 13) || pin == 0) + return -1; + if (slot == 11) + return (pin == 1) ? AU1550_PCI_INTC : 0xff; + if (slot == 12) { + switch (pin) { + case 1: return AU1550_PCI_INTB; + case 2: return AU1550_PCI_INTC; + case 3: return AU1550_PCI_INTD; + case 4: return AU1550_PCI_INTA; + } + } + if (slot == 13) { + switch (pin) { + case 1: return AU1550_PCI_INTA; + case 2: return AU1550_PCI_INTB; + case 3: return AU1550_PCI_INTC; + case 4: return AU1550_PCI_INTD; + } + } + return -1; +} + +static struct resource alchemy_pci_host_res[] = { + [0] = { + .start = AU1500_PCI_PHYS_ADDR, + .end = AU1500_PCI_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct alchemy_pci_platdata db1550_pci_pd = { + .board_map_irq = db1550_map_pci_irq, +}; + +static struct platform_device db1550_pci_host_dev = { + .dev.platform_data = &db1550_pci_pd, + .name = "alchemy-pci", + .id = 0, + .num_resources = ARRAY_SIZE(alchemy_pci_host_res), + .resource = alchemy_pci_host_res, +}; + +/**********************************************************************/ + +static struct platform_device *db1550_devs[] __initdata = { + &db1550_nand_dev, + &db1550_i2c_dev, + &db1550_ac97_dev, + &db1550_spi_dev, + &db1550_i2s_dev, + &db1550_stac_dev, + &db1550_ac97dma_dev, + &db1550_i2sdma_dev, + &db1550_sndac97_dev, + &db1550_sndi2s_dev, +}; + +/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */ +static int __init db1550_pci_init(void) +{ + return platform_device_register(&db1550_pci_host_dev); +} +arch_initcall(db1550_pci_init); + +static int __init db1550_dev_init(void) +{ + int swapped; + + irq_set_irq_type(AU1550_GPIO0_INT, IRQ_TYPE_EDGE_BOTH); /* CD0# */ + irq_set_irq_type(AU1550_GPIO1_INT, IRQ_TYPE_EDGE_BOTH); /* CD1# */ + irq_set_irq_type(AU1550_GPIO3_INT, IRQ_TYPE_LEVEL_LOW); /* CARD0# */ + irq_set_irq_type(AU1550_GPIO5_INT, IRQ_TYPE_LEVEL_LOW); /* CARD1# */ + irq_set_irq_type(AU1550_GPIO21_INT, IRQ_TYPE_LEVEL_LOW); /* STSCHG0# */ + irq_set_irq_type(AU1550_GPIO22_INT, IRQ_TYPE_LEVEL_LOW); /* STSCHG1# */ + + i2c_register_board_info(0, db1550_i2c_devs, + ARRAY_SIZE(db1550_i2c_devs)); + spi_register_board_info(db1550_spi_devs, + ARRAY_SIZE(db1550_i2c_devs)); + + /* Audio PSC clock is supplied by codecs (PSC1, 3) FIXME: platdata!! */ + __raw_writel(PSC_SEL_CLK_SERCLK, + (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); + wmb(); + __raw_writel(PSC_SEL_CLK_SERCLK, + (void __iomem *)KSEG1ADDR(AU1550_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET); + wmb(); + /* SPI/I2C use internally supplied 50MHz source */ + __raw_writel(PSC_SEL_CLK_INTCLK, + (void __iomem *)KSEG1ADDR(AU1550_PSC0_PHYS_ADDR) + PSC_SEL_OFFSET); + wmb(); + __raw_writel(PSC_SEL_CLK_INTCLK, + (void __iomem *)KSEG1ADDR(AU1550_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET); + wmb(); + + db1x_register_pcmcia_socket( + AU1000_PCMCIA_ATTR_PHYS_ADDR, + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + AU1000_PCMCIA_MEM_PHYS_ADDR, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + AU1000_PCMCIA_IO_PHYS_ADDR, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + AU1550_GPIO3_INT, AU1550_GPIO0_INT, + /*AU1550_GPIO21_INT*/0, 0, 0); + + db1x_register_pcmcia_socket( + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000, + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1, + AU1550_GPIO5_INT, AU1550_GPIO1_INT, + /*AU1550_GPIO22_INT*/0, 0, 1); + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; + db1x_register_norflash(128 << 20, 4, swapped); + + return platform_add_devices(db1550_devs, ARRAY_SIZE(db1550_devs)); +} +device_initcall(db1550_dev_init); diff --git a/arch/mips/alchemy/devboards/db1x00/Makefile b/arch/mips/alchemy/devboards/db1x00/Makefile deleted file mode 100644 index 613c0c0c8be9..000000000000 --- a/arch/mips/alchemy/devboards/db1x00/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright 2000, 2008 MontaVista Software Inc. -# Author: MontaVista Software, Inc. <source@mvista.com> -# -# Makefile for the Alchemy Semiconductor DBAu1xx0 boards. -# - -obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c deleted file mode 100644 index 7cd36e631f6c..000000000000 --- a/arch/mips/alchemy/devboards/db1x00/board_setup.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Alchemy Db1x00 board setup. - * - * Copyright 2000, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/pm.h> - -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-au1x00/au1xxx_eth.h> -#include <asm/mach-db1x00/db1x00.h> -#include <asm/mach-db1x00/bcsr.h> -#include <asm/reboot.h> - -#include <prom.h> - -#ifdef CONFIG_MIPS_BOSPORUS -char irq_tab_alchemy[][5] __initdata = { - [11] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 11 - miniPCI */ - [12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - SN1741 */ - [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */ -}; - -/* - * Micrel/Kendin 5 port switch attached to MAC0, - * MAC0 is associated with PHY address 5 (== WAN port) - * MAC1 is not associated with any PHY, since it's connected directly - * to the switch. - * no interrupts are used - */ -static struct au1000_eth_platform_data eth0_pdata = { - .phy_static_config = 1, - .phy_addr = 5, -}; - -static void bosporus_power_off(void) -{ - while (1) - asm volatile (".set mips3 ; wait ; .set mips0"); -} - -const char *get_system_type(void) -{ - return "Alchemy Bosporus Gateway Reference"; -} -#endif - - -#ifdef CONFIG_MIPS_MIRAGE -static void mirage_power_off(void) -{ - alchemy_gpio_direction_output(210, 1); -} - -const char *get_system_type(void) -{ - return "Alchemy Mirage"; -} -#endif - - -#if defined(CONFIG_MIPS_BOSPORUS) || defined(CONFIG_MIPS_MIRAGE) -static void mips_softreset(void) -{ - asm volatile ("jr\t%0" : : "r"(0xbfc00000)); -} - -#else - -const char *get_system_type(void) -{ - return "Alchemy Db1x00"; -} -#endif - - -void __init board_setup(void) -{ - unsigned long bcsr1, bcsr2; - - bcsr1 = DB1000_BCSR_PHYS_ADDR; - bcsr2 = DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS; - -#ifdef CONFIG_MIPS_DB1000 - printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n"); -#endif -#ifdef CONFIG_MIPS_DB1500 - printk(KERN_INFO "AMD Alchemy Au1500/Db1500 Board\n"); -#endif -#ifdef CONFIG_MIPS_DB1100 - printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n"); -#endif -#ifdef CONFIG_MIPS_BOSPORUS - au1xxx_override_eth_cfg(0, ð0_pdata); - - printk(KERN_INFO "AMD Alchemy Bosporus Board\n"); -#endif -#ifdef CONFIG_MIPS_MIRAGE - printk(KERN_INFO "AMD Alchemy Mirage Board\n"); -#endif -#ifdef CONFIG_MIPS_DB1550 - printk(KERN_INFO "AMD Alchemy Au1550/Db1550 Board\n"); - - bcsr1 = DB1550_BCSR_PHYS_ADDR; - bcsr2 = DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS; -#endif - - /* initialize board register space */ - bcsr_init(bcsr1, bcsr2); - -#if defined(CONFIG_IRDA) && defined(CONFIG_AU1000_FIR) - { - u32 pin_func; - - /* Set IRFIRSEL instead of GPIO15 */ - pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF; - au_writel(pin_func, SYS_PINFUNC); - /* Power off until the driver is in use */ - bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK, - BCSR_RESETS_IRDA_MODE_OFF); - } -#endif - bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */ - - /* Enable GPIO[31:0] inputs */ - alchemy_gpio1_input_enable(); - -#ifdef CONFIG_MIPS_MIRAGE - { - u32 pin_func; - - /* GPIO[20] is output */ - alchemy_gpio_direction_output(20, 0); - - /* Set GPIO[210:208] instead of SSI_0 */ - pin_func = au_readl(SYS_PINFUNC) | SYS_PF_S0; - - /* Set GPIO[215:211] for LEDs */ - pin_func |= 5 << 2; - - /* Set GPIO[214:213] for more LEDs */ - pin_func |= 5 << 12; - - /* Set GPIO[207:200] instead of PCMCIA/LCD */ - pin_func |= SYS_PF_LCD | SYS_PF_PC; - au_writel(pin_func, SYS_PINFUNC); - - /* - * Enable speaker amplifier. This should - * be part of the audio driver. - */ - alchemy_gpio_direction_output(209, 1); - - pm_power_off = mirage_power_off; - _machine_halt = mirage_power_off; - _machine_restart = (void(*)(char *))mips_softreset; - } -#endif - -#ifdef CONFIG_MIPS_BOSPORUS - pm_power_off = bosporus_power_off; - _machine_halt = bosporus_power_off; - _machine_restart = (void(*)(char *))mips_softreset; -#endif - au_sync(); -} - -static int __init db1x00_init_irq(void) -{ -#if defined(CONFIG_MIPS_MIRAGE) - irq_set_irq_type(AU1500_GPIO7_INT, IRQF_TRIGGER_RISING); /* TS pendown */ -#elif defined(CONFIG_MIPS_DB1550) - irq_set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */ - irq_set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW); /* CD1# */ - irq_set_irq_type(AU1550_GPIO3_INT, IRQF_TRIGGER_LOW); /* CARD0# */ - irq_set_irq_type(AU1550_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */ - irq_set_irq_type(AU1550_GPIO21_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ - irq_set_irq_type(AU1550_GPIO22_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */ -#elif defined(CONFIG_MIPS_DB1500) - irq_set_irq_type(AU1500_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */ - irq_set_irq_type(AU1500_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */ - irq_set_irq_type(AU1500_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */ - irq_set_irq_type(AU1500_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */ - irq_set_irq_type(AU1500_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ - irq_set_irq_type(AU1500_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */ -#elif defined(CONFIG_MIPS_DB1100) - irq_set_irq_type(AU1100_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */ - irq_set_irq_type(AU1100_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */ - irq_set_irq_type(AU1100_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */ - irq_set_irq_type(AU1100_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */ - irq_set_irq_type(AU1100_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ - irq_set_irq_type(AU1100_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */ -#elif defined(CONFIG_MIPS_DB1000) - irq_set_irq_type(AU1000_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */ - irq_set_irq_type(AU1000_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */ - irq_set_irq_type(AU1000_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */ - irq_set_irq_type(AU1000_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */ - irq_set_irq_type(AU1000_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ - irq_set_irq_type(AU1000_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */ -#endif - return 0; -} -arch_initcall(db1x00_init_irq); diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c deleted file mode 100644 index 9e6b3d442acd..000000000000 --- a/arch/mips/alchemy/devboards/db1x00/platform.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * DBAu1xxx board platform device registration - * - * Copyright (C) 2009 Manuel Lauss - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> - -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-au1x00/au1000_dma.h> -#include <asm/mach-db1x00/bcsr.h> -#include "../platform.h" - -struct pci_dev; - -/* DB1xxx PCMCIA interrupt sources: - * CD0/1 GPIO0/3 - * STSCHG0/1 GPIO1/4 - * CARD0/1 GPIO2/5 - * Db1550: 0/1, 21/22, 3/5 - */ - -#define DB1XXX_HAS_PCMCIA -#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT) - -#if defined(CONFIG_MIPS_DB1000) -#define DB1XXX_PCMCIA_CD0 AU1000_GPIO0_INT -#define DB1XXX_PCMCIA_STSCHG0 AU1000_GPIO1_INT -#define DB1XXX_PCMCIA_CARD0 AU1000_GPIO2_INT -#define DB1XXX_PCMCIA_CD1 AU1000_GPIO3_INT -#define DB1XXX_PCMCIA_STSCHG1 AU1000_GPIO4_INT -#define DB1XXX_PCMCIA_CARD1 AU1000_GPIO5_INT -#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ -#define BOARD_FLASH_WIDTH 4 /* 32-bits */ -#elif defined(CONFIG_MIPS_DB1100) -#define DB1XXX_PCMCIA_CD0 AU1100_GPIO0_INT -#define DB1XXX_PCMCIA_STSCHG0 AU1100_GPIO1_INT -#define DB1XXX_PCMCIA_CARD0 AU1100_GPIO2_INT -#define DB1XXX_PCMCIA_CD1 AU1100_GPIO3_INT -#define DB1XXX_PCMCIA_STSCHG1 AU1100_GPIO4_INT -#define DB1XXX_PCMCIA_CARD1 AU1100_GPIO5_INT -#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ -#define BOARD_FLASH_WIDTH 4 /* 32-bits */ -#elif defined(CONFIG_MIPS_DB1500) -#define DB1XXX_PCMCIA_CD0 AU1500_GPIO0_INT -#define DB1XXX_PCMCIA_STSCHG0 AU1500_GPIO1_INT -#define DB1XXX_PCMCIA_CARD0 AU1500_GPIO2_INT -#define DB1XXX_PCMCIA_CD1 AU1500_GPIO3_INT -#define DB1XXX_PCMCIA_STSCHG1 AU1500_GPIO4_INT -#define DB1XXX_PCMCIA_CARD1 AU1500_GPIO5_INT -#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ -#define BOARD_FLASH_WIDTH 4 /* 32-bits */ -#elif defined(CONFIG_MIPS_DB1550) -#define DB1XXX_PCMCIA_CD0 AU1550_GPIO0_INT -#define DB1XXX_PCMCIA_STSCHG0 AU1550_GPIO21_INT -#define DB1XXX_PCMCIA_CARD0 AU1550_GPIO3_INT -#define DB1XXX_PCMCIA_CD1 AU1550_GPIO1_INT -#define DB1XXX_PCMCIA_STSCHG1 AU1550_GPIO22_INT -#define DB1XXX_PCMCIA_CARD1 AU1550_GPIO5_INT -#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */ -#define BOARD_FLASH_WIDTH 4 /* 32-bits */ -#else -/* other board: no PCMCIA */ -#undef DB1XXX_HAS_PCMCIA -#undef F_SWAPPED -#define F_SWAPPED 0 -#if defined(CONFIG_MIPS_BOSPORUS) -#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */ -#define BOARD_FLASH_WIDTH 2 /* 16-bits */ -#elif defined(CONFIG_MIPS_MIRAGE) -#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ -#define BOARD_FLASH_WIDTH 4 /* 32-bits */ -#endif -#endif - -#ifdef CONFIG_PCI -#ifdef CONFIG_MIPS_DB1500 -static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) -{ - if ((slot < 12) || (slot > 13) || pin == 0) - return -1; - if (slot == 12) - return (pin == 1) ? AU1500_PCI_INTA : 0xff; - if (slot == 13) { - switch (pin) { - case 1: return AU1500_PCI_INTA; - case 2: return AU1500_PCI_INTB; - case 3: return AU1500_PCI_INTC; - case 4: return AU1500_PCI_INTD; - } - } - return -1; -} -#endif - -#ifdef CONFIG_MIPS_DB1550 -static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) -{ - if ((slot < 11) || (slot > 13) || pin == 0) - return -1; - if (slot == 11) - return (pin == 1) ? AU1550_PCI_INTC : 0xff; - if (slot == 12) { - switch (pin) { - case 1: return AU1550_PCI_INTB; - case 2: return AU1550_PCI_INTC; - case 3: return AU1550_PCI_INTD; - case 4: return AU1550_PCI_INTA; - } - } - if (slot == 13) { - switch (pin) { - case 1: return AU1550_PCI_INTA; - case 2: return AU1550_PCI_INTB; - case 3: return AU1550_PCI_INTC; - case 4: return AU1550_PCI_INTD; - } - } - return -1; -} -#endif - -#ifdef CONFIG_MIPS_BOSPORUS -static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) -{ - if ((slot < 11) || (slot > 13) || pin == 0) - return -1; - if (slot == 12) - return (pin == 1) ? AU1500_PCI_INTA : 0xff; - if (slot == 11) { - switch (pin) { - case 1: return AU1500_PCI_INTA; - case 2: return AU1500_PCI_INTB; - default: return 0xff; - } - } - if (slot == 13) { - switch (pin) { - case 1: return AU1500_PCI_INTA; - case 2: return AU1500_PCI_INTB; - case 3: return AU1500_PCI_INTC; - case 4: return AU1500_PCI_INTD; - } - } - return -1; -} -#endif - -#ifdef CONFIG_MIPS_MIRAGE -static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) -{ - if ((slot < 11) || (slot > 13) || pin == 0) - return -1; - if (slot == 11) - return (pin == 1) ? AU1500_PCI_INTD : 0xff; - if (slot == 12) - return (pin == 3) ? AU1500_PCI_INTC : 0xff; - if (slot == 13) { - switch (pin) { - case 1: return AU1500_PCI_INTA; - case 2: return AU1500_PCI_INTB; - default: return 0xff; - } - } - return -1; -} -#endif - -static struct resource alchemy_pci_host_res[] = { - [0] = { - .start = AU1500_PCI_PHYS_ADDR, - .end = AU1500_PCI_PHYS_ADDR + 0xfff, - .flags = IORESOURCE_MEM, - }, -}; - -static struct alchemy_pci_platdata db1xxx_pci_pd = { - .board_map_irq = db1xxx_map_pci_irq, -}; - -static struct platform_device db1xxx_pci_host_dev = { - .dev.platform_data = &db1xxx_pci_pd, - .name = "alchemy-pci", - .id = 0, - .num_resources = ARRAY_SIZE(alchemy_pci_host_res), - .resource = alchemy_pci_host_res, -}; - -static int __init db15x0_pci_init(void) -{ - return platform_device_register(&db1xxx_pci_host_dev); -} -/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */ -arch_initcall(db15x0_pci_init); -#endif - -#ifdef CONFIG_MIPS_DB1100 -static struct resource au1100_lcd_resources[] = { - [0] = { - .start = AU1100_LCD_PHYS_ADDR, - .end = AU1100_LCD_PHYS_ADDR + 0x800 - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = AU1100_LCD_INT, - .end = AU1100_LCD_INT, - .flags = IORESOURCE_IRQ, - } -}; - -static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32); - -static struct platform_device au1100_lcd_device = { - .name = "au1100-lcd", - .id = 0, - .dev = { - .dma_mask = &au1100_lcd_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(au1100_lcd_resources), - .resource = au1100_lcd_resources, -}; -#endif - -static struct resource alchemy_ac97c_res[] = { - [0] = { - .start = AU1000_AC97_PHYS_ADDR, - .end = AU1000_AC97_PHYS_ADDR + 0xfff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = DMA_ID_AC97C_TX, - .end = DMA_ID_AC97C_TX, - .flags = IORESOURCE_DMA, - }, - [2] = { - .start = DMA_ID_AC97C_RX, - .end = DMA_ID_AC97C_RX, - .flags = IORESOURCE_DMA, - }, -}; - -static struct platform_device alchemy_ac97c_dev = { - .name = "alchemy-ac97c", - .id = -1, - .resource = alchemy_ac97c_res, - .num_resources = ARRAY_SIZE(alchemy_ac97c_res), -}; - -static struct platform_device alchemy_ac97c_dma_dev = { - .name = "alchemy-pcm-dma", - .id = 0, -}; - -static struct platform_device db1x00_codec_dev = { - .name = "ac97-codec", - .id = -1, -}; - -static struct platform_device db1x00_audio_dev = { - .name = "db1000-audio", -}; - -static int __init db1xxx_dev_init(void) -{ -#ifdef DB1XXX_HAS_PCMCIA - db1x_register_pcmcia_socket( - AU1000_PCMCIA_ATTR_PHYS_ADDR, - AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, - AU1000_PCMCIA_MEM_PHYS_ADDR, - AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, - AU1000_PCMCIA_IO_PHYS_ADDR, - AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, - DB1XXX_PCMCIA_CARD0, DB1XXX_PCMCIA_CD0, - /*DB1XXX_PCMCIA_STSCHG0*/0, 0, 0); - - db1x_register_pcmcia_socket( - AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000, - AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1, - AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000, - AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1, - AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000, - AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1, - DB1XXX_PCMCIA_CARD1, DB1XXX_PCMCIA_CD1, - /*DB1XXX_PCMCIA_STSCHG1*/0, 0, 1); -#endif -#ifdef CONFIG_MIPS_DB1100 - platform_device_register(&au1100_lcd_device); -#endif - db1x_register_norflash(BOARD_FLASH_SIZE, BOARD_FLASH_WIDTH, F_SWAPPED); - - platform_device_register(&db1x00_codec_dev); - platform_device_register(&alchemy_ac97c_dma_dev); - platform_device_register(&alchemy_ac97c_dev); - platform_device_register(&db1x00_audio_dev); - - return 0; -} -device_initcall(db1xxx_dev_init); diff --git a/arch/mips/alchemy/devboards/pb1000/Makefile b/arch/mips/alchemy/devboards/pb1000/Makefile deleted file mode 100644 index 97c6615ba2bb..000000000000 --- a/arch/mips/alchemy/devboards/pb1000/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright 2000, 2008 MontaVista Software Inc. -# Author: MontaVista Software, Inc. <source@mvista.com> -# -# Makefile for the Alchemy Semiconductor Pb1000 board. -# - -obj-y := board_setup.o diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c deleted file mode 100644 index e64fdcbf75d0..000000000000 --- a/arch/mips/alchemy/devboards/pb1000/board_setup.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2000, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/delay.h> -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/pm.h> -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-pb1x00/pb1000.h> -#include <asm/reboot.h> -#include <prom.h> - -#include "../platform.h" - -const char *get_system_type(void) -{ - return "Alchemy Pb1000"; -} - -static void board_reset(char *c) -{ - asm volatile ("jr %0" : : "r" (0xbfc00000)); -} - -static void board_power_off(void) -{ - while (1) - asm volatile ( - " .set mips32 \n" - " wait \n" - " .set mips0 \n"); -} - -void __init board_setup(void) -{ - u32 pin_func, static_cfg0; - u32 sys_freqctrl, sys_clksrc; - u32 prid = read_c0_prid(); - - sys_freqctrl = 0; - sys_clksrc = 0; - - /* Set AUX clock to 12 MHz * 8 = 96 MHz */ - au_writel(8, SYS_AUXPLL); - alchemy_gpio1_input_enable(); - udelay(100); - -#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) - /* Zero and disable FREQ2 */ - sys_freqctrl = au_readl(SYS_FREQCTRL0); - sys_freqctrl &= ~0xFFF00000; - au_writel(sys_freqctrl, SYS_FREQCTRL0); - - /* Zero and disable USBH/USBD clocks */ - sys_clksrc = au_readl(SYS_CLKSRC); - sys_clksrc &= ~(SYS_CS_CUD | SYS_CS_DUD | SYS_CS_MUD_MASK | - SYS_CS_CUH | SYS_CS_DUH | SYS_CS_MUH_MASK); - au_writel(sys_clksrc, SYS_CLKSRC); - - sys_freqctrl = au_readl(SYS_FREQCTRL0); - sys_freqctrl &= ~0xFFF00000; - - sys_clksrc = au_readl(SYS_CLKSRC); - sys_clksrc &= ~(SYS_CS_CUD | SYS_CS_DUD | SYS_CS_MUD_MASK | - SYS_CS_CUH | SYS_CS_DUH | SYS_CS_MUH_MASK); - - switch (prid & 0x000000FF) { - case 0x00: /* DA */ - case 0x01: /* HA */ - case 0x02: /* HB */ - /* CPU core freq to 48 MHz to slow it way down... */ - au_writel(4, SYS_CPUPLL); - - /* - * Setup 48 MHz FREQ2 from CPUPLL for USB Host - * FRDIV2 = 3 -> div by 8 of 384 MHz -> 48 MHz - */ - sys_freqctrl |= (3 << SYS_FC_FRDIV2_BIT) | SYS_FC_FE2; - au_writel(sys_freqctrl, SYS_FREQCTRL0); - - /* CPU core freq to 384 MHz */ - au_writel(0x20, SYS_CPUPLL); - - printk(KERN_INFO "Au1000: 48 MHz OHCI workaround enabled\n"); - break; - - default: /* HC and newer */ - /* FREQ2 = aux / 2 = 48 MHz */ - sys_freqctrl |= (0 << SYS_FC_FRDIV2_BIT) | - SYS_FC_FE2 | SYS_FC_FS2; - au_writel(sys_freqctrl, SYS_FREQCTRL0); - break; - } - - /* - * Route 48 MHz FREQ2 into USB Host and/or Device - */ - sys_clksrc |= SYS_CS_MUX_FQ2 << SYS_CS_MUH_BIT; - au_writel(sys_clksrc, SYS_CLKSRC); - - /* Configure pins GPIO[14:9] as GPIO */ - pin_func = au_readl(SYS_PINFUNC) & ~(SYS_PF_UR3 | SYS_PF_USB); - - /* 2nd USB port is USB host */ - pin_func |= SYS_PF_USB; - - au_writel(pin_func, SYS_PINFUNC); - - alchemy_gpio_direction_input(11); - alchemy_gpio_direction_input(13); - alchemy_gpio_direction_output(4, 0); - alchemy_gpio_direction_output(5, 0); -#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ - - /* Make GPIO 15 an input (for interrupt line) */ - pin_func = au_readl(SYS_PINFUNC) & ~SYS_PF_IRF; - /* We don't need I2S, so make it available for GPIO[31:29] */ - pin_func |= SYS_PF_I2S; - au_writel(pin_func, SYS_PINFUNC); - - alchemy_gpio_direction_input(15); - - static_cfg0 = au_readl(MEM_STCFG0) & ~0xc00; - au_writel(static_cfg0, MEM_STCFG0); - - /* configure RCE2* for LCD */ - au_writel(0x00000004, MEM_STCFG2); - - /* MEM_STTIME2 */ - au_writel(0x09000000, MEM_STTIME2); - - /* Set 32-bit base address decoding for RCE2* */ - au_writel(0x10003ff0, MEM_STADDR2); - - /* - * PCI CPLD setup - * Expand CE0 to cover PCI - */ - au_writel(0x11803e40, MEM_STADDR1); - - /* Burst visibility on */ - au_writel(au_readl(MEM_STCFG0) | 0x1000, MEM_STCFG0); - - au_writel(0x83, MEM_STCFG1); /* ewait enabled, flash timing */ - au_writel(0x33030a10, MEM_STTIME1); /* slower timing for FPGA */ - - /* Setup the static bus controller */ - au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ - au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */ - au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ - - /* - * Enable Au1000 BCLK switching - note: sed1356 must not use - * its BCLK (Au1000 LCLK) for any timings - */ - switch (prid & 0x000000FF) { - case 0x00: /* DA */ - case 0x01: /* HA */ - case 0x02: /* HB */ - break; - default: /* HC and newer */ - /* - * Enable sys bus clock divider when IDLE state or no bus - * activity. - */ - au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); - break; - } - - pm_power_off = board_power_off; - _machine_halt = board_power_off; - _machine_restart = board_reset; -} - -static int __init pb1000_init_irq(void) -{ - irq_set_irq_type(AU1000_GPIO15_INT, IRQF_TRIGGER_LOW); - return 0; -} -arch_initcall(pb1000_init_irq); - -static int __init pb1000_device_init(void) -{ - return db1x_register_norflash(8 * 1024 * 1024, 4, 0); -} -device_initcall(pb1000_device_init); diff --git a/arch/mips/alchemy/devboards/pb1100/board_setup.c b/arch/mips/alchemy/devboards/pb1100.c index d108fd573aaf..cff50d05ddd4 100644 --- a/arch/mips/alchemy/devboards/pb1100/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1100.c @@ -1,42 +1,37 @@ /* - * Copyright 2002, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> + * Pb1100 board platform device registration * - * 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. + * Copyright (C) 2009 Manuel Lauss * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <linux/delay.h> #include <linux/gpio.h> #include <linux/init.h> -#include <linux/delay.h> #include <linux/interrupt.h> - +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-db1x00/bcsr.h> - #include <prom.h> - +#include "platform.h" const char *get_system_type(void) { - return "Alchemy Pb1100"; + return "PB1100"; } void __init board_setup(void) @@ -115,13 +110,58 @@ void __init board_setup(void) } } -static int __init pb1100_init_irq(void) +/******************************************************************************/ + +static struct resource au1100_lcd_resources[] = { + [0] = { + .start = AU1100_LCD_PHYS_ADDR, + .end = AU1100_LCD_PHYS_ADDR + 0x800 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1100_LCD_INT, + .end = AU1100_LCD_INT, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32); + +static struct platform_device au1100_lcd_device = { + .name = "au1100-lcd", + .id = 0, + .dev = { + .dma_mask = &au1100_lcd_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .num_resources = ARRAY_SIZE(au1100_lcd_resources), + .resource = au1100_lcd_resources, +}; + +static int __init pb1100_dev_init(void) { + int swapped; + irq_set_irq_type(AU1100_GPIO9_INT, IRQF_TRIGGER_LOW); /* PCCD# */ irq_set_irq_type(AU1100_GPIO10_INT, IRQF_TRIGGER_LOW); /* PCSTSCHG# */ irq_set_irq_type(AU1100_GPIO11_INT, IRQF_TRIGGER_LOW); /* PCCard# */ irq_set_irq_type(AU1100_GPIO13_INT, IRQF_TRIGGER_LOW); /* DC_IRQ# */ + /* PCMCIA. single socket, identical to Pb1500 */ + db1x_register_pcmcia_socket( + AU1000_PCMCIA_ATTR_PHYS_ADDR, + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + AU1000_PCMCIA_MEM_PHYS_ADDR, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + AU1000_PCMCIA_IO_PHYS_ADDR, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + AU1100_GPIO11_INT, AU1100_GPIO9_INT, /* card / insert */ + /*AU1100_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */ + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; + db1x_register_norflash(64 * 1024 * 1024, 4, swapped); + platform_device_register(&au1100_lcd_device); + return 0; } -arch_initcall(pb1100_init_irq); +device_initcall(pb1100_dev_init); diff --git a/arch/mips/alchemy/devboards/pb1100/Makefile b/arch/mips/alchemy/devboards/pb1100/Makefile deleted file mode 100644 index 7e3756c83fe5..000000000000 --- a/arch/mips/alchemy/devboards/pb1100/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright 2000, 2001, 2008 MontaVista Software Inc. -# Author: MontaVista Software, Inc. <source@mvista.com> -# -# Makefile for the Alchemy Semiconductor Pb1100 board. -# - -obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/pb1100/platform.c b/arch/mips/alchemy/devboards/pb1100/platform.c deleted file mode 100644 index 9c57c01a68c4..000000000000 --- a/arch/mips/alchemy/devboards/pb1100/platform.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Pb1100 board platform device registration - * - * Copyright (C) 2009 Manuel Lauss - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <linux/init.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> - -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-db1x00/bcsr.h> - -#include "../platform.h" - -static struct resource au1100_lcd_resources[] = { - [0] = { - .start = AU1100_LCD_PHYS_ADDR, - .end = AU1100_LCD_PHYS_ADDR + 0x800 - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = AU1100_LCD_INT, - .end = AU1100_LCD_INT, - .flags = IORESOURCE_IRQ, - } -}; - -static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32); - -static struct platform_device au1100_lcd_device = { - .name = "au1100-lcd", - .id = 0, - .dev = { - .dma_mask = &au1100_lcd_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(au1100_lcd_resources), - .resource = au1100_lcd_resources, -}; - -static int __init pb1100_dev_init(void) -{ - int swapped; - - /* PCMCIA. single socket, identical to Pb1500 */ - db1x_register_pcmcia_socket( - AU1000_PCMCIA_ATTR_PHYS_ADDR, - AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, - AU1000_PCMCIA_MEM_PHYS_ADDR, - AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, - AU1000_PCMCIA_IO_PHYS_ADDR, - AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, - AU1100_GPIO11_INT, AU1100_GPIO9_INT, /* card / insert */ - /*AU1100_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */ - - swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; - db1x_register_norflash(64 * 1024 * 1024, 4, swapped); - platform_device_register(&au1100_lcd_device); - - return 0; -} -device_initcall(pb1100_dev_init); diff --git a/arch/mips/alchemy/devboards/pb1200/Makefile b/arch/mips/alchemy/devboards/pb1200/Makefile deleted file mode 100644 index 18c1bd53e4c0..000000000000 --- a/arch/mips/alchemy/devboards/pb1200/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the Alchemy Semiconductor Pb1200/DBAu1200 boards. -# - -obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/pb1200/board_setup.c b/arch/mips/alchemy/devboards/pb1200/board_setup.c deleted file mode 100644 index 6d06b07c2381..000000000000 --- a/arch/mips/alchemy/devboards/pb1200/board_setup.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Alchemy Pb1200/Db1200 board setup. - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/sched.h> - -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-db1x00/bcsr.h> - -#ifdef CONFIG_MIPS_PB1200 -#include <asm/mach-pb1x00/pb1200.h> -#endif - -#ifdef CONFIG_MIPS_DB1200 -#include <asm/mach-db1x00/db1200.h> -#define PB1200_INT_BEGIN DB1200_INT_BEGIN -#define PB1200_INT_END DB1200_INT_END -#endif - -#include <prom.h> - -const char *get_system_type(void) -{ - return "Alchemy Pb1200"; -} - -void __init board_setup(void) -{ - printk(KERN_INFO "AMD Alchemy Pb1200 Board\n"); - bcsr_init(PB1200_BCSR_PHYS_ADDR, - PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS); - -#if 0 - { - u32 pin_func; - - /* - * Enable PSC1 SYNC for AC97. Normaly done in audio driver, - * but it is board specific code, so put it here. - */ - pin_func = au_readl(SYS_PINFUNC); - au_sync(); - pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1; - au_writel(pin_func, SYS_PINFUNC); - - au_writel(0, (u32)bcsr | 0x10); /* turn off PCMCIA power */ - au_sync(); - } -#endif - -#if defined(CONFIG_I2C_AU1550) - { - u32 freq0, clksrc; - u32 pin_func; - - /* Select SMBus in CPLD */ - bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0); - - pin_func = au_readl(SYS_PINFUNC); - au_sync(); - pin_func &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B); - /* Set GPIOs correctly */ - pin_func |= 2 << 17; - au_writel(pin_func, SYS_PINFUNC); - au_sync(); - - /* The I2C driver depends on 50 MHz clock */ - freq0 = au_readl(SYS_FREQCTRL0); - au_sync(); - freq0 &= ~(SYS_FC_FRDIV1_MASK | SYS_FC_FS1 | SYS_FC_FE1); - freq0 |= 3 << SYS_FC_FRDIV1_BIT; - /* 396 MHz / (3 + 1) * 2 == 49.5 MHz */ - au_writel(freq0, SYS_FREQCTRL0); - au_sync(); - freq0 |= SYS_FC_FE1; - au_writel(freq0, SYS_FREQCTRL0); - au_sync(); - - clksrc = au_readl(SYS_CLKSRC); - au_sync(); - clksrc &= ~(SYS_CS_CE0 | SYS_CS_DE0 | SYS_CS_ME0_MASK); - /* Bit 22 is EXTCLK0 for PSC0 */ - clksrc |= SYS_CS_MUX_FQ1 << SYS_CS_ME0_BIT; - au_writel(clksrc, SYS_CLKSRC); - au_sync(); - } -#endif - - /* - * The Pb1200 development board uses external MUX for PSC0 to - * support SMB/SPI. bcsr_resets bit 12: 0=SMB 1=SPI - */ -#ifdef CONFIG_I2C_AU1550 - bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0); -#endif - au_sync(); -} - -static int __init pb1200_init_irq(void) -{ - /* We have a problem with CPLD rev 3. */ - if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) { - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "Pb1200 must be at CPLD rev 4. Please have Pb1200\n"); - printk(KERN_ERR "updated to latest revision. This software will\n"); - printk(KERN_ERR "not work on anything less than CPLD rev 4.\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - panic("Game over. Your score is 0."); - } - - irq_set_irq_type(AU1200_GPIO7_INT, IRQF_TRIGGER_LOW); - bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1200_GPIO7_INT); - - return 0; -} -arch_initcall(pb1200_init_irq); - - -int board_au1200fb_panel(void) -{ - return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f; -} - -int board_au1200fb_panel_init(void) -{ - /* Apply power */ - bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | - BCSR_BOARD_LCDBL); - /* printk(KERN_DEBUG "board_au1200fb_panel_init()\n"); */ - return 0; -} - -int board_au1200fb_panel_shutdown(void) -{ - /* Remove power */ - bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | - BCSR_BOARD_LCDBL, 0); - /* printk(KERN_DEBUG "board_au1200fb_panel_shutdown()\n"); */ - return 0; -} diff --git a/arch/mips/alchemy/devboards/pb1200/platform.c b/arch/mips/alchemy/devboards/pb1200/platform.c deleted file mode 100644 index 54f7f7b0676e..000000000000 --- a/arch/mips/alchemy/devboards/pb1200/platform.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Pb1200/DBAu1200 board platform device registration - * - * Copyright (C) 2008 MontaVista Software Inc. <source@mvista.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. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <linux/dma-mapping.h> -#include <linux/init.h> -#include <linux/leds.h> -#include <linux/platform_device.h> -#include <linux/smc91x.h> - -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-au1x00/au1100_mmc.h> -#include <asm/mach-au1x00/au1xxx_dbdma.h> -#include <asm/mach-db1x00/bcsr.h> -#include <asm/mach-pb1x00/pb1200.h> - -#include "../platform.h" - -static int mmc_activity; - -static void pb1200mmc0_set_power(void *mmc_host, int state) -{ - if (state) - bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR); - else - bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0); - - msleep(1); -} - -static int pb1200mmc0_card_readonly(void *mmc_host) -{ - return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 1 : 0; -} - -static int pb1200mmc0_card_inserted(void *mmc_host) -{ - return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT) ? 1 : 0; -} - -static void pb1200_mmcled_set(struct led_classdev *led, - enum led_brightness brightness) -{ - if (brightness != LED_OFF) { - if (++mmc_activity == 1) - bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0); - } else { - if (--mmc_activity == 0) - bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0); - } -} - -static struct led_classdev pb1200mmc_led = { - .brightness_set = pb1200_mmcled_set, -}; - -static void pb1200mmc1_set_power(void *mmc_host, int state) -{ - if (state) - bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR); - else - bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0); - - msleep(1); -} - -static int pb1200mmc1_card_readonly(void *mmc_host) -{ - return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0; -} - -static int pb1200mmc1_card_inserted(void *mmc_host) -{ - return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0; -} - -static struct au1xmmc_platform_data pb1200mmc_platdata[2] = { - [0] = { - .set_power = pb1200mmc0_set_power, - .card_inserted = pb1200mmc0_card_inserted, - .card_readonly = pb1200mmc0_card_readonly, - .cd_setup = NULL, /* use poll-timer in driver */ - .led = &pb1200mmc_led, - }, - [1] = { - .set_power = pb1200mmc1_set_power, - .card_inserted = pb1200mmc1_card_inserted, - .card_readonly = pb1200mmc1_card_readonly, - .cd_setup = NULL, /* use poll-timer in driver */ - .led = &pb1200mmc_led, - }, -}; - -static u64 au1xxx_mmc_dmamask = DMA_BIT_MASK(32); - -static struct resource au1200_mmc0_res[] = { - [0] = { - .start = AU1100_SD0_PHYS_ADDR, - .end = AU1100_SD0_PHYS_ADDR + 0xfff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = AU1200_SD_INT, - .end = AU1200_SD_INT, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = AU1200_DSCR_CMD0_SDMS_TX0, - .end = AU1200_DSCR_CMD0_SDMS_TX0, - .flags = IORESOURCE_DMA, - }, - [3] = { - .start = AU1200_DSCR_CMD0_SDMS_RX0, - .end = AU1200_DSCR_CMD0_SDMS_RX0, - .flags = IORESOURCE_DMA, - } -}; - -static struct platform_device pb1200_mmc0_dev = { - .name = "au1xxx-mmc", - .id = 0, - .dev = { - .dma_mask = &au1xxx_mmc_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &pb1200mmc_platdata[0], - }, - .num_resources = ARRAY_SIZE(au1200_mmc0_res), - .resource = au1200_mmc0_res, -}; - -static struct resource au1200_mmc1_res[] = { - [0] = { - .start = AU1100_SD1_PHYS_ADDR, - .end = AU1100_SD1_PHYS_ADDR + 0xfff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = AU1200_SD_INT, - .end = AU1200_SD_INT, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = AU1200_DSCR_CMD0_SDMS_TX1, - .end = AU1200_DSCR_CMD0_SDMS_TX1, - .flags = IORESOURCE_DMA, - }, - [3] = { - .start = AU1200_DSCR_CMD0_SDMS_RX1, - .end = AU1200_DSCR_CMD0_SDMS_RX1, - .flags = IORESOURCE_DMA, - } -}; - -static struct platform_device pb1200_mmc1_dev = { - .name = "au1xxx-mmc", - .id = 1, - .dev = { - .dma_mask = &au1xxx_mmc_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &pb1200mmc_platdata[1], - }, - .num_resources = ARRAY_SIZE(au1200_mmc1_res), - .resource = au1200_mmc1_res, -}; - - -static struct resource ide_resources[] = { - [0] = { - .start = IDE_PHYS_ADDR, - .end = IDE_PHYS_ADDR + IDE_PHYS_LEN - 1, - .flags = IORESOURCE_MEM - }, - [1] = { - .start = IDE_INT, - .end = IDE_INT, - .flags = IORESOURCE_IRQ - }, - [2] = { - .start = AU1200_DSCR_CMD0_DMA_REQ1, - .end = AU1200_DSCR_CMD0_DMA_REQ1, - .flags = IORESOURCE_DMA, - }, -}; - -static u64 ide_dmamask = DMA_BIT_MASK(32); - -static struct platform_device ide_device = { - .name = "au1200-ide", - .id = 0, - .dev = { - .dma_mask = &ide_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(ide_resources), - .resource = ide_resources -}; - -static struct smc91x_platdata smc_data = { - .flags = SMC91X_NOWAIT | SMC91X_USE_16BIT, - .leda = RPC_LED_100_10, - .ledb = RPC_LED_TX_RX, -}; - -static struct resource smc91c111_resources[] = { - [0] = { - .name = "smc91x-regs", - .start = SMC91C111_PHYS_ADDR, - .end = SMC91C111_PHYS_ADDR + 0xf, - .flags = IORESOURCE_MEM - }, - [1] = { - .start = SMC91C111_INT, - .end = SMC91C111_INT, - .flags = IORESOURCE_IRQ - }, -}; - -static struct platform_device smc91c111_device = { - .dev = { - .platform_data = &smc_data, - }, - .name = "smc91x", - .id = -1, - .num_resources = ARRAY_SIZE(smc91c111_resources), - .resource = smc91c111_resources -}; - -static struct resource au1200_psc0_res[] = { - [0] = { - .start = AU1550_PSC0_PHYS_ADDR, - .end = AU1550_PSC0_PHYS_ADDR + 0xfff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = AU1200_PSC0_INT, - .end = AU1200_PSC0_INT, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = AU1200_DSCR_CMD0_PSC0_TX, - .end = AU1200_DSCR_CMD0_PSC0_TX, - .flags = IORESOURCE_DMA, - }, - [3] = { - .start = AU1200_DSCR_CMD0_PSC0_RX, - .end = AU1200_DSCR_CMD0_PSC0_RX, - .flags = IORESOURCE_DMA, - }, -}; - -static struct platform_device pb1200_i2c_dev = { - .name = "au1xpsc_smbus", - .id = 0, /* bus number */ - .num_resources = ARRAY_SIZE(au1200_psc0_res), - .resource = au1200_psc0_res, -}; - -static struct resource au1200_lcd_res[] = { - [0] = { - .start = AU1200_LCD_PHYS_ADDR, - .end = AU1200_LCD_PHYS_ADDR + 0x800 - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = AU1200_LCD_INT, - .end = AU1200_LCD_INT, - .flags = IORESOURCE_IRQ, - } -}; - -static u64 au1200_lcd_dmamask = DMA_BIT_MASK(32); - -static struct platform_device au1200_lcd_dev = { - .name = "au1200-lcd", - .id = 0, - .dev = { - .dma_mask = &au1200_lcd_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, - .num_resources = ARRAY_SIZE(au1200_lcd_res), - .resource = au1200_lcd_res, -}; - -static struct platform_device *board_platform_devices[] __initdata = { - &ide_device, - &smc91c111_device, - &pb1200_i2c_dev, - &pb1200_mmc0_dev, - &pb1200_mmc1_dev, - &au1200_lcd_dev, -}; - -static int __init board_register_devices(void) -{ - int swapped; - - db1x_register_pcmcia_socket( - AU1000_PCMCIA_ATTR_PHYS_ADDR, - AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, - AU1000_PCMCIA_MEM_PHYS_ADDR, - AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, - AU1000_PCMCIA_IO_PHYS_ADDR, - AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, - PB1200_PC0_INT, PB1200_PC0_INSERT_INT, - /*PB1200_PC0_STSCHG_INT*/0, PB1200_PC0_EJECT_INT, 0); - - db1x_register_pcmcia_socket( - AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008000000, - AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1, - AU1000_PCMCIA_MEM_PHYS_ADDR + 0x008000000, - AU1000_PCMCIA_MEM_PHYS_ADDR + 0x008400000 - 1, - AU1000_PCMCIA_IO_PHYS_ADDR + 0x008000000, - AU1000_PCMCIA_IO_PHYS_ADDR + 0x008010000 - 1, - PB1200_PC1_INT, PB1200_PC1_INSERT_INT, - /*PB1200_PC1_STSCHG_INT*/0, PB1200_PC1_EJECT_INT, 1); - - swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT; - db1x_register_norflash(128 * 1024 * 1024, 2, swapped); - - return platform_add_devices(board_platform_devices, - ARRAY_SIZE(board_platform_devices)); -} -device_initcall(board_register_devices); diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500.c index 37c1883b5ea9..e7b807b3ec51 100644 --- a/arch/mips/alchemy/devboards/pb1500/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1500.c @@ -1,41 +1,37 @@ /* - * Copyright 2000, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> + * Pb1500 board support. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * Copyright (C) 2009 Manuel Lauss * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/gpio.h> #include <linux/init.h> #include <linux/interrupt.h> - +#include <linux/platform_device.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-db1x00/bcsr.h> - #include <prom.h> +#include "platform.h" const char *get_system_type(void) { - return "Alchemy Pb1500"; + return "PB1500"; } void __init board_setup(void) @@ -123,17 +119,80 @@ void __init board_setup(void) } } -static int __init pb1500_init_irq(void) +/******************************************************************************/ + +static int pb1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) { - irq_set_irq_type(AU1500_GPIO9_INT, IRQF_TRIGGER_LOW); /* CD0# */ - irq_set_irq_type(AU1500_GPIO10_INT, IRQF_TRIGGER_LOW); /* CARD0 */ - irq_set_irq_type(AU1500_GPIO11_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ + if ((slot < 12) || (slot > 13) || pin == 0) + return -1; + if (slot == 12) + return (pin == 1) ? AU1500_PCI_INTA : 0xff; + if (slot == 13) { + switch (pin) { + case 1: return AU1500_PCI_INTA; + case 2: return AU1500_PCI_INTB; + case 3: return AU1500_PCI_INTC; + case 4: return AU1500_PCI_INTD; + } + } + return -1; +} + +static struct resource alchemy_pci_host_res[] = { + [0] = { + .start = AU1500_PCI_PHYS_ADDR, + .end = AU1500_PCI_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct alchemy_pci_platdata pb1500_pci_pd = { + .board_map_irq = pb1500_map_pci_irq, + .pci_cfg_set = PCI_CONFIG_AEN | PCI_CONFIG_R2H | PCI_CONFIG_R1H | + PCI_CONFIG_CH | +#if defined(__MIPSEB__) + PCI_CONFIG_SIC_HWA_DAT | PCI_CONFIG_SM, +#else + 0, +#endif +}; + +static struct platform_device pb1500_pci_host = { + .dev.platform_data = &pb1500_pci_pd, + .name = "alchemy-pci", + .id = 0, + .num_resources = ARRAY_SIZE(alchemy_pci_host_res), + .resource = alchemy_pci_host_res, +}; + +static int __init pb1500_dev_init(void) +{ + int swapped; + + irq_set_irq_type(AU1500_GPIO9_INT, IRQF_TRIGGER_LOW); /* CD0# */ + irq_set_irq_type(AU1500_GPIO10_INT, IRQF_TRIGGER_LOW); /* CARD0 */ + irq_set_irq_type(AU1500_GPIO11_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH); irq_set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW); irq_set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW); irq_set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW); irq_set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW); + /* PCMCIA. single socket, identical to Pb1100 */ + db1x_register_pcmcia_socket( + AU1000_PCMCIA_ATTR_PHYS_ADDR, + AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + AU1000_PCMCIA_MEM_PHYS_ADDR, + AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + AU1000_PCMCIA_IO_PHYS_ADDR, + AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + AU1500_GPIO11_INT, AU1500_GPIO9_INT, /* card / insert */ + /*AU1500_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */ + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; + db1x_register_norflash(64 * 1024 * 1024, 4, swapped); + platform_device_register(&pb1500_pci_host); + return 0; } -arch_initcall(pb1500_init_irq); +arch_initcall(pb1500_dev_init); diff --git a/arch/mips/alchemy/devboards/pb1500/Makefile b/arch/mips/alchemy/devboards/pb1500/Makefile deleted file mode 100644 index e83b151b5b63..000000000000 --- a/arch/mips/alchemy/devboards/pb1500/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright 2000, 2001, 2008 MontaVista Software Inc. -# Author: MontaVista Software, Inc. <source@mvista.com> -# -# Makefile for the Alchemy Semiconductor Pb1500 board. -# - -obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c deleted file mode 100644 index 1e52a01bac00..000000000000 --- a/arch/mips/alchemy/devboards/pb1500/platform.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Pb1500 board platform device registration - * - * Copyright (C) 2009 Manuel Lauss - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <linux/dma-mapping.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-db1x00/bcsr.h> - -#include "../platform.h" - -static int pb1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) -{ - if ((slot < 12) || (slot > 13) || pin == 0) - return -1; - if (slot == 12) - return (pin == 1) ? AU1500_PCI_INTA : 0xff; - if (slot == 13) { - switch (pin) { - case 1: return AU1500_PCI_INTA; - case 2: return AU1500_PCI_INTB; - case 3: return AU1500_PCI_INTC; - case 4: return AU1500_PCI_INTD; - } - } - return -1; -} - -static struct resource alchemy_pci_host_res[] = { - [0] = { - .start = AU1500_PCI_PHYS_ADDR, - .end = AU1500_PCI_PHYS_ADDR + 0xfff, - .flags = IORESOURCE_MEM, - }, -}; - -static struct alchemy_pci_platdata pb1500_pci_pd = { - .board_map_irq = pb1500_map_pci_irq, - .pci_cfg_set = PCI_CONFIG_AEN | PCI_CONFIG_R2H | PCI_CONFIG_R1H | - PCI_CONFIG_CH | -#if defined(__MIPSEB__) - PCI_CONFIG_SIC_HWA_DAT | PCI_CONFIG_SM, -#else - 0, -#endif -}; - -static struct platform_device pb1500_pci_host = { - .dev.platform_data = &pb1500_pci_pd, - .name = "alchemy-pci", - .id = 0, - .num_resources = ARRAY_SIZE(alchemy_pci_host_res), - .resource = alchemy_pci_host_res, -}; - -static int __init pb1500_dev_init(void) -{ - int swapped; - - /* PCMCIA. single socket, identical to Pb1100 */ - db1x_register_pcmcia_socket( - AU1000_PCMCIA_ATTR_PHYS_ADDR, - AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, - AU1000_PCMCIA_MEM_PHYS_ADDR, - AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, - AU1000_PCMCIA_IO_PHYS_ADDR, - AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, - AU1500_GPIO11_INT, AU1500_GPIO9_INT, /* card / insert */ - /*AU1500_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */ - - swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; - db1x_register_norflash(64 * 1024 * 1024, 4, swapped); - platform_device_register(&pb1500_pci_host); - - return 0; -} -arch_initcall(pb1500_dev_init); diff --git a/arch/mips/alchemy/devboards/pb1550/platform.c b/arch/mips/alchemy/devboards/pb1550.c index a4604b8a349e..b37e7de8d920 100644 --- a/arch/mips/alchemy/devboards/pb1550/platform.c +++ b/arch/mips/alchemy/devboards/pb1550.c @@ -1,7 +1,7 @@ /* - * Pb1550 board platform device registration + * Pb1550 board support. * - * Copyright (C) 2009 Manuel Lauss + * Copyright (C) 2009-2011 Manuel Lauss * * 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 @@ -20,13 +20,44 @@ #include <linux/dma-mapping.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/platform_device.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1xxx_dbdma.h> -#include <asm/mach-pb1x00/pb1550.h> +#include <asm/mach-au1x00/au1550nd.h> +#include <asm/mach-au1x00/gpio.h> #include <asm/mach-db1x00/bcsr.h> +#include "platform.h" -#include "../platform.h" +const char *get_system_type(void) +{ + return "PB1550"; +} + +void __init board_setup(void) +{ + u32 pin_func; + + bcsr_init(PB1550_BCSR_PHYS_ADDR, + PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS); + + alchemy_gpio2_enable(); + + /* + * Enable PSC1 SYNC for AC'97. Normaly done in audio driver, + * but it is board specific code, so put it here. + */ + pin_func = au_readl(SYS_PINFUNC); + au_sync(); + pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1; + au_writel(pin_func, SYS_PINFUNC); + + bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */ + + printk(KERN_INFO "AMD Alchemy Pb1550 Board\n"); +} + +/******************************************************************************/ static int pb1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) { @@ -101,10 +132,79 @@ static struct platform_device pb1550_i2c_dev = { .resource = au1550_psc2_res, }; +static struct mtd_partition pb1550_nand_parts[] = { + [0] = { + .name = "NAND FS 0", + .offset = 0, + .size = 8 * 1024 * 1024, + }, + [1] = { + .name = "NAND FS 1", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct au1550nd_platdata pb1550_nand_pd = { + .parts = pb1550_nand_parts, + .num_parts = ARRAY_SIZE(pb1550_nand_parts), + .devwidth = 0, /* x8 NAND default, needs fixing up */ +}; + +static struct resource pb1550_nand_res[] = { + [0] = { + .start = 0x20000000, + .end = 0x20000fff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device pb1550_nand_dev = { + .name = "au1550-nand", + .id = -1, + .resource = pb1550_nand_res, + .num_resources = ARRAY_SIZE(pb1550_nand_res), + .dev = { + .platform_data = &pb1550_nand_pd, + }, +}; + +static void __init pb1550_nand_setup(void) +{ + int boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | + ((bcsr_read(BCSR_STATUS) >> 6) & 0x1); + + switch (boot_swapboot) { + case 0: + case 2: + case 8: + case 0xC: + case 0xD: + /* x16 NAND Flash */ + pb1550_nand_pd.devwidth = 1; + /* fallthrough */ + case 1: + case 9: + case 3: + case 0xE: + case 0xF: + /* x8 NAND, already set up */ + platform_device_register(&pb1550_nand_dev); + } +} + static int __init pb1550_dev_init(void) { int swapped; + irq_set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW); + irq_set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW); + irq_set_irq_type(AU1550_GPIO201_205_INT, IRQF_TRIGGER_HIGH); + + /* enable both PCMCIA card irqs in the shared line */ + alchemy_gpio2_enable_int(201); + alchemy_gpio2_enable_int(202); + /* Pb1550, like all others, also has statuschange irqs; however they're * wired up on one of the Au1550's shared GPIO201_205 line, which also * services the PCMCIA card interrupts. So we ignore statuschange and @@ -130,6 +230,10 @@ static int __init pb1550_dev_init(void) AU1000_PCMCIA_IO_PHYS_ADDR + 0x008010000 - 1, AU1550_GPIO201_205_INT, AU1550_GPIO1_INT, 0, 0, 1); + /* NAND setup */ + gpio_direction_input(206); /* GPIO206 high */ + pb1550_nand_setup(); + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_PB1550_SWAPBOOT; db1x_register_norflash(128 * 1024 * 1024, 4, swapped); platform_device_register(&pb1550_pci_host); diff --git a/arch/mips/alchemy/devboards/pb1550/Makefile b/arch/mips/alchemy/devboards/pb1550/Makefile deleted file mode 100644 index 9661b6ec5dd3..000000000000 --- a/arch/mips/alchemy/devboards/pb1550/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright 2000, 2008 MontaVista Software Inc. -# Author: MontaVista Software, Inc. <source@mvista.com> -# -# Makefile for the Alchemy Semiconductor Pb1550 board. -# - -obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c deleted file mode 100644 index 0f62d1e3df24..000000000000 --- a/arch/mips/alchemy/devboards/pb1550/board_setup.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Alchemy Pb1550 board setup. - * - * Copyright 2000, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> - -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-pb1x00/pb1550.h> -#include <asm/mach-db1x00/bcsr.h> -#include <asm/mach-au1x00/gpio.h> - -#include <prom.h> - -const char *get_system_type(void) -{ - return "Alchemy Pb1550"; -} - -void __init board_setup(void) -{ - u32 pin_func; - - bcsr_init(PB1550_BCSR_PHYS_ADDR, - PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS); - - alchemy_gpio2_enable(); - - /* - * Enable PSC1 SYNC for AC'97. Normaly done in audio driver, - * but it is board specific code, so put it here. - */ - pin_func = au_readl(SYS_PINFUNC); - au_sync(); - pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1; - au_writel(pin_func, SYS_PINFUNC); - - bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */ - - printk(KERN_INFO "AMD Alchemy Pb1550 Board\n"); -} - -static int __init pb1550_init_irq(void) -{ - irq_set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1550_GPIO201_205_INT, IRQF_TRIGGER_HIGH); - - /* enable both PCMCIA card irqs in the shared line */ - alchemy_gpio2_enable_int(201); - alchemy_gpio2_enable_int(202); - - return 0; -} -arch_initcall(pb1550_init_irq); diff --git a/arch/mips/alchemy/devboards/platform.c b/arch/mips/alchemy/devboards/platform.c index 49a4b3244d8e..621f70afb63a 100644 --- a/arch/mips/alchemy/devboards/platform.c +++ b/arch/mips/alchemy/devboards/platform.c @@ -13,6 +13,13 @@ #include <asm/reboot.h> #include <asm/mach-db1x00/bcsr.h> + +static struct platform_device db1x00_rtc_dev = { + .name = "rtc-au1xxx", + .id = -1, +}; + + static void db1x_power_off(void) { bcsr_write(BCSR_RESETS, 0); @@ -25,7 +32,7 @@ static void db1x_reset(char *c) bcsr_write(BCSR_SYSTEM, 0); } -static int __init db1x_poweroff_setup(void) +static int __init db1x_late_setup(void) { if (!pm_power_off) pm_power_off = db1x_power_off; @@ -34,9 +41,11 @@ static int __init db1x_poweroff_setup(void) if (!_machine_restart) _machine_restart = db1x_reset; + platform_device_register(&db1x00_rtc_dev); + return 0; } -late_initcall(db1x_poweroff_setup); +device_initcall(db1x_late_setup); /* register a pcmcia socket */ int __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start, diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c index e5306b56da6d..93a22107cc41 100644 --- a/arch/mips/alchemy/devboards/prom.c +++ b/arch/mips/alchemy/devboards/prom.c @@ -33,10 +33,9 @@ #include <asm/mach-au1x00/au1000.h> #include <prom.h> -#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_DB1000) || \ - defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) || \ - defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_DB1500) || \ - defined(CONFIG_MIPS_BOSPORUS) || defined(CONFIG_MIPS_MIRAGE) +#if defined(CONFIG_MIPS_DB1000) || \ + defined(CONFIG_MIPS_PB1100) || \ + defined(CONFIG_MIPS_PB1500) #define ALCHEMY_BOARD_DEFAULT_MEMSIZE 0x04000000 #else /* Au1550/Au1200-based develboards */ @@ -62,5 +61,9 @@ void __init prom_init(void) void prom_putchar(unsigned char c) { +#ifdef CONFIG_MIPS_DB1300 + alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c); +#else alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); +#endif } diff --git a/arch/mips/alchemy/gpr/Makefile b/arch/mips/alchemy/gpr/Makefile deleted file mode 100644 index cb73fe256dce..000000000000 --- a/arch/mips/alchemy/gpr/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright 2003 MontaVista Software Inc. -# Author: MontaVista Software, Inc. <source@mvista.com> -# -# Makefile for Trapeze ITS GPR board. -# - -obj-y += board_setup.o init.o platform.o diff --git a/arch/mips/alchemy/gpr/board_setup.c b/arch/mips/alchemy/gpr/board_setup.c deleted file mode 100644 index dea45c78fdcd..000000000000 --- a/arch/mips/alchemy/gpr/board_setup.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2010 Wolfgang Grandegger <wg@denx.de> - * - * Copyright 2000-2003, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/pm.h> - -#include <asm/reboot.h> -#include <asm/mach-au1x00/au1000.h> - -#include <prom.h> - -static void gpr_reset(char *c) -{ - /* switch System-LED to orange (red# and green# on) */ - alchemy_gpio_direction_output(4, 0); - alchemy_gpio_direction_output(5, 0); - - /* trigger watchdog to reset board in 200ms */ - printk(KERN_EMERG "Triggering watchdog soft reset...\n"); - raw_local_irq_disable(); - alchemy_gpio_direction_output(1, 0); - udelay(1); - alchemy_gpio_set_value(1, 1); - while (1) - cpu_wait(); -} - -static void gpr_power_off(void) -{ - while (1) - cpu_wait(); -} - -void __init board_setup(void) -{ - printk(KERN_INFO "Trapeze ITS GPR board\n"); - - pm_power_off = gpr_power_off; - _machine_halt = gpr_power_off; - _machine_restart = gpr_reset; - - /* Enable UART1/3 */ - alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); - alchemy_uart_enable(AU1000_UART1_PHYS_ADDR); - - /* Take away Reset of UMTS-card */ - alchemy_gpio_direction_output(215, 1); -} diff --git a/arch/mips/alchemy/gpr/init.c b/arch/mips/alchemy/gpr/init.c deleted file mode 100644 index 229aafae680c..000000000000 --- a/arch/mips/alchemy/gpr/init.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2010 Wolfgang Grandegger <wg@denx.de> - * - * Copyright 2003, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/init.h> -#include <linux/kernel.h> - -#include <asm/bootinfo.h> -#include <asm/mach-au1x00/au1000.h> - -#include <prom.h> - -const char *get_system_type(void) -{ - return "GPR"; -} - -void __init prom_init(void) -{ - unsigned char *memsize_str; - unsigned long memsize; - - prom_argc = fw_arg0; - prom_argv = (char **)fw_arg1; - prom_envp = (char **)fw_arg2; - - prom_init_cmdline(); - - memsize_str = prom_getenv("memsize"); - if (!memsize_str) - memsize = 0x04000000; - else - strict_strtoul(memsize_str, 0, &memsize); - add_memory_region(0, memsize, BOOT_MEM_RAM); -} - -void prom_putchar(unsigned char c) -{ - alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); -} diff --git a/arch/mips/alchemy/mtx-1/Makefile b/arch/mips/alchemy/mtx-1/Makefile deleted file mode 100644 index 81b540ceaf88..000000000000 --- a/arch/mips/alchemy/mtx-1/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Copyright 2003 MontaVista Software Inc. -# Author: MontaVista Software, Inc. <source@mvista.com> -# Bruno Randolf <bruno.randolf@4g-systems.biz> -# -# Makefile for 4G Systems MTX-1 board. -# - -obj-y += init.o board_setup.o platform.o diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c deleted file mode 100644 index 851a5ab4c8f2..000000000000 --- a/arch/mips/alchemy/mtx-1/board_setup.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * 4G Systems MTX-1 board setup. - * - * Copyright 2003, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> - * Bruno Randolf <bruno.randolf@4g-systems.biz> - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/pm.h> - -#include <asm/reboot.h> -#include <asm/mach-au1x00/au1000.h> - -#include <prom.h> - -static void mtx1_reset(char *c) -{ - /* Jump to the reset vector */ - __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); -} - -static void mtx1_power_off(void) -{ - while (1) - asm volatile ( - " .set mips32 \n" - " wait \n" - " .set mips0 \n"); -} - -void __init board_setup(void) -{ -#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) - /* Enable USB power switch */ - alchemy_gpio_direction_output(204, 0); -#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ - - /* Initialize sys_pinfunc */ - au_writel(SYS_PF_NI2, SYS_PINFUNC); - - /* Initialize GPIO */ - au_writel(~0, KSEG1ADDR(AU1000_SYS_PHYS_ADDR) + SYS_TRIOUTCLR); - alchemy_gpio_direction_output(0, 0); /* Disable M66EN (PCI 66MHz) */ - alchemy_gpio_direction_output(3, 1); /* Disable PCI CLKRUN# */ - alchemy_gpio_direction_output(1, 1); /* Enable EXT_IO3 */ - alchemy_gpio_direction_output(5, 0); /* Disable eth PHY TX_ER */ - - /* Enable LED and set it to green */ - alchemy_gpio_direction_output(211, 1); /* green on */ - alchemy_gpio_direction_output(212, 0); /* red off */ - - pm_power_off = mtx1_power_off; - _machine_halt = mtx1_power_off; - _machine_restart = mtx1_reset; - - printk(KERN_INFO "4G Systems MTX-1 Board\n"); -} - -static int __init mtx1_init_irq(void) -{ - irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH); - irq_set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW); - - return 0; -} -arch_initcall(mtx1_init_irq); diff --git a/arch/mips/alchemy/mtx-1/init.c b/arch/mips/alchemy/mtx-1/init.c deleted file mode 100644 index 2e81cc7f3422..000000000000 --- a/arch/mips/alchemy/mtx-1/init.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * 4G Systems MTX-1 board setup - * - * Copyright 2003, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> - * Bruno Randolf <bruno.randolf@4g-systems.biz> - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/kernel.h> -#include <linux/init.h> - -#include <asm/bootinfo.h> -#include <asm/mach-au1x00/au1000.h> - -#include <prom.h> - -const char *get_system_type(void) -{ - return "MTX-1"; -} - -void __init prom_init(void) -{ - unsigned char *memsize_str; - unsigned long memsize; - - prom_argc = fw_arg0; - prom_argv = (char **)fw_arg1; - prom_envp = (char **)fw_arg2; - - prom_init_cmdline(); - - memsize_str = prom_getenv("memsize"); - if (!memsize_str) - memsize = 0x04000000; - else - strict_strtoul(memsize_str, 0, &memsize); - add_memory_region(0, memsize, BOOT_MEM_RAM); -} - -void prom_putchar(unsigned char c) -{ - alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); -} diff --git a/arch/mips/alchemy/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile deleted file mode 100644 index 91defcf4f335..000000000000 --- a/arch/mips/alchemy/xxs1500/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright 2003 MontaVista Software Inc. -# Author: MontaVista Software, Inc. <source@mvista.com> -# -# Makefile for MyCable XXS1500 board. -# - -obj-y += init.o board_setup.o platform.o diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c deleted file mode 100644 index 3fa83f72e014..000000000000 --- a/arch/mips/alchemy/xxs1500/board_setup.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2000-2003, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/pm.h> - -#include <asm/reboot.h> -#include <asm/mach-au1x00/au1000.h> - -#include <prom.h> - -static void xxs1500_reset(char *c) -{ - /* Jump to the reset vector */ - __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); -} - -static void xxs1500_power_off(void) -{ - while (1) - asm volatile ( - " .set mips32 \n" - " wait \n" - " .set mips0 \n"); -} - -void __init board_setup(void) -{ - u32 pin_func; - - pm_power_off = xxs1500_power_off; - _machine_halt = xxs1500_power_off; - _machine_restart = xxs1500_reset; - - alchemy_gpio1_input_enable(); - alchemy_gpio2_enable(); - - /* Set multiple use pins (UART3/GPIO) to UART (it's used as UART too) */ - pin_func = au_readl(SYS_PINFUNC) & ~SYS_PF_UR3; - pin_func |= SYS_PF_UR3; - au_writel(pin_func, SYS_PINFUNC); - - /* Enable UART */ - alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); - /* Enable DTR (MCR bit 0) = USB power up */ - __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18)); - wmb(); -} - -static int __init xxs1500_init_irq(void) -{ - irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH); - irq_set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO207_INT, IRQF_TRIGGER_LOW); - - irq_set_irq_type(AU1500_GPIO0_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO1_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO2_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO3_INT, IRQF_TRIGGER_LOW); - irq_set_irq_type(AU1500_GPIO4_INT, IRQF_TRIGGER_LOW); /* CF irq */ - irq_set_irq_type(AU1500_GPIO5_INT, IRQF_TRIGGER_LOW); - - return 0; -} -arch_initcall(xxs1500_init_irq); diff --git a/arch/mips/alchemy/xxs1500/init.c b/arch/mips/alchemy/xxs1500/init.c deleted file mode 100644 index 0ee02cfa989d..000000000000 --- a/arch/mips/alchemy/xxs1500/init.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * XXS1500 board setup - * - * Copyright 2003, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/init.h> -#include <linux/kernel.h> - -#include <asm/bootinfo.h> -#include <asm/mach-au1x00/au1000.h> - -#include <prom.h> - -const char *get_system_type(void) -{ - return "XXS1500"; -} - -void __init prom_init(void) -{ - unsigned char *memsize_str; - unsigned long memsize; - - prom_argc = fw_arg0; - prom_argv = (char **)fw_arg1; - prom_envp = (char **)fw_arg2; - - prom_init_cmdline(); - - memsize_str = prom_getenv("memsize"); - if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize)) - memsize = 0x04000000; - - add_memory_region(0, memsize, BOOT_MEM_RAM); -} - -void prom_putchar(unsigned char c) -{ - alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); -} diff --git a/arch/mips/alchemy/xxs1500/platform.c b/arch/mips/alchemy/xxs1500/platform.c deleted file mode 100644 index 06a3a459b8aa..000000000000 --- a/arch/mips/alchemy/xxs1500/platform.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * XXS1500 board platform device registration - * - * Copyright (C) 2009 Manuel Lauss - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <linux/init.h> -#include <linux/platform_device.h> - -#include <asm/mach-au1x00/au1000.h> - -static struct resource xxs1500_pcmcia_res[] = { - { - .name = "pcmcia-io", - .flags = IORESOURCE_MEM, - .start = AU1000_PCMCIA_IO_PHYS_ADDR, - .end = AU1000_PCMCIA_IO_PHYS_ADDR + 0x000400000 - 1, - }, - { - .name = "pcmcia-attr", - .flags = IORESOURCE_MEM, - .start = AU1000_PCMCIA_ATTR_PHYS_ADDR, - .end = AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, - }, - { - .name = "pcmcia-mem", - .flags = IORESOURCE_MEM, - .start = AU1000_PCMCIA_MEM_PHYS_ADDR, - .end = AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, - }, -}; - -static struct platform_device xxs1500_pcmcia_dev = { - .name = "xxs1500_pcmcia", - .id = -1, - .num_resources = ARRAY_SIZE(xxs1500_pcmcia_res), - .resource = xxs1500_pcmcia_res, -}; - -static struct platform_device *xxs1500_devs[] __initdata = { - &xxs1500_pcmcia_dev, -}; - -static int __init xxs1500_dev_init(void) -{ - return platform_add_devices(xxs1500_devs, - ARRAY_SIZE(xxs1500_devs)); -} -device_initcall(xxs1500_dev_init); diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c index bb571bcdb8f2..d8dbd8f0c1d2 100644 --- a/arch/mips/ar7/gpio.c +++ b/arch/mips/ar7/gpio.c @@ -217,7 +217,7 @@ struct titan_gpio_cfg { u32 func; }; -static struct titan_gpio_cfg titan_gpio_table[] = { +static const struct titan_gpio_cfg titan_gpio_table[] = { /* reg, start bit, mux value */ {4, 24, 1}, {4, 26, 1}, diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index 33ffecf6a6d6..1a24d317e7a3 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -462,6 +462,40 @@ static struct gpio_led fb_fon_leds[] = { }, }; +static struct gpio_led gt701_leds[] = { + { + .name = "inet:green", + .gpio = 13, + .active_low = 1, + }, + { + .name = "usb", + .gpio = 12, + .active_low = 1, + }, + { + .name = "inet:red", + .gpio = 9, + .active_low = 1, + }, + { + .name = "power:red", + .gpio = 7, + .active_low = 1, + }, + { + .name = "power:green", + .gpio = 8, + .active_low = 1, + .default_trigger = "default-on", + }, + { + .name = "ethernet", + .gpio = 10, + .active_low = 1, + }, +}; + static struct gpio_led_platform_data ar7_led_data; static struct platform_device ar7_gpio_leds = { @@ -503,6 +537,9 @@ static void __init detect_leds(void) } else if (strstr(prid, "CYWM") || strstr(prid, "CYWL")) { ar7_led_data.num_leds = ARRAY_SIZE(titan_leds); ar7_led_data.leds = titan_leds; + } else if (strstr(prid, "GT701")) { + ar7_led_data.num_leds = ARRAY_SIZE(gt701_leds); + ar7_led_data.leds = gt701_leds; } } @@ -536,7 +573,7 @@ static int __init ar7_register_uarts(void) bus_clk = clk_get(NULL, "bus"); if (IS_ERR(bus_clk)) - panic("unable to get bus clk\n"); + panic("unable to get bus clk"); uart_port.type = PORT_AR7; uart_port.uartclk = clk_get_rate(bus_clk) / 2; diff --git a/arch/mips/ar7/prom.c b/arch/mips/ar7/prom.c index 8088c6fdb83e..a23adc49d50f 100644 --- a/arch/mips/ar7/prom.c +++ b/arch/mips/ar7/prom.c @@ -69,7 +69,7 @@ struct psbl_rec { u32 ffs_size; }; -static __initdata char psp_env_version[] = "TIENV0.8"; +static const char psp_env_version[] __initconst = "TIENV0.8"; struct psp_env_chunk { u8 num; @@ -84,7 +84,7 @@ struct psp_var_map_entry { char *value; }; -static struct psp_var_map_entry psp_var_map[] = { +static const struct psp_var_map_entry psp_var_map[] = { { 1, "cpufrequency" }, { 2, "memsize" }, { 3, "flashsize" }, diff --git a/arch/mips/ar7/setup.c b/arch/mips/ar7/setup.c index f20b53e597c4..9a357fffcfbe 100644 --- a/arch/mips/ar7/setup.c +++ b/arch/mips/ar7/setup.c @@ -96,7 +96,7 @@ void __init plat_mem_setup(void) io_base = (unsigned long)ioremap(AR7_REGS_BASE, 0x10000); if (!io_base) - panic("Can't remap IO base!\n"); + panic("Can't remap IO base!"); set_io_port_base(io_base); prom_meminit(); diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig index 47707410582c..e0fae8f4442b 100644 --- a/arch/mips/ath79/Kconfig +++ b/arch/mips/ath79/Kconfig @@ -2,13 +2,26 @@ if ATH79 menu "Atheros AR71XX/AR724X/AR913X machine selection" +config ATH79_MACH_AP121 + bool "Atheros AP121 reference board" + select SOC_AR933X + select ATH79_DEV_GPIO_BUTTONS + select ATH79_DEV_LEDS_GPIO + select ATH79_DEV_SPI + select ATH79_DEV_USB + select ATH79_DEV_WMAC + help + Say 'Y' here if you want your kernel to support the + Atheros AP121 reference board. + config ATH79_MACH_AP81 bool "Atheros AP81 reference board" select SOC_AR913X - select ATH79_DEV_AR913X_WMAC select ATH79_DEV_GPIO_BUTTONS select ATH79_DEV_LEDS_GPIO select ATH79_DEV_SPI + select ATH79_DEV_USB + select ATH79_DEV_WMAC help Say 'Y' here if you want your kernel to support the Atheros AP81 reference board. @@ -19,10 +32,21 @@ config ATH79_MACH_PB44 select ATH79_DEV_GPIO_BUTTONS select ATH79_DEV_LEDS_GPIO select ATH79_DEV_SPI + select ATH79_DEV_USB help Say 'Y' here if you want your kernel to support the Atheros PB44 reference board. +config ATH79_MACH_UBNT_XM + bool "Ubiquiti Networks XM (rev 1.0) board" + select SOC_AR724X + select ATH79_DEV_GPIO_BUTTONS + select ATH79_DEV_LEDS_GPIO + select ATH79_DEV_SPI + help + Say 'Y' here if you want your kernel to support the + Ubiquiti Networks XM (rev 1.0) board. + endmenu config SOC_AR71XX @@ -33,14 +57,15 @@ config SOC_AR71XX config SOC_AR724X select USB_ARCH_HAS_EHCI select USB_ARCH_HAS_OHCI + select HW_HAS_PCI def_bool n config SOC_AR913X select USB_ARCH_HAS_EHCI def_bool n -config ATH79_DEV_AR913X_WMAC - depends on SOC_AR913X +config SOC_AR933X + select USB_ARCH_HAS_EHCI def_bool n config ATH79_DEV_GPIO_BUTTONS @@ -52,4 +77,11 @@ config ATH79_DEV_LEDS_GPIO config ATH79_DEV_SPI def_bool n +config ATH79_DEV_USB + def_bool n + +config ATH79_DEV_WMAC + depends on (SOC_AR913X || SOC_AR933X) + def_bool n + endif diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile index c33d4653007c..3b911e09dbec 100644 --- a/arch/mips/ath79/Makefile +++ b/arch/mips/ath79/Makefile @@ -16,13 +16,16 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o # Devices # obj-y += dev-common.o -obj-$(CONFIG_ATH79_DEV_AR913X_WMAC) += dev-ar913x-wmac.o obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o obj-$(CONFIG_ATH79_DEV_LEDS_GPIO) += dev-leds-gpio.o obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o +obj-$(CONFIG_ATH79_DEV_USB) += dev-usb.o +obj-$(CONFIG_ATH79_DEV_WMAC) += dev-wmac.o # # Machines # +obj-$(CONFIG_ATH79_MACH_AP121) += mach-ap121.o obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o +obj-$(CONFIG_ATH79_MACH_UBNT_XM) += mach-ubnt-xm.o diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c index 680bde99a26c..54d0eb4db987 100644 --- a/arch/mips/ath79/clock.c +++ b/arch/mips/ath79/clock.c @@ -110,6 +110,59 @@ static void __init ar913x_clocks_init(void) ath79_uart_clk.rate = ath79_ahb_clk.rate; } +static void __init ar933x_clocks_init(void) +{ + u32 clock_ctrl; + u32 cpu_config; + u32 freq; + u32 t; + + t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); + if (t & AR933X_BOOTSTRAP_REF_CLK_40) + ath79_ref_clk.rate = (40 * 1000 * 1000); + else + ath79_ref_clk.rate = (25 * 1000 * 1000); + + clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG); + if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { + ath79_cpu_clk.rate = ath79_ref_clk.rate; + ath79_ahb_clk.rate = ath79_ref_clk.rate; + ath79_ddr_clk.rate = ath79_ref_clk.rate; + } else { + cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG); + + t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & + AR933X_PLL_CPU_CONFIG_REFDIV_MASK; + freq = ath79_ref_clk.rate / t; + + t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & + AR933X_PLL_CPU_CONFIG_NINT_MASK; + freq *= t; + + t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & + AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; + if (t == 0) + t = 1; + + freq >>= t; + + t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & + AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; + ath79_cpu_clk.rate = freq / t; + + t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & + AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; + ath79_ddr_clk.rate = freq / t; + + t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & + AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; + ath79_ahb_clk.rate = freq / t; + } + + ath79_wdt_clk.rate = ath79_ref_clk.rate; + ath79_uart_clk.rate = ath79_ref_clk.rate; +} + void __init ath79_clocks_init(void) { if (soc_is_ar71xx()) @@ -118,6 +171,8 @@ void __init ath79_clocks_init(void) ar724x_clocks_init(); else if (soc_is_ar913x()) ar913x_clocks_init(); + else if (soc_is_ar933x()) + ar933x_clocks_init(); else BUG(); diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c index 58f60e722a03..f0fda982b965 100644 --- a/arch/mips/ath79/common.c +++ b/arch/mips/ath79/common.c @@ -30,6 +30,7 @@ u32 ath79_ddr_freq; EXPORT_SYMBOL_GPL(ath79_ddr_freq); enum ath79_soc_type ath79_soc; +unsigned int ath79_soc_rev; void __iomem *ath79_pll_base; void __iomem *ath79_reset_base; @@ -64,6 +65,8 @@ void ath79_device_reset_set(u32 mask) reg = AR724X_RESET_REG_RESET_MODULE; else if (soc_is_ar913x()) reg = AR913X_RESET_REG_RESET_MODULE; + else if (soc_is_ar933x()) + reg = AR933X_RESET_REG_RESET_MODULE; else BUG(); @@ -86,6 +89,8 @@ void ath79_device_reset_clear(u32 mask) reg = AR724X_RESET_REG_RESET_MODULE; else if (soc_is_ar913x()) reg = AR913X_RESET_REG_RESET_MODULE; + else if (soc_is_ar933x()) + reg = AR933X_RESET_REG_RESET_MODULE; else BUG(); diff --git a/arch/mips/ath79/dev-ar913x-wmac.c b/arch/mips/ath79/dev-ar913x-wmac.c deleted file mode 100644 index 48f425a5ba28..000000000000 --- a/arch/mips/ath79/dev-ar913x-wmac.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Atheros AR913X SoC built-in WMAC device support - * - * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> - * - * 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 <linux/init.h> -#include <linux/delay.h> -#include <linux/irq.h> -#include <linux/platform_device.h> -#include <linux/ath9k_platform.h> - -#include <asm/mach-ath79/ath79.h> -#include <asm/mach-ath79/ar71xx_regs.h> -#include "dev-ar913x-wmac.h" - -static struct ath9k_platform_data ar913x_wmac_data; - -static struct resource ar913x_wmac_resources[] = { - { - .start = AR913X_WMAC_BASE, - .end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1, - .flags = IORESOURCE_MEM, - }, { - .start = ATH79_CPU_IRQ_IP2, - .end = ATH79_CPU_IRQ_IP2, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device ar913x_wmac_device = { - .name = "ath9k", - .id = -1, - .resource = ar913x_wmac_resources, - .num_resources = ARRAY_SIZE(ar913x_wmac_resources), - .dev = { - .platform_data = &ar913x_wmac_data, - }, -}; - -void __init ath79_register_ar913x_wmac(u8 *cal_data) -{ - if (cal_data) - memcpy(ar913x_wmac_data.eeprom_data, cal_data, - sizeof(ar913x_wmac_data.eeprom_data)); - - /* reset the WMAC */ - ath79_device_reset_set(AR913X_RESET_AMBA2WMAC); - mdelay(10); - - ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC); - mdelay(10); - - platform_device_register(&ar913x_wmac_device); -} diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c index 3b82e325bebf..f4956f809072 100644 --- a/arch/mips/ath79/dev-common.c +++ b/arch/mips/ath79/dev-common.c @@ -20,6 +20,7 @@ #include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ar71xx_regs.h> +#include <asm/mach-ath79/ar933x_uart_platform.h> #include "common.h" #include "dev-common.h" @@ -54,6 +55,30 @@ static struct platform_device ath79_uart_device = { }, }; +static struct resource ar933x_uart_resources[] = { + { + .start = AR933X_UART_BASE, + .end = AR933X_UART_BASE + AR71XX_UART_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = ATH79_MISC_IRQ_UART, + .end = ATH79_MISC_IRQ_UART, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct ar933x_uart_platform_data ar933x_uart_data; +static struct platform_device ar933x_uart_device = { + .name = "ar933x-uart", + .id = -1, + .resource = ar933x_uart_resources, + .num_resources = ARRAY_SIZE(ar933x_uart_resources), + .dev = { + .platform_data = &ar933x_uart_data, + }, +}; + void __init ath79_register_uart(void) { struct clk *clk; @@ -62,8 +87,17 @@ void __init ath79_register_uart(void) if (IS_ERR(clk)) panic("unable to get UART clock, err=%ld", PTR_ERR(clk)); - ath79_uart_data[0].uartclk = clk_get_rate(clk); - platform_device_register(&ath79_uart_device); + if (soc_is_ar71xx() || + soc_is_ar724x() || + soc_is_ar913x()) { + ath79_uart_data[0].uartclk = clk_get_rate(clk); + platform_device_register(&ath79_uart_device); + } else if (soc_is_ar933x()) { + ar933x_uart_data.uartclk = clk_get_rate(clk); + platform_device_register(&ar933x_uart_device); + } else { + BUG(); + } } static struct platform_device ath79_wdt_device = { diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c new file mode 100644 index 000000000000..002d6d2afe04 --- /dev/null +++ b/arch/mips/ath79/dev-usb.c @@ -0,0 +1,197 @@ +/* + * Atheros AR7XXX/AR9XXX USB Host Controller device + * + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + * Parts of this file are based on Atheros' 2.6.15 BSP + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> + +#include <asm/mach-ath79/ath79.h> +#include <asm/mach-ath79/ar71xx_regs.h> +#include "common.h" +#include "dev-usb.h" + +static struct resource ath79_ohci_resources[] = { + [0] = { + /* .start and .end fields are filled dynamically */ + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ATH79_MISC_IRQ_OHCI, + .end = ATH79_MISC_IRQ_OHCI, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 ath79_ohci_dmamask = DMA_BIT_MASK(32); +static struct platform_device ath79_ohci_device = { + .name = "ath79-ohci", + .id = -1, + .resource = ath79_ohci_resources, + .num_resources = ARRAY_SIZE(ath79_ohci_resources), + .dev = { + .dma_mask = &ath79_ohci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource ath79_ehci_resources[] = { + [0] = { + /* .start and .end fields are filled dynamically */ + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ATH79_CPU_IRQ_USB, + .end = ATH79_CPU_IRQ_USB, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 ath79_ehci_dmamask = DMA_BIT_MASK(32); +static struct platform_device ath79_ehci_device = { + .name = "ath79-ehci", + .id = -1, + .resource = ath79_ehci_resources, + .num_resources = ARRAY_SIZE(ath79_ehci_resources), + .dev = { + .dma_mask = &ath79_ehci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +#define AR71XX_USB_RESET_MASK (AR71XX_RESET_USB_HOST | \ + AR71XX_RESET_USB_PHY | \ + AR71XX_RESET_USB_OHCI_DLL) + +static void __init ath79_usb_setup(void) +{ + void __iomem *usb_ctrl_base; + + ath79_device_reset_set(AR71XX_USB_RESET_MASK); + mdelay(1000); + ath79_device_reset_clear(AR71XX_USB_RESET_MASK); + + usb_ctrl_base = ioremap(AR71XX_USB_CTRL_BASE, AR71XX_USB_CTRL_SIZE); + + /* Turning on the Buff and Desc swap bits */ + __raw_writel(0xf0000, usb_ctrl_base + AR71XX_USB_CTRL_REG_CONFIG); + + /* WAR for HW bug. Here it adjusts the duration between two SOFS */ + __raw_writel(0x20c00, usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ); + + iounmap(usb_ctrl_base); + + mdelay(900); + + ath79_ohci_resources[0].start = AR71XX_OHCI_BASE; + ath79_ohci_resources[0].end = AR71XX_OHCI_BASE + AR71XX_OHCI_SIZE - 1; + platform_device_register(&ath79_ohci_device); + + ath79_ehci_resources[0].start = AR71XX_EHCI_BASE; + ath79_ehci_resources[0].end = AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1; + ath79_ehci_device.name = "ar71xx-ehci"; + platform_device_register(&ath79_ehci_device); +} + +static void __init ar7240_usb_setup(void) +{ + void __iomem *usb_ctrl_base; + + ath79_device_reset_clear(AR7240_RESET_OHCI_DLL); + ath79_device_reset_set(AR7240_RESET_USB_HOST); + + mdelay(1000); + + ath79_device_reset_set(AR7240_RESET_OHCI_DLL); + ath79_device_reset_clear(AR7240_RESET_USB_HOST); + + usb_ctrl_base = ioremap(AR7240_USB_CTRL_BASE, AR7240_USB_CTRL_SIZE); + + /* WAR for HW bug. Here it adjusts the duration between two SOFS */ + __raw_writel(0x3, usb_ctrl_base + AR71XX_USB_CTRL_REG_FLADJ); + + iounmap(usb_ctrl_base); + + ath79_ohci_resources[0].start = AR7240_OHCI_BASE; + ath79_ohci_resources[0].end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1; + platform_device_register(&ath79_ohci_device); +} + +static void __init ar724x_usb_setup(void) +{ + ath79_device_reset_set(AR724X_RESET_USBSUS_OVERRIDE); + mdelay(10); + + ath79_device_reset_clear(AR724X_RESET_USB_HOST); + mdelay(10); + + ath79_device_reset_clear(AR724X_RESET_USB_PHY); + mdelay(10); + + ath79_ehci_resources[0].start = AR724X_EHCI_BASE; + ath79_ehci_resources[0].end = AR724X_EHCI_BASE + AR724X_EHCI_SIZE - 1; + ath79_ehci_device.name = "ar724x-ehci"; + platform_device_register(&ath79_ehci_device); +} + +static void __init ar913x_usb_setup(void) +{ + ath79_device_reset_set(AR913X_RESET_USBSUS_OVERRIDE); + mdelay(10); + + ath79_device_reset_clear(AR913X_RESET_USB_HOST); + mdelay(10); + + ath79_device_reset_clear(AR913X_RESET_USB_PHY); + mdelay(10); + + ath79_ehci_resources[0].start = AR913X_EHCI_BASE; + ath79_ehci_resources[0].end = AR913X_EHCI_BASE + AR913X_EHCI_SIZE - 1; + ath79_ehci_device.name = "ar913x-ehci"; + platform_device_register(&ath79_ehci_device); +} + +static void __init ar933x_usb_setup(void) +{ + ath79_device_reset_set(AR933X_RESET_USBSUS_OVERRIDE); + mdelay(10); + + ath79_device_reset_clear(AR933X_RESET_USB_HOST); + mdelay(10); + + ath79_device_reset_clear(AR933X_RESET_USB_PHY); + mdelay(10); + + ath79_ehci_resources[0].start = AR933X_EHCI_BASE; + ath79_ehci_resources[0].end = AR933X_EHCI_BASE + AR933X_EHCI_SIZE - 1; + ath79_ehci_device.name = "ar933x-ehci"; + platform_device_register(&ath79_ehci_device); +} + +void __init ath79_register_usb(void) +{ + if (soc_is_ar71xx()) + ath79_usb_setup(); + else if (soc_is_ar7240()) + ar7240_usb_setup(); + else if (soc_is_ar7241() || soc_is_ar7242()) + ar724x_usb_setup(); + else if (soc_is_ar913x()) + ar913x_usb_setup(); + else if (soc_is_ar933x()) + ar933x_usb_setup(); + else + BUG(); +} diff --git a/arch/mips/ath79/dev-ar913x-wmac.h b/arch/mips/ath79/dev-usb.h index 579d562bbda8..4b86a69ca080 100644 --- a/arch/mips/ath79/dev-ar913x-wmac.h +++ b/arch/mips/ath79/dev-usb.h @@ -1,5 +1,5 @@ /* - * Atheros AR913X SoC built-in WMAC device support + * Atheros AR71XX/AR724X/AR913X USB Host Controller support * * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> @@ -9,9 +9,9 @@ * by the Free Software Foundation. */ -#ifndef _ATH79_DEV_AR913X_WMAC_H -#define _ATH79_DEV_AR913X_WMAC_H +#ifndef _ATH79_DEV_USB_H +#define _ATH79_DEV_USB_H -void ath79_register_ar913x_wmac(u8 *cal_data); +void ath79_register_usb(void); -#endif /* _ATH79_DEV_AR913X_WMAC_H */ +#endif /* _ATH79_DEV_USB_H */ diff --git a/arch/mips/ath79/dev-wmac.c b/arch/mips/ath79/dev-wmac.c new file mode 100644 index 000000000000..24f546985b69 --- /dev/null +++ b/arch/mips/ath79/dev-wmac.c @@ -0,0 +1,109 @@ +/* + * Atheros AR913X/AR933X SoC built-in WMAC device support + * + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + * 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 <linux/init.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/ath9k_platform.h> + +#include <asm/mach-ath79/ath79.h> +#include <asm/mach-ath79/ar71xx_regs.h> +#include "dev-wmac.h" + +static struct ath9k_platform_data ath79_wmac_data; + +static struct resource ath79_wmac_resources[] = { + { + /* .start and .end fields are filled dynamically */ + .flags = IORESOURCE_MEM, + }, { + .start = ATH79_CPU_IRQ_IP2, + .end = ATH79_CPU_IRQ_IP2, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ath79_wmac_device = { + .name = "ath9k", + .id = -1, + .resource = ath79_wmac_resources, + .num_resources = ARRAY_SIZE(ath79_wmac_resources), + .dev = { + .platform_data = &ath79_wmac_data, + }, +}; + +static void __init ar913x_wmac_setup(void) +{ + /* reset the WMAC */ + ath79_device_reset_set(AR913X_RESET_AMBA2WMAC); + mdelay(10); + + ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC); + mdelay(10); + + ath79_wmac_resources[0].start = AR913X_WMAC_BASE; + ath79_wmac_resources[0].end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1; +} + + +static int ar933x_wmac_reset(void) +{ + ath79_device_reset_clear(AR933X_RESET_WMAC); + ath79_device_reset_set(AR933X_RESET_WMAC); + + return 0; +} + +static int ar933x_r1_get_wmac_revision(void) +{ + return ath79_soc_rev; +} + +static void __init ar933x_wmac_setup(void) +{ + u32 t; + + ar933x_wmac_reset(); + + ath79_wmac_device.name = "ar933x_wmac"; + + ath79_wmac_resources[0].start = AR933X_WMAC_BASE; + ath79_wmac_resources[0].end = AR933X_WMAC_BASE + AR933X_WMAC_SIZE - 1; + + t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); + if (t & AR933X_BOOTSTRAP_REF_CLK_40) + ath79_wmac_data.is_clk_25mhz = false; + else + ath79_wmac_data.is_clk_25mhz = true; + + if (ath79_soc_rev == 1) + ath79_wmac_data.get_mac_revision = ar933x_r1_get_wmac_revision; + + ath79_wmac_data.external_reset = ar933x_wmac_reset; +} + +void __init ath79_register_wmac(u8 *cal_data) +{ + if (soc_is_ar913x()) + ar913x_wmac_setup(); + if (soc_is_ar933x()) + ar933x_wmac_setup(); + else + BUG(); + + if (cal_data) + memcpy(ath79_wmac_data.eeprom_data, cal_data, + sizeof(ath79_wmac_data.eeprom_data)); + + platform_device_register(&ath79_wmac_device); +} diff --git a/arch/mips/ath79/dev-wmac.h b/arch/mips/ath79/dev-wmac.h new file mode 100644 index 000000000000..c9cd8709f090 --- /dev/null +++ b/arch/mips/ath79/dev-wmac.h @@ -0,0 +1,17 @@ +/* + * Atheros AR913X/AR933X SoC built-in WMAC device support + * + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _ATH79_DEV_WMAC_H +#define _ATH79_DEV_WMAC_H + +void ath79_register_wmac(u8 *cal_data); + +#endif /* _ATH79_DEV_WMAC_H */ diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c index 7499b0e9df26..6a51ced7a293 100644 --- a/arch/mips/ath79/early_printk.c +++ b/arch/mips/ath79/early_printk.c @@ -1,7 +1,7 @@ /* - * Atheros AR71XX/AR724X/AR913X SoC early printk support + * Atheros AR7XXX/AR9XXX SoC early printk support * - * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> * * This program is free software; you can redistribute it and/or modify it @@ -10,27 +10,85 @@ */ #include <linux/io.h> +#include <linux/errno.h> #include <linux/serial_reg.h> #include <asm/addrspace.h> +#include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ar71xx_regs.h> +#include <asm/mach-ath79/ar933x_uart.h> -static inline void prom_wait_thre(void __iomem *base) +static void (*_prom_putchar) (unsigned char); + +static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val) { - u32 lsr; + u32 t; do { - lsr = __raw_readl(base + UART_LSR * 4); - if (lsr & UART_LSR_THRE) + t = __raw_readl(reg); + if ((t & mask) == val) break; } while (1); } -void prom_putchar(unsigned char ch) +static void prom_putchar_ar71xx(unsigned char ch) { void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE)); - prom_wait_thre(base); + prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE); __raw_writel(ch, base + UART_TX * 4); - prom_wait_thre(base); + prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE); +} + +static void prom_putchar_ar933x(unsigned char ch) +{ + void __iomem *base = (void __iomem *)(KSEG1ADDR(AR933X_UART_BASE)); + + prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR, + AR933X_UART_DATA_TX_CSR); + __raw_writel(AR933X_UART_DATA_TX_CSR | ch, base + AR933X_UART_DATA_REG); + prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR, + AR933X_UART_DATA_TX_CSR); +} + +static void prom_putchar_dummy(unsigned char ch) +{ + /* nothing to do */ +} + +static void prom_putchar_init(void) +{ + void __iomem *base; + u32 id; + + base = (void __iomem *)(KSEG1ADDR(AR71XX_RESET_BASE)); + id = __raw_readl(base + AR71XX_RESET_REG_REV_ID); + id &= REV_ID_MAJOR_MASK; + + switch (id) { + case REV_ID_MAJOR_AR71XX: + case REV_ID_MAJOR_AR7240: + case REV_ID_MAJOR_AR7241: + case REV_ID_MAJOR_AR7242: + case REV_ID_MAJOR_AR913X: + _prom_putchar = prom_putchar_ar71xx; + break; + + case REV_ID_MAJOR_AR9330: + case REV_ID_MAJOR_AR9331: + _prom_putchar = prom_putchar_ar933x; + break; + + default: + _prom_putchar = prom_putchar_dummy; + break; + } +} + +void prom_putchar(unsigned char ch) +{ + if (!_prom_putchar) + prom_putchar_init(); + + _prom_putchar(ch); } diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c index a0c426b82123..a2f8ca630ed6 100644 --- a/arch/mips/ath79/gpio.c +++ b/arch/mips/ath79/gpio.c @@ -153,6 +153,8 @@ void __init ath79_gpio_init(void) ath79_gpio_count = AR724X_GPIO_COUNT; else if (soc_is_ar913x()) ath79_gpio_count = AR913X_GPIO_COUNT; + else if (soc_is_ar933x()) + ath79_gpio_count = AR933X_GPIO_COUNT; else BUG(); diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index ac610d5fe3ba..1b073de44680 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -46,6 +46,15 @@ static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) else if (pending & MISC_INT_TIMER) generic_handle_irq(ATH79_MISC_IRQ_TIMER); + else if (pending & MISC_INT_TIMER2) + generic_handle_irq(ATH79_MISC_IRQ_TIMER2); + + else if (pending & MISC_INT_TIMER3) + generic_handle_irq(ATH79_MISC_IRQ_TIMER3); + + else if (pending & MISC_INT_TIMER4) + generic_handle_irq(ATH79_MISC_IRQ_TIMER4); + else if (pending & MISC_INT_OHCI) generic_handle_irq(ATH79_MISC_IRQ_OHCI); @@ -58,6 +67,9 @@ static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) else if (pending & MISC_INT_WDOG) generic_handle_irq(ATH79_MISC_IRQ_WDOG); + else if (pending & MISC_INT_ETHSW) + generic_handle_irq(ATH79_MISC_IRQ_ETHSW); + else spurious_interrupt(); } @@ -117,7 +129,7 @@ static void __init ath79_misc_irq_init(void) if (soc_is_ar71xx() || soc_is_ar913x()) ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; - else if (soc_is_ar724x()) + else if (soc_is_ar724x() || soc_is_ar933x()) ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; else BUG(); @@ -174,6 +186,9 @@ void __init arch_init_irq(void) } else if (soc_is_ar913x()) { ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC; ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB; + } else if (soc_is_ar933x()) { + ath79_ip2_flush_reg = AR933X_DDR_REG_FLUSH_WMAC; + ath79_ip3_flush_reg = AR933X_DDR_REG_FLUSH_USB; } else BUG(); diff --git a/arch/mips/ath79/mach-ap121.c b/arch/mips/ath79/mach-ap121.c new file mode 100644 index 000000000000..4c20200d7c72 --- /dev/null +++ b/arch/mips/ath79/mach-ap121.c @@ -0,0 +1,92 @@ +/* + * Atheros AP121 board support + * + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * + * 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 "machtypes.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-spi.h" +#include "dev-usb.h" +#include "dev-wmac.h" + +#define AP121_GPIO_LED_WLAN 0 +#define AP121_GPIO_LED_USB 1 + +#define AP121_GPIO_BTN_JUMPSTART 11 +#define AP121_GPIO_BTN_RESET 12 + +#define AP121_KEYS_POLL_INTERVAL 20 /* msecs */ +#define AP121_KEYS_DEBOUNCE_INTERVAL (3 * AP121_KEYS_POLL_INTERVAL) + +#define AP121_CAL_DATA_ADDR 0x1fff1000 + +static struct gpio_led ap121_leds_gpio[] __initdata = { + { + .name = "ap121:green:usb", + .gpio = AP121_GPIO_LED_USB, + .active_low = 0, + }, + { + .name = "ap121:green:wlan", + .gpio = AP121_GPIO_LED_WLAN, + .active_low = 0, + }, +}; + +static struct gpio_keys_button ap121_gpio_keys[] __initdata = { + { + .desc = "jumpstart button", + .type = EV_KEY, + .code = KEY_WPS_BUTTON, + .debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL, + .gpio = AP121_GPIO_BTN_JUMPSTART, + .active_low = 1, + }, + { + .desc = "reset button", + .type = EV_KEY, + .code = KEY_RESTART, + .debounce_interval = AP121_KEYS_DEBOUNCE_INTERVAL, + .gpio = AP121_GPIO_BTN_RESET, + .active_low = 1, + } +}; + +static struct spi_board_info ap121_spi_info[] = { + { + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 25000000, + .modalias = "mx25l1606e", + } +}; + +static struct ath79_spi_platform_data ap121_spi_data = { + .bus_num = 0, + .num_chipselect = 1, +}; + +static void __init ap121_setup(void) +{ + u8 *cal_data = (u8 *) KSEG1ADDR(AP121_CAL_DATA_ADDR); + + ath79_register_leds_gpio(-1, ARRAY_SIZE(ap121_leds_gpio), + ap121_leds_gpio); + ath79_register_gpio_keys_polled(-1, AP121_KEYS_POLL_INTERVAL, + ARRAY_SIZE(ap121_gpio_keys), + ap121_gpio_keys); + + ath79_register_spi(&ap121_spi_data, ap121_spi_info, + ARRAY_SIZE(ap121_spi_info)); + ath79_register_usb(); + ath79_register_wmac(cal_data); +} + +MIPS_MACHINE(ATH79_MACH_AP121, "AP121", "Atheros AP121 reference board", + ap121_setup); diff --git a/arch/mips/ath79/mach-ap81.c b/arch/mips/ath79/mach-ap81.c index eee4c121deb4..abe19836331c 100644 --- a/arch/mips/ath79/mach-ap81.c +++ b/arch/mips/ath79/mach-ap81.c @@ -10,10 +10,11 @@ */ #include "machtypes.h" -#include "dev-ar913x-wmac.h" +#include "dev-wmac.h" #include "dev-gpio-buttons.h" #include "dev-leds-gpio.h" #include "dev-spi.h" +#include "dev-usb.h" #define AP81_GPIO_LED_STATUS 1 #define AP81_GPIO_LED_AOSS 3 @@ -91,7 +92,8 @@ static void __init ap81_setup(void) ap81_gpio_keys); ath79_register_spi(&ap81_spi_data, ap81_spi_info, ARRAY_SIZE(ap81_spi_info)); - ath79_register_ar913x_wmac(cal_data); + ath79_register_wmac(cal_data); + ath79_register_usb(); } MIPS_MACHINE(ATH79_MACH_AP81, "AP81", "Atheros AP81 reference board", diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c index ec7b7a135d53..fe9701a32291 100644 --- a/arch/mips/ath79/mach-pb44.c +++ b/arch/mips/ath79/mach-pb44.c @@ -18,6 +18,7 @@ #include "dev-gpio-buttons.h" #include "dev-leds-gpio.h" #include "dev-spi.h" +#include "dev-usb.h" #define PB44_GPIO_I2C_SCL 0 #define PB44_GPIO_I2C_SDA 1 @@ -112,6 +113,7 @@ static void __init pb44_init(void) pb44_gpio_keys); ath79_register_spi(&pb44_spi_data, pb44_spi_info, ARRAY_SIZE(pb44_spi_info)); + ath79_register_usb(); } MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board", diff --git a/arch/mips/ath79/mach-ubnt-xm.c b/arch/mips/ath79/mach-ubnt-xm.c new file mode 100644 index 000000000000..3c311a539347 --- /dev/null +++ b/arch/mips/ath79/mach-ubnt-xm.c @@ -0,0 +1,119 @@ +/* + * Ubiquiti Networks XM (rev 1.0) board support + * + * Copyright (C) 2011 RenĂ© Bolldorf <xsecute@googlemail.com> + * + * Derived from: mach-pb44.c + * + * 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 <linux/init.h> +#include <linux/pci.h> + +#ifdef CONFIG_PCI +#include <linux/ath9k_platform.h> +#include <asm/mach-ath79/pci-ath724x.h> +#endif /* CONFIG_PCI */ + +#include "machtypes.h" +#include "dev-gpio-buttons.h" +#include "dev-leds-gpio.h" +#include "dev-spi.h" + +#define UBNT_XM_GPIO_LED_L1 0 +#define UBNT_XM_GPIO_LED_L2 1 +#define UBNT_XM_GPIO_LED_L3 11 +#define UBNT_XM_GPIO_LED_L4 7 + +#define UBNT_XM_GPIO_BTN_RESET 12 + +#define UBNT_XM_KEYS_POLL_INTERVAL 20 +#define UBNT_XM_KEYS_DEBOUNCE_INTERVAL (3 * UBNT_XM_KEYS_POLL_INTERVAL) + +#define UBNT_XM_PCI_IRQ 48 +#define UBNT_XM_EEPROM_ADDR (u8 *) KSEG1ADDR(0x1fff1000) + +static struct gpio_led ubnt_xm_leds_gpio[] __initdata = { + { + .name = "ubnt-xm:red:link1", + .gpio = UBNT_XM_GPIO_LED_L1, + .active_low = 0, + }, { + .name = "ubnt-xm:orange:link2", + .gpio = UBNT_XM_GPIO_LED_L2, + .active_low = 0, + }, { + .name = "ubnt-xm:green:link3", + .gpio = UBNT_XM_GPIO_LED_L3, + .active_low = 0, + }, { + .name = "ubnt-xm:green:link4", + .gpio = UBNT_XM_GPIO_LED_L4, + .active_low = 0, + }, +}; + +static struct gpio_keys_button ubnt_xm_gpio_keys[] __initdata = { + { + .desc = "reset", + .type = EV_KEY, + .code = KEY_RESTART, + .debounce_interval = UBNT_XM_KEYS_DEBOUNCE_INTERVAL, + .gpio = UBNT_XM_GPIO_BTN_RESET, + .active_low = 1, + } +}; + +static struct spi_board_info ubnt_xm_spi_info[] = { + { + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 25000000, + .modalias = "mx25l6405d", + } +}; + +static struct ath79_spi_platform_data ubnt_xm_spi_data = { + .bus_num = 0, + .num_chipselect = 1, +}; + +#ifdef CONFIG_PCI +static struct ath9k_platform_data ubnt_xm_eeprom_data; + +static struct ath724x_pci_data ubnt_xm_pci_data[] = { + { + .irq = UBNT_XM_PCI_IRQ, + .pdata = &ubnt_xm_eeprom_data, + }, +}; +#endif /* CONFIG_PCI */ + +static void __init ubnt_xm_init(void) +{ + ath79_register_leds_gpio(-1, ARRAY_SIZE(ubnt_xm_leds_gpio), + ubnt_xm_leds_gpio); + + ath79_register_gpio_keys_polled(-1, UBNT_XM_KEYS_POLL_INTERVAL, + ARRAY_SIZE(ubnt_xm_gpio_keys), + ubnt_xm_gpio_keys); + + ath79_register_spi(&ubnt_xm_spi_data, ubnt_xm_spi_info, + ARRAY_SIZE(ubnt_xm_spi_info)); + +#ifdef CONFIG_PCI + memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, + sizeof(ubnt_xm_eeprom_data.eeprom_data)); + + ath724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); +#endif /* CONFIG_PCI */ + +} + +MIPS_MACHINE(ATH79_MACH_UBNT_XM, + "UBNT-XM", + "Ubiquiti Networks XM (rev 1.0) board", + ubnt_xm_init); diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h index 3940fe470b2d..9a1f3826626e 100644 --- a/arch/mips/ath79/machtypes.h +++ b/arch/mips/ath79/machtypes.h @@ -16,8 +16,10 @@ enum ath79_mach_type { ATH79_MACH_GENERIC = 0, + ATH79_MACH_AP121, /* Atheros AP121 reference board */ ATH79_MACH_AP81, /* Atheros AP81 reference board */ ATH79_MACH_PB44, /* Atheros PB44 reference board */ + ATH79_MACH_UBNT_XM, /* Ubiquiti Networks XM board rev 1.0 */ }; #endif /* _ATH79_MACHTYPE_H */ diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index 159b42f106b0..80a7d4023d7f 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -101,19 +101,31 @@ static void __init ath79_detect_sys_type(void) case REV_ID_MAJOR_AR7240: ath79_soc = ATH79_SOC_AR7240; chip = "7240"; - rev = (id & AR724X_REV_ID_REVISION_MASK); + rev = id & AR724X_REV_ID_REVISION_MASK; break; case REV_ID_MAJOR_AR7241: ath79_soc = ATH79_SOC_AR7241; chip = "7241"; - rev = (id & AR724X_REV_ID_REVISION_MASK); + rev = id & AR724X_REV_ID_REVISION_MASK; break; case REV_ID_MAJOR_AR7242: ath79_soc = ATH79_SOC_AR7242; chip = "7242"; - rev = (id & AR724X_REV_ID_REVISION_MASK); + rev = id & AR724X_REV_ID_REVISION_MASK; + break; + + case REV_ID_MAJOR_AR9330: + ath79_soc = ATH79_SOC_AR9330; + chip = "9330"; + rev = id & AR933X_REV_ID_REVISION_MASK; + break; + + case REV_ID_MAJOR_AR9331: + ath79_soc = ATH79_SOC_AR9331; + chip = "9331"; + rev = id & AR933X_REV_ID_REVISION_MASK; break; case REV_ID_MAJOR_AR913X: @@ -134,9 +146,11 @@ static void __init ath79_detect_sys_type(void) break; default: - panic("ath79: unknown SoC, id:0x%08x\n", id); + panic("ath79: unknown SoC, id:0x%08x", id); } + ath79_soc_rev = rev; + sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev); pr_info("SoC: %s\n", ath79_sys_type); } diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 1cfdda03546a..aab6b0c40a75 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -289,7 +289,7 @@ static void __init bcm47xx_register_ssb(void) err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE, bcm47xx_get_invariants); if (err) - panic("Failed to initialize SSB bus (err %d)\n", err); + panic("Failed to initialize SSB bus (err %d)", err); mcore = &bcm47xx_bus.ssb.mipscore; if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) { @@ -314,7 +314,7 @@ static void __init bcm47xx_register_bcma(void) err = bcma_host_soc_register(&bcm47xx_bus.bcma); if (err) - panic("Failed to initialize BCMA bus (err %d)\n", err); + panic("Failed to initialize BCMA bus (err %d)", err); } #endif diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig index fb177d6df066..6b1b9ad8d857 100644 --- a/arch/mips/bcm63xx/Kconfig +++ b/arch/mips/bcm63xx/Kconfig @@ -20,6 +20,10 @@ config BCM63XX_CPU_6348 config BCM63XX_CPU_6358 bool "support 6358 CPU" select HW_HAS_PCI + +config BCM63XX_CPU_6368 + bool "support 6368 CPU" + select HW_HAS_PCI endmenu source "arch/mips/bcm63xx/boards/Kconfig" diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index c22385400fc9..2f1773f3fb7a 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -709,15 +709,9 @@ void __init board_prom_init(void) char cfe_version[32]; u32 val; - /* read base address of boot chip select (0) - * 6345 does not have MPI but boots from standard - * MIPS Flash address */ - if (BCMCPU_IS_6345()) - val = 0x1fc00000; - else { - val = bcm_mpi_readl(MPI_CSBASE_REG(0)); - val &= MPI_CSBASE_BASE_MASK; - } + /* read base address of boot chip select (0) */ + val = bcm_mpi_readl(MPI_CSBASE_REG(0)); + val &= MPI_CSBASE_BASE_MASK; boot_addr = (u8 *)KSEG1ADDR(val); /* dump cfe version */ @@ -797,18 +791,6 @@ void __init board_prom_init(void) } bcm_gpio_writel(val, GPIO_MODE_REG); - - /* Generate MAC address for WLAN and - * register our SPROM */ -#ifdef CONFIG_SSB_PCIHOST - if (!board_get_mac_address(bcm63xx_sprom.il0mac)) { - memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); - memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); - if (ssb_arch_register_fallback_sprom( - &bcm63xx_get_fallback_sprom) < 0) - printk(KERN_ERR PFX "failed to register fallback SPROM\n"); - } -#endif } /* @@ -895,13 +877,23 @@ int __init board_register_devices(void) if (board.has_dsp) bcm63xx_dsp_register(&board.dsp); - /* read base address of boot chip select (0) */ - if (BCMCPU_IS_6345()) - val = 0x1fc00000; - else { - val = bcm_mpi_readl(MPI_CSBASE_REG(0)); - val &= MPI_CSBASE_BASE_MASK; + /* Generate MAC address for WLAN and register our SPROM, + * do this after registering enet devices + */ +#ifdef CONFIG_SSB_PCIHOST + if (!board_get_mac_address(bcm63xx_sprom.il0mac)) { + memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); + memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); + if (ssb_arch_register_fallback_sprom( + &bcm63xx_get_fallback_sprom) < 0) + pr_err(PFX "failed to register fallback SPROM\n"); } +#endif + + /* read base address of boot chip select (0) */ + val = bcm_mpi_readl(MPI_CSBASE_REG(0)); + val &= MPI_CSBASE_BASE_MASK; + mtd_resources[0].start = val; mtd_resources[0].end = 0x1FFFFFFF; diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c index 2c68ee9ccee2..9d57c71b7b58 100644 --- a/arch/mips/bcm63xx/clk.c +++ b/arch/mips/bcm63xx/clk.c @@ -10,6 +10,7 @@ #include <linux/mutex.h> #include <linux/err.h> #include <linux/clk.h> +#include <linux/delay.h> #include <bcm63xx_cpu.h> #include <bcm63xx_io.h> #include <bcm63xx_regs.h> @@ -113,6 +114,34 @@ static struct clk clk_ephy = { }; /* + * Ethernet switch clock + */ +static void enetsw_set(struct clk *clk, int enable) +{ + if (!BCMCPU_IS_6368()) + return; + bcm_hwclock_set(CKCTL_6368_ROBOSW_CLK_EN | + CKCTL_6368_SWPKT_USB_EN | + CKCTL_6368_SWPKT_SAR_EN, enable); + if (enable) { + u32 val; + + /* reset switch core afer clock change */ + val = bcm_perf_readl(PERF_SOFTRESET_6368_REG); + val &= ~SOFTRESET_6368_ENETSW_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6368_REG); + msleep(10); + val |= SOFTRESET_6368_ENETSW_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6368_REG); + msleep(10); + } +} + +static struct clk clk_enetsw = { + .set = enetsw_set, +}; + +/* * PCM clock */ static void pcm_set(struct clk *clk, int enable) @@ -131,9 +160,10 @@ static struct clk clk_pcm = { */ static void usbh_set(struct clk *clk, int enable) { - if (!BCMCPU_IS_6348()) - return; - bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); + if (BCMCPU_IS_6348()) + bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); + else if (BCMCPU_IS_6368()) + bcm_hwclock_set(CKCTL_6368_USBH_CLK_EN, enable); } static struct clk clk_usbh = { @@ -162,6 +192,36 @@ static struct clk clk_spi = { }; /* + * XTM clock + */ +static void xtm_set(struct clk *clk, int enable) +{ + if (!BCMCPU_IS_6368()) + return; + + bcm_hwclock_set(CKCTL_6368_SAR_CLK_EN | + CKCTL_6368_SWPKT_SAR_EN, enable); + + if (enable) { + u32 val; + + /* reset sar core afer clock change */ + val = bcm_perf_readl(PERF_SOFTRESET_6368_REG); + val &= ~SOFTRESET_6368_SAR_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6368_REG); + mdelay(1); + val |= SOFTRESET_6368_SAR_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6368_REG); + mdelay(1); + } +} + + +static struct clk clk_xtm = { + .set = xtm_set, +}; + +/* * Internal peripheral clock */ static struct clk clk_periph = { @@ -204,12 +264,16 @@ struct clk *clk_get(struct device *dev, const char *id) return &clk_enet0; if (!strcmp(id, "enet1")) return &clk_enet1; + if (!strcmp(id, "enetsw")) + return &clk_enetsw; if (!strcmp(id, "ephy")) return &clk_ephy; if (!strcmp(id, "usbh")) return &clk_usbh; if (!strcmp(id, "spi")) return &clk_spi; + if (!strcmp(id, "xtm")) + return &clk_xtm; if (!strcmp(id, "periph")) return &clk_periph; if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c index 7c7e4d4486ce..8f0d6c7725ea 100644 --- a/arch/mips/bcm63xx/cpu.c +++ b/arch/mips/bcm63xx/cpu.c @@ -29,166 +29,47 @@ static u16 bcm63xx_cpu_rev; static unsigned int bcm63xx_cpu_freq; static unsigned int bcm63xx_memory_size; -/* - * 6338 register sets and irqs - */ -static const unsigned long bcm96338_regs_base[] = { - [RSET_DSL_LMEM] = BCM_6338_DSL_LMEM_BASE, - [RSET_PERF] = BCM_6338_PERF_BASE, - [RSET_TIMER] = BCM_6338_TIMER_BASE, - [RSET_WDT] = BCM_6338_WDT_BASE, - [RSET_UART0] = BCM_6338_UART0_BASE, - [RSET_UART1] = BCM_6338_UART1_BASE, - [RSET_GPIO] = BCM_6338_GPIO_BASE, - [RSET_SPI] = BCM_6338_SPI_BASE, - [RSET_OHCI0] = BCM_6338_OHCI0_BASE, - [RSET_OHCI_PRIV] = BCM_6338_OHCI_PRIV_BASE, - [RSET_USBH_PRIV] = BCM_6338_USBH_PRIV_BASE, - [RSET_UDC0] = BCM_6338_UDC0_BASE, - [RSET_MPI] = BCM_6338_MPI_BASE, - [RSET_PCMCIA] = BCM_6338_PCMCIA_BASE, - [RSET_SDRAM] = BCM_6338_SDRAM_BASE, - [RSET_DSL] = BCM_6338_DSL_BASE, - [RSET_ENET0] = BCM_6338_ENET0_BASE, - [RSET_ENET1] = BCM_6338_ENET1_BASE, - [RSET_ENETDMA] = BCM_6338_ENETDMA_BASE, - [RSET_MEMC] = BCM_6338_MEMC_BASE, - [RSET_DDR] = BCM_6338_DDR_BASE, +static const unsigned long bcm6338_regs_base[] = { + __GEN_CPU_REGS_TABLE(6338) }; -static const int bcm96338_irqs[] = { - [IRQ_TIMER] = BCM_6338_TIMER_IRQ, - [IRQ_UART0] = BCM_6338_UART0_IRQ, - [IRQ_DSL] = BCM_6338_DSL_IRQ, - [IRQ_ENET0] = BCM_6338_ENET0_IRQ, - [IRQ_ENET_PHY] = BCM_6338_ENET_PHY_IRQ, - [IRQ_ENET0_RXDMA] = BCM_6338_ENET0_RXDMA_IRQ, - [IRQ_ENET0_TXDMA] = BCM_6338_ENET0_TXDMA_IRQ, +static const int bcm6338_irqs[] = { + __GEN_CPU_IRQ_TABLE(6338) }; -/* - * 6345 register sets and irqs - */ -static const unsigned long bcm96345_regs_base[] = { - [RSET_DSL_LMEM] = BCM_6345_DSL_LMEM_BASE, - [RSET_PERF] = BCM_6345_PERF_BASE, - [RSET_TIMER] = BCM_6345_TIMER_BASE, - [RSET_WDT] = BCM_6345_WDT_BASE, - [RSET_UART0] = BCM_6345_UART0_BASE, - [RSET_UART1] = BCM_6345_UART1_BASE, - [RSET_GPIO] = BCM_6345_GPIO_BASE, - [RSET_SPI] = BCM_6345_SPI_BASE, - [RSET_UDC0] = BCM_6345_UDC0_BASE, - [RSET_OHCI0] = BCM_6345_OHCI0_BASE, - [RSET_OHCI_PRIV] = BCM_6345_OHCI_PRIV_BASE, - [RSET_USBH_PRIV] = BCM_6345_USBH_PRIV_BASE, - [RSET_MPI] = BCM_6345_MPI_BASE, - [RSET_PCMCIA] = BCM_6345_PCMCIA_BASE, - [RSET_DSL] = BCM_6345_DSL_BASE, - [RSET_ENET0] = BCM_6345_ENET0_BASE, - [RSET_ENET1] = BCM_6345_ENET1_BASE, - [RSET_ENETDMA] = BCM_6345_ENETDMA_BASE, - [RSET_EHCI0] = BCM_6345_EHCI0_BASE, - [RSET_SDRAM] = BCM_6345_SDRAM_BASE, - [RSET_MEMC] = BCM_6345_MEMC_BASE, - [RSET_DDR] = BCM_6345_DDR_BASE, +static const unsigned long bcm6345_regs_base[] = { + __GEN_CPU_REGS_TABLE(6345) }; -static const int bcm96345_irqs[] = { - [IRQ_TIMER] = BCM_6345_TIMER_IRQ, - [IRQ_UART0] = BCM_6345_UART0_IRQ, - [IRQ_DSL] = BCM_6345_DSL_IRQ, - [IRQ_ENET0] = BCM_6345_ENET0_IRQ, - [IRQ_ENET_PHY] = BCM_6345_ENET_PHY_IRQ, - [IRQ_ENET0_RXDMA] = BCM_6345_ENET0_RXDMA_IRQ, - [IRQ_ENET0_TXDMA] = BCM_6345_ENET0_TXDMA_IRQ, +static const int bcm6345_irqs[] = { + __GEN_CPU_IRQ_TABLE(6345) }; -/* - * 6348 register sets and irqs - */ -static const unsigned long bcm96348_regs_base[] = { - [RSET_DSL_LMEM] = BCM_6348_DSL_LMEM_BASE, - [RSET_PERF] = BCM_6348_PERF_BASE, - [RSET_TIMER] = BCM_6348_TIMER_BASE, - [RSET_WDT] = BCM_6348_WDT_BASE, - [RSET_UART0] = BCM_6348_UART0_BASE, - [RSET_UART1] = BCM_6348_UART1_BASE, - [RSET_GPIO] = BCM_6348_GPIO_BASE, - [RSET_SPI] = BCM_6348_SPI_BASE, - [RSET_OHCI0] = BCM_6348_OHCI0_BASE, - [RSET_OHCI_PRIV] = BCM_6348_OHCI_PRIV_BASE, - [RSET_USBH_PRIV] = BCM_6348_USBH_PRIV_BASE, - [RSET_MPI] = BCM_6348_MPI_BASE, - [RSET_PCMCIA] = BCM_6348_PCMCIA_BASE, - [RSET_SDRAM] = BCM_6348_SDRAM_BASE, - [RSET_DSL] = BCM_6348_DSL_BASE, - [RSET_ENET0] = BCM_6348_ENET0_BASE, - [RSET_ENET1] = BCM_6348_ENET1_BASE, - [RSET_ENETDMA] = BCM_6348_ENETDMA_BASE, - [RSET_MEMC] = BCM_6348_MEMC_BASE, - [RSET_DDR] = BCM_6348_DDR_BASE, +static const unsigned long bcm6348_regs_base[] = { + __GEN_CPU_REGS_TABLE(6348) }; -static const int bcm96348_irqs[] = { - [IRQ_TIMER] = BCM_6348_TIMER_IRQ, - [IRQ_UART0] = BCM_6348_UART0_IRQ, - [IRQ_DSL] = BCM_6348_DSL_IRQ, - [IRQ_ENET0] = BCM_6348_ENET0_IRQ, - [IRQ_ENET1] = BCM_6348_ENET1_IRQ, - [IRQ_ENET_PHY] = BCM_6348_ENET_PHY_IRQ, - [IRQ_OHCI0] = BCM_6348_OHCI0_IRQ, - [IRQ_PCMCIA] = BCM_6348_PCMCIA_IRQ, - [IRQ_ENET0_RXDMA] = BCM_6348_ENET0_RXDMA_IRQ, - [IRQ_ENET0_TXDMA] = BCM_6348_ENET0_TXDMA_IRQ, - [IRQ_ENET1_RXDMA] = BCM_6348_ENET1_RXDMA_IRQ, - [IRQ_ENET1_TXDMA] = BCM_6348_ENET1_TXDMA_IRQ, - [IRQ_PCI] = BCM_6348_PCI_IRQ, +static const int bcm6348_irqs[] = { + __GEN_CPU_IRQ_TABLE(6348) + }; -/* - * 6358 register sets and irqs - */ -static const unsigned long bcm96358_regs_base[] = { - [RSET_DSL_LMEM] = BCM_6358_DSL_LMEM_BASE, - [RSET_PERF] = BCM_6358_PERF_BASE, - [RSET_TIMER] = BCM_6358_TIMER_BASE, - [RSET_WDT] = BCM_6358_WDT_BASE, - [RSET_UART0] = BCM_6358_UART0_BASE, - [RSET_UART1] = BCM_6358_UART1_BASE, - [RSET_GPIO] = BCM_6358_GPIO_BASE, - [RSET_SPI] = BCM_6358_SPI_BASE, - [RSET_OHCI0] = BCM_6358_OHCI0_BASE, - [RSET_EHCI0] = BCM_6358_EHCI0_BASE, - [RSET_OHCI_PRIV] = BCM_6358_OHCI_PRIV_BASE, - [RSET_USBH_PRIV] = BCM_6358_USBH_PRIV_BASE, - [RSET_MPI] = BCM_6358_MPI_BASE, - [RSET_PCMCIA] = BCM_6358_PCMCIA_BASE, - [RSET_SDRAM] = BCM_6358_SDRAM_BASE, - [RSET_DSL] = BCM_6358_DSL_BASE, - [RSET_ENET0] = BCM_6358_ENET0_BASE, - [RSET_ENET1] = BCM_6358_ENET1_BASE, - [RSET_ENETDMA] = BCM_6358_ENETDMA_BASE, - [RSET_MEMC] = BCM_6358_MEMC_BASE, - [RSET_DDR] = BCM_6358_DDR_BASE, +static const unsigned long bcm6358_regs_base[] = { + __GEN_CPU_REGS_TABLE(6358) +}; + +static const int bcm6358_irqs[] = { + __GEN_CPU_IRQ_TABLE(6358) + }; -static const int bcm96358_irqs[] = { - [IRQ_TIMER] = BCM_6358_TIMER_IRQ, - [IRQ_UART0] = BCM_6358_UART0_IRQ, - [IRQ_UART1] = BCM_6358_UART1_IRQ, - [IRQ_DSL] = BCM_6358_DSL_IRQ, - [IRQ_ENET0] = BCM_6358_ENET0_IRQ, - [IRQ_ENET1] = BCM_6358_ENET1_IRQ, - [IRQ_ENET_PHY] = BCM_6358_ENET_PHY_IRQ, - [IRQ_OHCI0] = BCM_6358_OHCI0_IRQ, - [IRQ_EHCI0] = BCM_6358_EHCI0_IRQ, - [IRQ_PCMCIA] = BCM_6358_PCMCIA_IRQ, - [IRQ_ENET0_RXDMA] = BCM_6358_ENET0_RXDMA_IRQ, - [IRQ_ENET0_TXDMA] = BCM_6358_ENET0_TXDMA_IRQ, - [IRQ_ENET1_RXDMA] = BCM_6358_ENET1_RXDMA_IRQ, - [IRQ_ENET1_TXDMA] = BCM_6358_ENET1_TXDMA_IRQ, - [IRQ_PCI] = BCM_6358_PCI_IRQ, +static const unsigned long bcm6368_regs_base[] = { + __GEN_CPU_REGS_TABLE(6368) +}; + +static const int bcm6368_irqs[] = { + __GEN_CPU_IRQ_TABLE(6368) + }; u16 __bcm63xx_get_cpu_id(void) @@ -217,20 +98,19 @@ unsigned int bcm63xx_get_memory_size(void) static unsigned int detect_cpu_clock(void) { - unsigned int tmp, n1 = 0, n2 = 0, m1 = 0; - - /* BCM6338 has a fixed 240 Mhz frequency */ - if (BCMCPU_IS_6338()) + switch (bcm63xx_get_cpu_id()) { + case BCM6338_CPU_ID: + /* BCM6338 has a fixed 240 Mhz frequency */ return 240000000; - /* BCM6345 has a fixed 140Mhz frequency */ - if (BCMCPU_IS_6345()) + case BCM6345_CPU_ID: + /* BCM6345 has a fixed 140Mhz frequency */ return 140000000; - /* - * frequency depends on PLL configuration: - */ - if (BCMCPU_IS_6348()) { + case BCM6348_CPU_ID: + { + unsigned int tmp, n1, n2, m1; + /* 16MHz * (N1 + 1) * (N2 + 2) / (M1_CPU + 1) */ tmp = bcm_perf_readl(PERF_MIPSPLLCTL_REG); n1 = (tmp & MIPSPLLCTL_N1_MASK) >> MIPSPLLCTL_N1_SHIFT; @@ -239,17 +119,47 @@ static unsigned int detect_cpu_clock(void) n1 += 1; n2 += 2; m1 += 1; + return (16 * 1000000 * n1 * n2) / m1; } - if (BCMCPU_IS_6358()) { + case BCM6358_CPU_ID: + { + unsigned int tmp, n1, n2, m1; + /* 16MHz * N1 * N2 / M1_CPU */ tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_REG); n1 = (tmp & DMIPSPLLCFG_N1_MASK) >> DMIPSPLLCFG_N1_SHIFT; n2 = (tmp & DMIPSPLLCFG_N2_MASK) >> DMIPSPLLCFG_N2_SHIFT; m1 = (tmp & DMIPSPLLCFG_M1_MASK) >> DMIPSPLLCFG_M1_SHIFT; + return (16 * 1000000 * n1 * n2) / m1; } - return (16 * 1000000 * n1 * n2) / m1; + case BCM6368_CPU_ID: + { + unsigned int tmp, p1, p2, ndiv, m1; + + /* (64MHz / P1) * P2 * NDIV / M1_CPU */ + tmp = bcm_ddr_readl(DDR_DMIPSPLLCFG_6368_REG); + + p1 = (tmp & DMIPSPLLCFG_6368_P1_MASK) >> + DMIPSPLLCFG_6368_P1_SHIFT; + + p2 = (tmp & DMIPSPLLCFG_6368_P2_MASK) >> + DMIPSPLLCFG_6368_P2_SHIFT; + + ndiv = (tmp & DMIPSPLLCFG_6368_NDIV_MASK) >> + DMIPSPLLCFG_6368_NDIV_SHIFT; + + tmp = bcm_ddr_readl(DDR_DMIPSPLLDIV_6368_REG); + m1 = (tmp & DMIPSPLLDIV_6368_MDIV_MASK) >> + DMIPSPLLDIV_6368_MDIV_SHIFT; + + return (((64 * 1000000) / p1) * p2 * ndiv) / m1; + } + + default: + BUG(); + } } /* @@ -260,8 +170,10 @@ static unsigned int detect_memory_size(void) unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0; u32 val; - if (BCMCPU_IS_6345()) - return (8 * 1024 * 1024); + if (BCMCPU_IS_6345()) { + val = bcm_sdram_readl(SDRAM_MBASE_REG); + return (val * 8 * 1024 * 1024); + } if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) { val = bcm_sdram_readl(SDRAM_CFG_REG); @@ -271,7 +183,7 @@ static unsigned int detect_memory_size(void) banks = (val & SDRAM_CFG_BANK_MASK) ? 2 : 1; } - if (BCMCPU_IS_6358()) { + if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) { val = bcm_memc_readl(MEMC_CFG_REG); rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT; cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT; @@ -301,24 +213,33 @@ void __init bcm63xx_cpu_init(void) case CPU_BMIPS3300: if ((read_c0_prid() & 0xff00) == PRID_IMP_BMIPS3300_ALT) { expected_cpu_id = BCM6348_CPU_ID; - bcm63xx_regs_base = bcm96348_regs_base; - bcm63xx_irqs = bcm96348_irqs; + bcm63xx_regs_base = bcm6348_regs_base; + bcm63xx_irqs = bcm6348_irqs; } else { __cpu_name[cpu] = "Broadcom BCM6338"; expected_cpu_id = BCM6338_CPU_ID; - bcm63xx_regs_base = bcm96338_regs_base; - bcm63xx_irqs = bcm96338_irqs; + bcm63xx_regs_base = bcm6338_regs_base; + bcm63xx_irqs = bcm6338_irqs; } break; case CPU_BMIPS32: expected_cpu_id = BCM6345_CPU_ID; - bcm63xx_regs_base = bcm96345_regs_base; - bcm63xx_irqs = bcm96345_irqs; + bcm63xx_regs_base = bcm6345_regs_base; + bcm63xx_irqs = bcm6345_irqs; break; case CPU_BMIPS4350: - expected_cpu_id = BCM6358_CPU_ID; - bcm63xx_regs_base = bcm96358_regs_base; - bcm63xx_irqs = bcm96358_irqs; + switch (read_c0_prid() & 0xf0) { + case 0x10: + expected_cpu_id = BCM6358_CPU_ID; + bcm63xx_regs_base = bcm6358_regs_base; + bcm63xx_irqs = bcm6358_irqs; + break; + case 0x30: + expected_cpu_id = BCM6368_CPU_ID; + bcm63xx_regs_base = bcm6368_regs_base; + bcm63xx_irqs = bcm6368_irqs; + break; + } break; } diff --git a/arch/mips/bcm63xx/dev-uart.c b/arch/mips/bcm63xx/dev-uart.c index c2963da0253e..d6e42c608325 100644 --- a/arch/mips/bcm63xx/dev-uart.c +++ b/arch/mips/bcm63xx/dev-uart.c @@ -54,7 +54,7 @@ int __init bcm63xx_uart_register(unsigned int id) if (id >= ARRAY_SIZE(bcm63xx_uart_devices)) return -ENODEV; - if (id == 1 && !BCMCPU_IS_6358()) + if (id == 1 && (!BCMCPU_IS_6358() && !BCMCPU_IS_6368())) return -ENODEV; if (id == 0) { diff --git a/arch/mips/bcm63xx/gpio.c b/arch/mips/bcm63xx/gpio.c index f560fe7d38dd..a6c2135dbf38 100644 --- a/arch/mips/bcm63xx/gpio.c +++ b/arch/mips/bcm63xx/gpio.c @@ -4,7 +4,7 @@ * for more details. * * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> - * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org> + * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org> */ #include <linux/kernel.h> @@ -18,6 +18,34 @@ #include <bcm63xx_io.h> #include <bcm63xx_regs.h> +#ifndef BCMCPU_RUNTIME_DETECT +#define gpio_out_low_reg GPIO_DATA_LO_REG +#ifdef CONFIG_BCM63XX_CPU_6345 +#ifdef gpio_out_low_reg +#undef gpio_out_low_reg +#define gpio_out_low_reg GPIO_DATA_LO_REG_6345 +#endif /* gpio_out_low_reg */ +#endif /* CONFIG_BCM63XX_CPU_6345 */ + +static inline void bcm63xx_gpio_out_low_reg_init(void) +{ +} +#else /* ! BCMCPU_RUNTIME_DETECT */ +static u32 gpio_out_low_reg; + +static void bcm63xx_gpio_out_low_reg_init(void) +{ + switch (bcm63xx_get_cpu_id()) { + case BCM6345_CPU_ID: + gpio_out_low_reg = GPIO_DATA_LO_REG_6345; + break; + default: + gpio_out_low_reg = GPIO_DATA_LO_REG; + break; + } +} +#endif /* ! BCMCPU_RUNTIME_DETECT */ + static DEFINE_SPINLOCK(bcm63xx_gpio_lock); static u32 gpio_out_low, gpio_out_high; @@ -33,7 +61,7 @@ static void bcm63xx_gpio_set(struct gpio_chip *chip, BUG(); if (gpio < 32) { - reg = GPIO_DATA_LO_REG; + reg = gpio_out_low_reg; mask = 1 << gpio; v = &gpio_out_low; } else { @@ -60,7 +88,7 @@ static int bcm63xx_gpio_get(struct gpio_chip *chip, unsigned gpio) BUG(); if (gpio < 32) { - reg = GPIO_DATA_LO_REG; + reg = gpio_out_low_reg; mask = 1 << gpio; } else { reg = GPIO_DATA_HI_REG; @@ -125,8 +153,11 @@ static struct gpio_chip bcm63xx_gpio_chip = { int __init bcm63xx_gpio_init(void) { - gpio_out_low = bcm_gpio_readl(GPIO_DATA_LO_REG); - gpio_out_high = bcm_gpio_readl(GPIO_DATA_HI_REG); + bcm63xx_gpio_out_low_reg_init(); + + gpio_out_low = bcm_gpio_readl(gpio_out_low_reg); + if (!BCMCPU_IS_6345()) + gpio_out_high = bcm_gpio_readl(GPIO_DATA_HI_REG); bcm63xx_gpio_chip.ngpio = bcm63xx_gpio_count(); pr_info("registering %d GPIOs\n", bcm63xx_gpio_chip.ngpio); diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 162e11b4ed75..9a216a451d92 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -19,19 +19,187 @@ #include <bcm63xx_io.h> #include <bcm63xx_irq.h> +static void __dispatch_internal(void) __maybe_unused; +static void __dispatch_internal_64(void) __maybe_unused; +static void __internal_irq_mask_32(unsigned int irq) __maybe_unused; +static void __internal_irq_mask_64(unsigned int irq) __maybe_unused; +static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused; +static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; + +#ifndef BCMCPU_RUNTIME_DETECT +#ifdef CONFIG_BCM63XX_CPU_6338 +#define irq_stat_reg PERF_IRQSTAT_6338_REG +#define irq_mask_reg PERF_IRQMASK_6338_REG +#define irq_bits 32 +#define is_ext_irq_cascaded 0 +#define ext_irq_start 0 +#define ext_irq_end 0 +#define ext_irq_count 4 +#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6338 +#define ext_irq_cfg_reg2 0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6345 +#define irq_stat_reg PERF_IRQSTAT_6345_REG +#define irq_mask_reg PERF_IRQMASK_6345_REG +#define irq_bits 32 +#define is_ext_irq_cascaded 0 +#define ext_irq_start 0 +#define ext_irq_end 0 +#define ext_irq_count 0 +#define ext_irq_cfg_reg1 0 +#define ext_irq_cfg_reg2 0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6348 +#define irq_stat_reg PERF_IRQSTAT_6348_REG +#define irq_mask_reg PERF_IRQMASK_6348_REG +#define irq_bits 32 +#define is_ext_irq_cascaded 0 +#define ext_irq_start 0 +#define ext_irq_end 0 +#define ext_irq_count 4 +#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6348 +#define ext_irq_cfg_reg2 0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6358 +#define irq_stat_reg PERF_IRQSTAT_6358_REG +#define irq_mask_reg PERF_IRQMASK_6358_REG +#define irq_bits 32 +#define is_ext_irq_cascaded 1 +#define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE) +#define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE) +#define ext_irq_count 4 +#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6358 +#define ext_irq_cfg_reg2 0 +#endif +#ifdef CONFIG_BCM63XX_CPU_6368 +#define irq_stat_reg PERF_IRQSTAT_6368_REG +#define irq_mask_reg PERF_IRQMASK_6368_REG +#define irq_bits 64 +#define is_ext_irq_cascaded 1 +#define ext_irq_start (BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE) +#define ext_irq_end (BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE) +#define ext_irq_count 6 +#define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6368 +#define ext_irq_cfg_reg2 PERF_EXTIRQ_CFG_REG2_6368 +#endif + +#if irq_bits == 32 +#define dispatch_internal __dispatch_internal +#define internal_irq_mask __internal_irq_mask_32 +#define internal_irq_unmask __internal_irq_unmask_32 +#else +#define dispatch_internal __dispatch_internal_64 +#define internal_irq_mask __internal_irq_mask_64 +#define internal_irq_unmask __internal_irq_unmask_64 +#endif + +#define irq_stat_addr (bcm63xx_regset_address(RSET_PERF) + irq_stat_reg) +#define irq_mask_addr (bcm63xx_regset_address(RSET_PERF) + irq_mask_reg) + +static inline void bcm63xx_init_irq(void) +{ +} +#else /* ! BCMCPU_RUNTIME_DETECT */ + +static u32 irq_stat_addr, irq_mask_addr; +static void (*dispatch_internal)(void); +static int is_ext_irq_cascaded; +static unsigned int ext_irq_count; +static unsigned int ext_irq_start, ext_irq_end; +static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; +static void (*internal_irq_mask)(unsigned int irq); +static void (*internal_irq_unmask)(unsigned int irq); + +static void bcm63xx_init_irq(void) +{ + int irq_bits; + + irq_stat_addr = bcm63xx_regset_address(RSET_PERF); + irq_mask_addr = bcm63xx_regset_address(RSET_PERF); + + switch (bcm63xx_get_cpu_id()) { + case BCM6338_CPU_ID: + irq_stat_addr += PERF_IRQSTAT_6338_REG; + irq_mask_addr += PERF_IRQMASK_6338_REG; + irq_bits = 32; + break; + case BCM6345_CPU_ID: + irq_stat_addr += PERF_IRQSTAT_6345_REG; + irq_mask_addr += PERF_IRQMASK_6345_REG; + irq_bits = 32; + break; + case BCM6348_CPU_ID: + irq_stat_addr += PERF_IRQSTAT_6348_REG; + irq_mask_addr += PERF_IRQMASK_6348_REG; + irq_bits = 32; + ext_irq_count = 4; + ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; + break; + case BCM6358_CPU_ID: + irq_stat_addr += PERF_IRQSTAT_6358_REG; + irq_mask_addr += PERF_IRQMASK_6358_REG; + irq_bits = 32; + ext_irq_count = 4; + is_ext_irq_cascaded = 1; + ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; + ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; + ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; + break; + case BCM6368_CPU_ID: + irq_stat_addr += PERF_IRQSTAT_6368_REG; + irq_mask_addr += PERF_IRQMASK_6368_REG; + irq_bits = 64; + ext_irq_count = 6; + is_ext_irq_cascaded = 1; + ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE; + ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE; + ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368; + ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368; + break; + default: + BUG(); + } + + if (irq_bits == 32) { + dispatch_internal = __dispatch_internal; + internal_irq_mask = __internal_irq_mask_32; + internal_irq_unmask = __internal_irq_unmask_32; + } else { + dispatch_internal = __dispatch_internal_64; + internal_irq_mask = __internal_irq_mask_64; + internal_irq_unmask = __internal_irq_unmask_64; + } +} +#endif /* ! BCMCPU_RUNTIME_DETECT */ + +static inline u32 get_ext_irq_perf_reg(int irq) +{ + if (irq < 4) + return ext_irq_cfg_reg1; + return ext_irq_cfg_reg2; +} + +static inline void handle_internal(int intbit) +{ + if (is_ext_irq_cascaded && + intbit >= ext_irq_start && intbit <= ext_irq_end) + do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE); + else + do_IRQ(intbit + IRQ_INTERNAL_BASE); +} + /* * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not * prioritize any interrupt relatively to another. the static counter * will resume the loop where it ended the last time we left this * function. */ -static void bcm63xx_irq_dispatch_internal(void) +static void __dispatch_internal(void) { u32 pending; static int i; - pending = bcm_perf_readl(PERF_IRQMASK_REG) & - bcm_perf_readl(PERF_IRQSTAT_REG); + pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr); if (!pending) return ; @@ -41,7 +209,28 @@ static void bcm63xx_irq_dispatch_internal(void) i = (i + 1) & 0x1f; if (pending & (1 << to_call)) { - do_IRQ(to_call + IRQ_INTERNAL_BASE); + handle_internal(to_call); + break; + } + } +} + +static void __dispatch_internal_64(void) +{ + u64 pending; + static int i; + + pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr); + + if (!pending) + return ; + + while (1) { + int to_call = i; + + i = (i + 1) & 0x3f; + if (pending & (1ull << to_call)) { + handle_internal(to_call); break; } } @@ -60,15 +249,17 @@ asmlinkage void plat_irq_dispatch(void) if (cause & CAUSEF_IP7) do_IRQ(7); if (cause & CAUSEF_IP2) - bcm63xx_irq_dispatch_internal(); - if (cause & CAUSEF_IP3) - do_IRQ(IRQ_EXT_0); - if (cause & CAUSEF_IP4) - do_IRQ(IRQ_EXT_1); - if (cause & CAUSEF_IP5) - do_IRQ(IRQ_EXT_2); - if (cause & CAUSEF_IP6) - do_IRQ(IRQ_EXT_3); + dispatch_internal(); + if (!is_ext_irq_cascaded) { + if (cause & CAUSEF_IP3) + do_IRQ(IRQ_EXT_0); + if (cause & CAUSEF_IP4) + do_IRQ(IRQ_EXT_1); + if (cause & CAUSEF_IP5) + do_IRQ(IRQ_EXT_2); + if (cause & CAUSEF_IP6) + do_IRQ(IRQ_EXT_3); + } } while (1); } @@ -76,24 +267,50 @@ asmlinkage void plat_irq_dispatch(void) * internal IRQs operations: only mask/unmask on PERF irq mask * register. */ -static inline void bcm63xx_internal_irq_mask(struct irq_data *d) +static void __internal_irq_mask_32(unsigned int irq) { - unsigned int irq = d->irq - IRQ_INTERNAL_BASE; u32 mask; - mask = bcm_perf_readl(PERF_IRQMASK_REG); + mask = bcm_readl(irq_mask_addr); mask &= ~(1 << irq); - bcm_perf_writel(mask, PERF_IRQMASK_REG); + bcm_writel(mask, irq_mask_addr); } -static void bcm63xx_internal_irq_unmask(struct irq_data *d) +static void __internal_irq_mask_64(unsigned int irq) +{ + u64 mask; + + mask = bcm_readq(irq_mask_addr); + mask &= ~(1ull << irq); + bcm_writeq(mask, irq_mask_addr); +} + +static void __internal_irq_unmask_32(unsigned int irq) { - unsigned int irq = d->irq - IRQ_INTERNAL_BASE; u32 mask; - mask = bcm_perf_readl(PERF_IRQMASK_REG); + mask = bcm_readl(irq_mask_addr); mask |= (1 << irq); - bcm_perf_writel(mask, PERF_IRQMASK_REG); + bcm_writel(mask, irq_mask_addr); +} + +static void __internal_irq_unmask_64(unsigned int irq) +{ + u64 mask; + + mask = bcm_readq(irq_mask_addr); + mask |= (1ull << irq); + bcm_writeq(mask, irq_mask_addr); +} + +static void bcm63xx_internal_irq_mask(struct irq_data *d) +{ + internal_irq_mask(d->irq - IRQ_INTERNAL_BASE); +} + +static void bcm63xx_internal_irq_unmask(struct irq_data *d) +{ + internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE); } /* @@ -102,94 +319,131 @@ static void bcm63xx_internal_irq_unmask(struct irq_data *d) */ static void bcm63xx_external_irq_mask(struct irq_data *d) { - unsigned int irq = d->irq - IRQ_EXT_BASE; - u32 reg; + unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; + u32 reg, regaddr; - reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); - reg &= ~EXTIRQ_CFG_MASK(irq); - bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); + regaddr = get_ext_irq_perf_reg(irq); + reg = bcm_perf_readl(regaddr); + + if (BCMCPU_IS_6348()) + reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4); + else + reg &= ~EXTIRQ_CFG_MASK(irq % 4); + + bcm_perf_writel(reg, regaddr); + if (is_ext_irq_cascaded) + internal_irq_mask(irq + ext_irq_start); } static void bcm63xx_external_irq_unmask(struct irq_data *d) { - unsigned int irq = d->irq - IRQ_EXT_BASE; - u32 reg; + unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; + u32 reg, regaddr; - reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); - reg |= EXTIRQ_CFG_MASK(irq); - bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); + regaddr = get_ext_irq_perf_reg(irq); + reg = bcm_perf_readl(regaddr); + + if (BCMCPU_IS_6348()) + reg |= EXTIRQ_CFG_MASK_6348(irq % 4); + else + reg |= EXTIRQ_CFG_MASK(irq % 4); + + bcm_perf_writel(reg, regaddr); + + if (is_ext_irq_cascaded) + internal_irq_unmask(irq + ext_irq_start); } static void bcm63xx_external_irq_clear(struct irq_data *d) { - unsigned int irq = d->irq - IRQ_EXT_BASE; - u32 reg; + unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; + u32 reg, regaddr; - reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); - reg |= EXTIRQ_CFG_CLEAR(irq); - bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); -} + regaddr = get_ext_irq_perf_reg(irq); + reg = bcm_perf_readl(regaddr); -static unsigned int bcm63xx_external_irq_startup(struct irq_data *d) -{ - set_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE)); - irq_enable_hazard(); - bcm63xx_external_irq_unmask(d); - return 0; -} + if (BCMCPU_IS_6348()) + reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4); + else + reg |= EXTIRQ_CFG_CLEAR(irq % 4); -static void bcm63xx_external_irq_shutdown(struct irq_data *d) -{ - bcm63xx_external_irq_mask(d); - clear_c0_status(0x100 << (d->irq - IRQ_MIPS_BASE)); - irq_disable_hazard(); + bcm_perf_writel(reg, regaddr); } static int bcm63xx_external_irq_set_type(struct irq_data *d, unsigned int flow_type) { - unsigned int irq = d->irq - IRQ_EXT_BASE; - u32 reg; + unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; + u32 reg, regaddr; + int levelsense, sense, bothedge; flow_type &= IRQ_TYPE_SENSE_MASK; if (flow_type == IRQ_TYPE_NONE) flow_type = IRQ_TYPE_LEVEL_LOW; - reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); + levelsense = sense = bothedge = 0; switch (flow_type) { case IRQ_TYPE_EDGE_BOTH: - reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); - reg |= EXTIRQ_CFG_BOTHEDGE(irq); + bothedge = 1; break; case IRQ_TYPE_EDGE_RISING: - reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); - reg |= EXTIRQ_CFG_SENSE(irq); - reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); + sense = 1; break; case IRQ_TYPE_EDGE_FALLING: - reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); - reg &= ~EXTIRQ_CFG_SENSE(irq); - reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); break; case IRQ_TYPE_LEVEL_HIGH: - reg |= EXTIRQ_CFG_LEVELSENSE(irq); - reg |= EXTIRQ_CFG_SENSE(irq); + levelsense = 1; + sense = 1; break; case IRQ_TYPE_LEVEL_LOW: - reg |= EXTIRQ_CFG_LEVELSENSE(irq); - reg &= ~EXTIRQ_CFG_SENSE(irq); + levelsense = 1; break; default: printk(KERN_ERR "bogus flow type combination given !\n"); return -EINVAL; } - bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); + + regaddr = get_ext_irq_perf_reg(irq); + reg = bcm_perf_readl(regaddr); + irq %= 4; + + if (BCMCPU_IS_6348()) { + if (levelsense) + reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq); + else + reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq); + if (sense) + reg |= EXTIRQ_CFG_SENSE_6348(irq); + else + reg &= ~EXTIRQ_CFG_SENSE_6348(irq); + if (bothedge) + reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq); + else + reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq); + } + + if (BCMCPU_IS_6338() || BCMCPU_IS_6358() || BCMCPU_IS_6368()) { + if (levelsense) + reg |= EXTIRQ_CFG_LEVELSENSE(irq); + else + reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); + if (sense) + reg |= EXTIRQ_CFG_SENSE(irq); + else + reg &= ~EXTIRQ_CFG_SENSE(irq); + if (bothedge) + reg |= EXTIRQ_CFG_BOTHEDGE(irq); + else + reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); + } + + bcm_perf_writel(reg, regaddr); irqd_set_trigger_type(d, flow_type); if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) @@ -208,9 +462,6 @@ static struct irq_chip bcm63xx_internal_irq_chip = { static struct irq_chip bcm63xx_external_irq_chip = { .name = "bcm63xx_epic", - .irq_startup = bcm63xx_external_irq_startup, - .irq_shutdown = bcm63xx_external_irq_shutdown, - .irq_ack = bcm63xx_external_irq_clear, .irq_mask = bcm63xx_external_irq_mask, @@ -225,18 +476,30 @@ static struct irqaction cpu_ip2_cascade_action = { .flags = IRQF_NO_THREAD, }; +static struct irqaction cpu_ext_cascade_action = { + .handler = no_action, + .name = "cascade_extirq", + .flags = IRQF_NO_THREAD, +}; + void __init arch_init_irq(void) { int i; + bcm63xx_init_irq(); mips_cpu_irq_init(); for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i) irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip, handle_level_irq); - for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i) + for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i) irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip, handle_edge_irq); - setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action); + if (!is_ext_irq_cascaded) { + for (i = 3; i < 3 + ext_irq_count; ++i) + setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action); + } + + setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action); } diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c index be252efa0757..99d7f405cbeb 100644 --- a/arch/mips/bcm63xx/prom.c +++ b/arch/mips/bcm63xx/prom.c @@ -32,9 +32,12 @@ void __init prom_init(void) mask = CKCTL_6345_ALL_SAFE_EN; else if (BCMCPU_IS_6348()) mask = CKCTL_6348_ALL_SAFE_EN; - else - /* BCMCPU_IS_6358() */ + else if (BCMCPU_IS_6358()) mask = CKCTL_6358_ALL_SAFE_EN; + else if (BCMCPU_IS_6368()) + mask = CKCTL_6368_ALL_SAFE_EN; + else + mask = 0; reg = bcm_perf_readl(PERF_CKCTL_REG); reg &= ~mask; diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index d0056598fbfc..d209f85d87bb 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -63,13 +63,33 @@ static void bcm6348_a1_reboot(void) void bcm63xx_machine_reboot(void) { - u32 reg; + u32 reg, perf_regs[2] = { 0, 0 }; + unsigned int i; /* mask and clear all external irq */ - reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG); - reg &= ~EXTIRQ_CFG_MASK_ALL; - reg |= EXTIRQ_CFG_CLEAR_ALL; - bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG); + switch (bcm63xx_get_cpu_id()) { + case BCM6338_CPU_ID: + perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338; + break; + case BCM6348_CPU_ID: + perf_regs[0] = PERF_EXTIRQ_CFG_REG_6348; + break; + case BCM6358_CPU_ID: + perf_regs[0] = PERF_EXTIRQ_CFG_REG_6358; + break; + } + + for (i = 0; i < 2; i++) { + reg = bcm_perf_readl(perf_regs[i]); + if (BCMCPU_IS_6348()) { + reg &= ~EXTIRQ_CFG_MASK_ALL_6348; + reg |= EXTIRQ_CFG_CLEAR_ALL_6348; + } else { + reg &= ~EXTIRQ_CFG_MASK_ALL; + reg |= EXTIRQ_CFG_CLEAR_ALL; + } + bcm_perf_writel(reg, perf_regs[i]); + } if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1)) bcm6348_a1_reboot(); @@ -124,4 +144,4 @@ int __init bcm63xx_register_devices(void) return board_register_devices(); } -arch_initcall(bcm63xx_register_devices); +device_initcall(bcm63xx_register_devices); diff --git a/arch/mips/boot/compressed/uart-alchemy.c b/arch/mips/boot/compressed/uart-alchemy.c index eb063e6dead9..3112df8f90db 100644 --- a/arch/mips/boot/compressed/uart-alchemy.c +++ b/arch/mips/boot/compressed/uart-alchemy.c @@ -2,6 +2,9 @@ void putc(char c) { - /* all current (Jan. 2010) in-kernel boards */ +#ifdef CONFIG_MIPS_DB1300 + alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c); +#else alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c); +#endif } diff --git a/arch/mips/cavium-octeon/Kconfig b/arch/mips/cavium-octeon/Kconfig index cad555ebeca3..f9e275a50d98 100644 --- a/arch/mips/cavium-octeon/Kconfig +++ b/arch/mips/cavium-octeon/Kconfig @@ -86,10 +86,6 @@ config ARCH_SPARSEMEM_ENABLE def_bool y select SPARSEMEM_STATIC -config CAVIUM_OCTEON_HELPER - def_bool y - depends on OCTEON_ETHERNET || PCI - config IOMMU_HELPER bool diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c index ea4febaa4bb1..b6bb92c16a47 100644 --- a/arch/mips/cavium-octeon/dma-octeon.c +++ b/arch/mips/cavium-octeon/dma-octeon.c @@ -61,6 +61,16 @@ static phys_addr_t octeon_gen1_dma_to_phys(struct device *dev, dma_addr_t daddr) return daddr; } +static dma_addr_t octeon_gen2_phys_to_dma(struct device *dev, phys_addr_t paddr) +{ + return octeon_hole_phys_to_dma(paddr); +} + +static phys_addr_t octeon_gen2_dma_to_phys(struct device *dev, dma_addr_t daddr) +{ + return octeon_hole_dma_to_phys(daddr); +} + static dma_addr_t octeon_big_phys_to_dma(struct device *dev, phys_addr_t paddr) { if (paddr >= 0x410000000ull && paddr < 0x420000000ull) @@ -262,11 +272,11 @@ void __init plat_swiotlb_setup(void) for (i = 0 ; i < boot_mem_map.nr_map; i++) { struct boot_mem_map_entry *e = &boot_mem_map.map[i]; - if (e->type != BOOT_MEM_RAM) + if (e->type != BOOT_MEM_RAM && e->type != BOOT_MEM_INIT_RAM) continue; /* These addresses map low for PCI. */ - if (e->addr > 0x410000000ull) + if (e->addr > 0x410000000ull && !OCTEON_IS_MODEL(OCTEON_CN6XXX)) continue; addr_size += e->size; @@ -296,6 +306,11 @@ void __init plat_swiotlb_setup(void) swiotlbsize = 64 * (1<<20); } #endif +#ifdef CONFIG_USB_OCTEON_OHCI + /* OCTEON II ohci is only 32-bit. */ + if (OCTEON_IS_MODEL(OCTEON_CN6XXX) && max_addr >= 0x100000000ul) + swiotlbsize = 64 * (1<<20); +#endif swiotlb_nslabs = swiotlbsize >> IO_TLB_SHIFT; swiotlb_nslabs = ALIGN(swiotlb_nslabs, IO_TLB_SEGSIZE); swiotlbsize = swiotlb_nslabs << IO_TLB_SHIFT; @@ -330,6 +345,10 @@ struct dma_map_ops *octeon_pci_dma_map_ops; void __init octeon_pci_dma_init(void) { switch (octeon_dma_bar_type) { + case OCTEON_DMA_BAR_TYPE_PCIE2: + _octeon_pci_dma_map_ops.phys_to_dma = octeon_gen2_phys_to_dma; + _octeon_pci_dma_map_ops.dma_to_phys = octeon_gen2_dma_to_phys; + break; case OCTEON_DMA_BAR_TYPE_PCIE: _octeon_pci_dma_map_ops.phys_to_dma = octeon_gen1_phys_to_dma; _octeon_pci_dma_map_ops.dma_to_phys = octeon_gen1_dma_to_phys; diff --git a/arch/mips/cavium-octeon/executive/Makefile b/arch/mips/cavium-octeon/executive/Makefile index 7f41c5be2190..b6d6e841a984 100644 --- a/arch/mips/cavium-octeon/executive/Makefile +++ b/arch/mips/cavium-octeon/executive/Makefile @@ -10,5 +10,10 @@ # obj-y += cvmx-bootmem.o cvmx-l2c.o cvmx-sysinfo.o octeon-model.o +obj-y += cvmx-pko.o cvmx-spi.o cvmx-cmd-queue.o \ + cvmx-helper-board.o cvmx-helper.o cvmx-helper-xaui.o \ + cvmx-helper-rgmii.o cvmx-helper-sgmii.o cvmx-helper-npi.o \ + cvmx-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \ + cvmx-interrupt-decodes.o cvmx-interrupt-rsl.o -obj-$(CONFIG_CAVIUM_OCTEON_HELPER) += cvmx-helper-errata.o cvmx-helper-jtag.o +obj-y += cvmx-helper-errata.o cvmx-helper-jtag.o diff --git a/drivers/staging/octeon/cvmx-cmd-queue.c b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c index e9809d375162..132bccc66a93 100644 --- a/drivers/staging/octeon/cvmx-cmd-queue.c +++ b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c @@ -34,13 +34,13 @@ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" -#include "cvmx-fpa.h" -#include "cvmx-cmd-queue.h" +#include <asm/octeon/cvmx-config.h> +#include <asm/octeon/cvmx-fpa.h> +#include <asm/octeon/cvmx-cmd-queue.h> #include <asm/octeon/cvmx-npei-defs.h> #include <asm/octeon/cvmx-pexp-defs.h> -#include "cvmx-pko-defs.h" +#include <asm/octeon/cvmx-pko-defs.h> /** * This application uses this pointer to access the global queue diff --git a/drivers/staging/octeon/cvmx-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-fpa.c index ad44b8bd8057..ad44b8bd8057 100644 --- a/drivers/staging/octeon/cvmx-fpa.c +++ b/arch/mips/cavium-octeon/executive/cvmx-fpa.c diff --git a/drivers/staging/octeon/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index 57d35dc63ddb..fd2015331a20 100644 --- a/drivers/staging/octeon/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -34,16 +34,16 @@ #include <asm/octeon/octeon.h> #include <asm/octeon/cvmx-bootinfo.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-mdio.h" +#include <asm/octeon/cvmx-mdio.h> -#include "cvmx-helper.h" -#include "cvmx-helper-util.h" -#include "cvmx-helper-board.h" +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-helper-util.h> +#include <asm/octeon/cvmx-helper-board.h> -#include "cvmx-gmxx-defs.h" -#include "cvmx-asxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> +#include <asm/octeon/cvmx-asxx-defs.h> /** * cvmx_override_board_link_get(int ipd_port) is a function @@ -117,6 +117,10 @@ int cvmx_helper_board_get_mii_address(int ipd_port) case CVMX_BOARD_TYPE_EBH5200: case CVMX_BOARD_TYPE_EBH5201: case CVMX_BOARD_TYPE_EBT5200: + /* Board has 2 management ports */ + if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) && + (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2))) + return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT; /* * Board has 4 SGMII ports. The PHYs start right after the MII * ports MII0 = 0, MII1 = 1, SGMII = 2-5. @@ -128,6 +132,9 @@ int cvmx_helper_board_get_mii_address(int ipd_port) case CVMX_BOARD_TYPE_EBH5600: case CVMX_BOARD_TYPE_EBH5601: case CVMX_BOARD_TYPE_EBH5610: + /* Board has 1 management port */ + if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) + return 0; /* * Board has 8 SGMII ports. 4 connect out, two connect * to a switch, and 2 loop to each other @@ -147,6 +154,19 @@ int cvmx_helper_board_get_mii_address(int ipd_port) return ipd_port - 16 + 1; else return -1; + case CVMX_BOARD_TYPE_NIC_XLE_10G: + case CVMX_BOARD_TYPE_NIC10E: + return -1; + case CVMX_BOARD_TYPE_NIC4E: + if (ipd_port >= 0 && ipd_port <= 3) + return (ipd_port + 0x1f) & 0x1f; + else + return -1; + case CVMX_BOARD_TYPE_NIC2E: + if (ipd_port >= 0 && ipd_port <= 1) + return ipd_port + 1; + else + return -1; case CVMX_BOARD_TYPE_BBGW_REF: /* * No PHYs are connected to Octeon, everything is @@ -493,7 +513,6 @@ int cvmx_helper_board_link_set_phy(int phy_addr, cvmx_mdio_phy_reg_control_t reg_control; cvmx_mdio_phy_reg_status_t reg_status; cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; - cvmx_mdio_phy_reg_extended_status_t reg_extended_status; cvmx_mdio_phy_reg_control_1000_t reg_control_1000; reg_status.u16 = @@ -508,9 +527,6 @@ int cvmx_helper_board_link_set_phy(int phy_addr, reg_autoneg_adver.s.advert_100base_tx_full = 0; reg_autoneg_adver.s.advert_100base_tx_half = 0; if (reg_status.s.capable_extended_status) { - reg_extended_status.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_EXTENDED_STATUS); reg_control_1000.u16 = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, CVMX_MDIO_PHY_REG_CONTROL_1000); diff --git a/drivers/staging/octeon/cvmx-helper-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c index c239e5f4ab9a..c239e5f4ab9a 100644 --- a/drivers/staging/octeon/cvmx-helper-fpa.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c diff --git a/drivers/staging/octeon/cvmx-helper-loop.c b/arch/mips/cavium-octeon/executive/cvmx-helper-loop.c index 55a571a69529..bfbd46115e71 100644 --- a/drivers/staging/octeon/cvmx-helper-loop.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-loop.c @@ -31,10 +31,10 @@ */ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-helper.h" -#include "cvmx-pip-defs.h" +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-pip-defs.h> /** * Probe a LOOP interface and determine the number of ports diff --git a/drivers/staging/octeon/cvmx-helper-npi.c b/arch/mips/cavium-octeon/executive/cvmx-helper-npi.c index 7388a1e72b38..cc94cfa545b4 100644 --- a/drivers/staging/octeon/cvmx-helper-npi.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-npi.c @@ -31,11 +31,11 @@ */ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-pip-defs.h" +#include <asm/octeon/cvmx-pip-defs.h> /** * Probe a NPI interface and determine the number of ports diff --git a/drivers/staging/octeon/cvmx-helper-rgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c index aa2d5d7fee2b..82b21843421c 100644 --- a/drivers/staging/octeon/cvmx-helper-rgmii.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c @@ -31,18 +31,18 @@ */ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-mdio.h" -#include "cvmx-pko.h" -#include "cvmx-helper.h" -#include "cvmx-helper-board.h" +#include <asm/octeon/cvmx-mdio.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-helper-board.h> #include <asm/octeon/cvmx-npi-defs.h> -#include "cvmx-gmxx-defs.h" -#include "cvmx-asxx-defs.h" -#include "cvmx-dbg-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> +#include <asm/octeon/cvmx-asxx-defs.h> +#include <asm/octeon/cvmx-dbg-defs.h> void __cvmx_interrupt_gmxx_enable(int interface); void __cvmx_interrupt_asxx_enable(int block); @@ -326,6 +326,7 @@ int __cvmx_helper_rgmii_link_set(int ipd_port, cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & ~(1 << index)); + memset(pko_mem_queue_qos_save, 0, sizeof(pko_mem_queue_qos_save)); /* Disable all queues so that TX should become idle */ for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) { int queue = cvmx_pko_get_base_queue(ipd_port) + i; diff --git a/drivers/staging/octeon/cvmx-helper-sgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c index 6214e3b6d975..0c0bf5d30e70 100644 --- a/drivers/staging/octeon/cvmx-helper-sgmii.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c @@ -32,14 +32,14 @@ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-mdio.h" -#include "cvmx-helper.h" -#include "cvmx-helper-board.h" +#include <asm/octeon/cvmx-mdio.h> +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-helper-board.h> -#include "cvmx-gmxx-defs.h" -#include "cvmx-pcsx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> +#include <asm/octeon/cvmx-pcsx-defs.h> void __cvmx_interrupt_gmxx_enable(int interface); void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block); @@ -326,6 +326,10 @@ static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports) return 0; } +int __cvmx_helper_sgmii_enumerate(int interface) +{ + return 4; +} /** * Probe a SGMII interface and determine the number of ports * connected to it. The SGMII interface should still be down after @@ -347,7 +351,7 @@ int __cvmx_helper_sgmii_probe(int interface) mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); mode.s.en = 1; cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); - return 4; + return __cvmx_helper_sgmii_enumerate(interface); } /** diff --git a/drivers/staging/octeon/cvmx-helper-spi.c b/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c index 8ba6c832471e..2830e4bdf7f3 100644 --- a/drivers/staging/octeon/cvmx-helper-spi.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c @@ -35,12 +35,12 @@ void __cvmx_interrupt_stxx_int_msk_enable(int index); */ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" -#include "cvmx-spi.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-config.h> +#include <asm/octeon/cvmx-spi.h> +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-pip-defs.h" -#include "cvmx-pko-defs.h" +#include <asm/octeon/cvmx-pip-defs.h> +#include <asm/octeon/cvmx-pko-defs.h> /* * CVMX_HELPER_SPI_TIMEOUT is used to determine how long the SPI @@ -51,6 +51,16 @@ void __cvmx_interrupt_stxx_int_msk_enable(int index); #define CVMX_HELPER_SPI_TIMEOUT 10 #endif +int __cvmx_helper_spi_enumerate(int interface) +{ + if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) && + cvmx_spi4000_is_present(interface)) { + return 10; + } else { + return 16; + } +} + /** * Probe a SPI interface and determine the number of ports * connected to it. The SPI interface should still be down after diff --git a/drivers/staging/octeon/cvmx-helper-util.c b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c index 131182bf5abb..116dea17acf5 100644 --- a/drivers/staging/octeon/cvmx-helper-util.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c @@ -32,16 +32,16 @@ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-fpa.h" -#include "cvmx-pip.h" -#include "cvmx-pko.h" -#include "cvmx-ipd.h" -#include "cvmx-spi.h" +#include <asm/octeon/cvmx-fpa.h> +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-ipd.h> +#include <asm/octeon/cvmx-spi.h> -#include "cvmx-helper.h" -#include "cvmx-helper-util.h" +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-helper-util.h> #include <asm/octeon/cvmx-ipd-defs.h> diff --git a/drivers/staging/octeon/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c index a11e6769e234..1723248e987d 100644 --- a/drivers/staging/octeon/cvmx-helper-xaui.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c @@ -33,17 +33,30 @@ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-pko-defs.h" -#include "cvmx-gmxx-defs.h" -#include "cvmx-pcsxx-defs.h" +#include <asm/octeon/cvmx-pko-defs.h> +#include <asm/octeon/cvmx-gmxx-defs.h> +#include <asm/octeon/cvmx-pcsxx-defs.h> void __cvmx_interrupt_gmxx_enable(int interface); void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block); void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index); + +int __cvmx_helper_xaui_enumerate(int interface) +{ + union cvmx_gmxx_hg2_control gmx_hg2_control; + + /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */ + gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface)); + if (gmx_hg2_control.s.hg2tx_en) + return 16; + else + return 1; +} + /** * Probe a XAUI interface and determine the number of ports * connected to it. The XAUI interface should still be down @@ -56,7 +69,6 @@ void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index); int __cvmx_helper_xaui_probe(int interface) { int i; - union cvmx_gmxx_hg2_control gmx_hg2_control; union cvmx_gmxx_inf_mode mode; /* @@ -90,13 +102,7 @@ int __cvmx_helper_xaui_probe(int interface) pko_mem_port_ptrs.s.pid = interface * 16 + i; cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64); } - - /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */ - gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface)); - if (gmx_hg2_control.s.hg2tx_en) - return 16; - else - return 1; + return __cvmx_helper_xaui_enumerate(interface); } /** diff --git a/drivers/staging/octeon/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index e9c5c836ceff..fa4963856353 100644 --- a/drivers/staging/octeon/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -32,19 +32,19 @@ */ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-fpa.h" -#include "cvmx-pip.h" -#include "cvmx-pko.h" -#include "cvmx-ipd.h" -#include "cvmx-spi.h" -#include "cvmx-helper.h" -#include "cvmx-helper-board.h" +#include <asm/octeon/cvmx-fpa.h> +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-ipd.h> +#include <asm/octeon/cvmx-spi.h> +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-helper-board.h> -#include "cvmx-pip-defs.h" -#include "cvmx-smix-defs.h" -#include "cvmx-asxx-defs.h" +#include <asm/octeon/cvmx-pip-defs.h> +#include <asm/octeon/cvmx-smix-defs.h> +#include <asm/octeon/cvmx-asxx-defs.h> /** * cvmx_override_pko_queue_priority(int ipd_port, uint64_t @@ -234,21 +234,16 @@ static int __cvmx_helper_port_setup_ipd(int ipd_port) } /** - * This function probes an interface to determine the actual - * number of hardware ports connected to it. It doesn't setup the - * ports or enable them. The main goal here is to set the global - * interface_port_count[interface] correctly. Hardware setup of the - * ports will be performed later. + * This function sets the interface_port_count[interface] correctly, + * without modifying any hardware configuration. Hardware setup of + * the ports will be performed later. * * @interface: Interface to probe * * Returns Zero on success, negative on failure */ -int cvmx_helper_interface_probe(int interface) +int cvmx_helper_interface_enumerate(int interface) { - /* At this stage in the game we don't want packets to be moving yet. - The following probe calls should perform hardware setup - needed to determine port counts. Receive must still be disabled */ switch (cvmx_helper_interface_get_mode(interface)) { /* These types don't support ports to IPD/PKO */ case CVMX_HELPER_INTERFACE_MODE_DISABLED: @@ -258,7 +253,7 @@ int cvmx_helper_interface_probe(int interface) /* XAUI is a single high speed port */ case CVMX_HELPER_INTERFACE_MODE_XAUI: interface_port_count[interface] = - __cvmx_helper_xaui_probe(interface); + __cvmx_helper_xaui_enumerate(interface); break; /* * RGMII/GMII/MII are all treated about the same. Most @@ -267,7 +262,7 @@ int cvmx_helper_interface_probe(int interface) case CVMX_HELPER_INTERFACE_MODE_RGMII: case CVMX_HELPER_INTERFACE_MODE_GMII: interface_port_count[interface] = - __cvmx_helper_rgmii_probe(interface); + __cvmx_helper_rgmii_enumerate(interface); break; /* * SPI4 can have 1-16 ports depending on the device at @@ -275,7 +270,7 @@ int cvmx_helper_interface_probe(int interface) */ case CVMX_HELPER_INTERFACE_MODE_SPI: interface_port_count[interface] = - __cvmx_helper_spi_probe(interface); + __cvmx_helper_spi_enumerate(interface); break; /* * SGMII can have 1-4 ports depending on how many are @@ -284,12 +279,12 @@ int cvmx_helper_interface_probe(int interface) case CVMX_HELPER_INTERFACE_MODE_SGMII: case CVMX_HELPER_INTERFACE_MODE_PICMG: interface_port_count[interface] = - __cvmx_helper_sgmii_probe(interface); + __cvmx_helper_sgmii_enumerate(interface); break; /* PCI target Network Packet Interface */ case CVMX_HELPER_INTERFACE_MODE_NPI: interface_port_count[interface] = - __cvmx_helper_npi_probe(interface); + __cvmx_helper_npi_enumerate(interface); break; /* * Special loopback only ports. These are not the same @@ -297,7 +292,7 @@ int cvmx_helper_interface_probe(int interface) */ case CVMX_HELPER_INTERFACE_MODE_LOOP: interface_port_count[interface] = - __cvmx_helper_loop_probe(interface); + __cvmx_helper_loop_enumerate(interface); break; } @@ -313,6 +308,74 @@ int cvmx_helper_interface_probe(int interface) } /** + * This function probes an interface to determine the actual + * number of hardware ports connected to it. It doesn't setup the + * ports or enable them. The main goal here is to set the global + * interface_port_count[interface] correctly. Hardware setup of the + * ports will be performed later. + * + * @interface: Interface to probe + * + * Returns Zero on success, negative on failure + */ +int cvmx_helper_interface_probe(int interface) +{ + cvmx_helper_interface_enumerate(interface); + /* At this stage in the game we don't want packets to be moving yet. + The following probe calls should perform hardware setup + needed to determine port counts. Receive must still be disabled */ + switch (cvmx_helper_interface_get_mode(interface)) { + /* These types don't support ports to IPD/PKO */ + case CVMX_HELPER_INTERFACE_MODE_DISABLED: + case CVMX_HELPER_INTERFACE_MODE_PCIE: + break; + /* XAUI is a single high speed port */ + case CVMX_HELPER_INTERFACE_MODE_XAUI: + __cvmx_helper_xaui_probe(interface); + break; + /* + * RGMII/GMII/MII are all treated about the same. Most + * functions refer to these ports as RGMII. + */ + case CVMX_HELPER_INTERFACE_MODE_RGMII: + case CVMX_HELPER_INTERFACE_MODE_GMII: + __cvmx_helper_rgmii_probe(interface); + break; + /* + * SPI4 can have 1-16 ports depending on the device at + * the other end. + */ + case CVMX_HELPER_INTERFACE_MODE_SPI: + __cvmx_helper_spi_probe(interface); + break; + /* + * SGMII can have 1-4 ports depending on how many are + * hooked up. + */ + case CVMX_HELPER_INTERFACE_MODE_SGMII: + case CVMX_HELPER_INTERFACE_MODE_PICMG: + __cvmx_helper_sgmii_probe(interface); + break; + /* PCI target Network Packet Interface */ + case CVMX_HELPER_INTERFACE_MODE_NPI: + __cvmx_helper_npi_probe(interface); + break; + /* + * Special loopback only ports. These are not the same + * as other ports in loopback mode. + */ + case CVMX_HELPER_INTERFACE_MODE_LOOP: + __cvmx_helper_loop_probe(interface); + break; + } + + /* Make sure all global variables propagate to other cores */ + CVMX_SYNCWS; + + return 0; +} + +/** * Setup the IPD/PIP for the ports on an interface. Packet * classification and tagging are set for every port on the * interface. The number of ports on the interface must already @@ -548,7 +611,6 @@ int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) union cvmx_gmxx_prtx_cfg gmx_cfg; int retry_cnt; int retry_loop_cnt; - int mtu; int i; cvmx_helper_link_info_t link_info; @@ -662,10 +724,6 @@ int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 1 << INDEX(FIX_IPD_OUTPORT)); - mtu = - cvmx_read_csr(CVMX_GMXX_RXX_JABBER - (INDEX(FIX_IPD_OUTPORT), - INTERFACE(FIX_IPD_OUTPORT))); cvmx_write_csr(CVMX_GMXX_RXX_JABBER (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4); diff --git a/drivers/staging/octeon/cvmx-interrupt-decodes.c b/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c index a3337e382ee9..e59d1b79f24c 100644 --- a/drivers/staging/octeon/cvmx-interrupt-decodes.c +++ b/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c @@ -34,11 +34,11 @@ #include <asm/octeon/octeon.h> -#include "cvmx-gmxx-defs.h" -#include "cvmx-pcsx-defs.h" -#include "cvmx-pcsxx-defs.h" -#include "cvmx-spxx-defs.h" -#include "cvmx-stxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> +#include <asm/octeon/cvmx-pcsx-defs.h> +#include <asm/octeon/cvmx-pcsxx-defs.h> +#include <asm/octeon/cvmx-spxx-defs.h> +#include <asm/octeon/cvmx-stxx-defs.h> #ifndef PRINT_ERROR #define PRINT_ERROR(format, ...) diff --git a/drivers/staging/octeon/cvmx-interrupt-rsl.c b/arch/mips/cavium-octeon/executive/cvmx-interrupt-rsl.c index df50048cfbc0..bea7538ea4e9 100644 --- a/drivers/staging/octeon/cvmx-interrupt-rsl.c +++ b/arch/mips/cavium-octeon/executive/cvmx-interrupt-rsl.c @@ -32,8 +32,8 @@ #include <asm/octeon/octeon.h> -#include "cvmx-asxx-defs.h" -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-asxx-defs.h> +#include <asm/octeon/cvmx-gmxx-defs.h> #ifndef PRINT_ERROR #define PRINT_ERROR(format, ...) diff --git a/drivers/staging/octeon/cvmx-pko.c b/arch/mips/cavium-octeon/executive/cvmx-pko.c index 50a2c9bd5a55..f557084b1092 100644 --- a/drivers/staging/octeon/cvmx-pko.c +++ b/arch/mips/cavium-octeon/executive/cvmx-pko.c @@ -31,9 +31,9 @@ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" -#include "cvmx-pko.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-config.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-helper.h> /** * Internal state of packet output @@ -54,7 +54,7 @@ void cvmx_pko_initialize_global(void) /* * Set the size of the PKO command buffers to an odd number of * 64bit words. This allows the normal two word send to stay - * aligned and never span a command word buffer. + * aligned and never span a comamnd word buffer. */ config.u64 = 0; config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL; diff --git a/drivers/staging/octeon/cvmx-spi.c b/arch/mips/cavium-octeon/executive/cvmx-spi.c index 82794d920cec..74afb1710cd9 100644 --- a/drivers/staging/octeon/cvmx-spi.c +++ b/arch/mips/cavium-octeon/executive/cvmx-spi.c @@ -31,14 +31,14 @@ */ #include <asm/octeon/octeon.h> -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> -#include "cvmx-pko.h" -#include "cvmx-spi.h" +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-spi.h> -#include "cvmx-spxx-defs.h" -#include "cvmx-stxx-defs.h" -#include "cvmx-srxx-defs.h" +#include <asm/octeon/cvmx-spxx-defs.h> +#include <asm/octeon/cvmx-stxx-defs.h> +#include <asm/octeon/cvmx-srxx-defs.h> #define INVOKE_CB(function_p, args...) \ do { \ diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c index c8d35684504e..f4c1b36fdf65 100644 --- a/arch/mips/cavium-octeon/executive/octeon-model.c +++ b/arch/mips/cavium-octeon/executive/octeon-model.c @@ -4,7 +4,7 @@ * Contact: support@caviumnetworks.com * This file is part of the OCTEON SDK * - * Copyright (c) 2003-2008 Cavium Networks + * Copyright (c) 2003-2010 Cavium Networks * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as @@ -25,10 +25,6 @@ * Contact Cavium Networks for more information ***********************license end**************************************/ -/* - * File defining functions for working with different Octeon - * models. - */ #include <asm/octeon/octeon.h> /** @@ -69,11 +65,12 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) char fuse_model[10]; uint32_t fuse_data = 0; - fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); + fus3.u64 = 0; + if (!OCTEON_IS_MODEL(OCTEON_CN6XXX)) + fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); - - num_cores = cvmx_octeon_num_cores(); + num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU_FUSE)); /* Make sure the non existent devices look disabled */ switch ((chip_id >> 8) & 0xff) { @@ -108,7 +105,7 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) * Assume pass number is encoded using <5:3><2:0>. Exceptions * will be fixed later. */ - sprintf(pass, "%u.%u", ((chip_id >> 3) & 7) + 1, chip_id & 7); + sprintf(pass, "%d.%d", (int)((chip_id >> 3) & 7) + 1, (int)chip_id & 7); /* * Use the number of cores to determine the last 2 digits of @@ -116,6 +113,12 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) * later. */ switch (num_cores) { + case 32: + core_model = "80"; + break; + case 24: + core_model = "70"; + break; case 16: core_model = "60"; break; @@ -246,8 +249,8 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) break; case 3: /* CN58XX */ family = "58"; - /* Special case. 4 core, no crypto */ - if ((num_cores == 4) && fus_dat2.cn38xx.nocrypto) + /* Special case. 4 core, half cache (CP with half cache) */ + if ((num_cores == 4) && fus3.cn58xx.crip_1024k && !strncmp(suffix, "CP", 2)) core_model = "29"; /* Pass 1 uses different encodings for pass numbers */ @@ -285,6 +288,9 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) suffix = "NSP"; if (fus_dat3.s.nozip) suffix = "SCP"; + + if (fus_dat3.s.bar2_en) + suffix = "NSPB2"; } if (fus3.cn56xx.crip_1024k) family = "54"; @@ -301,6 +307,60 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) else family = "52"; break; + case 0x93: /* CN61XX */ + family = "61"; + if (fus_dat2.cn61xx.nocrypto && fus_dat2.cn61xx.dorm_crypto) + suffix = "AP"; + if (fus_dat2.cn61xx.nocrypto) + suffix = "CP"; + else if (fus_dat2.cn61xx.dorm_crypto) + suffix = "DAP"; + else if (fus_dat3.cn61xx.nozip) + suffix = "SCP"; + break; + case 0x90: /* CN63XX */ + family = "63"; + if (fus_dat3.s.l2c_crip == 2) + family = "62"; + if (num_cores == 6) /* Other core counts match generic */ + core_model = "35"; + if (fus_dat2.cn63xx.nocrypto) + suffix = "CP"; + else if (fus_dat2.cn63xx.dorm_crypto) + suffix = "DAP"; + else if (fus_dat3.cn63xx.nozip) + suffix = "SCP"; + else + suffix = "AAP"; + break; + case 0x92: /* CN66XX */ + family = "66"; + if (num_cores == 6) /* Other core counts match generic */ + core_model = "35"; + if (fus_dat2.cn66xx.nocrypto && fus_dat2.cn66xx.dorm_crypto) + suffix = "AP"; + if (fus_dat2.cn66xx.nocrypto) + suffix = "CP"; + else if (fus_dat2.cn66xx.dorm_crypto) + suffix = "DAP"; + else if (fus_dat3.cn66xx.nozip) + suffix = "SCP"; + else + suffix = "AAP"; + break; + case 0x91: /* CN68XX */ + family = "68"; + if (fus_dat2.cn68xx.nocrypto && fus_dat3.cn68xx.nozip) + suffix = "CP"; + else if (fus_dat2.cn68xx.dorm_crypto) + suffix = "DAP"; + else if (fus_dat3.cn68xx.nozip) + suffix = "SCP"; + else if (fus_dat2.cn68xx.nocrypto) + suffix = "SP"; + else + suffix = "AAP"; + break; default: family = "XX"; core_model = "XX"; @@ -310,49 +370,40 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) } clock_mhz = octeon_get_clock_rate() / 1000000; - if (family[0] != '3') { + int fuse_base = 384 / 8; + if (family[0] == '6') + fuse_base = 832 / 8; + /* Check for model in fuses, overrides normal decode */ /* This is _not_ valid for Octeon CN3XXX models */ - fuse_data |= cvmx_fuse_read_byte(51); + fuse_data |= cvmx_fuse_read_byte(fuse_base + 3); fuse_data = fuse_data << 8; - fuse_data |= cvmx_fuse_read_byte(50); + fuse_data |= cvmx_fuse_read_byte(fuse_base + 2); fuse_data = fuse_data << 8; - fuse_data |= cvmx_fuse_read_byte(49); + fuse_data |= cvmx_fuse_read_byte(fuse_base + 1); fuse_data = fuse_data << 8; - fuse_data |= cvmx_fuse_read_byte(48); + fuse_data |= cvmx_fuse_read_byte(fuse_base); if (fuse_data & 0x7ffff) { int model = fuse_data & 0x3fff; int suffix = (fuse_data >> 14) & 0x1f; if (suffix && model) { - /* - * Have both number and suffix in - * fuses, so both - */ - sprintf(fuse_model, "%d%c", - model, 'A' + suffix - 1); + /* Have both number and suffix in fuses, so both */ + sprintf(fuse_model, "%d%c", model, 'A' + suffix - 1); core_model = ""; family = fuse_model; } else if (suffix && !model) { - /* - * Only have suffix, so add suffix to - * 'normal' model number. - */ - sprintf(fuse_model, "%s%c", core_model, - 'A' + suffix - 1); + /* Only have suffix, so add suffix to 'normal' model number */ + sprintf(fuse_model, "%s%c", core_model, 'A' + suffix - 1); core_model = fuse_model; } else { - /* - * Don't have suffix, so just use - * model from fuses. - */ + /* Don't have suffix, so just use model from fuses */ sprintf(fuse_model, "%d", model); core_model = ""; family = fuse_model; } } } - sprintf(buffer, "CN%s%sp%s-%d-%s", - family, core_model, pass, clock_mhz, suffix); + sprintf(buffer, "CN%s%sp%s-%d-%s", family, core_model, pass, clock_mhz, suffix); return buffer; } diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 2d9028f1474c..260b27367347 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -642,14 +642,6 @@ void __init plat_mem_setup(void) total = 0; - /* First add the init memory we will be returning. */ - memory = __pa_symbol(&__init_begin) & PAGE_MASK; - mem_alloc_size = (__pa_symbol(&__init_end) & PAGE_MASK) - memory; - if (mem_alloc_size > 0) { - add_memory_region(memory, mem_alloc_size, BOOT_MEM_RAM); - total += mem_alloc_size; - } - /* * The Mips memory init uses the first memory location for * some memory vectors. When SPARSEMEM is in use, it doesn't @@ -767,11 +759,11 @@ void prom_free_prom_memory(void) : "=r" (insn) : : "$31", "memory"); if ((insn >> 26) != 0x33) - panic("No PREF instruction at Core-14449 probe point.\n"); + panic("No PREF instruction at Core-14449 probe point."); if (((insn >> 16) & 0x1f) != 28) panic("Core-14449 WAR not in place (%04x).\n" - "Please build kernel with proper options (CONFIG_CAVIUM_CN63XXP1).\n", insn); + "Please build kernel with proper options (CONFIG_CAVIUM_CN63XXP1).", insn); } #ifdef CONFIG_CAVIUM_DECODE_RSL cvmx_interrupt_rsl_enable(); @@ -779,7 +771,7 @@ void prom_free_prom_memory(void) /* Add an interrupt handler for general failures. */ if (request_irq(OCTEON_IRQ_RML, octeon_rlm_interrupt, IRQF_SHARED, "RML/RSL", octeon_rlm_interrupt)) { - panic("Unable to request_irq(OCTEON_IRQ_RML)\n"); + panic("Unable to request_irq(OCTEON_IRQ_RML)"); } #endif } diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c index efcfff4d4627..b1535fe409d4 100644 --- a/arch/mips/cavium-octeon/smp.c +++ b/arch/mips/cavium-octeon/smp.c @@ -210,7 +210,7 @@ void octeon_prepare_cpus(unsigned int max_cpus) if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_PERCPU | IRQF_NO_THREAD, "SMP-IPI", mailbox_interrupt)) { - panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n"); + panic("Cannot request_irq(OCTEON_IRQ_MBOX0)"); } } diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index 4044c9e0fb73..17a36c125172 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig @@ -1,118 +1,359 @@ +CONFIG_MIPS=y CONFIG_MIPS_ALCHEMY=y +CONFIG_MIPS_DB1000=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_TICK_ONESHOT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_100=y -# CONFIG_SECCOMP is not set +CONFIG_HZ=100 +CONFIG_PREEMPT_NONE=y CONFIG_EXPERIMENTAL=y -CONFIG_LOCALVERSION="-db1000" +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-db1x00" +CONFIG_LOCALVERSION_AUTO=y CONFIG_KERNEL_LZMA=y +CONFIG_DEFAULT_HOSTNAME="db1x00" +CONFIG_SWAP=y CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_FHANDLE=y +CONFIG_AUDIT=y CONFIG_TINY_RCU=y -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_SYSCTL=y CONFIG_EXPERT=y -# CONFIG_KALLSYMS is not set -# CONFIG_PCSPKR_PLATFORM is not set -# CONFIG_VM_EVENT_COUNTERS is not set -# CONFIG_COMPAT_BRK is not set +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PCI_QUIRKS=y CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_LBDAF is not set -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set +CONFIG_SLABINFO=y +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_IOSCHED_NOOP=y +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_FREEZER=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y CONFIG_PCCARD=y +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y -CONFIG_PM=y +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_PM_SLEEP=y CONFIG_PM_RUNTIME=y +CONFIG_PM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y +CONFIG_XFRM=y CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_NET_IPIP=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_LRO=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_IPV6=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +CONFIG_IPV6_SIT=y +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_STP=y +CONFIG_GARP=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_IGMP_SNOOPING=y +CONFIG_VLAN_8021Q=y +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_LLC=y +CONFIG_LLC2=y +CONFIG_DNS_RESOLVER=y +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIBTUSB=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +CONFIG_MTD_CFI_I4=y +CONFIG_MTD_CFI_I8=y +CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_UTIL=y CONFIG_MTD_PHYSMAP=y -# CONFIG_MISC_DEVICES is not set +CONFIG_SCSI_MOD=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_ATA=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_SFF=y +CONFIG_ATA_BMDMA=y +CONFIG_PATA_HPT37X=y +CONFIG_PATA_PCMCIA=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_FIREWIRE=y +CONFIG_FIREWIRE_OHCI=y +CONFIG_FIREWIRE_OHCI_DEBUG=y +CONFIG_FIREWIRE_NET=y CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_QSEMI_PHY=y -CONFIG_LXT_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_SMSC_PHY=y -CONFIG_BROADCOM_PHY=y -CONFIG_ICPLUS_PHY=y -CONFIG_REALTEK_PHY=y -CONFIG_NATIONAL_PHY=y -CONFIG_STE10XP=y -CONFIG_LSI_ET1011C_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_MII=y +CONFIG_PHYLIB=y +CONFIG_NET_ETHERNET=y CONFIG_MIPS_AU1X00_ENET=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=y +CONFIG_PCMCIA_PCNET=y +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOE=y +CONFIG_INPUT=y CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_DEVKMEM=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -# CONFIG_VGA_CONSOLE is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_TTY_PRINTK=y +CONFIG_DEVPORT=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_FB=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_AU1100=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FONTS=y +CONFIG_FONT_8x16=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +CONFIG_SND_SEQUENCER=y +CONFIG_SND_HRTIMER=y +CONFIG_SND_SEQ_HRTIMER_DEFAULT=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_VMASTER=y +CONFIG_SND_AC97_CODEC=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_AC97_BUS=y +CONFIG_SND_SOC_AU1XAUDIO=y +CONFIG_SND_SOC_AU1XAC97C=y +CONFIG_SND_SOC_DB1000=y +CONFIG_SND_SOC_AC97_CODEC=y +CONFIG_AC97_BUS=y +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +CONFIG_HIDRAW=y +CONFIG_USB_HID=y +CONFIG_USB_SUPPORT=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_DYNAMIC_MINORS=y CONFIG_USB_SUSPEND=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y CONFIG_RTC_DRV_AU1XXX=y -CONFIG_EXT2_FS=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -# CONFIG_EXT3_FS_XATTR is not set -# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_XATTR=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_JBD2=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_GENERIC_ACL=y +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y CONFIG_TMPFS=y -CONFIG_CRAMFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +CONFIG_JFFS2_RUBIN=y +CONFIG_JFFS2_CMODE_PRIORITY=y CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_ZLIB=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_PNFS_FILE_LAYOUT=y +CONFIG_PNFS_BLOCK=y CONFIG_ROOT_NFS=y +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_USE_NEW_IDMAPPER=y +CONFIG_NFSD=y +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SUNRPC_BACKCHANNEL=y +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_CODEPAGE_1250=y +CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=y CONFIG_NLS_UTF8=y -# CONFIG_ENABLE_WARN_DEPRECATED is not set -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_STRIP_ASM_SYMS=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_FTRACE is not set +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_EARLY_PRINTK=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="noirqdebug rootwait root=/dev/sda1 rootfstype=ext4 console=ttyS0,115200 video=au1100fb:panel:CRT_800x600_16" CONFIG_DEBUG_ZBOOT=y CONFIG_KEYS=y CONFIG_KEYS_DEBUG_PROC_KEYS=y +CONFIG_SECURITYFS=y +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_XZ_DEC=y diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig deleted file mode 100644 index c6b49938ee84..000000000000 --- a/arch/mips/configs/db1100_defconfig +++ /dev/null @@ -1,122 +0,0 @@ -CONFIG_MIPS_ALCHEMY=y -CONFIG_MIPS_DB1100=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_HZ_100=y -# CONFIG_SECCOMP is not set -CONFIG_EXPERIMENTAL=y -CONFIG_LOCALVERSION="-db1100" -CONFIG_KERNEL_LZMA=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_TINY_RCU=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set -# CONFIG_KALLSYMS is not set -# CONFIG_PCSPKR_PLATFORM is not set -# CONFIG_COMPAT_BRK is not set -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_LBDAF is not set -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_PCCARD=y -CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y -CONFIG_PM=y -CONFIG_PM_RUNTIME=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -# CONFIG_BLK_DEV is not set -# CONFIG_MISC_DEVICES is not set -CONFIG_IDE=y -CONFIG_IDE_TASK_IOCTL=y -CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_QSEMI_PHY=y -CONFIG_LXT_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_SMSC_PHY=y -CONFIG_BROADCOM_PHY=y -CONFIG_ICPLUS_PHY=y -CONFIG_REALTEK_PHY=y -CONFIG_NATIONAL_PHY=y -CONFIG_STE10XP=y -CONFIG_LSI_ET1011C_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_MIPS_AU1X00_ENET=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -CONFIG_FB=y -CONFIG_FB_AU1100=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_8x16=y -# CONFIG_HID_SUPPORT is not set -CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_DYNAMIC_MINORS=y -CONFIG_USB_SUSPEND=y -CONFIG_USB_OHCI_HCD=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_AU1XXX=y -CONFIG_EXT2_FS=y -# CONFIG_PROC_PAGE_MONITOR is not set -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_FS_XATTR=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_JFFS2_LZO=y -CONFIG_JFFS2_RUBIN=y -CONFIG_SQUASHFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_STRIP_ASM_SYMS=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_FTRACE is not set -CONFIG_DEBUG_ZBOOT=y -CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y -CONFIG_SECURITYFS=y diff --git a/arch/mips/configs/db1300_defconfig b/arch/mips/configs/db1300_defconfig new file mode 100644 index 000000000000..c38b190151c4 --- /dev/null +++ b/arch/mips/configs/db1300_defconfig @@ -0,0 +1,391 @@ +CONFIG_MIPS=y +CONFIG_MIPS_ALCHEMY=y +CONFIG_ALCHEMY_GPIOINT_AU1300=y +CONFIG_MIPS_DB1300=y +CONFIG_SOC_AU1300=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_CEVT_R4K_LIB=y +CONFIG_CSRC_R4K_LIB=y +CONFIG_DMA_COHERENT=y +CONFIG_SYS_HAS_EARLY_PRINTK=y +CONFIG_MIPS_DISABLE_OBSOLETE_IDE=y +CONFIG_GENERIC_GPIO=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_IRQ_CPU=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 +CONFIG_CPU_MIPS32_R1=y +CONFIG_SYS_SUPPORTS_ZBOOT=y +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_HARDWARE_WATCHPOINTS=y +CONFIG_32BIT=y +CONFIG_PAGE_SIZE_4KB=y +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_MIPS_MT_DISABLED=y +CONFIG_64BIT_PHYS_ADDR=y +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_NEED_PER_CPU_KM=y +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_HZ_100=y +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_HZ=100 +CONFIG_PREEMPT_NONE=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y +CONFIG_HAVE_IRQ_WORK=y +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-db1300" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_LZMA=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_FHANDLE=y +CONFIG_HAVE_GENERIC_HARDIRQS=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_TINY_RCU=y +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EXPERT=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_SLAB=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +CONFIG_IOSCHED_NOOP=y +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" +CONFIG_INLINE_SPIN_UNLOCK=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_MMU=y +CONFIG_PCCARD=y +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_TRAD_SIGNALS=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_INET_TUNNEL=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_IPV6=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +CONFIG_IPV6_SIT=y +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_UTIL=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_NAND_PLATFORM=y +CONFIG_BLK_DEV=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_UB=y +CONFIG_HAVE_IDE=y +CONFIG_IDE=y +CONFIG_IDE_GD=y +CONFIG_IDE_GD_ATA=y +CONFIG_BLK_DEV_IDECS=y +CONFIG_IDE_TASK_IOCTL=y +CONFIG_IDE_PROC_FS=y +CONFIG_BLK_DEV_PLATFORM=y +CONFIG_SCSI_MOD=y +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_PHYLIB=y +CONFIG_SMSC_PHY=y +CONFIG_NET_ETHERNET=y +CONFIG_SMSC911X=y +CONFIG_INPUT=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_WM97XX=y +CONFIG_TOUCHSCREEN_WM9712=y +CONFIG_TOUCHSCREEN_WM9713=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_SMBUS=y +CONFIG_I2C_AU1550=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_AU1550=y +CONFIG_SPI_BITBANG=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_HWMON=y +CONFIG_HWMON_VID=y +CONFIG_SENSORS_ADM1025=y +CONFIG_FB=y +CONFIG_FB_AU1200=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FONTS=y +CONFIG_FONT_ACORN_8x8=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +CONFIG_SND_HRTIMER=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_VERBOSE_PROCFS=y +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_VMASTER=y +CONFIG_SND_AC97_CODEC=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_CACHE_LZO=y +CONFIG_SND_SOC_AC97_BUS=y +CONFIG_SND_SOC_AU1XPSC=y +CONFIG_SND_SOC_AU1XPSC_I2S=y +CONFIG_SND_SOC_AU1XPSC_AC97=y +CONFIG_SND_SOC_DB1300=y +CONFIG_SND_SOC_I2C_AND_SPI=y +CONFIG_SND_SOC_WM8731=y +CONFIG_SND_SOC_WM9712=y +CONFIG_AC97_BUS=y +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +CONFIG_HIDRAW=y +CONFIG_USB_HID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +CONFIG_RTC_INTF_DEV_UIE_EMUL=y +CONFIG_RTC_DRV_AU1XXX=y +CONFIG_EXT2_FS=y +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_GENERIC_ACL=y +CONFIG_FAT_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +CONFIG_MISC_FILESYSTEMS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_FS_POSIX_ACL=y +CONFIG_JFFS2_FS_SECURITY=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y +CONFIG_JFFS2_RUBIN=y +CONFIG_JFFS2_CMODE_PRIORITY=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_UTF8=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_PRINTK_TIME=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_EARLY_PRINTK=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="video=au1200fb:panel:bs console=tty console=ttyS2,115200" +CONFIG_DEBUG_ZBOOT=y +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y +CONFIG_BITREVERSE=y +CONFIG_CRC32=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig deleted file mode 100644 index b6e21c7cb6bd..000000000000 --- a/arch/mips/configs/db1500_defconfig +++ /dev/null @@ -1,128 +0,0 @@ -CONFIG_MIPS_ALCHEMY=y -CONFIG_MIPS_DB1500=y -CONFIG_CPU_LITTLE_ENDIAN=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_HZ_100=y -# CONFIG_SECCOMP is not set -CONFIG_EXPERIMENTAL=y -CONFIG_LOCALVERSION="-db1500" -CONFIG_KERNEL_LZMA=y -CONFIG_SYSVIPC=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EXPERT=y -# CONFIG_KALLSYMS is not set -# CONFIG_PCSPKR_PLATFORM is not set -# CONFIG_VM_EVENT_COUNTERS is not set -# CONFIG_COMPAT_BRK is not set -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_PCI=y -CONFIG_PCCARD=y -# CONFIG_CARDBUS is not set -CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y -CONFIG_PM=y -CONFIG_PM_RUNTIME=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -# CONFIG_MISC_DEVICES is not set -CONFIG_IDE=y -CONFIG_BLK_DEV_IDECS=y -# CONFIG_IDEPCI_PCIBUS_ORDER is not set -CONFIG_BLK_DEV_HPT366=y -CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_QSEMI_PHY=y -CONFIG_LXT_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_SMSC_PHY=y -CONFIG_BROADCOM_PHY=y -CONFIG_ICPLUS_PHY=y -CONFIG_REALTEK_PHY=y -CONFIG_NATIONAL_PHY=y -CONFIG_STE10XP=y -CONFIG_LSI_ET1011C_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_MIPS_AU1X00_ENET=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_SERIAL_8250_PCI is not set -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -# CONFIG_HWMON is not set -# CONFIG_VGA_ARB is not set -# CONFIG_VGA_CONSOLE is not set -# CONFIG_HID_SUPPORT is not set -CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_DYNAMIC_MINORS=y -CONFIG_USB_SUSPEND=y -CONFIG_USB_OHCI_HCD=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_AU1XXX=y -CONFIG_EXT2_FS=y -# CONFIG_PROC_PAGE_MONITOR is not set -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_FS_XATTR=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_JFFS2_LZO=y -CONFIG_JFFS2_RUBIN=y -CONFIG_SQUASHFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_CODEPAGE_1250=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_15=y -CONFIG_NLS_UTF8=y -CONFIG_STRIP_ASM_SYMS=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -# CONFIG_FTRACE is not set -CONFIG_DEBUG_ZBOOT=y -CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y -CONFIG_SECURITYFS=y diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index 798a553c9e80..36cda27725e7 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig @@ -1,145 +1,262 @@ +CONFIG_MIPS=y CONFIG_MIPS_ALCHEMY=y CONFIG_MIPS_DB1550=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_GENERIC_GPIO=y +CONFIG_TICK_ONESHOT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_HZ_100=y -# CONFIG_SECCOMP is not set +CONFIG_HZ=100 CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="-db1550" +CONFIG_LOCALVERSION_AUTO=y CONFIG_KERNEL_LZMA=y +CONFIG_DEFAULT_HOSTNAME="db1550" +CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_FHANDLE=y +CONFIG_AUDIT=y CONFIG_TINY_RCU=y -CONFIG_LOG_BUF_SHIFT=14 +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +CONFIG_USER_NS=y +CONFIG_PID_NS=y +CONFIG_NET_NS=y CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set -# CONFIG_KALLSYMS is not set -# CONFIG_PCSPKR_PLATFORM is not set -# CONFIG_VM_EVENT_COUNTERS is not set -# CONFIG_COMPAT_BRK is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_EMBEDDED=y +CONFIG_PCI_QUIRKS=y CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set +CONFIG_BLOCK=y +CONFIG_LBDAF=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +CONFIG_IOSCHED_NOOP=y +CONFIG_DEFAULT_NOOP=y +CONFIG_DEFAULT_IOSCHED="noop" CONFIG_PCI=y CONFIG_PCCARD=y -# CONFIG_CARDBUS is not set +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y -CONFIG_PM=y +CONFIG_BINFMT_ELF=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_BINFMT_MISC=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_PM_SLEEP=y CONFIG_PM_RUNTIME=y +CONFIG_PM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y +CONFIG_XFRM=y CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_INET_TUNNEL=y +CONFIG_INET_LRO=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_IPV6=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +CONFIG_IPV6_SIT=y +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_DNS_RESOLVER=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_UTIL=y CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_AU1550=y -CONFIG_BLK_DEV_UB=y -# CONFIG_MISC_DEVICES is not set -CONFIG_IDE=y -CONFIG_BLK_DEV_IDECS=y -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS is not set -CONFIG_IDE_TASK_IOCTL=y -# CONFIG_IDEPCI_PCIBUS_ORDER is not set -CONFIG_BLK_DEV_HPT366=y +CONFIG_MTD_NAND_IDS=y +CONFIG_MTD_NAND_PLATFORM=y +CONFIG_MISC_DEVICES=y +CONFIG_EEPROM_AT24=y +CONFIG_SCSI_MOD=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_ATA=y +CONFIG_ATA_SFF=y +CONFIG_ATA_BMDMA=y +CONFIG_PATA_HPT37X=y +CONFIG_PATA_PCMCIA=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y CONFIG_NETDEVICES=y -CONFIG_MARVELL_PHY=y -CONFIG_DAVICOM_PHY=y -CONFIG_QSEMI_PHY=y -CONFIG_LXT_PHY=y -CONFIG_CICADA_PHY=y -CONFIG_VITESSE_PHY=y -CONFIG_SMSC_PHY=y -CONFIG_BROADCOM_PHY=y -CONFIG_ICPLUS_PHY=y -CONFIG_REALTEK_PHY=y -CONFIG_NATIONAL_PHY=y -CONFIG_STE10XP=y -CONFIG_LSI_ET1011C_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_MII=y +CONFIG_PHYLIB=y +CONFIG_NET_ETHERNET=y CONFIG_MIPS_AU1X00_ENET=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=y +CONFIG_PCMCIA_PCNET=y +CONFIG_INPUT=y CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_DEVKMEM=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_DEVPORT=y CONFIG_I2C=y -# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_BOARDINFO=y CONFIG_I2C_CHARDEV=y -# CONFIG_I2C_HELPER_AUTO is not set CONFIG_I2C_AU1550=y CONFIG_SPI=y +CONFIG_SPI_MASTER=y CONFIG_SPI_AU1550=y -# CONFIG_HWMON is not set -# CONFIG_VGA_ARB is not set -# CONFIG_VGA_CONSOLE is not set +CONFIG_SPI_BITBANG=y +CONFIG_HWMON=y +CONFIG_SENSORS_ADM1025=y +CONFIG_SENSORS_LM70=y +CONFIG_DUMMY_CONSOLE=y CONFIG_SOUND=y CONFIG_SND=y -CONFIG_SND_HRTIMER=y -CONFIG_SND_DYNAMIC_MINORS=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_DRIVERS is not set -# CONFIG_SND_PCI is not set -# CONFIG_SND_SPI is not set -# CONFIG_SND_MIPS is not set -# CONFIG_SND_PCMCIA is not set +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +CONFIG_SND_VMASTER=y +CONFIG_SND_AC97_CODEC=y CONFIG_SND_SOC=y +CONFIG_SND_SOC_AC97_BUS=y CONFIG_SND_SOC_AU1XPSC=y -# CONFIG_HID_SUPPORT is not set +CONFIG_SND_SOC_AU1XPSC_I2S=y +CONFIG_SND_SOC_AU1XPSC_AC97=y +CONFIG_SND_SOC_DB1200=y +CONFIG_SND_SOC_I2C_AND_SPI=y +CONFIG_SND_SOC_AC97_CODEC=y +CONFIG_SND_SOC_WM8731=y +CONFIG_SND_SOC_WM9712=y +CONFIG_AC97_BUS=y CONFIG_USB=y -# CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_DYNAMIC_MINORS=y -CONFIG_USB_SUSPEND=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y CONFIG_RTC_DRV_AU1XXX=y -CONFIG_EXT2_FS=y -# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +CONFIG_EXT4_FS_XATTR=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_JBD2=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y CONFIG_TMPFS=y CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_WRITEBUFFER=y CONFIG_JFFS2_SUMMARY=y CONFIG_JFFS2_FS_XATTR=y -# CONFIG_JFFS2_FS_POSIX_ACL is not set -# CONFIG_JFFS2_FS_SECURITY is not set CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RTIME=y CONFIG_JFFS2_RUBIN=y +CONFIG_JFFS2_CMODE_PRIORITY=y CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_ZLIB=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_PNFS_FILE_LAYOUT=y +CONFIG_PNFS_BLOCK=y CONFIG_ROOT_NFS=y +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_USE_NEW_IDMAPPER=y +CONFIG_NFSD=y +CONFIG_NFSD_V2_ACL=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SUNRPC_BACKCHANNEL=y +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_850=y CONFIG_NLS_CODEPAGE_852=y @@ -148,10 +265,21 @@ CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=y CONFIG_NLS_UTF8=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_FTRACE is not set -CONFIG_DEBUG_ZBOOT=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_FRAME_WARN=1024 +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="noirqdebug console=ttyS0,115200 root=/dev/sda1 rootfstype=ext4" CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITYFS=y +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_BITREVERSE=y +CONFIG_CRC16=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_BCH=y +CONFIG_NLATTR=y diff --git a/arch/mips/configs/nlm_xlp_defconfig b/arch/mips/configs/nlm_xlp_defconfig new file mode 100644 index 000000000000..4479fd669ac1 --- /dev/null +++ b/arch/mips/configs/nlm_xlp_defconfig @@ -0,0 +1,570 @@ +CONFIG_NLM_XLP_BOARD=y +CONFIG_64BIT=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_SMP=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_SECCOMP is not set +CONFIG_USE_OF=y +CONFIG_EXPERIMENTAL=y +CONFIG_CROSS_COMPILE="mips-linux-gnu-" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_AUDIT=y +CONFIG_CGROUPS=y +CONFIG_NAMESPACES=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs.xlp" +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_INITRAMFS_COMPRESSION_LZMA=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLK_DEV_INTEGRITY=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_MISC=y +CONFIG_MIPS32_COMPAT=y +CONFIG_MIPS32_O32=y +CONFIG_MIPS32_N32=y +CONFIG_PM_RUNTIME=y +CONFIG_PM_DEBUG=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_NET_IPIP=m +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_TRANSPORT=m +CONFIG_INET_XFRM_MODE_TUNNEL=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETLABEL=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_UDPLITE=m +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_NOTRACK=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_FTP=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NF_CONNTRACK_IPV6=m +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_DECNET_NF_GRABULATOR=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_ULOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_IP_DCCP=m +CONFIG_RDS=m +CONFIG_RDS_TCP=m +CONFIG_TIPC=m +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_DECNET=m +CONFIG_LLC2=m +CONFIG_IPX=m +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_IPDDP=m +CONFIG_IPDDP_ENCAP=y +CONFIG_IPDDP_DECAP=y +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_ECONET=m +CONFIG_ECONET_AUNUDP=y +CONFIG_ECONET_NATIVE=y +CONFIG_WAN_ROUTER=m +CONFIG_PHONET=m +CONFIG_IEEE802154=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_ATM=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_DCB=y +CONFIG_NET_PKTGEN=m +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_CONNECTOR=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_OSD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_CDROM_PKTCDVD=y +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=y +CONFIG_SCSI_TGT=m +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_CHR_DEV_OSST=m +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_TGT_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_SCSI_SRP_TGT_ATTRS=y +CONFIG_ISCSI_TCP=m +CONFIG_LIBFCOE=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_SCSI_OSD_INITIATOR=m +CONFIG_SCSI_OSD_ULD=m +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_DEVPTS_MULTIPLE_INSTANCES=y +CONFIG_LEGACY_PTY_COUNT=0 +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_N_HDLC=m +# CONFIG_DEVKMEM is not set +CONFIG_STALDRV=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=m +CONFIG_RAW_DRIVER=m +# CONFIG_HWMON is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_UIO=y +CONFIG_UIO_PDRV=m +CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=y +CONFIG_OCFS2_FS=m +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_NILFS2_FS=m +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=y +CONFIG_CUSE=m +CONFIG_FSCACHE=m +CONFIG_FSCACHE_STATS=y +CONFIG_FSCACHE_HISTOGRAM=y +CONFIG_CACHEFILES=m +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ADFS_FS=m +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=y +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_CRAMFS=m +CONFIG_SQUASHFS=m +CONFIG_VXFS_FS=m +CONFIG_MINIX_FS=m +CONFIG_OMFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_ROMFS_FS=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +CONFIG_EXOFS_FS=m +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_CIFS=m +CONFIG_CIFS_WEAK_PW_HASH=y +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_NCP_FS=m +CONFIG_NCPFS_PACKET_SIGNING=y +CONFIG_NCPFS_IOCTL_LOCKING=y +CONFIG_NCPFS_STRONG=y +CONFIG_NCPFS_NFS_NS=y +CONFIG_NCPFS_OS2_NS=y +CONFIG_NCPFS_NLS=y +CONFIG_NCPFS_EXTRAS=y +CONFIG_CODA_FS=m +CONFIG_AFS_FS=m +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +CONFIG_ACORN_PARTITION_ICS=y +CONFIG_ACORN_PARTITION_RISCIX=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_EFI_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_PRINTK_TIME=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_SCHED_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_KGDB=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0 +CONFIG_SECURITY_SELINUX_DISABLE=y +CONFIG_SECURITY_SMACK=y +CONFIG_SECURITY_TOMOYO=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_CCM=m +CONFIG_CRYPTO_GCM=m +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_XTS=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_RMD128=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_RMD256=m +CONFIG_CRYPTO_RMD320=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_FCRYPT=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SALSA20=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_ZLIB=m +CONFIG_CRYPTO_LZO=m +CONFIG_CRC_CCITT=m +CONFIG_CRC7=m diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig index e4b399fdaa61..7c68666fdd64 100644 --- a/arch/mips/configs/nlm_xlr_defconfig +++ b/arch/mips/configs/nlm_xlr_defconfig @@ -8,7 +8,7 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT_VOLUNTARY=y CONFIG_KEXEC=y CONFIG_EXPERIMENTAL=y -CONFIG_CROSS_COMPILE="mips64-unknown-linux-gnu-" +CONFIG_CROSS_COMPILE="mips-linux-gnu-" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -22,15 +22,13 @@ CONFIG_AUDIT=y CONFIG_NAMESPACES=y CONFIG_SCHED_AUTOGROUP=y CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs" +CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs.xlr" CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y CONFIG_INITRAMFS_COMPRESSION_GZIP=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y # CONFIG_ELF_CORE is not set -# CONFIG_PCSPKR_PLATFORM is not set # CONFIG_PERF_EVENTS is not set # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y @@ -39,6 +37,9 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_DEBUG=y CONFIG_BINFMT_MISC=m CONFIG_PM_RUNTIME=y CONFIG_PM_DEBUG=y @@ -297,12 +298,10 @@ CONFIG_NET_ACT_SIMP=m CONFIG_NET_ACT_SKBEDIT=m CONFIG_DCB=y CONFIG_NET_PKTGEN=m -# CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set CONFIG_CONNECTOR=y -CONFIG_MTD=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m @@ -339,6 +338,9 @@ CONFIG_SCSI_DH_EMC=m CONFIG_SCSI_DH_ALUA=m CONFIG_SCSI_OSD_INITIATOR=m CONFIG_SCSI_OSD_ULD=m +CONFIG_NETDEVICES=y +CONFIG_E1000E=y +CONFIG_SKY2=y # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m @@ -443,7 +445,6 @@ CONFIG_CIFS_UPCALL=y CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y CONFIG_CIFS_DFS_UPCALL=y -CONFIG_CIFS_EXPERIMENTAL=y CONFIG_NCP_FS=m CONFIG_NCPFS_PACKET_SIGNING=y CONFIG_NCPFS_IOCTL_LOCKING=y @@ -516,7 +517,6 @@ CONFIG_PRINTK_TIME=y # CONFIG_ENABLE_WARN_DEPRECATED is not set # CONFIG_ENABLE_MUST_CHECK is not set CONFIG_UNUSED_SYMBOLS=y -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_SCHEDSTATS=y CONFIG_TIMER_STATS=y diff --git a/arch/mips/configs/pb1200_defconfig b/arch/mips/configs/pb1200_defconfig deleted file mode 100644 index dcbe2704e5ed..000000000000 --- a/arch/mips/configs/pb1200_defconfig +++ /dev/null @@ -1,170 +0,0 @@ -CONFIG_MIPS_ALCHEMY=y -CONFIG_MIPS_PB1200=y -CONFIG_KSM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_HZ_100=y -# CONFIG_SECCOMP is not set -CONFIG_EXPERIMENTAL=y -CONFIG_LOCALVERSION="-pb1200" -CONFIG_KERNEL_LZMA=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_TINY_RCU=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EXPERT=y -# CONFIG_SYSCTL_SYSCALL is not set -# CONFIG_KALLSYMS is not set -# CONFIG_PCSPKR_PLATFORM is not set -# CONFIG_VM_EVENT_COUNTERS is not set -# CONFIG_COMPAT_BRK is not set -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_LBDAF is not set -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_PCCARD=y -CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y -CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y -CONFIG_BINFMT_MISC=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_PNP=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_PLATFORM=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_UB=y -# CONFIG_MISC_DEVICES is not set -CONFIG_IDE=y -CONFIG_BLK_DEV_IDECS=y -CONFIG_BLK_DEV_IDECD=y -CONFIG_IDE_TASK_IOCTL=y -# CONFIG_IDE_PROC_FS is not set -CONFIG_BLK_DEV_IDE_AU1XXX=y -CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_SMC91X=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_VT_HW_CONSOLE_BINDING=y -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=2 -CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -# CONFIG_LEGACY_PTYS is not set -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -# CONFIG_I2C_COMPAT is not set -CONFIG_I2C_CHARDEV=y -# CONFIG_I2C_HELPER_AUTO is not set -CONFIG_I2C_AU1550=y -CONFIG_SPI=y -CONFIG_SPI_AU1550=y -CONFIG_GPIOLIB=y -CONFIG_GPIO_SYSFS=y -CONFIG_SENSORS_ADM1025=y -CONFIG_SENSORS_LM70=y -CONFIG_FB=y -CONFIG_FB_AU1200=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y -CONFIG_FONT_8x16=y -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_DYNAMIC_MINORS=y -# CONFIG_SND_SUPPORT_OLD_API is not set -# CONFIG_SND_VERBOSE_PROCFS is not set -# CONFIG_SND_DRIVERS is not set -# CONFIG_SND_SPI is not set -# CONFIG_SND_MIPS is not set -# CONFIG_SND_USB is not set -# CONFIG_SND_PCMCIA is not set -CONFIG_SND_SOC=y -CONFIG_SND_SOC_AU1XPSC=y -CONFIG_SND_SOC_DB1200=y -CONFIG_HIDRAW=y -CONFIG_USB_HIDDEV=y -CONFIG_USB=y -CONFIG_USB_DEBUG=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -# CONFIG_USB_DEVICE_CLASS is not set -CONFIG_USB_DYNAMIC_MINORS=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -CONFIG_USB_OHCI_HCD=y -CONFIG_MMC=y -# CONFIG_MMC_BLOCK_BOUNCE is not set -CONFIG_MMC_AU1X=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_TRIGGERS=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_AU1XXX=y -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=y -CONFIG_VFAT_FS=y -# CONFIG_PROC_PAGE_MONITOR is not set -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_JFFS2_SUMMARY=y -CONFIG_JFFS2_COMPRESSION_OPTIONS=y -CONFIG_JFFS2_LZO=y -CONFIG_JFFS2_RUBIN=y -CONFIG_SQUASHFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_EFI_PARTITION=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_CODEPAGE_852=y -CONFIG_NLS_CODEPAGE_1250=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_2=y -CONFIG_NLS_ISO8859_15=y -CONFIG_NLS_UTF8=y -# CONFIG_ENABLE_WARN_DEPRECATED is not set -# CONFIG_ENABLE_MUST_CHECK is not set -CONFIG_MAGIC_SYSRQ=y -CONFIG_STRIP_ASM_SYMS=y -CONFIG_DEBUG_KERNEL=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_FTRACE is not set -CONFIG_CMDLINE_BOOL=y -CONFIG_CMDLINE="console=ttyS0,115200" -CONFIG_DEBUG_ZBOOT=y -CONFIG_KEYS=y -CONFIG_KEYS_DEBUG_PROC_KEYS=y -CONFIG_SECURITYFS=y diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index f7b7ba6d5c45..b874accd878a 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -110,7 +110,6 @@ static struct irqaction fpuirq = { }; static struct irqaction busirq = { - .flags = IRQF_DISABLED, .name = "bus error", .flags = IRQF_NO_THREAD, }; diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index 7897f05e3165..f53f9ca73996 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -1,3 +1,5 @@ include include/asm-generic/Kbuild.asm -header-y += cachectl.h sgidefs.h sysmips.h +header-y += cachectl.h +header-y += sgidefs.h +header-y += sysmips.h diff --git a/arch/mips/include/asm/bmips.h b/arch/mips/include/asm/bmips.h new file mode 100644 index 000000000000..552a65a0cf2b --- /dev/null +++ b/arch/mips/include/asm/bmips.h @@ -0,0 +1,110 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011 by Kevin Cernekee (cernekee@gmail.com) + * + * Definitions for BMIPS processors + */ +#ifndef _ASM_BMIPS_H +#define _ASM_BMIPS_H + +#include <linux/compiler.h> +#include <linux/linkage.h> +#include <asm/addrspace.h> +#include <asm/mipsregs.h> +#include <asm/hazards.h> + +/* NOTE: the CBR register returns a PA, and it can be above 0xff00_0000 */ +#define BMIPS_GET_CBR() ((void __iomem *)(CKSEG1 | \ + (unsigned long) \ + ((read_c0_brcm_cbr() >> 18) << 18))) + +#define BMIPS_RAC_CONFIG 0x00000000 +#define BMIPS_RAC_ADDRESS_RANGE 0x00000004 +#define BMIPS_RAC_CONFIG_1 0x00000008 +#define BMIPS_L2_CONFIG 0x0000000c +#define BMIPS_LMB_CONTROL 0x0000001c +#define BMIPS_SYSTEM_BASE 0x00000020 +#define BMIPS_PERF_GLOBAL_CONTROL 0x00020000 +#define BMIPS_PERF_CONTROL_0 0x00020004 +#define BMIPS_PERF_CONTROL_1 0x00020008 +#define BMIPS_PERF_COUNTER_0 0x00020010 +#define BMIPS_PERF_COUNTER_1 0x00020014 +#define BMIPS_PERF_COUNTER_2 0x00020018 +#define BMIPS_PERF_COUNTER_3 0x0002001c +#define BMIPS_RELO_VECTOR_CONTROL_0 0x00030000 +#define BMIPS_RELO_VECTOR_CONTROL_1 0x00038000 + +#define BMIPS_NMI_RESET_VEC 0x80000000 +#define BMIPS_WARM_RESTART_VEC 0x80000380 + +#define ZSCM_REG_BASE 0x97000000 + +#if !defined(__ASSEMBLY__) + +#include <linux/cpumask.h> +#include <asm/r4kcache.h> + +extern struct plat_smp_ops bmips_smp_ops; +extern char bmips_reset_nmi_vec; +extern char bmips_reset_nmi_vec_end; +extern char bmips_smp_movevec; +extern char bmips_smp_int_vec; +extern char bmips_smp_int_vec_end; + +extern int bmips_smp_enabled; +extern int bmips_cpu_offset; +extern cpumask_t bmips_booted_mask; + +extern void bmips_ebase_setup(void); +extern asmlinkage void plat_wired_tlb_setup(void); + +static inline unsigned long bmips_read_zscm_reg(unsigned int offset) +{ + unsigned long ret; + + __asm__ __volatile__( + ".set push\n" + ".set noreorder\n" + "cache %1, 0(%2)\n" + "sync\n" + "_ssnop\n" + "_ssnop\n" + "_ssnop\n" + "_ssnop\n" + "_ssnop\n" + "_ssnop\n" + "_ssnop\n" + "mfc0 %0, $28, 3\n" + "_ssnop\n" + ".set pop\n" + : "=&r" (ret) + : "i" (Index_Load_Tag_S), "r" (ZSCM_REG_BASE + offset) + : "memory"); + return ret; +} + +static inline void bmips_write_zscm_reg(unsigned int offset, unsigned long data) +{ + __asm__ __volatile__( + ".set push\n" + ".set noreorder\n" + "mtc0 %0, $28, 3\n" + "_ssnop\n" + "_ssnop\n" + "_ssnop\n" + "cache %1, 0(%2)\n" + "_ssnop\n" + "_ssnop\n" + "_ssnop\n" + : /* no outputs */ + : "r" (data), + "i" (Index_Store_Tag_S), "r" (ZSCM_REG_BASE + offset) + : "memory"); +} + +#endif /* !defined(__ASSEMBLY__) */ + +#endif /* _ASM_BMIPS_H */ diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index 35cd1bab69c3..7a51d879e6ca 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -86,6 +86,7 @@ extern unsigned long mips_machtype; #define BOOT_MEM_RAM 1 #define BOOT_MEM_ROM_DATA 2 #define BOOT_MEM_RESERVED 3 +#define BOOT_MEM_INIT_RAM 4 /* * A memory map that's built upon what was determined diff --git a/arch/mips/include/asm/branch.h b/arch/mips/include/asm/branch.h index 37c6857c8d4a..888766ae1f85 100644 --- a/arch/mips/include/asm/branch.h +++ b/arch/mips/include/asm/branch.h @@ -9,6 +9,7 @@ #define _ASM_BRANCH_H #include <asm/ptrace.h> +#include <asm/inst.h> static inline int delay_slot(struct pt_regs *regs) { @@ -23,7 +24,11 @@ static inline unsigned long exception_epc(struct pt_regs *regs) return regs->cp0_epc + 4; } +#define BRANCH_LIKELY_TAKEN 0x0001 + extern int __compute_return_epc(struct pt_regs *regs); +extern int __compute_return_epc_for_insn(struct pt_regs *regs, + union mips_instruction insn); static inline int compute_return_epc(struct pt_regs *regs) { diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 2f7f41873f24..f9fa2a479dd0 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -169,6 +169,10 @@ #define PRID_IMP_NETLOGIC_XLS412B 0x4c00 #define PRID_IMP_NETLOGIC_XLS408B 0x4e00 #define PRID_IMP_NETLOGIC_XLS404B 0x4f00 +#define PRID_IMP_NETLOGIC_AU13XX 0x8000 + +#define PRID_IMP_NETLOGIC_XLP8XX 0x1000 +#define PRID_IMP_NETLOGIC_XLP3XX 0x1100 /* * Definitions for 7:0 on legacy processors @@ -263,7 +267,7 @@ enum cpu_type_enum { */ CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2, CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2, - CPU_XLR, + CPU_XLR, CPU_XLP, CPU_LAST }; diff --git a/arch/mips/include/asm/gio_device.h b/arch/mips/include/asm/gio_device.h new file mode 100644 index 000000000000..5437c84664bf --- /dev/null +++ b/arch/mips/include/asm/gio_device.h @@ -0,0 +1,56 @@ +#include <linux/device.h> +#include <linux/mod_devicetable.h> + +struct gio_device_id { + __u8 id; +}; + +struct gio_device { + struct device dev; + struct resource resource; + unsigned int irq; + unsigned int slotno; + + const char *name; + struct gio_device_id id; + unsigned id32:1; + unsigned gio64:1; +}; +#define to_gio_device(d) container_of(d, struct gio_device, dev) + +struct gio_driver { + const char *name; + struct module *owner; + const struct gio_device_id *id_table; + + int (*probe)(struct gio_device *, const struct gio_device_id *); + void (*remove)(struct gio_device *); + int (*suspend)(struct gio_device *, pm_message_t); + int (*resume)(struct gio_device *); + void (*shutdown)(struct gio_device *); + + struct device_driver driver; +}; +#define to_gio_driver(drv) container_of(drv, struct gio_driver, driver) + +extern const struct gio_device_id *gio_match_device(const struct gio_device_id *, + const struct gio_device *); +extern struct gio_device *gio_dev_get(struct gio_device *); +extern void gio_dev_put(struct gio_device *); + +extern int gio_device_register(struct gio_device *); +extern void gio_device_unregister(struct gio_device *); +extern void gio_release_dev(struct device *); + +static inline void gio_device_free(struct gio_device *dev) +{ + gio_release_dev(&dev->dev); +} + +extern int gio_register_driver(struct gio_driver *); +extern void gio_unregister_driver(struct gio_driver *); + +#define gio_get_drvdata(_dev) drv_get_drvdata(&(_dev)->dev) +#define gio_set_drvdata(_dev, data) drv_set_drvdata(&(_dev)->dev, (data)) + +extern void gio_set_master(struct gio_device *); diff --git a/arch/mips/include/asm/hazards.h b/arch/mips/include/asm/hazards.h index 4e332165d7b7..b4c20e4f87cd 100644 --- a/arch/mips/include/asm/hazards.h +++ b/arch/mips/include/asm/hazards.h @@ -87,7 +87,8 @@ do { \ : "=r" (tmp)); \ } while (0) -#elif defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MIPS_ALCHEMY) +#elif (defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MIPS_ALCHEMY)) || \ + defined(CONFIG_CPU_BMIPS) /* * These are slightly complicated by the fact that we guarantee R1 kernels to @@ -139,8 +140,8 @@ do { \ } while (0) #elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \ - defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \ - defined(CONFIG_CPU_R5500) + defined(CONFIG_CPU_LOONGSON2) || defined(CONFIG_CPU_R10000) || \ + defined(CONFIG_CPU_R5500) /* * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer. diff --git a/arch/mips/include/asm/hugetlb.h b/arch/mips/include/asm/hugetlb.h index c565b7c3f0b5..58d36889f09b 100644 --- a/arch/mips/include/asm/hugetlb.h +++ b/arch/mips/include/asm/hugetlb.h @@ -70,7 +70,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) { - flush_tlb_mm(vma->vm_mm); + flush_tlb_page(vma, addr & huge_page_mask(hstate_vma(vma))); } static inline int huge_pte_none(pte_t pte) diff --git a/arch/mips/include/asm/kprobes.h b/arch/mips/include/asm/kprobes.h index e6ea4d4d7205..1fbbca01e681 100644 --- a/arch/mips/include/asm/kprobes.h +++ b/arch/mips/include/asm/kprobes.h @@ -74,6 +74,8 @@ struct prev_kprobe { : MAX_JPROBES_STACK_SIZE) +#define SKIP_DELAYSLOT 0x0001 + /* per-cpu kprobe control block */ struct kprobe_ctlblk { unsigned long kprobe_status; @@ -82,6 +84,9 @@ struct kprobe_ctlblk { unsigned long kprobe_saved_epc; unsigned long jprobe_saved_sp; struct pt_regs jprobe_saved_regs; + /* Per-thread fields, used while emulating branches */ + unsigned long flags; + unsigned long target_epc; u8 jprobes_stack[MAX_JPROBES_STACK_SIZE]; struct prev_kprobe prev_kprobe; }; diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index cda1c8070b27..2f0becb4ec8f 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -20,6 +20,10 @@ #include <linux/bitops.h> #define AR71XX_APB_BASE 0x18000000 +#define AR71XX_EHCI_BASE 0x1b000000 +#define AR71XX_EHCI_SIZE 0x1000 +#define AR71XX_OHCI_BASE 0x1c000000 +#define AR71XX_OHCI_SIZE 0x1000 #define AR71XX_SPI_BASE 0x1f000000 #define AR71XX_SPI_SIZE 0x01000000 @@ -27,6 +31,8 @@ #define AR71XX_DDR_CTRL_SIZE 0x100 #define AR71XX_UART_BASE (AR71XX_APB_BASE + 0x00020000) #define AR71XX_UART_SIZE 0x100 +#define AR71XX_USB_CTRL_BASE (AR71XX_APB_BASE + 0x00030000) +#define AR71XX_USB_CTRL_SIZE 0x100 #define AR71XX_GPIO_BASE (AR71XX_APB_BASE + 0x00040000) #define AR71XX_GPIO_SIZE 0x100 #define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000) @@ -34,9 +40,26 @@ #define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000) #define AR71XX_RESET_SIZE 0x100 +#define AR7240_USB_CTRL_BASE (AR71XX_APB_BASE + 0x00030000) +#define AR7240_USB_CTRL_SIZE 0x100 +#define AR7240_OHCI_BASE 0x1b000000 +#define AR7240_OHCI_SIZE 0x1000 + +#define AR724X_EHCI_BASE 0x1b000000 +#define AR724X_EHCI_SIZE 0x1000 + +#define AR913X_EHCI_BASE 0x1b000000 +#define AR913X_EHCI_SIZE 0x1000 #define AR913X_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000) #define AR913X_WMAC_SIZE 0x30000 +#define AR933X_UART_BASE (AR71XX_APB_BASE + 0x00020000) +#define AR933X_UART_SIZE 0x14 +#define AR933X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) +#define AR933X_WMAC_SIZE 0x20000 +#define AR933X_EHCI_BASE 0x1b000000 +#define AR933X_EHCI_SIZE 0x1000 + /* * DDR_CTRL block */ @@ -63,6 +86,11 @@ #define AR913X_DDR_REG_FLUSH_USB 0x84 #define AR913X_DDR_REG_FLUSH_WMAC 0x88 +#define AR933X_DDR_REG_FLUSH_GE0 0x7c +#define AR933X_DDR_REG_FLUSH_GE1 0x80 +#define AR933X_DDR_REG_FLUSH_USB 0x84 +#define AR933X_DDR_REG_FLUSH_WMAC 0x88 + /* * PLL block */ @@ -104,6 +132,30 @@ #define AR913X_AHB_DIV_SHIFT 19 #define AR913X_AHB_DIV_MASK 0x1 +#define AR933X_PLL_CPU_CONFIG_REG 0x00 +#define AR933X_PLL_CLOCK_CTRL_REG 0x08 + +#define AR933X_PLL_CPU_CONFIG_NINT_SHIFT 10 +#define AR933X_PLL_CPU_CONFIG_NINT_MASK 0x3f +#define AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT 16 +#define AR933X_PLL_CPU_CONFIG_REFDIV_MASK 0x1f +#define AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT 23 +#define AR933X_PLL_CPU_CONFIG_OUTDIV_MASK 0x7 + +#define AR933X_PLL_CLOCK_CTRL_BYPASS BIT(2) +#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT 5 +#define AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK 0x3 +#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT 10 +#define AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK 0x3 +#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT 15 +#define AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK 0x7 + +/* + * USB_CONFIG block + */ +#define AR71XX_USB_CTRL_REG_FLADJ 0x00 +#define AR71XX_USB_CTRL_REG_CONFIG 0x04 + /* * RESET block */ @@ -130,6 +182,13 @@ #define AR724X_RESET_REG_RESET_MODULE 0x1c +#define AR933X_RESET_REG_RESET_MODULE 0x1c +#define AR933X_RESET_REG_BOOTSTRAP 0xac + +#define MISC_INT_ETHSW BIT(12) +#define MISC_INT_TIMER4 BIT(10) +#define MISC_INT_TIMER3 BIT(9) +#define MISC_INT_TIMER2 BIT(8) #define MISC_INT_DMA BIT(7) #define MISC_INT_OHCI BIT(6) #define MISC_INT_PERFC BIT(5) @@ -158,14 +217,29 @@ #define AR71XX_RESET_PCI_BUS BIT(1) #define AR71XX_RESET_PCI_CORE BIT(0) +#define AR7240_RESET_USB_HOST BIT(5) +#define AR7240_RESET_OHCI_DLL BIT(3) + #define AR724X_RESET_GE1_MDIO BIT(23) #define AR724X_RESET_GE0_MDIO BIT(22) #define AR724X_RESET_PCIE_PHY_SERIAL BIT(10) #define AR724X_RESET_PCIE_PHY BIT(7) #define AR724X_RESET_PCIE BIT(6) -#define AR724X_RESET_OHCI_DLL BIT(3) +#define AR724X_RESET_USB_HOST BIT(5) +#define AR724X_RESET_USB_PHY BIT(4) +#define AR724X_RESET_USBSUS_OVERRIDE BIT(3) #define AR913X_RESET_AMBA2WMAC BIT(22) +#define AR913X_RESET_USBSUS_OVERRIDE BIT(10) +#define AR913X_RESET_USB_HOST BIT(5) +#define AR913X_RESET_USB_PHY BIT(4) + +#define AR933X_RESET_WMAC BIT(11) +#define AR933X_RESET_USB_HOST BIT(5) +#define AR933X_RESET_USB_PHY BIT(4) +#define AR933X_RESET_USBSUS_OVERRIDE BIT(3) + +#define AR933X_BOOTSTRAP_REF_CLK_40 BIT(0) #define REV_ID_MAJOR_MASK 0xfff0 #define REV_ID_MAJOR_AR71XX 0x00a0 @@ -173,6 +247,8 @@ #define REV_ID_MAJOR_AR7240 0x00c0 #define REV_ID_MAJOR_AR7241 0x0100 #define REV_ID_MAJOR_AR7242 0x1100 +#define REV_ID_MAJOR_AR9330 0x0110 +#define REV_ID_MAJOR_AR9331 0x1110 #define AR71XX_REV_ID_MINOR_MASK 0x3 #define AR71XX_REV_ID_MINOR_AR7130 0x0 @@ -187,6 +263,8 @@ #define AR913X_REV_ID_REVISION_MASK 0x3 #define AR913X_REV_ID_REVISION_SHIFT 2 +#define AR933X_REV_ID_REVISION_MASK 0x3 + #define AR724X_REV_ID_REVISION_MASK 0x3 /* @@ -229,5 +307,6 @@ #define AR71XX_GPIO_COUNT 16 #define AR724X_GPIO_COUNT 18 #define AR913X_GPIO_COUNT 22 +#define AR933X_GPIO_COUNT 30 #endif /* __ASM_MACH_AR71XX_REGS_H */ diff --git a/arch/mips/include/asm/mach-ath79/ar933x_uart.h b/arch/mips/include/asm/mach-ath79/ar933x_uart.h new file mode 100644 index 000000000000..52730555937f --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ar933x_uart.h @@ -0,0 +1,67 @@ +/* + * Atheros AR933X UART defines + * + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * + * 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 __AR933X_UART_H +#define __AR933X_UART_H + +#define AR933X_UART_REGS_SIZE 20 +#define AR933X_UART_FIFO_SIZE 16 + +#define AR933X_UART_DATA_REG 0x00 +#define AR933X_UART_CS_REG 0x04 +#define AR933X_UART_CLOCK_REG 0x08 +#define AR933X_UART_INT_REG 0x0c +#define AR933X_UART_INT_EN_REG 0x10 + +#define AR933X_UART_DATA_TX_RX_MASK 0xff +#define AR933X_UART_DATA_RX_CSR BIT(8) +#define AR933X_UART_DATA_TX_CSR BIT(9) + +#define AR933X_UART_CS_PARITY_S 0 +#define AR933X_UART_CS_PARITY_M 0x3 +#define AR933X_UART_CS_PARITY_NONE 0 +#define AR933X_UART_CS_PARITY_ODD 1 +#define AR933X_UART_CS_PARITY_EVEN 2 +#define AR933X_UART_CS_IF_MODE_S 2 +#define AR933X_UART_CS_IF_MODE_M 0x3 +#define AR933X_UART_CS_IF_MODE_NONE 0 +#define AR933X_UART_CS_IF_MODE_DTE 1 +#define AR933X_UART_CS_IF_MODE_DCE 2 +#define AR933X_UART_CS_FLOW_CTRL_S 4 +#define AR933X_UART_CS_FLOW_CTRL_M 0x3 +#define AR933X_UART_CS_DMA_EN BIT(6) +#define AR933X_UART_CS_TX_READY_ORIDE BIT(7) +#define AR933X_UART_CS_RX_READY_ORIDE BIT(8) +#define AR933X_UART_CS_TX_READY BIT(9) +#define AR933X_UART_CS_RX_BREAK BIT(10) +#define AR933X_UART_CS_TX_BREAK BIT(11) +#define AR933X_UART_CS_HOST_INT BIT(12) +#define AR933X_UART_CS_HOST_INT_EN BIT(13) +#define AR933X_UART_CS_TX_BUSY BIT(14) +#define AR933X_UART_CS_RX_BUSY BIT(15) + +#define AR933X_UART_CLOCK_STEP_M 0xffff +#define AR933X_UART_CLOCK_SCALE_M 0xfff +#define AR933X_UART_CLOCK_SCALE_S 16 +#define AR933X_UART_CLOCK_STEP_M 0xffff + +#define AR933X_UART_INT_RX_VALID BIT(0) +#define AR933X_UART_INT_TX_READY BIT(1) +#define AR933X_UART_INT_RX_FRAMING_ERR BIT(2) +#define AR933X_UART_INT_RX_OFLOW_ERR BIT(3) +#define AR933X_UART_INT_TX_OFLOW_ERR BIT(4) +#define AR933X_UART_INT_RX_PARITY_ERR BIT(5) +#define AR933X_UART_INT_RX_BREAK_ON BIT(6) +#define AR933X_UART_INT_RX_BREAK_OFF BIT(7) +#define AR933X_UART_INT_RX_FULL BIT(8) +#define AR933X_UART_INT_TX_EMPTY BIT(9) +#define AR933X_UART_INT_ALLINTS 0x3ff + +#endif /* __AR933X_UART_H */ diff --git a/arch/mips/include/asm/mach-ath79/ar933x_uart_platform.h b/arch/mips/include/asm/mach-ath79/ar933x_uart_platform.h new file mode 100644 index 000000000000..6cb30f2b7198 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/ar933x_uart_platform.h @@ -0,0 +1,18 @@ +/* + * Platform data definition for Atheros AR933X UART + * + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * + * 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 _AR933X_UART_PLATFORM_H +#define _AR933X_UART_PLATFORM_H + +struct ar933x_uart_platform_data { + unsigned uartclk; +}; + +#endif /* _AR933X_UART_PLATFORM_H */ diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h index 6a9f168506fe..6d0c6c9d5622 100644 --- a/arch/mips/include/asm/mach-ath79/ath79.h +++ b/arch/mips/include/asm/mach-ath79/ath79.h @@ -26,10 +26,13 @@ enum ath79_soc_type { ATH79_SOC_AR7241, ATH79_SOC_AR7242, ATH79_SOC_AR9130, - ATH79_SOC_AR9132 + ATH79_SOC_AR9132, + ATH79_SOC_AR9330, + ATH79_SOC_AR9331, }; extern enum ath79_soc_type ath79_soc; +extern unsigned int ath79_soc_rev; static inline int soc_is_ar71xx(void) { @@ -66,6 +69,12 @@ static inline int soc_is_ar913x(void) ath79_soc == ATH79_SOC_AR9132); } +static inline int soc_is_ar933x(void) +{ + return (ath79_soc == ATH79_SOC_AR9330 || + ath79_soc == ATH79_SOC_AR9331); +} + extern void __iomem *ath79_ddr_base; extern void __iomem *ath79_pll_base; extern void __iomem *ath79_reset_base; diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h index 189bc6eb9c10..519958fe4e3c 100644 --- a/arch/mips/include/asm/mach-ath79/irq.h +++ b/arch/mips/include/asm/mach-ath79/irq.h @@ -10,10 +10,10 @@ #define __ASM_MACH_ATH79_IRQ_H #define MIPS_CPU_IRQ_BASE 0 -#define NR_IRQS 16 +#define NR_IRQS 40 #define ATH79_MISC_IRQ_BASE 8 -#define ATH79_MISC_IRQ_COUNT 8 +#define ATH79_MISC_IRQ_COUNT 32 #define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2) #define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3) @@ -30,6 +30,10 @@ #define ATH79_MISC_IRQ_PERFC (ATH79_MISC_IRQ_BASE + 5) #define ATH79_MISC_IRQ_OHCI (ATH79_MISC_IRQ_BASE + 6) #define ATH79_MISC_IRQ_DMA (ATH79_MISC_IRQ_BASE + 7) +#define ATH79_MISC_IRQ_TIMER2 (ATH79_MISC_IRQ_BASE + 8) +#define ATH79_MISC_IRQ_TIMER3 (ATH79_MISC_IRQ_BASE + 9) +#define ATH79_MISC_IRQ_TIMER4 (ATH79_MISC_IRQ_BASE + 10) +#define ATH79_MISC_IRQ_ETHSW (ATH79_MISC_IRQ_BASE + 12) #include_next <irq.h> diff --git a/arch/mips/include/asm/mach-ath79/pci-ath724x.h b/arch/mips/include/asm/mach-ath79/pci-ath724x.h new file mode 100644 index 000000000000..454885fa30c3 --- /dev/null +++ b/arch/mips/include/asm/mach-ath79/pci-ath724x.h @@ -0,0 +1,21 @@ +/* + * Atheros 724x PCI support + * + * Copyright (C) 2011 RenĂ© Bolldorf <xsecute@googlemail.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 __ASM_MACH_ATH79_PCI_ATH724X_H +#define __ASM_MACH_ATH79_PCI_ATH724X_H + +struct ath724x_pci_data { + int irq; + void *pdata; +}; + +void ath724x_pci_add_data(struct ath724x_pci_data *data, int size); + +#endif /* __ASM_MACH_ATH79_PCI_ATH724X_H */ diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index de24ec57dd2f..569828d3ccab 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -136,6 +136,7 @@ static inline int au1xxx_cpu_needs_config_od(void) #define ALCHEMY_CPU_AU1100 2 #define ALCHEMY_CPU_AU1550 3 #define ALCHEMY_CPU_AU1200 4 +#define ALCHEMY_CPU_AU1300 5 static inline int alchemy_get_cputype(void) { @@ -156,6 +157,9 @@ static inline int alchemy_get_cputype(void) case 0x05030000: return ALCHEMY_CPU_AU1200; break; + case 0x800c0000: + return ALCHEMY_CPU_AU1300; + break; } return ALCHEMY_CPU_UNKNOWN; @@ -166,6 +170,7 @@ static inline int alchemy_get_uarts(int type) { switch (type) { case ALCHEMY_CPU_AU1000: + case ALCHEMY_CPU_AU1300: return 4; case ALCHEMY_CPU_AU1500: case ALCHEMY_CPU_AU1200: @@ -243,6 +248,7 @@ extern unsigned long au1xxx_calc_clock(void); /* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */ void alchemy_sleep_au1000(void); void alchemy_sleep_au1550(void); +void alchemy_sleep_au1300(void); void au_sleep(void); /* USB: drivers/usb/host/alchemy-common.c */ @@ -251,6 +257,7 @@ enum alchemy_usb_block { ALCHEMY_USB_UDC0, ALCHEMY_USB_EHCI0, ALCHEMY_USB_OTG0, + ALCHEMY_USB_OHCI1, }; int alchemy_usb_control(int block, int enable); @@ -263,14 +270,92 @@ struct alchemy_pci_platdata { unsigned long pci_cfg_clr; }; -/* SOC Interrupt numbers */ +/* Multifunction pins: Each of these pins can either be assigned to the + * GPIO controller or a on-chip peripheral. + * Call "au1300_pinfunc_to_dev()" or "au1300_pinfunc_to_gpio()" to + * assign one of these to either the GPIO controller or the device. + */ +enum au1300_multifunc_pins { + /* wake-from-str pins 0-3 */ + AU1300_PIN_WAKE0 = 0, AU1300_PIN_WAKE1, AU1300_PIN_WAKE2, + AU1300_PIN_WAKE3, + /* external clock sources for PSCs: 4-5 */ + AU1300_PIN_EXTCLK0, AU1300_PIN_EXTCLK1, + /* 8bit MMC interface on SD0: 6-9 */ + AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6, + AU1300_PIN_SD0DAT7, + /* aux clk input for freqgen 3: 10 */ + AU1300_PIN_FG3AUX, + /* UART1 pins: 11-18 */ + AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR, + AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR, + AU1300_PIN_U1RX, AU1300_PIN_U1TX, + /* UART0 pins: 19-24 */ + AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR, + AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR, + /* UART2: 25-26 */ + AU1300_PIN_U2RX, AU1300_PIN_U2TX, + /* UART3: 27-28 */ + AU1300_PIN_U3RX, AU1300_PIN_U3TX, + /* LCD controller PWMs, ext pixclock: 29-31 */ + AU1300_PIN_LCDPWM0, AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN, + /* SD1 interface: 32-37 */ + AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2, + AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK, + /* SD2 interface: 38-43 */ + AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2, + AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK, + /* PSC0/1 clocks: 44-45 */ + AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK, + /* PSCs: 46-49/50-53/54-57/58-61 */ + AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0, + AU1300_PIN_PSC0D1, + AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0, + AU1300_PIN_PSC1D1, + AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_PSC2D0, + AU1300_PIN_PSC2D1, + AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0, + AU1300_PIN_PSC3D1, + /* PCMCIA interface: 62-70 */ + AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16, + AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT, + AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW, + /* camera interface H/V sync inputs: 71-72 */ + AU1300_PIN_CIMLS, AU1300_PIN_CIMFS, + /* PSC2/3 clocks: 73-74 */ + AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK, +}; + +/* GPIC (Au1300) pin management: arch/mips/alchemy/common/gpioint.c */ +extern void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio); +extern void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio); +extern void au1300_set_irq_priority(unsigned int irq, int p); +extern void au1300_set_dbdma_gpio(int dchan, unsigned int gpio); + +/* Au1300 allows to disconnect certain blocks from internal power supply */ +enum au1300_vss_block { + AU1300_VSS_MPE = 0, + AU1300_VSS_BSA, + AU1300_VSS_GPE, + AU1300_VSS_MGP, +}; +extern void au1300_vss_block_control(int block, int enable); + + +/* SOC Interrupt numbers */ +/* Au1000-style (IC0/1): 2 controllers with 32 sources each */ #define AU1000_INTC0_INT_BASE (MIPS_CPU_IRQ_BASE + 8) #define AU1000_INTC0_INT_LAST (AU1000_INTC0_INT_BASE + 31) #define AU1000_INTC1_INT_BASE (AU1000_INTC0_INT_LAST + 1) #define AU1000_INTC1_INT_LAST (AU1000_INTC1_INT_BASE + 31) #define AU1000_MAX_INTR AU1000_INTC1_INT_LAST +/* Au1300-style (GPIC): 1 controller with up to 128 sources */ +#define ALCHEMY_GPIC_INT_BASE (MIPS_CPU_IRQ_BASE + 8) +#define ALCHEMY_GPIC_INT_NUM 128 +#define ALCHEMY_GPIC_INT_LAST (ALCHEMY_GPIC_INT_BASE + ALCHEMY_GPIC_INT_NUM - 1) + enum soc_au1000_ints { AU1000_FIRST_INT = AU1000_INTC0_INT_BASE, AU1000_UART0_INT = AU1000_FIRST_INT, @@ -591,24 +676,77 @@ enum soc_au1200_ints { #endif /* !defined (_LANGUAGE_ASSEMBLY) */ +/* Au1300 peripheral interrupt numbers */ +#define AU1300_FIRST_INT (ALCHEMY_GPIC_INT_BASE) +#define AU1300_UART1_INT (AU1300_FIRST_INT + 17) +#define AU1300_UART2_INT (AU1300_FIRST_INT + 25) +#define AU1300_UART3_INT (AU1300_FIRST_INT + 27) +#define AU1300_SD1_INT (AU1300_FIRST_INT + 32) +#define AU1300_SD2_INT (AU1300_FIRST_INT + 38) +#define AU1300_PSC0_INT (AU1300_FIRST_INT + 48) +#define AU1300_PSC1_INT (AU1300_FIRST_INT + 52) +#define AU1300_PSC2_INT (AU1300_FIRST_INT + 56) +#define AU1300_PSC3_INT (AU1300_FIRST_INT + 60) +#define AU1300_NAND_INT (AU1300_FIRST_INT + 62) +#define AU1300_DDMA_INT (AU1300_FIRST_INT + 75) +#define AU1300_MMU_INT (AU1300_FIRST_INT + 76) +#define AU1300_MPU_INT (AU1300_FIRST_INT + 77) +#define AU1300_GPU_INT (AU1300_FIRST_INT + 78) +#define AU1300_UDMA_INT (AU1300_FIRST_INT + 79) +#define AU1300_TOY_INT (AU1300_FIRST_INT + 80) +#define AU1300_TOY_MATCH0_INT (AU1300_FIRST_INT + 81) +#define AU1300_TOY_MATCH1_INT (AU1300_FIRST_INT + 82) +#define AU1300_TOY_MATCH2_INT (AU1300_FIRST_INT + 83) +#define AU1300_RTC_INT (AU1300_FIRST_INT + 84) +#define AU1300_RTC_MATCH0_INT (AU1300_FIRST_INT + 85) +#define AU1300_RTC_MATCH1_INT (AU1300_FIRST_INT + 86) +#define AU1300_RTC_MATCH2_INT (AU1300_FIRST_INT + 87) +#define AU1300_UART0_INT (AU1300_FIRST_INT + 88) +#define AU1300_SD0_INT (AU1300_FIRST_INT + 89) +#define AU1300_USB_INT (AU1300_FIRST_INT + 90) +#define AU1300_LCD_INT (AU1300_FIRST_INT + 91) +#define AU1300_BSA_INT (AU1300_FIRST_INT + 92) +#define AU1300_MPE_INT (AU1300_FIRST_INT + 93) +#define AU1300_ITE_INT (AU1300_FIRST_INT + 94) +#define AU1300_AES_INT (AU1300_FIRST_INT + 95) +#define AU1300_CIM_INT (AU1300_FIRST_INT + 96) + +/**********************************************************************/ + /* * Physical base addresses for integrated peripherals - * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200 + * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200 5..au1300 */ #define AU1000_AC97_PHYS_ADDR 0x10000000 /* 012 */ +#define AU1300_ROM_PHYS_ADDR 0x10000000 /* 5 */ +#define AU1300_OTP_PHYS_ADDR 0x10002000 /* 5 */ +#define AU1300_VSS_PHYS_ADDR 0x10003000 /* 5 */ +#define AU1300_UART0_PHYS_ADDR 0x10100000 /* 5 */ +#define AU1300_UART1_PHYS_ADDR 0x10101000 /* 5 */ +#define AU1300_UART2_PHYS_ADDR 0x10102000 /* 5 */ +#define AU1300_UART3_PHYS_ADDR 0x10103000 /* 5 */ #define AU1000_USB_OHCI_PHYS_ADDR 0x10100000 /* 012 */ #define AU1000_USB_UDC_PHYS_ADDR 0x10200000 /* 0123 */ +#define AU1300_GPIC_PHYS_ADDR 0x10200000 /* 5 */ #define AU1000_IRDA_PHYS_ADDR 0x10300000 /* 02 */ -#define AU1200_AES_PHYS_ADDR 0x10300000 /* 4 */ +#define AU1200_AES_PHYS_ADDR 0x10300000 /* 45 */ #define AU1000_IC0_PHYS_ADDR 0x10400000 /* 01234 */ +#define AU1300_GPU_PHYS_ADDR 0x10500000 /* 5 */ #define AU1000_MAC0_PHYS_ADDR 0x10500000 /* 023 */ #define AU1000_MAC1_PHYS_ADDR 0x10510000 /* 023 */ #define AU1000_MACEN_PHYS_ADDR 0x10520000 /* 023 */ -#define AU1100_SD0_PHYS_ADDR 0x10600000 /* 24 */ +#define AU1100_SD0_PHYS_ADDR 0x10600000 /* 245 */ +#define AU1300_SD1_PHYS_ADDR 0x10601000 /* 5 */ +#define AU1300_SD2_PHYS_ADDR 0x10602000 /* 5 */ #define AU1100_SD1_PHYS_ADDR 0x10680000 /* 24 */ +#define AU1300_SYS_PHYS_ADDR 0x10900000 /* 5 */ #define AU1550_PSC2_PHYS_ADDR 0x10A00000 /* 3 */ #define AU1550_PSC3_PHYS_ADDR 0x10B00000 /* 3 */ +#define AU1300_PSC0_PHYS_ADDR 0x10A00000 /* 5 */ +#define AU1300_PSC1_PHYS_ADDR 0x10A01000 /* 5 */ +#define AU1300_PSC2_PHYS_ADDR 0x10A02000 /* 5 */ +#define AU1300_PSC3_PHYS_ADDR 0x10A03000 /* 5 */ #define AU1000_I2S_PHYS_ADDR 0x11000000 /* 02 */ #define AU1500_MAC0_PHYS_ADDR 0x11500000 /* 1 */ #define AU1500_MAC1_PHYS_ADDR 0x11510000 /* 1 */ @@ -622,37 +760,96 @@ enum soc_au1200_ints { #define AU1000_SSI1_PHYS_ADDR 0x11680000 /* 02 */ #define AU1500_GPIO2_PHYS_ADDR 0x11700000 /* 1234 */ #define AU1000_IC1_PHYS_ADDR 0x11800000 /* 01234 */ -#define AU1000_SYS_PHYS_ADDR 0x11900000 /* 01234 */ +#define AU1000_SYS_PHYS_ADDR 0x11900000 /* 012345 */ #define AU1550_PSC0_PHYS_ADDR 0x11A00000 /* 34 */ #define AU1550_PSC1_PHYS_ADDR 0x11B00000 /* 34 */ #define AU1000_MEM_PHYS_ADDR 0x14000000 /* 01234 */ #define AU1000_STATIC_MEM_PHYS_ADDR 0x14001000 /* 01234 */ +#define AU1300_UDMA_PHYS_ADDR 0x14001800 /* 5 */ #define AU1000_DMA_PHYS_ADDR 0x14002000 /* 012 */ -#define AU1550_DBDMA_PHYS_ADDR 0x14002000 /* 34 */ -#define AU1550_DBDMA_CONF_PHYS_ADDR 0x14003000 /* 34 */ +#define AU1550_DBDMA_PHYS_ADDR 0x14002000 /* 345 */ +#define AU1550_DBDMA_CONF_PHYS_ADDR 0x14003000 /* 345 */ #define AU1000_MACDMA0_PHYS_ADDR 0x14004000 /* 0123 */ #define AU1000_MACDMA1_PHYS_ADDR 0x14004200 /* 0123 */ -#define AU1200_CIM_PHYS_ADDR 0x14004000 /* 4 */ +#define AU1200_CIM_PHYS_ADDR 0x14004000 /* 45 */ #define AU1500_PCI_PHYS_ADDR 0x14005000 /* 13 */ #define AU1550_PE_PHYS_ADDR 0x14008000 /* 3 */ #define AU1200_MAEBE_PHYS_ADDR 0x14010000 /* 4 */ #define AU1200_MAEFE_PHYS_ADDR 0x14012000 /* 4 */ +#define AU1300_MAEITE_PHYS_ADDR 0x14010000 /* 5 */ +#define AU1300_MAEMPE_PHYS_ADDR 0x14014000 /* 5 */ #define AU1550_USB_OHCI_PHYS_ADDR 0x14020000 /* 3 */ #define AU1200_USB_CTL_PHYS_ADDR 0x14020000 /* 4 */ #define AU1200_USB_OTG_PHYS_ADDR 0x14020020 /* 4 */ #define AU1200_USB_OHCI_PHYS_ADDR 0x14020100 /* 4 */ #define AU1200_USB_EHCI_PHYS_ADDR 0x14020200 /* 4 */ #define AU1200_USB_UDC_PHYS_ADDR 0x14022000 /* 4 */ +#define AU1300_USB_EHCI_PHYS_ADDR 0x14020000 /* 5 */ +#define AU1300_USB_OHCI0_PHYS_ADDR 0x14020400 /* 5 */ +#define AU1300_USB_OHCI1_PHYS_ADDR 0x14020800 /* 5 */ +#define AU1300_USB_CTL_PHYS_ADDR 0x14021000 /* 5 */ +#define AU1300_USB_OTG_PHYS_ADDR 0x14022000 /* 5 */ +#define AU1300_MAEBSA_PHYS_ADDR 0x14030000 /* 5 */ #define AU1100_LCD_PHYS_ADDR 0x15000000 /* 2 */ -#define AU1200_LCD_PHYS_ADDR 0x15000000 /* 4 */ +#define AU1200_LCD_PHYS_ADDR 0x15000000 /* 45 */ #define AU1500_PCI_MEM_PHYS_ADDR 0x400000000ULL /* 13 */ #define AU1500_PCI_IO_PHYS_ADDR 0x500000000ULL /* 13 */ #define AU1500_PCI_CONFIG0_PHYS_ADDR 0x600000000ULL /* 13 */ #define AU1500_PCI_CONFIG1_PHYS_ADDR 0x680000000ULL /* 13 */ -#define AU1000_PCMCIA_IO_PHYS_ADDR 0xF00000000ULL /* 01234 */ -#define AU1000_PCMCIA_ATTR_PHYS_ADDR 0xF40000000ULL /* 01234 */ -#define AU1000_PCMCIA_MEM_PHYS_ADDR 0xF80000000ULL /* 01234 */ +#define AU1000_PCMCIA_IO_PHYS_ADDR 0xF00000000ULL /* 012345 */ +#define AU1000_PCMCIA_ATTR_PHYS_ADDR 0xF40000000ULL /* 012345 */ +#define AU1000_PCMCIA_MEM_PHYS_ADDR 0xF80000000ULL /* 012345 */ +/**********************************************************************/ + + +/* + * Au1300 GPIO+INT controller (GPIC) register offsets and bits + * Registers are 128bits (0x10 bytes), divided into 4 "banks". + */ +#define AU1300_GPIC_PINVAL 0x0000 +#define AU1300_GPIC_PINVALCLR 0x0010 +#define AU1300_GPIC_IPEND 0x0020 +#define AU1300_GPIC_PRIENC 0x0030 +#define AU1300_GPIC_IEN 0x0040 /* int_mask in manual */ +#define AU1300_GPIC_IDIS 0x0050 /* int_maskclr in manual */ +#define AU1300_GPIC_DMASEL 0x0060 +#define AU1300_GPIC_DEVSEL 0x0080 +#define AU1300_GPIC_DEVCLR 0x0090 +#define AU1300_GPIC_RSTVAL 0x00a0 +/* pin configuration space. one 32bit register for up to 128 IRQs */ +#define AU1300_GPIC_PINCFG 0x1000 + +#define GPIC_GPIO_TO_BIT(gpio) \ + (1 << ((gpio) & 0x1f)) + +#define GPIC_GPIO_BANKOFF(gpio) \ + (((gpio) >> 5) * 4) + +/* Pin Control bits: who owns the pin, what does it do */ +#define GPIC_CFG_PC_GPIN 0 +#define GPIC_CFG_PC_DEV 1 +#define GPIC_CFG_PC_GPOLOW 2 +#define GPIC_CFG_PC_GPOHIGH 3 +#define GPIC_CFG_PC_MASK 3 + +/* assign pin to MIPS IRQ line */ +#define GPIC_CFG_IL_SET(x) (((x) & 3) << 2) +#define GPIC_CFG_IL_MASK (3 << 2) + +/* pin interrupt type setup */ +#define GPIC_CFG_IC_OFF (0 << 4) +#define GPIC_CFG_IC_LEVEL_LOW (1 << 4) +#define GPIC_CFG_IC_LEVEL_HIGH (2 << 4) +#define GPIC_CFG_IC_EDGE_FALL (5 << 4) +#define GPIC_CFG_IC_EDGE_RISE (6 << 4) +#define GPIC_CFG_IC_EDGE_BOTH (7 << 4) +#define GPIC_CFG_IC_MASK (7 << 4) + +/* allow interrupt to wake cpu from 'wait' */ +#define GPIC_CFG_IDLEWAKE (1 << 7) + +/***********************************************************************/ /* Au1000 SDRAM memory controller register offsets */ #define AU1000_MEM_SDMODE0 0x0000 @@ -1068,44 +1265,20 @@ enum soc_au1200_ints { #define SSI_ENABLE_CD (1 << 1) #define SSI_ENABLE_E (1 << 0) -/* IrDA Controller */ -#define IRDA_BASE 0xB0300000 -#define IR_RING_PTR_STATUS (IRDA_BASE + 0x00) -#define IR_RING_BASE_ADDR_H (IRDA_BASE + 0x04) -#define IR_RING_BASE_ADDR_L (IRDA_BASE + 0x08) -#define IR_RING_SIZE (IRDA_BASE + 0x0C) -#define IR_RING_PROMPT (IRDA_BASE + 0x10) -#define IR_RING_ADDR_CMPR (IRDA_BASE + 0x14) -#define IR_INT_CLEAR (IRDA_BASE + 0x18) -#define IR_CONFIG_1 (IRDA_BASE + 0x20) -# define IR_RX_INVERT_LED (1 << 0) -# define IR_TX_INVERT_LED (1 << 1) -# define IR_ST (1 << 2) -# define IR_SF (1 << 3) -# define IR_SIR (1 << 4) -# define IR_MIR (1 << 5) -# define IR_FIR (1 << 6) -# define IR_16CRC (1 << 7) -# define IR_TD (1 << 8) -# define IR_RX_ALL (1 << 9) -# define IR_DMA_ENABLE (1 << 10) -# define IR_RX_ENABLE (1 << 11) -# define IR_TX_ENABLE (1 << 12) -# define IR_LOOPBACK (1 << 14) -# define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \ - IR_RX_ALL | IR_RX_ENABLE | IR_SF | IR_16CRC) -#define IR_SIR_FLAGS (IRDA_BASE + 0x24) -#define IR_ENABLE (IRDA_BASE + 0x28) -# define IR_RX_STATUS (1 << 9) -# define IR_TX_STATUS (1 << 10) -#define IR_READ_PHY_CONFIG (IRDA_BASE + 0x2C) -#define IR_WRITE_PHY_CONFIG (IRDA_BASE + 0x30) -#define IR_MAX_PKT_LEN (IRDA_BASE + 0x34) -#define IR_RX_BYTE_CNT (IRDA_BASE + 0x38) -#define IR_CONFIG_2 (IRDA_BASE + 0x3C) -# define IR_MODE_INV (1 << 0) -# define IR_ONE_PIN (1 << 1) -#define IR_INTERFACE_CONFIG (IRDA_BASE + 0x40) + +/* + * The IrDA peripheral has an IRFIRSEL pin, but on the DB/PB boards it's not + * used to select FIR/SIR mode on the transceiver but as a GPIO. Instead a + * CPLD has to be told about the mode. + */ +#define AU1000_IRDA_PHY_MODE_OFF 0 +#define AU1000_IRDA_PHY_MODE_SIR 1 +#define AU1000_IRDA_PHY_MODE_FIR 2 + +struct au1k_irda_platform_data { + void(*set_phy_mode)(int mode); +}; + /* GPIO */ #define SYS_PINFUNC 0xB190002C diff --git a/arch/mips/include/asm/mach-au1x00/au1100_mmc.h b/arch/mips/include/asm/mach-au1x00/au1100_mmc.h index 94000a3b6f0b..e221659f1bca 100644 --- a/arch/mips/include/asm/mach-au1x00/au1100_mmc.h +++ b/arch/mips/include/asm/mach-au1x00/au1100_mmc.h @@ -130,8 +130,10 @@ struct au1xmmc_platform_data { #define SD_CONFIG2_DF (0x00000008) #define SD_CONFIG2_DC (0x00000010) #define SD_CONFIG2_xx2 (0x000000e0) +#define SD_CONFIG2_BB (0x00000080) #define SD_CONFIG2_WB (0x00000100) #define SD_CONFIG2_RW (0x00000200) +#define SD_CONFIG2_DP (0x00000400) /* diff --git a/arch/mips/include/asm/mach-au1x00/au1200fb.h b/arch/mips/include/asm/mach-au1x00/au1200fb.h new file mode 100644 index 000000000000..b3c87cc64bb9 --- /dev/null +++ b/arch/mips/include/asm/mach-au1x00/au1200fb.h @@ -0,0 +1,14 @@ +/* + * platform data for au1200fb driver. + */ + +#ifndef _AU1200FB_PLAT_H_ +#define _AU1200FB_PLAT_H_ + +struct au1200fb_platdata { + int (*panel_index)(void); + int (*panel_init)(void); + int (*panel_shutdown)(void); +}; + +#endif diff --git a/arch/mips/include/asm/mach-au1x00/au1550nd.h b/arch/mips/include/asm/mach-au1x00/au1550nd.h new file mode 100644 index 000000000000..ad4c0a03afef --- /dev/null +++ b/arch/mips/include/asm/mach-au1x00/au1550nd.h @@ -0,0 +1,16 @@ +/* + * platform data for the Au1550 NAND driver + */ + +#ifndef _AU1550ND_H_ +#define _AU1550ND_H_ + +#include <linux/mtd/partitions.h> + +struct au1550nd_platdata { + struct mtd_partition *parts; + int num_parts; + int devwidth; /* 0 = 8bit device, 1 = 16bit device */ +}; + +#endif diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h index 323ce2d145f2..217810e18361 100644 --- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h +++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h @@ -183,6 +183,37 @@ typedef volatile struct au1xxx_ddma_desc { #define AU1200_DSCR_CMD0_PSC1_SYNC 25 #define AU1200_DSCR_CMD0_CIM_SYNC 26 +#define AU1300_DSCR_CMD0_UART0_TX 0 +#define AU1300_DSCR_CMD0_UART0_RX 1 +#define AU1300_DSCR_CMD0_UART1_TX 2 +#define AU1300_DSCR_CMD0_UART1_RX 3 +#define AU1300_DSCR_CMD0_UART2_TX 4 +#define AU1300_DSCR_CMD0_UART2_RX 5 +#define AU1300_DSCR_CMD0_UART3_TX 6 +#define AU1300_DSCR_CMD0_UART3_RX 7 +#define AU1300_DSCR_CMD0_SDMS_TX0 8 +#define AU1300_DSCR_CMD0_SDMS_RX0 9 +#define AU1300_DSCR_CMD0_SDMS_TX1 10 +#define AU1300_DSCR_CMD0_SDMS_RX1 11 +#define AU1300_DSCR_CMD0_AES_TX 12 +#define AU1300_DSCR_CMD0_AES_RX 13 +#define AU1300_DSCR_CMD0_PSC0_TX 14 +#define AU1300_DSCR_CMD0_PSC0_RX 15 +#define AU1300_DSCR_CMD0_PSC1_TX 16 +#define AU1300_DSCR_CMD0_PSC1_RX 17 +#define AU1300_DSCR_CMD0_PSC2_TX 18 +#define AU1300_DSCR_CMD0_PSC2_RX 19 +#define AU1300_DSCR_CMD0_PSC3_TX 20 +#define AU1300_DSCR_CMD0_PSC3_RX 21 +#define AU1300_DSCR_CMD0_LCD 22 +#define AU1300_DSCR_CMD0_NAND_FLASH 23 +#define AU1300_DSCR_CMD0_SDMS_TX2 24 +#define AU1300_DSCR_CMD0_SDMS_RX2 25 +#define AU1300_DSCR_CMD0_CIM_SYNC 26 +#define AU1300_DSCR_CMD0_UDMA 27 +#define AU1300_DSCR_CMD0_DMA_REQ0 28 +#define AU1300_DSCR_CMD0_DMA_REQ1 29 + #define DSCR_CMD0_THROTTLE 30 #define DSCR_CMD0_ALWAYS 31 #define DSCR_NDEV_IDS 32 diff --git a/arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h b/arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h index d5df0cab9b87..3f741af37d47 100644 --- a/arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-au1x00/cpu-feature-overrides.h @@ -13,12 +13,14 @@ #define cpu_has_4k_cache 1 #define cpu_has_tx39_cache 0 #define cpu_has_fpu 0 +#define cpu_has_32fpr 0 #define cpu_has_counter 1 #define cpu_has_watch 1 #define cpu_has_divec 1 #define cpu_has_vce 0 #define cpu_has_cache_cdex_p 0 #define cpu_has_cache_cdex_s 0 +#define cpu_has_prefetch 1 #define cpu_has_mcheck 1 #define cpu_has_ejtag 1 #define cpu_has_llsc 1 @@ -29,6 +31,7 @@ #define cpu_has_vtag_icache 0 #define cpu_has_dc_aliases 0 #define cpu_has_ic_fills_f_dc 1 +#define cpu_has_pindexed_dcache 0 #define cpu_has_mips32r1 1 #define cpu_has_mips32r2 0 #define cpu_has_mips64r1 0 diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1300.h b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h new file mode 100644 index 000000000000..556e1be20bf6 --- /dev/null +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h @@ -0,0 +1,241 @@ +/* + * gpio-au1300.h -- GPIO control for Au1300 GPIC and compatibles. + * + * Copyright (c) 2009-2011 Manuel Lauss <manuel.lauss@googlemail.com> + */ + +#ifndef _GPIO_AU1300_H_ +#define _GPIO_AU1300_H_ + +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/mach-au1x00/au1000.h> + +/* with the current GPIC design, up to 128 GPIOs are possible. + * The only implementation so far is in the Au1300, which has 75 externally + * available GPIOs. + */ +#define AU1300_GPIO_BASE 0 +#define AU1300_GPIO_NUM 75 +#define AU1300_GPIO_MAX (AU1300_GPIO_BASE + AU1300_GPIO_NUM - 1) + +#define AU1300_GPIC_ADDR \ + (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR) + +static inline int au1300_gpio_get_value(unsigned int gpio) +{ + void __iomem *roff = AU1300_GPIC_ADDR; + int bit; + + gpio -= AU1300_GPIO_BASE; + roff += GPIC_GPIO_BANKOFF(gpio); + bit = GPIC_GPIO_TO_BIT(gpio); + return __raw_readl(roff + AU1300_GPIC_PINVAL) & bit; +} + +static inline int au1300_gpio_direction_input(unsigned int gpio) +{ + void __iomem *roff = AU1300_GPIC_ADDR; + unsigned long bit; + + gpio -= AU1300_GPIO_BASE; + + roff += GPIC_GPIO_BANKOFF(gpio); + bit = GPIC_GPIO_TO_BIT(gpio); + __raw_writel(bit, roff + AU1300_GPIC_DEVCLR); + wmb(); + + return 0; +} + +static inline int au1300_gpio_set_value(unsigned int gpio, int v) +{ + void __iomem *roff = AU1300_GPIC_ADDR; + unsigned long bit; + + gpio -= AU1300_GPIO_BASE; + + roff += GPIC_GPIO_BANKOFF(gpio); + bit = GPIC_GPIO_TO_BIT(gpio); + __raw_writel(bit, roff + (v ? AU1300_GPIC_PINVAL + : AU1300_GPIC_PINVALCLR)); + wmb(); + + return 0; +} + +static inline int au1300_gpio_direction_output(unsigned int gpio, int v) +{ + /* hw switches to output automatically */ + return au1300_gpio_set_value(gpio, v); +} + +static inline int au1300_gpio_to_irq(unsigned int gpio) +{ + return AU1300_FIRST_INT + (gpio - AU1300_GPIO_BASE); +} + +static inline int au1300_irq_to_gpio(unsigned int irq) +{ + return (irq - AU1300_FIRST_INT) + AU1300_GPIO_BASE; +} + +static inline int au1300_gpio_is_valid(unsigned int gpio) +{ + int ret; + + switch (alchemy_get_cputype()) { + case ALCHEMY_CPU_AU1300: + ret = ((gpio >= AU1300_GPIO_BASE) && (gpio <= AU1300_GPIO_MAX)); + break; + default: + ret = 0; + } + return ret; +} + +static inline int au1300_gpio_cansleep(unsigned int gpio) +{ + return 0; +} + +/* hardware remembers gpio 0-63 levels on powerup */ +static inline int au1300_gpio_getinitlvl(unsigned int gpio) +{ + void __iomem *roff = AU1300_GPIC_ADDR; + unsigned long v; + + if (unlikely(gpio > 63)) + return 0; + else if (gpio > 31) { + gpio -= 32; + roff += 4; + } + + v = __raw_readl(roff + AU1300_GPIC_RSTVAL); + return (v >> gpio) & 1; +} + +/**********************************************************************/ + +/* Linux gpio framework integration. +* +* 4 use cases of Alchemy GPIOS: +*(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y: +* Board must register gpiochips. +*(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n: +* A gpiochip for the 75 GPIOs is registered. +* +*(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y: +* the boards' gpio.h must provide the linux gpio wrapper functions, +* +*(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n: +* inlinable gpio functions are provided which enable access to the +* Au1300 gpios only by using the numbers straight out of the data- +* sheets. + +* Cases 1 and 3 are intended for boards which want to provide their own +* GPIO namespace and -operations (i.e. for example you have 8 GPIOs +* which are in part provided by spare Au1300 GPIO pins and in part by +* an external FPGA but you still want them to be accssible in linux +* as gpio0-7. The board can of course use the alchemy_gpioX_* functions +* as required). +*/ + +#ifndef CONFIG_GPIOLIB + +#ifdef CONFIG_ALCHEMY_GPIOINT_AU1300 + +#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT /* case (4) */ + +static inline int gpio_direction_input(unsigned int gpio) +{ + return au1300_gpio_direction_input(gpio); +} + +static inline int gpio_direction_output(unsigned int gpio, int v) +{ + return au1300_gpio_direction_output(gpio, v); +} + +static inline int gpio_get_value(unsigned int gpio) +{ + return au1300_gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned int gpio, int v) +{ + au1300_gpio_set_value(gpio, v); +} + +static inline int gpio_get_value_cansleep(unsigned gpio) +{ + return gpio_get_value(gpio); +} + +static inline void gpio_set_value_cansleep(unsigned gpio, int value) +{ + gpio_set_value(gpio, value); +} + +static inline int gpio_is_valid(unsigned int gpio) +{ + return au1300_gpio_is_valid(gpio); +} + +static inline int gpio_cansleep(unsigned int gpio) +{ + return au1300_gpio_cansleep(gpio); +} + +static inline int gpio_to_irq(unsigned int gpio) +{ + return au1300_gpio_to_irq(gpio); +} + +static inline int irq_to_gpio(unsigned int irq) +{ + return au1300_irq_to_gpio(irq); +} + +static inline int gpio_request(unsigned int gpio, const char *label) +{ + return 0; +} + +static inline void gpio_free(unsigned int gpio) +{ +} + +static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) +{ + return -ENOSYS; +} + +static inline void gpio_unexport(unsigned gpio) +{ +} + +static inline int gpio_export(unsigned gpio, bool direction_may_change) +{ + return -ENOSYS; +} + +static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) +{ + return -ENOSYS; +} + +static inline int gpio_export_link(struct device *dev, const char *name, + unsigned gpio) +{ + return -ENOSYS; +} + +#endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ + +#endif /* CONFIG_ALCHEMY_GPIOINT_AU1300 */ + +#endif /* CONFIG GPIOLIB */ + +#endif /* _GPIO_AU1300_H_ */ diff --git a/arch/mips/include/asm/mach-au1x00/gpio.h b/arch/mips/include/asm/mach-au1x00/gpio.h index fcdc8c4809db..22e7ff17fc48 100644 --- a/arch/mips/include/asm/mach-au1x00/gpio.h +++ b/arch/mips/include/asm/mach-au1x00/gpio.h @@ -12,6 +12,7 @@ #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/gpio-au1000.h> +#include <asm/mach-au1x00/gpio-au1300.h> /* On Au1000, Au1500 and Au1100 GPIOs won't work as inputs before * SYS_PININPUTEN is written to at least once. On Au1550/Au1200/Au1300 this @@ -58,6 +59,8 @@ static inline int __au_irq_to_gpio(unsigned int irq) switch (alchemy_get_cputype()) { case ALCHEMY_CPU_AU1000...ALCHEMY_CPU_AU1200: return alchemy_irq_to_gpio(irq); + case ALCHEMY_CPU_AU1300: + return au1300_irq_to_gpio(irq); } return -EINVAL; } diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h index 96a2391ad85b..5b8d15bb5fe8 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h @@ -13,6 +13,7 @@ #define BCM6345_CPU_ID 0x6345 #define BCM6348_CPU_ID 0x6348 #define BCM6358_CPU_ID 0x6358 +#define BCM6368_CPU_ID 0x6368 void __init bcm63xx_cpu_init(void); u16 __bcm63xx_get_cpu_id(void); @@ -71,6 +72,19 @@ unsigned int bcm63xx_get_cpu_freq(void); # define BCMCPU_IS_6358() (0) #endif +#ifdef CONFIG_BCM63XX_CPU_6368 +# ifdef bcm63xx_get_cpu_id +# undef bcm63xx_get_cpu_id +# define bcm63xx_get_cpu_id() __bcm63xx_get_cpu_id() +# define BCMCPU_RUNTIME_DETECT +# else +# define bcm63xx_get_cpu_id() BCM6368_CPU_ID +# endif +# define BCMCPU_IS_6368() (bcm63xx_get_cpu_id() == BCM6368_CPU_ID) +#else +# define BCMCPU_IS_6368() (0) +#endif + #ifndef bcm63xx_get_cpu_id #error "No CPU support configured" #endif @@ -88,6 +102,7 @@ enum bcm63xx_regs_set { RSET_UART1, RSET_GPIO, RSET_SPI, + RSET_SPI2, RSET_UDC0, RSET_OHCI0, RSET_OHCI_PRIV, @@ -98,10 +113,23 @@ enum bcm63xx_regs_set { RSET_ENET0, RSET_ENET1, RSET_ENETDMA, + RSET_ENETDMAC, + RSET_ENETDMAS, + RSET_ENETSW, RSET_EHCI0, RSET_SDRAM, RSET_MEMC, RSET_DDR, + RSET_M2M, + RSET_ATM, + RSET_XTM, + RSET_XTMDMA, + RSET_XTMDMAC, + RSET_XTMDMAS, + RSET_PCM, + RSET_PCMDMA, + RSET_PCMDMAC, + RSET_PCMDMAS, }; #define RSET_DSL_LMEM_SIZE (64 * 1024 * 4) @@ -109,11 +137,18 @@ enum bcm63xx_regs_set { #define RSET_WDT_SIZE 12 #define RSET_ENET_SIZE 2048 #define RSET_ENETDMA_SIZE 2048 +#define RSET_ENETSW_SIZE 65536 #define RSET_UART_SIZE 24 #define RSET_UDC_SIZE 256 #define RSET_OHCI_SIZE 256 #define RSET_EHCI_SIZE 256 #define RSET_PCMCIA_SIZE 12 +#define RSET_M2M_SIZE 256 +#define RSET_ATM_SIZE 4096 +#define RSET_XTM_SIZE 10240 +#define RSET_XTMDMA_SIZE 256 +#define RSET_XTMDMAC_SIZE(chans) (16 * (chans)) +#define RSET_XTMDMAS_SIZE(chans) (16 * (chans)) /* * 6338 register sets base address @@ -127,6 +162,7 @@ enum bcm63xx_regs_set { #define BCM_6338_UART1_BASE (0xdeadbeef) #define BCM_6338_GPIO_BASE (0xfffe0400) #define BCM_6338_SPI_BASE (0xfffe0c00) +#define BCM_6338_SPI2_BASE (0xdeadbeef) #define BCM_6338_UDC0_BASE (0xdeadbeef) #define BCM_6338_USBDMA_BASE (0xfffe2400) #define BCM_6338_OHCI0_BASE (0xdeadbeef) @@ -136,15 +172,27 @@ enum bcm63xx_regs_set { #define BCM_6338_PCMCIA_BASE (0xdeadbeef) #define BCM_6338_SDRAM_REGS_BASE (0xfffe3100) #define BCM_6338_DSL_BASE (0xfffe1000) -#define BCM_6338_SAR_BASE (0xfffe2000) #define BCM_6338_UBUS_BASE (0xdeadbeef) #define BCM_6338_ENET0_BASE (0xfffe2800) #define BCM_6338_ENET1_BASE (0xdeadbeef) #define BCM_6338_ENETDMA_BASE (0xfffe2400) +#define BCM_6338_ENETDMAC_BASE (0xfffe2500) +#define BCM_6338_ENETDMAS_BASE (0xfffe2600) +#define BCM_6338_ENETSW_BASE (0xdeadbeef) #define BCM_6338_EHCI0_BASE (0xdeadbeef) #define BCM_6338_SDRAM_BASE (0xfffe3100) #define BCM_6338_MEMC_BASE (0xdeadbeef) #define BCM_6338_DDR_BASE (0xdeadbeef) +#define BCM_6338_M2M_BASE (0xdeadbeef) +#define BCM_6338_ATM_BASE (0xfffe2000) +#define BCM_6338_XTM_BASE (0xdeadbeef) +#define BCM_6338_XTMDMA_BASE (0xdeadbeef) +#define BCM_6338_XTMDMAC_BASE (0xdeadbeef) +#define BCM_6338_XTMDMAS_BASE (0xdeadbeef) +#define BCM_6338_PCM_BASE (0xdeadbeef) +#define BCM_6338_PCMDMA_BASE (0xdeadbeef) +#define BCM_6338_PCMDMAC_BASE (0xdeadbeef) +#define BCM_6338_PCMDMAS_BASE (0xdeadbeef) /* * 6345 register sets base address @@ -158,24 +206,37 @@ enum bcm63xx_regs_set { #define BCM_6345_UART1_BASE (0xdeadbeef) #define BCM_6345_GPIO_BASE (0xfffe0400) #define BCM_6345_SPI_BASE (0xdeadbeef) +#define BCM_6345_SPI2_BASE (0xdeadbeef) #define BCM_6345_UDC0_BASE (0xdeadbeef) #define BCM_6345_USBDMA_BASE (0xfffe2800) #define BCM_6345_ENET0_BASE (0xfffe1800) #define BCM_6345_ENETDMA_BASE (0xfffe2800) +#define BCM_6345_ENETDMAC_BASE (0xfffe2900) +#define BCM_6345_ENETDMAS_BASE (0xfffe2a00) +#define BCM_6345_ENETSW_BASE (0xdeadbeef) #define BCM_6345_PCMCIA_BASE (0xfffe2028) -#define BCM_6345_MPI_BASE (0xdeadbeef) +#define BCM_6345_MPI_BASE (0xfffe2000) #define BCM_6345_OHCI0_BASE (0xfffe2100) #define BCM_6345_OHCI_PRIV_BASE (0xfffe2200) #define BCM_6345_USBH_PRIV_BASE (0xdeadbeef) #define BCM_6345_SDRAM_REGS_BASE (0xfffe2300) #define BCM_6345_DSL_BASE (0xdeadbeef) -#define BCM_6345_SAR_BASE (0xdeadbeef) #define BCM_6345_UBUS_BASE (0xdeadbeef) #define BCM_6345_ENET1_BASE (0xdeadbeef) #define BCM_6345_EHCI0_BASE (0xdeadbeef) #define BCM_6345_SDRAM_BASE (0xfffe2300) #define BCM_6345_MEMC_BASE (0xdeadbeef) #define BCM_6345_DDR_BASE (0xdeadbeef) +#define BCM_6345_M2M_BASE (0xdeadbeef) +#define BCM_6345_ATM_BASE (0xfffe4000) +#define BCM_6345_XTM_BASE (0xdeadbeef) +#define BCM_6345_XTMDMA_BASE (0xdeadbeef) +#define BCM_6345_XTMDMAC_BASE (0xdeadbeef) +#define BCM_6345_XTMDMAS_BASE (0xdeadbeef) +#define BCM_6345_PCM_BASE (0xdeadbeef) +#define BCM_6345_PCMDMA_BASE (0xdeadbeef) +#define BCM_6345_PCMDMAC_BASE (0xdeadbeef) +#define BCM_6345_PCMDMAS_BASE (0xdeadbeef) /* * 6348 register sets base address @@ -188,6 +249,7 @@ enum bcm63xx_regs_set { #define BCM_6348_UART1_BASE (0xdeadbeef) #define BCM_6348_GPIO_BASE (0xfffe0400) #define BCM_6348_SPI_BASE (0xfffe0c00) +#define BCM_6348_SPI2_BASE (0xdeadbeef) #define BCM_6348_UDC0_BASE (0xfffe1000) #define BCM_6348_OHCI0_BASE (0xfffe1b00) #define BCM_6348_OHCI_PRIV_BASE (0xfffe1c00) @@ -195,14 +257,27 @@ enum bcm63xx_regs_set { #define BCM_6348_MPI_BASE (0xfffe2000) #define BCM_6348_PCMCIA_BASE (0xfffe2054) #define BCM_6348_SDRAM_REGS_BASE (0xfffe2300) +#define BCM_6348_M2M_BASE (0xfffe2800) #define BCM_6348_DSL_BASE (0xfffe3000) #define BCM_6348_ENET0_BASE (0xfffe6000) #define BCM_6348_ENET1_BASE (0xfffe6800) #define BCM_6348_ENETDMA_BASE (0xfffe7000) +#define BCM_6348_ENETDMAC_BASE (0xfffe7100) +#define BCM_6348_ENETDMAS_BASE (0xfffe7200) +#define BCM_6348_ENETSW_BASE (0xdeadbeef) #define BCM_6348_EHCI0_BASE (0xdeadbeef) #define BCM_6348_SDRAM_BASE (0xfffe2300) #define BCM_6348_MEMC_BASE (0xdeadbeef) #define BCM_6348_DDR_BASE (0xdeadbeef) +#define BCM_6348_ATM_BASE (0xfffe4000) +#define BCM_6348_XTM_BASE (0xdeadbeef) +#define BCM_6348_XTMDMA_BASE (0xdeadbeef) +#define BCM_6348_XTMDMAC_BASE (0xdeadbeef) +#define BCM_6348_XTMDMAS_BASE (0xdeadbeef) +#define BCM_6348_PCM_BASE (0xdeadbeef) +#define BCM_6348_PCMDMA_BASE (0xdeadbeef) +#define BCM_6348_PCMDMAC_BASE (0xdeadbeef) +#define BCM_6348_PCMDMAS_BASE (0xdeadbeef) /* * 6358 register sets base address @@ -215,6 +290,7 @@ enum bcm63xx_regs_set { #define BCM_6358_UART1_BASE (0xfffe0120) #define BCM_6358_GPIO_BASE (0xfffe0080) #define BCM_6358_SPI_BASE (0xdeadbeef) +#define BCM_6358_SPI2_BASE (0xfffe0800) #define BCM_6358_UDC0_BASE (0xfffe0800) #define BCM_6358_OHCI0_BASE (0xfffe1400) #define BCM_6358_OHCI_PRIV_BASE (0xdeadbeef) @@ -222,214 +298,175 @@ enum bcm63xx_regs_set { #define BCM_6358_MPI_BASE (0xfffe1000) #define BCM_6358_PCMCIA_BASE (0xfffe1054) #define BCM_6358_SDRAM_REGS_BASE (0xfffe2300) +#define BCM_6358_M2M_BASE (0xdeadbeef) #define BCM_6358_DSL_BASE (0xfffe3000) #define BCM_6358_ENET0_BASE (0xfffe4000) #define BCM_6358_ENET1_BASE (0xfffe4800) #define BCM_6358_ENETDMA_BASE (0xfffe5000) +#define BCM_6358_ENETDMAC_BASE (0xfffe5100) +#define BCM_6358_ENETDMAS_BASE (0xfffe5200) +#define BCM_6358_ENETSW_BASE (0xdeadbeef) #define BCM_6358_EHCI0_BASE (0xfffe1300) #define BCM_6358_SDRAM_BASE (0xdeadbeef) #define BCM_6358_MEMC_BASE (0xfffe1200) #define BCM_6358_DDR_BASE (0xfffe12a0) +#define BCM_6358_ATM_BASE (0xfffe2000) +#define BCM_6358_XTM_BASE (0xdeadbeef) +#define BCM_6358_XTMDMA_BASE (0xdeadbeef) +#define BCM_6358_XTMDMAC_BASE (0xdeadbeef) +#define BCM_6358_XTMDMAS_BASE (0xdeadbeef) +#define BCM_6358_PCM_BASE (0xfffe1600) +#define BCM_6358_PCMDMA_BASE (0xfffe1800) +#define BCM_6358_PCMDMAC_BASE (0xfffe1900) +#define BCM_6358_PCMDMAS_BASE (0xfffe1a00) + + +/* + * 6368 register sets base address + */ +#define BCM_6368_DSL_LMEM_BASE (0xdeadbeef) +#define BCM_6368_PERF_BASE (0xb0000000) +#define BCM_6368_TIMER_BASE (0xb0000040) +#define BCM_6368_WDT_BASE (0xb000005c) +#define BCM_6368_UART0_BASE (0xb0000100) +#define BCM_6368_UART1_BASE (0xb0000120) +#define BCM_6368_GPIO_BASE (0xb0000080) +#define BCM_6368_SPI_BASE (0xdeadbeef) +#define BCM_6368_SPI2_BASE (0xb0000800) +#define BCM_6368_UDC0_BASE (0xdeadbeef) +#define BCM_6368_OHCI0_BASE (0xb0001600) +#define BCM_6368_OHCI_PRIV_BASE (0xdeadbeef) +#define BCM_6368_USBH_PRIV_BASE (0xb0001700) +#define BCM_6368_MPI_BASE (0xb0001000) +#define BCM_6368_PCMCIA_BASE (0xb0001054) +#define BCM_6368_SDRAM_REGS_BASE (0xdeadbeef) +#define BCM_6368_M2M_BASE (0xdeadbeef) +#define BCM_6368_DSL_BASE (0xdeadbeef) +#define BCM_6368_ENET0_BASE (0xdeadbeef) +#define BCM_6368_ENET1_BASE (0xdeadbeef) +#define BCM_6368_ENETDMA_BASE (0xb0006800) +#define BCM_6368_ENETDMAC_BASE (0xb0006a00) +#define BCM_6368_ENETDMAS_BASE (0xb0006c00) +#define BCM_6368_ENETSW_BASE (0xb0f00000) +#define BCM_6368_EHCI0_BASE (0xb0001500) +#define BCM_6368_SDRAM_BASE (0xdeadbeef) +#define BCM_6368_MEMC_BASE (0xb0001200) +#define BCM_6368_DDR_BASE (0xb0001280) +#define BCM_6368_ATM_BASE (0xdeadbeef) +#define BCM_6368_XTM_BASE (0xb0001800) +#define BCM_6368_XTMDMA_BASE (0xb0005000) +#define BCM_6368_XTMDMAC_BASE (0xb0005200) +#define BCM_6368_XTMDMAS_BASE (0xb0005400) +#define BCM_6368_PCM_BASE (0xb0004000) +#define BCM_6368_PCMDMA_BASE (0xb0005800) +#define BCM_6368_PCMDMAC_BASE (0xb0005a00) +#define BCM_6368_PCMDMAS_BASE (0xb0005c00) extern const unsigned long *bcm63xx_regs_base; +#define __GEN_RSET_BASE(__cpu, __rset) \ + case RSET_## __rset : \ + return BCM_## __cpu ##_## __rset ##_BASE; + +#define __GEN_RSET(__cpu) \ + switch (set) { \ + __GEN_RSET_BASE(__cpu, DSL_LMEM) \ + __GEN_RSET_BASE(__cpu, PERF) \ + __GEN_RSET_BASE(__cpu, TIMER) \ + __GEN_RSET_BASE(__cpu, WDT) \ + __GEN_RSET_BASE(__cpu, UART0) \ + __GEN_RSET_BASE(__cpu, UART1) \ + __GEN_RSET_BASE(__cpu, GPIO) \ + __GEN_RSET_BASE(__cpu, SPI) \ + __GEN_RSET_BASE(__cpu, SPI2) \ + __GEN_RSET_BASE(__cpu, UDC0) \ + __GEN_RSET_BASE(__cpu, OHCI0) \ + __GEN_RSET_BASE(__cpu, OHCI_PRIV) \ + __GEN_RSET_BASE(__cpu, USBH_PRIV) \ + __GEN_RSET_BASE(__cpu, MPI) \ + __GEN_RSET_BASE(__cpu, PCMCIA) \ + __GEN_RSET_BASE(__cpu, DSL) \ + __GEN_RSET_BASE(__cpu, ENET0) \ + __GEN_RSET_BASE(__cpu, ENET1) \ + __GEN_RSET_BASE(__cpu, ENETDMA) \ + __GEN_RSET_BASE(__cpu, ENETDMAC) \ + __GEN_RSET_BASE(__cpu, ENETDMAS) \ + __GEN_RSET_BASE(__cpu, ENETSW) \ + __GEN_RSET_BASE(__cpu, EHCI0) \ + __GEN_RSET_BASE(__cpu, SDRAM) \ + __GEN_RSET_BASE(__cpu, MEMC) \ + __GEN_RSET_BASE(__cpu, DDR) \ + __GEN_RSET_BASE(__cpu, M2M) \ + __GEN_RSET_BASE(__cpu, ATM) \ + __GEN_RSET_BASE(__cpu, XTM) \ + __GEN_RSET_BASE(__cpu, XTMDMA) \ + __GEN_RSET_BASE(__cpu, XTMDMAC) \ + __GEN_RSET_BASE(__cpu, XTMDMAS) \ + __GEN_RSET_BASE(__cpu, PCM) \ + __GEN_RSET_BASE(__cpu, PCMDMA) \ + __GEN_RSET_BASE(__cpu, PCMDMAC) \ + __GEN_RSET_BASE(__cpu, PCMDMAS) \ + } + +#define __GEN_CPU_REGS_TABLE(__cpu) \ + [RSET_DSL_LMEM] = BCM_## __cpu ##_DSL_LMEM_BASE, \ + [RSET_PERF] = BCM_## __cpu ##_PERF_BASE, \ + [RSET_TIMER] = BCM_## __cpu ##_TIMER_BASE, \ + [RSET_WDT] = BCM_## __cpu ##_WDT_BASE, \ + [RSET_UART0] = BCM_## __cpu ##_UART0_BASE, \ + [RSET_UART1] = BCM_## __cpu ##_UART1_BASE, \ + [RSET_GPIO] = BCM_## __cpu ##_GPIO_BASE, \ + [RSET_SPI] = BCM_## __cpu ##_SPI_BASE, \ + [RSET_SPI2] = BCM_## __cpu ##_SPI2_BASE, \ + [RSET_UDC0] = BCM_## __cpu ##_UDC0_BASE, \ + [RSET_OHCI0] = BCM_## __cpu ##_OHCI0_BASE, \ + [RSET_OHCI_PRIV] = BCM_## __cpu ##_OHCI_PRIV_BASE, \ + [RSET_USBH_PRIV] = BCM_## __cpu ##_USBH_PRIV_BASE, \ + [RSET_MPI] = BCM_## __cpu ##_MPI_BASE, \ + [RSET_PCMCIA] = BCM_## __cpu ##_PCMCIA_BASE, \ + [RSET_DSL] = BCM_## __cpu ##_DSL_BASE, \ + [RSET_ENET0] = BCM_## __cpu ##_ENET0_BASE, \ + [RSET_ENET1] = BCM_## __cpu ##_ENET1_BASE, \ + [RSET_ENETDMA] = BCM_## __cpu ##_ENETDMA_BASE, \ + [RSET_ENETDMAC] = BCM_## __cpu ##_ENETDMAC_BASE, \ + [RSET_ENETDMAS] = BCM_## __cpu ##_ENETDMAS_BASE, \ + [RSET_ENETSW] = BCM_## __cpu ##_ENETSW_BASE, \ + [RSET_EHCI0] = BCM_## __cpu ##_EHCI0_BASE, \ + [RSET_SDRAM] = BCM_## __cpu ##_SDRAM_BASE, \ + [RSET_MEMC] = BCM_## __cpu ##_MEMC_BASE, \ + [RSET_DDR] = BCM_## __cpu ##_DDR_BASE, \ + [RSET_M2M] = BCM_## __cpu ##_M2M_BASE, \ + [RSET_ATM] = BCM_## __cpu ##_ATM_BASE, \ + [RSET_XTM] = BCM_## __cpu ##_XTM_BASE, \ + [RSET_XTMDMA] = BCM_## __cpu ##_XTMDMA_BASE, \ + [RSET_XTMDMAC] = BCM_## __cpu ##_XTMDMAC_BASE, \ + [RSET_XTMDMAS] = BCM_## __cpu ##_XTMDMAS_BASE, \ + [RSET_PCM] = BCM_## __cpu ##_PCM_BASE, \ + [RSET_PCMDMA] = BCM_## __cpu ##_PCMDMA_BASE, \ + [RSET_PCMDMAC] = BCM_## __cpu ##_PCMDMAC_BASE, \ + [RSET_PCMDMAS] = BCM_## __cpu ##_PCMDMAS_BASE, \ + + static inline unsigned long bcm63xx_regset_address(enum bcm63xx_regs_set set) { #ifdef BCMCPU_RUNTIME_DETECT return bcm63xx_regs_base[set]; #else #ifdef CONFIG_BCM63XX_CPU_6338 - switch (set) { - case RSET_DSL_LMEM: - return BCM_6338_DSL_LMEM_BASE; - case RSET_PERF: - return BCM_6338_PERF_BASE; - case RSET_TIMER: - return BCM_6338_TIMER_BASE; - case RSET_WDT: - return BCM_6338_WDT_BASE; - case RSET_UART0: - return BCM_6338_UART0_BASE; - case RSET_UART1: - return BCM_6338_UART1_BASE; - case RSET_GPIO: - return BCM_6338_GPIO_BASE; - case RSET_SPI: - return BCM_6338_SPI_BASE; - case RSET_UDC0: - return BCM_6338_UDC0_BASE; - case RSET_OHCI0: - return BCM_6338_OHCI0_BASE; - case RSET_OHCI_PRIV: - return BCM_6338_OHCI_PRIV_BASE; - case RSET_USBH_PRIV: - return BCM_6338_USBH_PRIV_BASE; - case RSET_MPI: - return BCM_6338_MPI_BASE; - case RSET_PCMCIA: - return BCM_6338_PCMCIA_BASE; - case RSET_DSL: - return BCM_6338_DSL_BASE; - case RSET_ENET0: - return BCM_6338_ENET0_BASE; - case RSET_ENET1: - return BCM_6338_ENET1_BASE; - case RSET_ENETDMA: - return BCM_6338_ENETDMA_BASE; - case RSET_EHCI0: - return BCM_6338_EHCI0_BASE; - case RSET_SDRAM: - return BCM_6338_SDRAM_BASE; - case RSET_MEMC: - return BCM_6338_MEMC_BASE; - case RSET_DDR: - return BCM_6338_DDR_BASE; - } + __GEN_RSET(6338) #endif #ifdef CONFIG_BCM63XX_CPU_6345 - switch (set) { - case RSET_DSL_LMEM: - return BCM_6345_DSL_LMEM_BASE; - case RSET_PERF: - return BCM_6345_PERF_BASE; - case RSET_TIMER: - return BCM_6345_TIMER_BASE; - case RSET_WDT: - return BCM_6345_WDT_BASE; - case RSET_UART0: - return BCM_6345_UART0_BASE; - case RSET_UART1: - return BCM_6345_UART1_BASE; - case RSET_GPIO: - return BCM_6345_GPIO_BASE; - case RSET_SPI: - return BCM_6345_SPI_BASE; - case RSET_UDC0: - return BCM_6345_UDC0_BASE; - case RSET_OHCI0: - return BCM_6345_OHCI0_BASE; - case RSET_OHCI_PRIV: - return BCM_6345_OHCI_PRIV_BASE; - case RSET_USBH_PRIV: - return BCM_6345_USBH_PRIV_BASE; - case RSET_MPI: - return BCM_6345_MPI_BASE; - case RSET_PCMCIA: - return BCM_6345_PCMCIA_BASE; - case RSET_DSL: - return BCM_6345_DSL_BASE; - case RSET_ENET0: - return BCM_6345_ENET0_BASE; - case RSET_ENET1: - return BCM_6345_ENET1_BASE; - case RSET_ENETDMA: - return BCM_6345_ENETDMA_BASE; - case RSET_EHCI0: - return BCM_6345_EHCI0_BASE; - case RSET_SDRAM: - return BCM_6345_SDRAM_BASE; - case RSET_MEMC: - return BCM_6345_MEMC_BASE; - case RSET_DDR: - return BCM_6345_DDR_BASE; - } + __GEN_RSET(6345) #endif #ifdef CONFIG_BCM63XX_CPU_6348 - switch (set) { - case RSET_DSL_LMEM: - return BCM_6348_DSL_LMEM_BASE; - case RSET_PERF: - return BCM_6348_PERF_BASE; - case RSET_TIMER: - return BCM_6348_TIMER_BASE; - case RSET_WDT: - return BCM_6348_WDT_BASE; - case RSET_UART0: - return BCM_6348_UART0_BASE; - case RSET_UART1: - return BCM_6348_UART1_BASE; - case RSET_GPIO: - return BCM_6348_GPIO_BASE; - case RSET_SPI: - return BCM_6348_SPI_BASE; - case RSET_UDC0: - return BCM_6348_UDC0_BASE; - case RSET_OHCI0: - return BCM_6348_OHCI0_BASE; - case RSET_OHCI_PRIV: - return BCM_6348_OHCI_PRIV_BASE; - case RSET_USBH_PRIV: - return BCM_6348_USBH_PRIV_BASE; - case RSET_MPI: - return BCM_6348_MPI_BASE; - case RSET_PCMCIA: - return BCM_6348_PCMCIA_BASE; - case RSET_DSL: - return BCM_6348_DSL_BASE; - case RSET_ENET0: - return BCM_6348_ENET0_BASE; - case RSET_ENET1: - return BCM_6348_ENET1_BASE; - case RSET_ENETDMA: - return BCM_6348_ENETDMA_BASE; - case RSET_EHCI0: - return BCM_6348_EHCI0_BASE; - case RSET_SDRAM: - return BCM_6348_SDRAM_BASE; - case RSET_MEMC: - return BCM_6348_MEMC_BASE; - case RSET_DDR: - return BCM_6348_DDR_BASE; - } + __GEN_RSET(6348) #endif #ifdef CONFIG_BCM63XX_CPU_6358 - switch (set) { - case RSET_DSL_LMEM: - return BCM_6358_DSL_LMEM_BASE; - case RSET_PERF: - return BCM_6358_PERF_BASE; - case RSET_TIMER: - return BCM_6358_TIMER_BASE; - case RSET_WDT: - return BCM_6358_WDT_BASE; - case RSET_UART0: - return BCM_6358_UART0_BASE; - case RSET_UART1: - return BCM_6358_UART1_BASE; - case RSET_GPIO: - return BCM_6358_GPIO_BASE; - case RSET_SPI: - return BCM_6358_SPI_BASE; - case RSET_UDC0: - return BCM_6358_UDC0_BASE; - case RSET_OHCI0: - return BCM_6358_OHCI0_BASE; - case RSET_OHCI_PRIV: - return BCM_6358_OHCI_PRIV_BASE; - case RSET_USBH_PRIV: - return BCM_6358_USBH_PRIV_BASE; - case RSET_MPI: - return BCM_6358_MPI_BASE; - case RSET_PCMCIA: - return BCM_6358_PCMCIA_BASE; - case RSET_ENET0: - return BCM_6358_ENET0_BASE; - case RSET_ENET1: - return BCM_6358_ENET1_BASE; - case RSET_ENETDMA: - return BCM_6358_ENETDMA_BASE; - case RSET_DSL: - return BCM_6358_DSL_BASE; - case RSET_EHCI0: - return BCM_6358_EHCI0_BASE; - case RSET_SDRAM: - return BCM_6358_SDRAM_BASE; - case RSET_MEMC: - return BCM_6358_MEMC_BASE; - case RSET_DDR: - return BCM_6358_DDR_BASE; - } + __GEN_RSET(6358) +#endif +#ifdef CONFIG_BCM63XX_CPU_6368 + __GEN_RSET(6368) #endif #endif /* unreached */ @@ -449,75 +486,114 @@ enum bcm63xx_irq { IRQ_ENET_PHY, IRQ_OHCI0, IRQ_EHCI0, - IRQ_PCMCIA0, IRQ_ENET0_RXDMA, IRQ_ENET0_TXDMA, IRQ_ENET1_RXDMA, IRQ_ENET1_TXDMA, IRQ_PCI, IRQ_PCMCIA, + IRQ_ATM, + IRQ_ENETSW_RXDMA0, + IRQ_ENETSW_RXDMA1, + IRQ_ENETSW_RXDMA2, + IRQ_ENETSW_RXDMA3, + IRQ_ENETSW_TXDMA0, + IRQ_ENETSW_TXDMA1, + IRQ_ENETSW_TXDMA2, + IRQ_ENETSW_TXDMA3, + IRQ_XTM, + IRQ_XTM_DMA0, }; /* * 6338 irqs */ #define BCM_6338_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) -#define BCM_6338_SPI_IRQ (IRQ_INTERNAL_BASE + 1) #define BCM_6338_UART0_IRQ (IRQ_INTERNAL_BASE + 2) -#define BCM_6338_DG_IRQ (IRQ_INTERNAL_BASE + 4) +#define BCM_6338_UART1_IRQ 0 #define BCM_6338_DSL_IRQ (IRQ_INTERNAL_BASE + 5) -#define BCM_6338_ATM_IRQ (IRQ_INTERNAL_BASE + 6) -#define BCM_6338_UDC0_IRQ (IRQ_INTERNAL_BASE + 7) #define BCM_6338_ENET0_IRQ (IRQ_INTERNAL_BASE + 8) +#define BCM_6338_ENET1_IRQ 0 #define BCM_6338_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 9) -#define BCM_6338_SDRAM_IRQ (IRQ_INTERNAL_BASE + 10) -#define BCM_6338_USB_CNTL_RX_DMA_IRQ (IRQ_INTERNAL_BASE + 11) -#define BCM_6338_USB_CNTL_TX_DMA_IRQ (IRQ_INTERNAL_BASE + 12) -#define BCM_6338_USB_BULK_RX_DMA_IRQ (IRQ_INTERNAL_BASE + 13) -#define BCM_6338_USB_BULK_TX_DMA_IRQ (IRQ_INTERNAL_BASE + 14) +#define BCM_6338_OHCI0_IRQ 0 +#define BCM_6338_EHCI0_IRQ 0 #define BCM_6338_ENET0_RXDMA_IRQ (IRQ_INTERNAL_BASE + 15) #define BCM_6338_ENET0_TXDMA_IRQ (IRQ_INTERNAL_BASE + 16) -#define BCM_6338_SDIO_IRQ (IRQ_INTERNAL_BASE + 17) +#define BCM_6338_ENET1_RXDMA_IRQ 0 +#define BCM_6338_ENET1_TXDMA_IRQ 0 +#define BCM_6338_PCI_IRQ 0 +#define BCM_6338_PCMCIA_IRQ 0 +#define BCM_6338_ATM_IRQ 0 +#define BCM_6338_ENETSW_RXDMA0_IRQ 0 +#define BCM_6338_ENETSW_RXDMA1_IRQ 0 +#define BCM_6338_ENETSW_RXDMA2_IRQ 0 +#define BCM_6338_ENETSW_RXDMA3_IRQ 0 +#define BCM_6338_ENETSW_TXDMA0_IRQ 0 +#define BCM_6338_ENETSW_TXDMA1_IRQ 0 +#define BCM_6338_ENETSW_TXDMA2_IRQ 0 +#define BCM_6338_ENETSW_TXDMA3_IRQ 0 +#define BCM_6338_XTM_IRQ 0 +#define BCM_6338_XTM_DMA0_IRQ 0 /* * 6345 irqs */ #define BCM_6345_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) #define BCM_6345_UART0_IRQ (IRQ_INTERNAL_BASE + 2) +#define BCM_6345_UART1_IRQ 0 #define BCM_6345_DSL_IRQ (IRQ_INTERNAL_BASE + 3) -#define BCM_6345_ATM_IRQ (IRQ_INTERNAL_BASE + 4) -#define BCM_6345_USB_IRQ (IRQ_INTERNAL_BASE + 5) #define BCM_6345_ENET0_IRQ (IRQ_INTERNAL_BASE + 8) +#define BCM_6345_ENET1_IRQ 0 #define BCM_6345_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 12) +#define BCM_6345_OHCI0_IRQ 0 +#define BCM_6345_EHCI0_IRQ 0 #define BCM_6345_ENET0_RXDMA_IRQ (IRQ_INTERNAL_BASE + 13 + 1) #define BCM_6345_ENET0_TXDMA_IRQ (IRQ_INTERNAL_BASE + 13 + 2) -#define BCM_6345_EBI_RX_IRQ (IRQ_INTERNAL_BASE + 13 + 5) -#define BCM_6345_EBI_TX_IRQ (IRQ_INTERNAL_BASE + 13 + 6) -#define BCM_6345_RESERVED_RX_IRQ (IRQ_INTERNAL_BASE + 13 + 9) -#define BCM_6345_RESERVED_TX_IRQ (IRQ_INTERNAL_BASE + 13 + 10) -#define BCM_6345_USB_BULK_RX_DMA_IRQ (IRQ_INTERNAL_BASE + 13 + 13) -#define BCM_6345_USB_BULK_TX_DMA_IRQ (IRQ_INTERNAL_BASE + 13 + 14) -#define BCM_6345_USB_CNTL_RX_DMA_IRQ (IRQ_INTERNAL_BASE + 13 + 15) -#define BCM_6345_USB_CNTL_TX_DMA_IRQ (IRQ_INTERNAL_BASE + 13 + 16) -#define BCM_6345_USB_ISO_RX_DMA_IRQ (IRQ_INTERNAL_BASE + 13 + 17) -#define BCM_6345_USB_ISO_TX_DMA_IRQ (IRQ_INTERNAL_BASE + 13 + 18) +#define BCM_6345_ENET1_RXDMA_IRQ 0 +#define BCM_6345_ENET1_TXDMA_IRQ 0 +#define BCM_6345_PCI_IRQ 0 +#define BCM_6345_PCMCIA_IRQ 0 +#define BCM_6345_ATM_IRQ 0 +#define BCM_6345_ENETSW_RXDMA0_IRQ 0 +#define BCM_6345_ENETSW_RXDMA1_IRQ 0 +#define BCM_6345_ENETSW_RXDMA2_IRQ 0 +#define BCM_6345_ENETSW_RXDMA3_IRQ 0 +#define BCM_6345_ENETSW_TXDMA0_IRQ 0 +#define BCM_6345_ENETSW_TXDMA1_IRQ 0 +#define BCM_6345_ENETSW_TXDMA2_IRQ 0 +#define BCM_6345_ENETSW_TXDMA3_IRQ 0 +#define BCM_6345_XTM_IRQ 0 +#define BCM_6345_XTM_DMA0_IRQ 0 /* * 6348 irqs */ #define BCM_6348_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) #define BCM_6348_UART0_IRQ (IRQ_INTERNAL_BASE + 2) +#define BCM_6348_UART1_IRQ 0 #define BCM_6348_DSL_IRQ (IRQ_INTERNAL_BASE + 4) -#define BCM_6348_ENET1_IRQ (IRQ_INTERNAL_BASE + 7) #define BCM_6348_ENET0_IRQ (IRQ_INTERNAL_BASE + 8) +#define BCM_6348_ENET1_IRQ (IRQ_INTERNAL_BASE + 7) #define BCM_6348_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 9) #define BCM_6348_OHCI0_IRQ (IRQ_INTERNAL_BASE + 12) +#define BCM_6348_EHCI0_IRQ 0 #define BCM_6348_ENET0_RXDMA_IRQ (IRQ_INTERNAL_BASE + 20) #define BCM_6348_ENET0_TXDMA_IRQ (IRQ_INTERNAL_BASE + 21) #define BCM_6348_ENET1_RXDMA_IRQ (IRQ_INTERNAL_BASE + 22) #define BCM_6348_ENET1_TXDMA_IRQ (IRQ_INTERNAL_BASE + 23) -#define BCM_6348_PCMCIA_IRQ (IRQ_INTERNAL_BASE + 24) #define BCM_6348_PCI_IRQ (IRQ_INTERNAL_BASE + 24) +#define BCM_6348_PCMCIA_IRQ (IRQ_INTERNAL_BASE + 24) +#define BCM_6348_ATM_IRQ (IRQ_INTERNAL_BASE + 5) +#define BCM_6348_ENETSW_RXDMA0_IRQ 0 +#define BCM_6348_ENETSW_RXDMA1_IRQ 0 +#define BCM_6348_ENETSW_RXDMA2_IRQ 0 +#define BCM_6348_ENETSW_RXDMA3_IRQ 0 +#define BCM_6348_ENETSW_TXDMA0_IRQ 0 +#define BCM_6348_ENETSW_TXDMA1_IRQ 0 +#define BCM_6348_ENETSW_TXDMA2_IRQ 0 +#define BCM_6348_ENETSW_TXDMA3_IRQ 0 +#define BCM_6348_XTM_IRQ 0 +#define BCM_6348_XTM_DMA0_IRQ 0 /* * 6358 irqs @@ -525,21 +601,108 @@ enum bcm63xx_irq { #define BCM_6358_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) #define BCM_6358_UART0_IRQ (IRQ_INTERNAL_BASE + 2) #define BCM_6358_UART1_IRQ (IRQ_INTERNAL_BASE + 3) -#define BCM_6358_OHCI0_IRQ (IRQ_INTERNAL_BASE + 5) -#define BCM_6358_ENET1_IRQ (IRQ_INTERNAL_BASE + 6) +#define BCM_6358_DSL_IRQ (IRQ_INTERNAL_BASE + 29) #define BCM_6358_ENET0_IRQ (IRQ_INTERNAL_BASE + 8) +#define BCM_6358_ENET1_IRQ (IRQ_INTERNAL_BASE + 6) #define BCM_6358_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 9) +#define BCM_6358_OHCI0_IRQ (IRQ_INTERNAL_BASE + 5) #define BCM_6358_EHCI0_IRQ (IRQ_INTERNAL_BASE + 10) #define BCM_6358_ENET0_RXDMA_IRQ (IRQ_INTERNAL_BASE + 15) #define BCM_6358_ENET0_TXDMA_IRQ (IRQ_INTERNAL_BASE + 16) #define BCM_6358_ENET1_RXDMA_IRQ (IRQ_INTERNAL_BASE + 17) #define BCM_6358_ENET1_TXDMA_IRQ (IRQ_INTERNAL_BASE + 18) -#define BCM_6358_DSL_IRQ (IRQ_INTERNAL_BASE + 29) #define BCM_6358_PCI_IRQ (IRQ_INTERNAL_BASE + 31) #define BCM_6358_PCMCIA_IRQ (IRQ_INTERNAL_BASE + 24) +#define BCM_6358_ATM_IRQ (IRQ_INTERNAL_BASE + 19) +#define BCM_6358_ENETSW_RXDMA0_IRQ 0 +#define BCM_6358_ENETSW_RXDMA1_IRQ 0 +#define BCM_6358_ENETSW_RXDMA2_IRQ 0 +#define BCM_6358_ENETSW_RXDMA3_IRQ 0 +#define BCM_6358_ENETSW_TXDMA0_IRQ 0 +#define BCM_6358_ENETSW_TXDMA1_IRQ 0 +#define BCM_6358_ENETSW_TXDMA2_IRQ 0 +#define BCM_6358_ENETSW_TXDMA3_IRQ 0 +#define BCM_6358_XTM_IRQ 0 +#define BCM_6358_XTM_DMA0_IRQ 0 + +#define BCM_6358_PCM_DMA0_IRQ (IRQ_INTERNAL_BASE + 23) +#define BCM_6358_PCM_DMA1_IRQ (IRQ_INTERNAL_BASE + 24) +#define BCM_6358_EXT_IRQ0 (IRQ_INTERNAL_BASE + 25) +#define BCM_6358_EXT_IRQ1 (IRQ_INTERNAL_BASE + 26) +#define BCM_6358_EXT_IRQ2 (IRQ_INTERNAL_BASE + 27) +#define BCM_6358_EXT_IRQ3 (IRQ_INTERNAL_BASE + 28) + +/* + * 6368 irqs + */ +#define BCM_6368_HIGH_IRQ_BASE (IRQ_INTERNAL_BASE + 32) + +#define BCM_6368_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) +#define BCM_6368_UART0_IRQ (IRQ_INTERNAL_BASE + 2) +#define BCM_6368_UART1_IRQ (IRQ_INTERNAL_BASE + 3) +#define BCM_6368_DSL_IRQ (IRQ_INTERNAL_BASE + 4) +#define BCM_6368_ENET0_IRQ 0 +#define BCM_6368_ENET1_IRQ 0 +#define BCM_6368_ENET_PHY_IRQ (IRQ_INTERNAL_BASE + 15) +#define BCM_6368_OHCI0_IRQ (IRQ_INTERNAL_BASE + 5) +#define BCM_6368_EHCI0_IRQ (IRQ_INTERNAL_BASE + 7) +#define BCM_6368_PCMCIA_IRQ 0 +#define BCM_6368_ENET0_RXDMA_IRQ 0 +#define BCM_6368_ENET0_TXDMA_IRQ 0 +#define BCM_6368_ENET1_RXDMA_IRQ 0 +#define BCM_6368_ENET1_TXDMA_IRQ 0 +#define BCM_6368_PCI_IRQ (IRQ_INTERNAL_BASE + 13) +#define BCM_6368_ATM_IRQ 0 +#define BCM_6368_ENETSW_RXDMA0_IRQ (BCM_6368_HIGH_IRQ_BASE + 0) +#define BCM_6368_ENETSW_RXDMA1_IRQ (BCM_6368_HIGH_IRQ_BASE + 1) +#define BCM_6368_ENETSW_RXDMA2_IRQ (BCM_6368_HIGH_IRQ_BASE + 2) +#define BCM_6368_ENETSW_RXDMA3_IRQ (BCM_6368_HIGH_IRQ_BASE + 3) +#define BCM_6368_ENETSW_TXDMA0_IRQ (BCM_6368_HIGH_IRQ_BASE + 4) +#define BCM_6368_ENETSW_TXDMA1_IRQ (BCM_6368_HIGH_IRQ_BASE + 5) +#define BCM_6368_ENETSW_TXDMA2_IRQ (BCM_6368_HIGH_IRQ_BASE + 6) +#define BCM_6368_ENETSW_TXDMA3_IRQ (BCM_6368_HIGH_IRQ_BASE + 7) +#define BCM_6368_XTM_IRQ (IRQ_INTERNAL_BASE + 11) +#define BCM_6368_XTM_DMA0_IRQ (BCM_6368_HIGH_IRQ_BASE + 8) + +#define BCM_6368_PCM_DMA0_IRQ (BCM_6368_HIGH_IRQ_BASE + 30) +#define BCM_6368_PCM_DMA1_IRQ (BCM_6368_HIGH_IRQ_BASE + 31) +#define BCM_6368_EXT_IRQ0 (IRQ_INTERNAL_BASE + 20) +#define BCM_6368_EXT_IRQ1 (IRQ_INTERNAL_BASE + 21) +#define BCM_6368_EXT_IRQ2 (IRQ_INTERNAL_BASE + 22) +#define BCM_6368_EXT_IRQ3 (IRQ_INTERNAL_BASE + 23) +#define BCM_6368_EXT_IRQ4 (IRQ_INTERNAL_BASE + 24) +#define BCM_6368_EXT_IRQ5 (IRQ_INTERNAL_BASE + 25) extern const int *bcm63xx_irqs; +#define __GEN_CPU_IRQ_TABLE(__cpu) \ + [IRQ_TIMER] = BCM_## __cpu ##_TIMER_IRQ, \ + [IRQ_UART0] = BCM_## __cpu ##_UART0_IRQ, \ + [IRQ_UART1] = BCM_## __cpu ##_UART1_IRQ, \ + [IRQ_DSL] = BCM_## __cpu ##_DSL_IRQ, \ + [IRQ_ENET0] = BCM_## __cpu ##_ENET0_IRQ, \ + [IRQ_ENET1] = BCM_## __cpu ##_ENET1_IRQ, \ + [IRQ_ENET_PHY] = BCM_## __cpu ##_ENET_PHY_IRQ, \ + [IRQ_OHCI0] = BCM_## __cpu ##_OHCI0_IRQ, \ + [IRQ_EHCI0] = BCM_## __cpu ##_EHCI0_IRQ, \ + [IRQ_ENET0_RXDMA] = BCM_## __cpu ##_ENET0_RXDMA_IRQ, \ + [IRQ_ENET0_TXDMA] = BCM_## __cpu ##_ENET0_TXDMA_IRQ, \ + [IRQ_ENET1_RXDMA] = BCM_## __cpu ##_ENET1_RXDMA_IRQ, \ + [IRQ_ENET1_TXDMA] = BCM_## __cpu ##_ENET1_TXDMA_IRQ, \ + [IRQ_PCI] = BCM_## __cpu ##_PCI_IRQ, \ + [IRQ_PCMCIA] = BCM_## __cpu ##_PCMCIA_IRQ, \ + [IRQ_ATM] = BCM_## __cpu ##_ATM_IRQ, \ + [IRQ_ENETSW_RXDMA0] = BCM_## __cpu ##_ENETSW_RXDMA0_IRQ, \ + [IRQ_ENETSW_RXDMA1] = BCM_## __cpu ##_ENETSW_RXDMA1_IRQ, \ + [IRQ_ENETSW_RXDMA2] = BCM_## __cpu ##_ENETSW_RXDMA2_IRQ, \ + [IRQ_ENETSW_RXDMA3] = BCM_## __cpu ##_ENETSW_RXDMA3_IRQ, \ + [IRQ_ENETSW_TXDMA0] = BCM_## __cpu ##_ENETSW_TXDMA0_IRQ, \ + [IRQ_ENETSW_TXDMA1] = BCM_## __cpu ##_ENETSW_TXDMA1_IRQ, \ + [IRQ_ENETSW_TXDMA2] = BCM_## __cpu ##_ENETSW_TXDMA2_IRQ, \ + [IRQ_ENETSW_TXDMA3] = BCM_## __cpu ##_ENETSW_TXDMA3_IRQ, \ + [IRQ_XTM] = BCM_## __cpu ##_XTM_IRQ, \ + [IRQ_XTM_DMA0] = BCM_## __cpu ##_XTM_DMA0_IRQ, \ + static inline int bcm63xx_get_irq_number(enum bcm63xx_irq irq) { return bcm63xx_irqs[irq]; @@ -550,4 +713,8 @@ static inline int bcm63xx_get_irq_number(enum bcm63xx_irq irq) */ unsigned int bcm63xx_get_memory_size(void); +void bcm63xx_machine_halt(void); + +void bcm63xx_machine_reboot(void); + #endif /* !BCM63XX_CPU_H_ */ diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h index 3999ec0aa7f5..3d5de96d4036 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h @@ -14,6 +14,8 @@ static inline unsigned long bcm63xx_gpio_count(void) return 8; case BCM6345_CPU_ID: return 16; + case BCM6368_CPU_ID: + return 38; case BCM6348_CPU_ID: default: return 37; diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h index 91180fac6ed9..72477a6441dd 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_io.h @@ -49,9 +49,11 @@ #define bcm_readb(a) (*(volatile unsigned char *) BCM_REGS_VA(a)) #define bcm_readw(a) (*(volatile unsigned short *) BCM_REGS_VA(a)) #define bcm_readl(a) (*(volatile unsigned int *) BCM_REGS_VA(a)) +#define bcm_readq(a) (*(volatile u64 *) BCM_REGS_VA(a)) #define bcm_writeb(v, a) (*(volatile unsigned char *) BCM_REGS_VA((a)) = (v)) #define bcm_writew(v, a) (*(volatile unsigned short *) BCM_REGS_VA((a)) = (v)) #define bcm_writel(v, a) (*(volatile unsigned int *) BCM_REGS_VA((a)) = (v)) +#define bcm_writeq(v, a) (*(volatile u64 *) BCM_REGS_VA((a)) = (v)) /* * IO helpers to access register set for current CPU diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h index 5f95577c8213..0c3074b871b8 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_irq.h @@ -3,13 +3,11 @@ #include <bcm63xx_cpu.h> -#define IRQ_MIPS_BASE 0 #define IRQ_INTERNAL_BASE 8 - -#define IRQ_EXT_BASE (IRQ_MIPS_BASE + 3) -#define IRQ_EXT_0 (IRQ_EXT_BASE + 0) -#define IRQ_EXT_1 (IRQ_EXT_BASE + 1) -#define IRQ_EXT_2 (IRQ_EXT_BASE + 2) -#define IRQ_EXT_3 (IRQ_EXT_BASE + 3) +#define IRQ_EXTERNAL_BASE 100 +#define IRQ_EXT_0 (IRQ_EXTERNAL_BASE + 0) +#define IRQ_EXT_1 (IRQ_EXTERNAL_BASE + 1) +#define IRQ_EXT_2 (IRQ_EXTERNAL_BASE + 2) +#define IRQ_EXT_3 (IRQ_EXTERNAL_BASE + 3) #endif /* ! BCM63XX_IRQ_H_ */ diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index 0ed5230243c9..94d4faad29a1 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -83,30 +83,86 @@ CKCTL_6358_USBSU_EN | \ CKCTL_6358_EPHY_EN) +#define CKCTL_6368_VDSL_QPROC_EN (1 << 2) +#define CKCTL_6368_VDSL_AFE_EN (1 << 3) +#define CKCTL_6368_VDSL_BONDING_EN (1 << 4) +#define CKCTL_6368_VDSL_EN (1 << 5) +#define CKCTL_6368_PHYMIPS_EN (1 << 6) +#define CKCTL_6368_SWPKT_USB_EN (1 << 7) +#define CKCTL_6368_SWPKT_SAR_EN (1 << 8) +#define CKCTL_6368_SPI_CLK_EN (1 << 9) +#define CKCTL_6368_USBD_CLK_EN (1 << 10) +#define CKCTL_6368_SAR_CLK_EN (1 << 11) +#define CKCTL_6368_ROBOSW_CLK_EN (1 << 12) +#define CKCTL_6368_UTOPIA_CLK_EN (1 << 13) +#define CKCTL_6368_PCM_CLK_EN (1 << 14) +#define CKCTL_6368_USBH_CLK_EN (1 << 15) +#define CKCTL_6368_DISABLE_GLESS_EN (1 << 16) +#define CKCTL_6368_NAND_CLK_EN (1 << 17) +#define CKCTL_6368_IPSEC_CLK_EN (1 << 17) + +#define CKCTL_6368_ALL_SAFE_EN (CKCTL_6368_SWPKT_USB_EN | \ + CKCTL_6368_SWPKT_SAR_EN | \ + CKCTL_6368_SPI_CLK_EN | \ + CKCTL_6368_USBD_CLK_EN | \ + CKCTL_6368_SAR_CLK_EN | \ + CKCTL_6368_ROBOSW_CLK_EN | \ + CKCTL_6368_UTOPIA_CLK_EN | \ + CKCTL_6368_PCM_CLK_EN | \ + CKCTL_6368_USBH_CLK_EN | \ + CKCTL_6368_DISABLE_GLESS_EN | \ + CKCTL_6368_NAND_CLK_EN | \ + CKCTL_6368_IPSEC_CLK_EN) + /* System PLL Control register */ #define PERF_SYS_PLL_CTL_REG 0x8 #define SYS_PLL_SOFT_RESET 0x1 /* Interrupt Mask register */ -#define PERF_IRQMASK_REG 0xc +#define PERF_IRQMASK_6338_REG 0xc +#define PERF_IRQMASK_6345_REG 0xc +#define PERF_IRQMASK_6348_REG 0xc +#define PERF_IRQMASK_6358_REG 0xc +#define PERF_IRQMASK_6368_REG 0x20 /* Interrupt Status register */ -#define PERF_IRQSTAT_REG 0x10 +#define PERF_IRQSTAT_6338_REG 0x10 +#define PERF_IRQSTAT_6345_REG 0x10 +#define PERF_IRQSTAT_6348_REG 0x10 +#define PERF_IRQSTAT_6358_REG 0x10 +#define PERF_IRQSTAT_6368_REG 0x28 /* External Interrupt Configuration register */ -#define PERF_EXTIRQ_CFG_REG 0x14 +#define PERF_EXTIRQ_CFG_REG_6338 0x14 +#define PERF_EXTIRQ_CFG_REG_6348 0x14 +#define PERF_EXTIRQ_CFG_REG_6358 0x14 +#define PERF_EXTIRQ_CFG_REG_6368 0x18 + +#define PERF_EXTIRQ_CFG_REG2_6368 0x1c + +/* for 6348 only */ +#define EXTIRQ_CFG_SENSE_6348(x) (1 << (x)) +#define EXTIRQ_CFG_STAT_6348(x) (1 << (x + 5)) +#define EXTIRQ_CFG_CLEAR_6348(x) (1 << (x + 10)) +#define EXTIRQ_CFG_MASK_6348(x) (1 << (x + 15)) +#define EXTIRQ_CFG_BOTHEDGE_6348(x) (1 << (x + 20)) +#define EXTIRQ_CFG_LEVELSENSE_6348(x) (1 << (x + 25)) +#define EXTIRQ_CFG_CLEAR_ALL_6348 (0xf << 10) +#define EXTIRQ_CFG_MASK_ALL_6348 (0xf << 15) + +/* for all others */ #define EXTIRQ_CFG_SENSE(x) (1 << (x)) -#define EXTIRQ_CFG_STAT(x) (1 << (x + 5)) -#define EXTIRQ_CFG_CLEAR(x) (1 << (x + 10)) -#define EXTIRQ_CFG_MASK(x) (1 << (x + 15)) -#define EXTIRQ_CFG_BOTHEDGE(x) (1 << (x + 20)) -#define EXTIRQ_CFG_LEVELSENSE(x) (1 << (x + 25)) - -#define EXTIRQ_CFG_CLEAR_ALL (0xf << 10) -#define EXTIRQ_CFG_MASK_ALL (0xf << 15) +#define EXTIRQ_CFG_STAT(x) (1 << (x + 4)) +#define EXTIRQ_CFG_CLEAR(x) (1 << (x + 8)) +#define EXTIRQ_CFG_MASK(x) (1 << (x + 12)) +#define EXTIRQ_CFG_BOTHEDGE(x) (1 << (x + 16)) +#define EXTIRQ_CFG_LEVELSENSE(x) (1 << (x + 20)) +#define EXTIRQ_CFG_CLEAR_ALL (0xf << 8) +#define EXTIRQ_CFG_MASK_ALL (0xf << 12) /* Soft Reset register */ #define PERF_SOFTRESET_REG 0x28 +#define PERF_SOFTRESET_6368_REG 0x10 #define SOFTRESET_6338_SPI_MASK (1 << 0) #define SOFTRESET_6338_ENET_MASK (1 << 2) @@ -147,6 +203,15 @@ SOFTRESET_6348_ACLC_MASK | \ SOFTRESET_6348_ADSLMIPSPLL_MASK) +#define SOFTRESET_6368_SPI_MASK (1 << 0) +#define SOFTRESET_6368_MPI_MASK (1 << 3) +#define SOFTRESET_6368_EPHY_MASK (1 << 6) +#define SOFTRESET_6368_SAR_MASK (1 << 7) +#define SOFTRESET_6368_ENETSW_MASK (1 << 10) +#define SOFTRESET_6368_USBS_MASK (1 << 11) +#define SOFTRESET_6368_USBH_MASK (1 << 12) +#define SOFTRESET_6368_PCM_MASK (1 << 13) + /* MIPS PLL control register */ #define PERF_MIPSPLLCTL_REG 0x34 #define MIPSPLLCTL_N1_SHIFT 20 @@ -372,6 +437,7 @@ #define GPIO_CTL_LO_REG 0x4 #define GPIO_DATA_HI_REG 0x8 #define GPIO_DATA_LO_REG 0xC +#define GPIO_DATA_LO_REG_6345 0x8 /* GPIO mux registers and constants */ #define GPIO_MODE_REG 0x18 @@ -402,6 +468,44 @@ #define GPIO_MODE_6358_SERIAL_LED (1 << 10) #define GPIO_MODE_6358_UTOPIA (1 << 12) +#define GPIO_MODE_6368_ANALOG_AFE_0 (1 << 0) +#define GPIO_MODE_6368_ANALOG_AFE_1 (1 << 1) +#define GPIO_MODE_6368_SYS_IRQ (1 << 2) +#define GPIO_MODE_6368_SERIAL_LED_DATA (1 << 3) +#define GPIO_MODE_6368_SERIAL_LED_CLK (1 << 4) +#define GPIO_MODE_6368_INET_LED (1 << 5) +#define GPIO_MODE_6368_EPHY0_LED (1 << 6) +#define GPIO_MODE_6368_EPHY1_LED (1 << 7) +#define GPIO_MODE_6368_EPHY2_LED (1 << 8) +#define GPIO_MODE_6368_EPHY3_LED (1 << 9) +#define GPIO_MODE_6368_ROBOSW_LED_DAT (1 << 10) +#define GPIO_MODE_6368_ROBOSW_LED_CLK (1 << 11) +#define GPIO_MODE_6368_ROBOSW_LED0 (1 << 12) +#define GPIO_MODE_6368_ROBOSW_LED1 (1 << 13) +#define GPIO_MODE_6368_USBD_LED (1 << 14) +#define GPIO_MODE_6368_NTR_PULSE (1 << 15) +#define GPIO_MODE_6368_PCI_REQ1 (1 << 16) +#define GPIO_MODE_6368_PCI_GNT1 (1 << 17) +#define GPIO_MODE_6368_PCI_INTB (1 << 18) +#define GPIO_MODE_6368_PCI_REQ0 (1 << 19) +#define GPIO_MODE_6368_PCI_GNT0 (1 << 20) +#define GPIO_MODE_6368_PCMCIA_CD1 (1 << 22) +#define GPIO_MODE_6368_PCMCIA_CD2 (1 << 23) +#define GPIO_MODE_6368_PCMCIA_VS1 (1 << 24) +#define GPIO_MODE_6368_PCMCIA_VS2 (1 << 25) +#define GPIO_MODE_6368_EBI_CS2 (1 << 26) +#define GPIO_MODE_6368_EBI_CS3 (1 << 27) +#define GPIO_MODE_6368_SPI_SSN2 (1 << 28) +#define GPIO_MODE_6368_SPI_SSN3 (1 << 29) +#define GPIO_MODE_6368_SPI_SSN4 (1 << 30) +#define GPIO_MODE_6368_SPI_SSN5 (1 << 31) + + +#define GPIO_BASEMODE_6368_REG 0x38 +#define GPIO_BASEMODE_6368_UART2 0x1 +#define GPIO_BASEMODE_6368_GPIO 0x0 +#define GPIO_BASEMODE_6368_MASK 0x7 +/* those bits must be kept as read in gpio basemode register*/ /************************************************************************* * _REG relative to RSET_ENET @@ -548,6 +652,56 @@ /************************************************************************* + * _REG relative to RSET_ENETDMAC + *************************************************************************/ + +/* Channel Configuration register */ +#define ENETDMAC_CHANCFG_REG(x) ((x) * 0x10) +#define ENETDMAC_CHANCFG_EN_SHIFT 0 +#define ENETDMAC_CHANCFG_EN_MASK (1 << ENETDMA_CHANCFG_EN_SHIFT) +#define ENETDMAC_CHANCFG_PKTHALT_SHIFT 1 +#define ENETDMAC_CHANCFG_PKTHALT_MASK (1 << ENETDMA_CHANCFG_PKTHALT_SHIFT) + +/* Interrupt Control/Status register */ +#define ENETDMAC_IR_REG(x) (0x4 + (x) * 0x10) +#define ENETDMAC_IR_BUFDONE_MASK (1 << 0) +#define ENETDMAC_IR_PKTDONE_MASK (1 << 1) +#define ENETDMAC_IR_NOTOWNER_MASK (1 << 2) + +/* Interrupt Mask register */ +#define ENETDMAC_IRMASK_REG(x) (0x8 + (x) * 0x10) + +/* Maximum Burst Length */ +#define ENETDMAC_MAXBURST_REG(x) (0xc + (x) * 0x10) + + +/************************************************************************* + * _REG relative to RSET_ENETDMAS + *************************************************************************/ + +/* Ring Start Address register */ +#define ENETDMAS_RSTART_REG(x) ((x) * 0x10) + +/* State Ram Word 2 */ +#define ENETDMAS_SRAM2_REG(x) (0x4 + (x) * 0x10) + +/* State Ram Word 3 */ +#define ENETDMAS_SRAM3_REG(x) (0x8 + (x) * 0x10) + +/* State Ram Word 4 */ +#define ENETDMAS_SRAM4_REG(x) (0xc + (x) * 0x10) + + +/************************************************************************* + * _REG relative to RSET_ENETSW + *************************************************************************/ + +/* MIB register */ +#define ENETSW_MIB_REG(x) (0x2800 + (x) * 4) +#define ENETSW_MIB_REG_COUNT 47 + + +/************************************************************************* * _REG relative to RSET_OHCI_PRIV *************************************************************************/ @@ -562,7 +716,9 @@ * _REG relative to RSET_USBH_PRIV *************************************************************************/ -#define USBH_PRIV_SWAP_REG 0x0 +#define USBH_PRIV_SWAP_6358_REG 0x0 +#define USBH_PRIV_SWAP_6368_REG 0x1c + #define USBH_PRIV_SWAP_EHCI_ENDN_SHIFT 4 #define USBH_PRIV_SWAP_EHCI_ENDN_MASK (1 << USBH_PRIV_SWAP_EHCI_ENDN_SHIFT) #define USBH_PRIV_SWAP_EHCI_DATA_SHIFT 3 @@ -572,7 +728,13 @@ #define USBH_PRIV_SWAP_OHCI_DATA_SHIFT 0 #define USBH_PRIV_SWAP_OHCI_DATA_MASK (1 << USBH_PRIV_SWAP_OHCI_DATA_SHIFT) -#define USBH_PRIV_TEST_REG 0x24 +#define USBH_PRIV_TEST_6358_REG 0x24 +#define USBH_PRIV_TEST_6368_REG 0x14 + +#define USBH_PRIV_SETUP_6368_REG 0x28 +#define USBH_PRIV_SETUP_IOC_SHIFT 4 +#define USBH_PRIV_SETUP_IOC_MASK (1 << USBH_PRIV_SETUP_IOC_SHIFT) + /************************************************************************* @@ -734,6 +896,8 @@ #define SDRAM_CFG_BANK_SHIFT 13 #define SDRAM_CFG_BANK_MASK (1 << SDRAM_CFG_BANK_SHIFT) +#define SDRAM_MBASE_REG 0xc + #define SDRAM_PRIO_REG 0x2C #define SDRAM_PRIO_MIPS_SHIFT 29 #define SDRAM_PRIO_MIPS_MASK (1 << SDRAM_PRIO_MIPS_SHIFT) @@ -768,4 +932,45 @@ #define DMIPSPLLCFG_N2_SHIFT 29 #define DMIPSPLLCFG_N2_MASK (0x7 << DMIPSPLLCFG_N2_SHIFT) +#define DDR_DMIPSPLLCFG_6368_REG 0x20 +#define DMIPSPLLCFG_6368_P1_SHIFT 0 +#define DMIPSPLLCFG_6368_P1_MASK (0xf << DMIPSPLLCFG_6368_P1_SHIFT) +#define DMIPSPLLCFG_6368_P2_SHIFT 4 +#define DMIPSPLLCFG_6368_P2_MASK (0xf << DMIPSPLLCFG_6368_P2_SHIFT) +#define DMIPSPLLCFG_6368_NDIV_SHIFT 16 +#define DMIPSPLLCFG_6368_NDIV_MASK (0x1ff << DMIPSPLLCFG_6368_NDIV_SHIFT) + +#define DDR_DMIPSPLLDIV_6368_REG 0x24 +#define DMIPSPLLDIV_6368_MDIV_SHIFT 0 +#define DMIPSPLLDIV_6368_MDIV_MASK (0xff << DMIPSPLLDIV_6368_MDIV_SHIFT) + + +/************************************************************************* + * _REG relative to RSET_M2M + *************************************************************************/ + +#define M2M_RX 0 +#define M2M_TX 1 + +#define M2M_SRC_REG(x) ((x) * 0x40 + 0x00) +#define M2M_DST_REG(x) ((x) * 0x40 + 0x04) +#define M2M_SIZE_REG(x) ((x) * 0x40 + 0x08) + +#define M2M_CTRL_REG(x) ((x) * 0x40 + 0x0c) +#define M2M_CTRL_ENABLE_MASK (1 << 0) +#define M2M_CTRL_IRQEN_MASK (1 << 1) +#define M2M_CTRL_ERROR_CLR_MASK (1 << 6) +#define M2M_CTRL_DONE_CLR_MASK (1 << 7) +#define M2M_CTRL_NOINC_MASK (1 << 8) +#define M2M_CTRL_PCMCIASWAP_MASK (1 << 9) +#define M2M_CTRL_SWAPBYTE_MASK (1 << 10) +#define M2M_CTRL_ENDIAN_MASK (1 << 11) + +#define M2M_STAT_REG(x) ((x) * 0x40 + 0x10) +#define M2M_STAT_DONE (1 << 0) +#define M2M_STAT_ERROR (1 << 1) + +#define M2M_SRCID_REG(x) ((x) * 0x40 + 0x14) +#define M2M_DSTID_REG(x) ((x) * 0x40 + 0x18) + #endif /* BCM63XX_REGS_H_ */ diff --git a/arch/mips/include/asm/mach-bcm63xx/ioremap.h b/arch/mips/include/asm/mach-bcm63xx/ioremap.h new file mode 100644 index 000000000000..ef94ba73646e --- /dev/null +++ b/arch/mips/include/asm/mach-bcm63xx/ioremap.h @@ -0,0 +1,42 @@ +#ifndef BCM63XX_IOREMAP_H_ +#define BCM63XX_IOREMAP_H_ + +#include <bcm63xx_cpu.h> + +static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) +{ + return phys_addr; +} + +static inline int is_bcm63xx_internal_registers(phys_t offset) +{ + switch (bcm63xx_get_cpu_id()) { + case BCM6338_CPU_ID: + case BCM6345_CPU_ID: + case BCM6348_CPU_ID: + case BCM6358_CPU_ID: + if (offset >= 0xfff00000) + return 1; + break; + case BCM6368_CPU_ID: + if (offset >= 0xb0000000 && offset < 0xb1000000) + return 1; + break; + } + return 0; +} + +static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size, + unsigned long flags) +{ + if (is_bcm63xx_internal_registers(offset)) + return (void __iomem *)offset; + return NULL; +} + +static inline int plat_iounmap(const volatile void __iomem *addr) +{ + return is_bcm63xx_internal_registers((unsigned long)addr); +} + +#endif /* BCM63XX_IOREMAP_H_ */ diff --git a/arch/mips/include/asm/mach-bcm63xx/irq.h b/arch/mips/include/asm/mach-bcm63xx/irq.h new file mode 100644 index 000000000000..9332e788a5c9 --- /dev/null +++ b/arch/mips/include/asm/mach-bcm63xx/irq.h @@ -0,0 +1,7 @@ +#ifndef __ASM_MACH_BCM63XX_IRQ_H +#define __ASM_MACH_BCM63XX_IRQ_H + +#define NR_IRQS 128 +#define MIPS_CPU_IRQ_BASE 0 + +#endif diff --git a/arch/mips/include/asm/mach-db1x00/bcsr.h b/arch/mips/include/asm/mach-db1x00/bcsr.h index 618d2de02ed3..bb9fc23d853a 100644 --- a/arch/mips/include/asm/mach-db1x00/bcsr.h +++ b/arch/mips/include/asm/mach-db1x00/bcsr.h @@ -34,6 +34,8 @@ #define PB1200_BCSR_PHYS_ADDR 0x0D800000 #define PB1200_BCSR_HEXLED_OFS 0x00400000 +#define DB1300_BCSR_PHYS_ADDR 0x19800000 +#define DB1300_BCSR_HEXLED_OFS 0x00400000 enum bcsr_id { /* BCSR base 1 */ @@ -105,6 +107,7 @@ enum bcsr_whoami_boards { BCSR_WHOAMI_PB1200 = BCSR_WHOAMI_PB1200_DDR1, BCSR_WHOAMI_PB1200_DDR2, BCSR_WHOAMI_DB1200, + BCSR_WHOAMI_DB1300, }; /* STATUS reg. Unless otherwise noted, they're valid on all boards. @@ -118,12 +121,12 @@ enum bcsr_whoami_boards { #define BCSR_STATUS_SRAMWIDTH 0x0080 #define BCSR_STATUS_FLASHBUSY 0x0100 #define BCSR_STATUS_ROMBUSY 0x0400 -#define BCSR_STATUS_SD0WP 0x0400 /* DB1200 */ +#define BCSR_STATUS_SD0WP 0x0400 /* DB1200/DB1300:SD1 */ #define BCSR_STATUS_SD1WP 0x0800 #define BCSR_STATUS_USBOTGID 0x0800 /* PB/DB1550 */ #define BCSR_STATUS_DB1000_SWAPBOOT 0x2000 -#define BCSR_STATUS_DB1200_SWAPBOOT 0x0040 /* DB1200 */ -#define BCSR_STATUS_IDECBLID 0x0200 /* DB1200 */ +#define BCSR_STATUS_DB1200_SWAPBOOT 0x0040 /* DB1200/1300 */ +#define BCSR_STATUS_IDECBLID 0x0200 /* DB1200/1300 */ #define BCSR_STATUS_DB1200_U0RXD 0x1000 /* DB1200 */ #define BCSR_STATUS_DB1200_U1RXD 0x2000 /* DB1200 */ #define BCSR_STATUS_FLASHDEN 0xC000 @@ -133,6 +136,11 @@ enum bcsr_whoami_boards { #define BCSR_STATUS_PB1550_U1RXD 0x2000 /* PB1550 */ #define BCSR_STATUS_PB1550_U3RXD 0x8000 /* PB1550 */ +#define BCSR_STATUS_CFWP 0x4000 /* DB1300 */ +#define BCSR_STATUS_USBOCn 0x2000 /* DB1300 */ +#define BCSR_STATUS_OTGOCn 0x1000 /* DB1300 */ +#define BCSR_STATUS_DCDMARQ 0x0010 /* DB1300 */ +#define BCSR_STATUS_IDEDMARQ 0x0020 /* DB1300 */ /* DB/PB1000,1100,1500,1550 */ #define BCSR_RESETS_PHY0 0x0001 @@ -155,17 +163,17 @@ enum bcsr_whoami_boards { #define BCSR_BOARD_GPIO200RST 0x0400 #define BCSR_BOARD_PCICLKOUT 0x0800 #define BCSR_BOARD_PCICFG 0x1000 -#define BCSR_BOARD_SPISEL 0x4000 /* PB/DB1550 */ +#define BCSR_BOARD_SPISEL 0x2000 /* PB/DB1550 */ #define BCSR_BOARD_SD0WP 0x4000 /* DB1100 */ #define BCSR_BOARD_SD1WP 0x8000 /* DB1100 */ -/* DB/PB1200 */ +/* DB/PB1200/1300 */ #define BCSR_RESETS_ETH 0x0001 #define BCSR_RESETS_CAMERA 0x0002 #define BCSR_RESETS_DC 0x0004 #define BCSR_RESETS_IDE 0x0008 -#define BCSR_RESETS_TV 0x0010 /* DB1200 */ +#define BCSR_RESETS_TV 0x0010 /* DB1200/1300 */ /* Not resets but in the same register */ #define BCSR_RESETS_PWMR1MUX 0x0800 /* DB1200 */ #define BCSR_RESETS_PB1200_WSCFSM 0x0800 /* PB1200 */ @@ -174,13 +182,22 @@ enum bcsr_whoami_boards { #define BCSR_RESETS_SPISEL 0x4000 #define BCSR_RESETS_SD1MUX 0x8000 /* PB1200 */ +#define BCSR_RESETS_VDDQSHDN 0x0200 /* DB1300 */ +#define BCSR_RESETS_OTPPGM 0x0400 /* DB1300 */ +#define BCSR_RESETS_OTPSCLK 0x0800 /* DB1300 */ +#define BCSR_RESETS_OTPWRPROT 0x1000 /* DB1300 */ +#define BCSR_RESETS_OTPCSB 0x2000 /* DB1300 */ +#define BCSR_RESETS_OTGPWR 0x4000 /* DB1300 */ +#define BCSR_RESETS_USBHPWR 0x8000 /* DB1300 */ + #define BCSR_BOARD_LCDVEE 0x0001 #define BCSR_BOARD_LCDVDD 0x0002 #define BCSR_BOARD_LCDBL 0x0004 #define BCSR_BOARD_CAMSNAP 0x0010 #define BCSR_BOARD_CAMPWR 0x0020 #define BCSR_BOARD_SD0PWR 0x0040 - +#define BCSR_BOARD_CAMCS 0x0010 /* DB1300 */ +#define BCSR_BOARD_HDMI_DE 0x0040 /* DB1300 */ #define BCSR_SWITCHES_DIP 0x00FF #define BCSR_SWITCHES_DIP_1 0x0080 @@ -214,7 +231,10 @@ enum bcsr_whoami_boards { #define BCSR_SYSTEM_RESET 0x8000 /* clear to reset */ #define BCSR_SYSTEM_PWROFF 0x4000 /* set to power off */ #define BCSR_SYSTEM_VDDI 0x001F /* PB1xxx boards */ - +#define BCSR_SYSTEM_DEBUGCSMASK 0x003F /* DB1300 */ +#define BCSR_SYSTEM_UDMAMODE 0x0100 /* DB1300 */ +#define BCSR_SYSTEM_WAKEONIRQ 0x0200 /* DB1300 */ +#define BCSR_SYSTEM_VDDI1300 0x3C00 /* DB1300 */ diff --git a/arch/mips/include/asm/mach-db1x00/db1200.h b/arch/mips/include/asm/mach-db1x00/db1200.h index 7a39657108c4..b2a8319521e5 100644 --- a/arch/mips/include/asm/mach-db1x00/db1200.h +++ b/arch/mips/include/asm/mach-db1x00/db1200.h @@ -43,15 +43,20 @@ #define BCSR_INT_PC1EJECT 0x0800 #define BCSR_INT_SD0INSERT 0x1000 #define BCSR_INT_SD0EJECT 0x2000 +#define BCSR_INT_SD1INSERT 0x4000 +#define BCSR_INT_SD1EJECT 0x8000 -#define IDE_PHYS_ADDR 0x18800000 #define IDE_REG_SHIFT 5 -#define DB1200_IDE_PHYS_ADDR IDE_PHYS_ADDR +#define DB1200_IDE_PHYS_ADDR 0x18800000 #define DB1200_IDE_PHYS_LEN (16 << IDE_REG_SHIFT) #define DB1200_ETH_PHYS_ADDR 0x19000300 #define DB1200_NAND_PHYS_ADDR 0x20000000 +#define PB1200_IDE_PHYS_ADDR 0x0C800000 +#define PB1200_ETH_PHYS_ADDR 0x0D000300 +#define PB1200_NAND_PHYS_ADDR 0x1C000000 + /* * External Interrupts for DBAu1200 as of 8/6/2004. * Bit positions in the CPLD registers can be calculated by taking @@ -77,6 +82,8 @@ enum external_db1200_ints { DB1200_PC1_EJECT_INT, DB1200_SD0_INSERT_INT, DB1200_SD0_EJECT_INT, + PB1200_SD1_INSERT_INT, + PB1200_SD1_EJECT_INT, DB1200_INT_END = DB1200_INT_BEGIN + 15, }; diff --git a/arch/mips/include/asm/mach-db1x00/db1300.h b/arch/mips/include/asm/mach-db1x00/db1300.h new file mode 100644 index 000000000000..7fe5fb3ba877 --- /dev/null +++ b/arch/mips/include/asm/mach-db1x00/db1300.h @@ -0,0 +1,40 @@ +/* + * NetLogic DB1300 board constants + */ + +#ifndef _DB1300_H_ +#define _DB1300_H_ + +/* FPGA (external mux) interrupt sources */ +#define DB1300_FIRST_INT (ALCHEMY_GPIC_INT_LAST + 1) +#define DB1300_IDE_INT (DB1300_FIRST_INT + 0) +#define DB1300_ETH_INT (DB1300_FIRST_INT + 1) +#define DB1300_CF_INT (DB1300_FIRST_INT + 2) +#define DB1300_VIDEO_INT (DB1300_FIRST_INT + 4) +#define DB1300_HDMI_INT (DB1300_FIRST_INT + 5) +#define DB1300_DC_INT (DB1300_FIRST_INT + 6) +#define DB1300_FLASH_INT (DB1300_FIRST_INT + 7) +#define DB1300_CF_INSERT_INT (DB1300_FIRST_INT + 8) +#define DB1300_CF_EJECT_INT (DB1300_FIRST_INT + 9) +#define DB1300_AC97_INT (DB1300_FIRST_INT + 10) +#define DB1300_AC97_PEN_INT (DB1300_FIRST_INT + 11) +#define DB1300_SD1_INSERT_INT (DB1300_FIRST_INT + 12) +#define DB1300_SD1_EJECT_INT (DB1300_FIRST_INT + 13) +#define DB1300_OTG_VBUS_OC_INT (DB1300_FIRST_INT + 14) +#define DB1300_HOST_VBUS_OC_INT (DB1300_FIRST_INT + 15) +#define DB1300_LAST_INT (DB1300_FIRST_INT + 15) + +/* SMSC9210 CS */ +#define DB1300_ETH_PHYS_ADDR 0x19000000 +#define DB1300_ETH_PHYS_END 0x197fffff + +/* ATA CS */ +#define DB1300_IDE_PHYS_ADDR 0x18800000 +#define DB1300_IDE_REG_SHIFT 5 +#define DB1300_IDE_PHYS_LEN (16 << DB1300_IDE_REG_SHIFT) + +/* NAND CS */ +#define DB1300_NAND_PHYS_ADDR 0x20000000 +#define DB1300_NAND_PHYS_END 0x20000fff + +#endif /* _DB1300_H_ */ diff --git a/arch/mips/include/asm/mach-db1x00/db1x00.h b/arch/mips/include/asm/mach-db1x00/db1x00.h deleted file mode 100644 index a5affb0568ef..000000000000 --- a/arch/mips/include/asm/mach-db1x00/db1x00.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * AMD Alchemy DBAu1x00 Reference Boards - * - * Copyright 2001, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> - * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) - * - * ######################################################################## - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * - */ -#ifndef __ASM_DB1X00_H -#define __ASM_DB1X00_H - -#include <asm/mach-au1x00/au1xxx_psc.h> - -#ifdef CONFIG_MIPS_DB1550 - -#define DBDMA_AC97_TX_CHAN AU1550_DSCR_CMD0_PSC1_TX -#define DBDMA_AC97_RX_CHAN AU1550_DSCR_CMD0_PSC1_RX -#define DBDMA_I2S_TX_CHAN AU1550_DSCR_CMD0_PSC3_TX -#define DBDMA_I2S_RX_CHAN AU1550_DSCR_CMD0_PSC3_RX - -#define SPI_PSC_BASE AU1550_PSC0_PHYS_ADDR -#define AC97_PSC_BASE AU1550_PSC1_PHYS_ADDR -#define SMBUS_PSC_BASE AU1550_PSC2_PHYS_ADDR -#define I2S_PSC_BASE AU1550_PSC3_PHYS_ADDR - -#define NAND_PHYS_ADDR 0x20000000 - -#endif - -/* - * NAND defines - * - * Timing values as described in databook, * ns value stripped of the - * lower 2 bits. - * These defines are here rather than an Au1550 generic file because - * the parts chosen on another board may be different and may require - * different timings. - */ -#define NAND_T_H (18 >> 2) -#define NAND_T_PUL (30 >> 2) -#define NAND_T_SU (30 >> 2) -#define NAND_T_WH (30 >> 2) - -/* Bitfield shift amounts */ -#define NAND_T_H_SHIFT 0 -#define NAND_T_PUL_SHIFT 4 -#define NAND_T_SU_SHIFT 8 -#define NAND_T_WH_SHIFT 12 - -#define NAND_TIMING (((NAND_T_H & 0xF) << NAND_T_H_SHIFT) | \ - ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \ - ((NAND_T_SU & 0xF) << NAND_T_SU_SHIFT) | \ - ((NAND_T_WH & 0xF) << NAND_T_WH_SHIFT)) -#define NAND_CS 1 - -/* Should be done by YAMON */ -#define NAND_STCFG 0x00400005 /* 8-bit NAND */ -#define NAND_STTIME 0x00007774 /* valid for 396 MHz SD=2 only */ -#define NAND_STADDR 0x12000FFF /* physical address 0x20000000 */ - -#endif /* __ASM_DB1X00_H */ diff --git a/arch/mips/include/asm/mach-db1x00/irq.h b/arch/mips/include/asm/mach-db1x00/irq.h new file mode 100644 index 000000000000..15b26693238f --- /dev/null +++ b/arch/mips/include/asm/mach-db1x00/irq.h @@ -0,0 +1,23 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2003 by Ralf Baechle + */ +#ifndef __ASM_MACH_GENERIC_IRQ_H +#define __ASM_MACH_GENERIC_IRQ_H + + +#ifdef NR_IRQS +#undef NR_IRQS +#endif + +#ifndef MIPS_CPU_IRQ_BASE +#define MIPS_CPU_IRQ_BASE 0 +#endif + +/* 8 (MIPS) + 128 (au1300) + 16 (cpld) */ +#define NR_IRQS 152 + +#endif /* __ASM_MACH_GENERIC_IRQ_H */ diff --git a/arch/mips/include/asm/mach-generic/floppy.h b/arch/mips/include/asm/mach-generic/floppy.h index 001a8ce17c17..a38f4d43e5e5 100644 --- a/arch/mips/include/asm/mach-generic/floppy.h +++ b/arch/mips/include/asm/mach-generic/floppy.h @@ -98,7 +98,7 @@ static inline void fd_disable_irq(void) static inline int fd_request_irq(void) { return request_irq(FLOPPY_IRQ, floppy_interrupt, - IRQF_DISABLED, "floppy", NULL); + 0, "floppy", NULL); } static inline void fd_free_irq(void) diff --git a/arch/mips/include/asm/mach-jazz/floppy.h b/arch/mips/include/asm/mach-jazz/floppy.h index 56e9ca6ae426..88b5acb75145 100644 --- a/arch/mips/include/asm/mach-jazz/floppy.h +++ b/arch/mips/include/asm/mach-jazz/floppy.h @@ -90,7 +90,7 @@ static inline void fd_disable_irq(void) static inline int fd_request_irq(void) { return request_irq(FLOPPY_IRQ, floppy_interrupt, - IRQF_DISABLED, "floppy", NULL); + 0, "floppy", NULL); } static inline void fd_free_irq(void) diff --git a/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h index 3b728275b9b0..d193fb68cf27 100644 --- a/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h @@ -24,24 +24,33 @@ #define cpu_has_llsc 1 #define cpu_has_vtag_icache 0 -#define cpu_has_dc_aliases 0 -#define cpu_has_ic_fills_f_dc 0 +#define cpu_has_ic_fills_f_dc 1 #define cpu_has_dsp 0 #define cpu_has_mipsmt 0 -#define cpu_has_userlocal 0 -#define cpu_icache_snoops_remote_store 0 +#define cpu_icache_snoops_remote_store 1 -#define cpu_has_nofpuex 0 #define cpu_has_64bits 1 #define cpu_has_mips32r1 1 -#define cpu_has_mips32r2 0 #define cpu_has_mips64r1 1 -#define cpu_has_mips64r2 0 #define cpu_has_inclusive_pcaches 0 #define cpu_dcache_line_size() 32 #define cpu_icache_line_size() 32 +#if defined(CONFIG_CPU_XLR) +#define cpu_has_userlocal 0 +#define cpu_has_dc_aliases 0 +#define cpu_has_mips32r2 0 +#define cpu_has_mips64r2 0 +#elif defined(CONFIG_CPU_XLP) +#define cpu_has_userlocal 1 +#define cpu_has_mips32r2 1 +#define cpu_has_mips64r2 1 +#define cpu_has_dc_aliases 1 +#else +#error "Unknown Netlogic CPU" +#endif + #endif /* __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H */ diff --git a/arch/mips/include/asm/mach-pb1x00/mc146818rtc.h b/arch/mips/include/asm/mach-pb1x00/mc146818rtc.h deleted file mode 100644 index 622c58710e5b..000000000000 --- a/arch/mips/include/asm/mach-pb1x00/mc146818rtc.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1998, 2001, 03 by Ralf Baechle - * - * RTC routines for PC style attached Dallas chip. - */ -#ifndef __ASM_MACH_AU1XX_MC146818RTC_H -#define __ASM_MACH_AU1XX_MC146818RTC_H - -#include <asm/io.h> -#include <asm/mach-au1x00/au1000.h> - -#define RTC_PORT(x) (0x0c000000 + (x)) -#define RTC_IRQ 8 -#define PB1500_RTC_ADDR 0x0c000000 - -static inline unsigned char CMOS_READ(unsigned long offset) -{ - offset <<= 2; - return (u8)(au_readl(offset + PB1500_RTC_ADDR) & 0xff); -} - -static inline void CMOS_WRITE(unsigned char data, unsigned long offset) -{ - offset <<= 2; - au_writel(data, offset + PB1500_RTC_ADDR); -} - -#define RTC_ALWAYS_BCD 1 - -#endif /* __ASM_MACH_AU1XX_MC146818RTC_H */ diff --git a/arch/mips/include/asm/mach-pb1x00/pb1000.h b/arch/mips/include/asm/mach-pb1x00/pb1000.h deleted file mode 100644 index 65059255dc1e..000000000000 --- a/arch/mips/include/asm/mach-pb1x00/pb1000.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Alchemy Semi Pb1000 Reference Board - * - * Copyright 2001, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> - * - * ######################################################################## - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * - */ -#ifndef __ASM_PB1000_H -#define __ASM_PB1000_H - -/* PCMCIA PB1000 specific defines */ -#define PCMCIA_MAX_SOCK 1 -#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1) - -#define PB1000_PCR 0xBE000000 -# define PCR_SLOT_0_VPP0 (1 << 0) -# define PCR_SLOT_0_VPP1 (1 << 1) -# define PCR_SLOT_0_VCC0 (1 << 2) -# define PCR_SLOT_0_VCC1 (1 << 3) -# define PCR_SLOT_0_RST (1 << 4) -# define PCR_SLOT_1_VPP0 (1 << 8) -# define PCR_SLOT_1_VPP1 (1 << 9) -# define PCR_SLOT_1_VCC0 (1 << 10) -# define PCR_SLOT_1_VCC1 (1 << 11) -# define PCR_SLOT_1_RST (1 << 12) - -#define PB1000_MDR 0xBE000004 -# define MDR_PI (1 << 5) /* PCMCIA int latch */ -# define MDR_EPI (1 << 14) /* enable PCMCIA int */ -# define MDR_CPI (1 << 15) /* clear PCMCIA int */ - -#define PB1000_ACR1 0xBE000008 -# define ACR1_SLOT_0_CD1 (1 << 0) /* card detect 1 */ -# define ACR1_SLOT_0_CD2 (1 << 1) /* card detect 2 */ -# define ACR1_SLOT_0_READY (1 << 2) /* ready */ -# define ACR1_SLOT_0_STATUS (1 << 3) /* status change */ -# define ACR1_SLOT_0_VS1 (1 << 4) /* voltage sense 1 */ -# define ACR1_SLOT_0_VS2 (1 << 5) /* voltage sense 2 */ -# define ACR1_SLOT_0_INPACK (1 << 6) /* inpack pin status */ -# define ACR1_SLOT_1_CD1 (1 << 8) /* card detect 1 */ -# define ACR1_SLOT_1_CD2 (1 << 9) /* card detect 2 */ -# define ACR1_SLOT_1_READY (1 << 10) /* ready */ -# define ACR1_SLOT_1_STATUS (1 << 11) /* status change */ -# define ACR1_SLOT_1_VS1 (1 << 12) /* voltage sense 1 */ -# define ACR1_SLOT_1_VS2 (1 << 13) /* voltage sense 2 */ -# define ACR1_SLOT_1_INPACK (1 << 14) /* inpack pin status */ - -#define CPLD_AUX0 0xBE00000C -#define CPLD_AUX1 0xBE000010 -#define CPLD_AUX2 0xBE000014 - -/* Voltage levels */ - -/* VPPEN1 - VPPEN0 */ -#define VPP_GND ((0 << 1) | (0 << 0)) -#define VPP_5V ((1 << 1) | (0 << 0)) -#define VPP_3V ((0 << 1) | (1 << 0)) -#define VPP_12V ((0 << 1) | (1 << 0)) -#define VPP_HIZ ((1 << 1) | (1 << 0)) - -/* VCCEN1 - VCCEN0 */ -#define VCC_3V ((0 << 1) | (1 << 0)) -#define VCC_5V ((1 << 1) | (0 << 0)) -#define VCC_HIZ ((0 << 1) | (0 << 0)) - -/* VPP/VCC */ -#define SET_VCC_VPP(VCC, VPP, SLOT) \ - ((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8)) -#endif /* __ASM_PB1000_H */ diff --git a/arch/mips/include/asm/mach-pb1x00/pb1200.h b/arch/mips/include/asm/mach-pb1x00/pb1200.h deleted file mode 100644 index 374416adb65b..000000000000 --- a/arch/mips/include/asm/mach-pb1x00/pb1200.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * AMD Alchemy Pb1200 Reference Board - * Board Registers defines. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * - */ -#ifndef __ASM_PB1200_H -#define __ASM_PB1200_H - -#include <linux/types.h> -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-au1x00/au1xxx_psc.h> - -#define DBDMA_AC97_TX_CHAN AU1200_DSCR_CMD0_PSC1_TX -#define DBDMA_AC97_RX_CHAN AU1200_DSCR_CMD0_PSC1_RX -#define DBDMA_I2S_TX_CHAN AU1200_DSCR_CMD0_PSC1_TX -#define DBDMA_I2S_RX_CHAN AU1200_DSCR_CMD0_PSC1_RX - -/* - * SPI and SMB are muxed on the Pb1200 board. - * Refer to board documentation. - */ -#define SPI_PSC_BASE AU1550_PSC0_PHYS_ADDR -#define SMBUS_PSC_BASE AU1550_PSC0_PHYS_ADDR -/* - * AC97 and I2S are muxed on the Pb1200 board. - * Refer to board documentation. - */ -#define AC97_PSC_BASE AU1550_PSC1_PHYS_ADDR -#define I2S_PSC_BASE AU1550_PSC1_PHYS_ADDR - - -#define BCSR_SYSTEM_VDDI 0x001F -#define BCSR_SYSTEM_POWEROFF 0x4000 -#define BCSR_SYSTEM_RESET 0x8000 - -/* Bit positions for the different interrupt sources */ -#define BCSR_INT_IDE 0x0001 -#define BCSR_INT_ETH 0x0002 -#define BCSR_INT_PC0 0x0004 -#define BCSR_INT_PC0STSCHG 0x0008 -#define BCSR_INT_PC1 0x0010 -#define BCSR_INT_PC1STSCHG 0x0020 -#define BCSR_INT_DC 0x0040 -#define BCSR_INT_FLASHBUSY 0x0080 -#define BCSR_INT_PC0INSERT 0x0100 -#define BCSR_INT_PC0EJECT 0x0200 -#define BCSR_INT_PC1INSERT 0x0400 -#define BCSR_INT_PC1EJECT 0x0800 -#define BCSR_INT_SD0INSERT 0x1000 -#define BCSR_INT_SD0EJECT 0x2000 -#define BCSR_INT_SD1INSERT 0x4000 -#define BCSR_INT_SD1EJECT 0x8000 - -#define SMC91C111_PHYS_ADDR 0x0D000300 -#define SMC91C111_INT PB1200_ETH_INT - -#define IDE_PHYS_ADDR 0x0C800000 -#define IDE_REG_SHIFT 5 -#define IDE_PHYS_LEN (16 << IDE_REG_SHIFT) -#define IDE_INT PB1200_IDE_INT - -#define NAND_PHYS_ADDR 0x1C000000 - -/* - * Timing values as described in databook, * ns value stripped of - * lower 2 bits. - * These defines are here rather than an Au1200 generic file because - * the parts chosen on another board may be different and may require - * different timings. - */ -#define NAND_T_H (18 >> 2) -#define NAND_T_PUL (30 >> 2) -#define NAND_T_SU (30 >> 2) -#define NAND_T_WH (30 >> 2) - -/* Bitfield shift amounts */ -#define NAND_T_H_SHIFT 0 -#define NAND_T_PUL_SHIFT 4 -#define NAND_T_SU_SHIFT 8 -#define NAND_T_WH_SHIFT 12 - -#define NAND_TIMING (((NAND_T_H & 0xF) << NAND_T_H_SHIFT) | \ - ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \ - ((NAND_T_SU & 0xF) << NAND_T_SU_SHIFT) | \ - ((NAND_T_WH & 0xF) << NAND_T_WH_SHIFT)) - -/* - * External Interrupts for Pb1200 as of 8/6/2004. - * Bit positions in the CPLD registers can be calculated by taking - * the interrupt define and subtracting the PB1200_INT_BEGIN value. - * - * Example: IDE bis pos is = 64 - 64 - * ETH bit pos is = 65 - 64 - */ -enum external_pb1200_ints { - PB1200_INT_BEGIN = AU1000_MAX_INTR + 1, - - PB1200_IDE_INT = PB1200_INT_BEGIN, - PB1200_ETH_INT, - PB1200_PC0_INT, - PB1200_PC0_STSCHG_INT, - PB1200_PC1_INT, - PB1200_PC1_STSCHG_INT, - PB1200_DC_INT, - PB1200_FLASHBUSY_INT, - PB1200_PC0_INSERT_INT, - PB1200_PC0_EJECT_INT, - PB1200_PC1_INSERT_INT, - PB1200_PC1_EJECT_INT, - PB1200_SD0_INSERT_INT, - PB1200_SD0_EJECT_INT, - PB1200_SD1_INSERT_INT, - PB1200_SD1_EJECT_INT, - - PB1200_INT_END = PB1200_INT_BEGIN + 15 -}; - -/* NAND chip select */ -#define NAND_CS 1 - -#endif /* __ASM_PB1200_H */ diff --git a/arch/mips/include/asm/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h deleted file mode 100644 index 443b88adebf1..000000000000 --- a/arch/mips/include/asm/mach-pb1x00/pb1550.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * AMD Alchemy Semi PB1550 Reference Board - * Board Registers defines. - * - * Copyright 2004 Embedded Edge LLC. - * Copyright 2005 Ralf Baechle (ralf@linux-mips.org) - * - * ######################################################################## - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * - */ -#ifndef __ASM_PB1550_H -#define __ASM_PB1550_H - -#include <linux/types.h> -#include <asm/mach-au1x00/au1xxx_psc.h> - -#define DBDMA_AC97_TX_CHAN AU1550_DSCR_CMD0_PSC1_TX -#define DBDMA_AC97_RX_CHAN AU1550_DSCR_CMD0_PSC1_RX -#define DBDMA_I2S_TX_CHAN AU1550_DSCR_CMD0_PSC3_TX -#define DBDMA_I2S_RX_CHAN AU1550_DSCR_CMD0_PSC3_RX - -#define SPI_PSC_BASE AU1550_PSC0_PHYS_ADDR -#define AC97_PSC_BASE AU1550_PSC1_PHYS_ADDR -#define SMBUS_PSC_BASE AU1550_PSC2_PHYS_ADDR -#define I2S_PSC_BASE AU1550_PSC3_PHYS_ADDR - -/* - * Timing values as described in databook, * ns value stripped of - * lower 2 bits. - * These defines are here rather than an SOC1550 generic file because - * the parts chosen on another board may be different and may require - * different timings. - */ -#define NAND_T_H (18 >> 2) -#define NAND_T_PUL (30 >> 2) -#define NAND_T_SU (30 >> 2) -#define NAND_T_WH (30 >> 2) - -/* Bitfield shift amounts */ -#define NAND_T_H_SHIFT 0 -#define NAND_T_PUL_SHIFT 4 -#define NAND_T_SU_SHIFT 8 -#define NAND_T_WH_SHIFT 12 - -#define NAND_TIMING (((NAND_T_H & 0xF) << NAND_T_H_SHIFT) | \ - ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \ - ((NAND_T_SU & 0xF) << NAND_T_SU_SHIFT) | \ - ((NAND_T_WH & 0xF) << NAND_T_WH_SHIFT)) - -#define NAND_CS 1 - -/* Should be done by YAMON */ -#define NAND_STCFG 0x00400005 /* 8-bit NAND */ -#define NAND_STTIME 0x00007774 /* valid for 396 MHz SD=2 only */ -#define NAND_STADDR 0x12000FFF /* physical address 0x20000000 */ - -#endif /* __ASM_PB1550_H */ diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 2ea7b817feb8..7f87d824eeb0 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1106,7 +1106,7 @@ do { \ #define read_c0_brcm_reset() __read_32bit_c0_register($22, 5) #define write_c0_brcm_reset(val) __write_32bit_c0_register($22, 5, val) -/* BMIPS4380 */ +/* BMIPS43xx */ #define read_c0_brcm_cmt_intr() __read_32bit_c0_register($22, 1) #define write_c0_brcm_cmt_intr(val) __write_32bit_c0_register($22, 1, val) @@ -1667,6 +1667,13 @@ __BUILD_SET_C0(config) __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap) +__BUILD_SET_C0(brcm_config_0) +__BUILD_SET_C0(brcm_bus_pll) +__BUILD_SET_C0(brcm_reset) +__BUILD_SET_C0(brcm_cmt_intr) +__BUILD_SET_C0(brcm_cmt_ctrl) +__BUILD_SET_C0(brcm_config) +__BUILD_SET_C0(brcm_mode) #endif /* !__ASSEMBLY__ */ diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h index bc01a02cacd8..7467d1d933d5 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h @@ -74,7 +74,9 @@ search_module_dbetables(unsigned long addr) } #endif -#ifdef CONFIG_CPU_MIPS32_R1 +#ifdef CONFIG_CPU_BMIPS +#define MODULE_PROC_FAMILY "BMIPS " +#elif defined CONFIG_CPU_MIPS32_R1 #define MODULE_PROC_FAMILY "MIPS32_R1 " #elif defined CONFIG_CPU_MIPS32_R2 #define MODULE_PROC_FAMILY "MIPS32_R2 " @@ -120,6 +122,8 @@ search_module_dbetables(unsigned long addr) #define MODULE_PROC_FAMILY "OCTEON " #elif defined CONFIG_CPU_XLR #define MODULE_PROC_FAMILY "XLR " +#elif defined CONFIG_CPU_XLP +#define MODULE_PROC_FAMILY "XLP " #else #error MODULE_PROC_FAMILY undefined for your processor configuration #endif diff --git a/arch/mips/include/asm/netlogic/common.h b/arch/mips/include/asm/netlogic/common.h new file mode 100644 index 000000000000..fdd2f44c7b59 --- /dev/null +++ b/arch/mips/include/asm/netlogic/common.h @@ -0,0 +1,76 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NETLOGIC_COMMON_H_ +#define _NETLOGIC_COMMON_H_ + +/* + * Common SMP definitions + */ +#define RESET_VEC_PHYS 0x1fc00000 +#define RESET_DATA_PHYS (RESET_VEC_PHYS + (1<<10)) +#define BOOT_THREAD_MODE 0 +#define BOOT_NMI_LOCK 4 +#define BOOT_NMI_HANDLER 8 + +#ifndef __ASSEMBLY__ +struct irq_desc; +extern struct plat_smp_ops nlm_smp_ops; +extern char nlm_reset_entry[], nlm_reset_entry_end[]; +void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc); +void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc); +void nlm_smp_irq_init(void); +void nlm_boot_secondary_cpus(void); +int nlm_wakeup_secondary_cpus(u32 wakeup_mask); +void nlm_rmiboot_preboot(void); + +static inline void +nlm_set_nmi_handler(void *handler) +{ + char *reset_data; + + reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS); + *(int64_t *)(reset_data + BOOT_NMI_HANDLER) = (long)handler; +} + +/* + * Misc. + */ +unsigned int nlm_get_cpu_frequency(void); + +extern unsigned long nlm_common_ebase; +extern int nlm_threads_per_core; +extern uint32_t nlm_cpumask, nlm_coremask; +#endif +#endif /* _NETLOGIC_COMMON_H_ */ diff --git a/arch/mips/include/asm/netlogic/haldefs.h b/arch/mips/include/asm/netlogic/haldefs.h new file mode 100644 index 000000000000..72a0c788b472 --- /dev/null +++ b/arch/mips/include/asm/netlogic/haldefs.h @@ -0,0 +1,163 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NLM_HAL_HALDEFS_H__ +#define __NLM_HAL_HALDEFS_H__ + +/* + * This file contains platform specific memory mapped IO implementation + * and will provide a way to read 32/64 bit memory mapped registers in + * all ABIs + */ +#if !defined(CONFIG_64BIT) && defined(CONFIG_CPU_XLP) +#error "o32 compile not supported on XLP yet" +#endif +/* + * For o32 compilation, we have to disable interrupts and enable KX bit to + * access 64 bit addresses or data. + * + * We need to disable interrupts because we save just the lower 32 bits of + * registers in interrupt handling. So if we get hit by an interrupt while + * using the upper 32 bits of a register, we lose. + */ +static inline uint32_t nlm_save_flags_kx(void) +{ + return change_c0_status(ST0_KX | ST0_IE, ST0_KX); +} + +static inline uint32_t nlm_save_flags_cop2(void) +{ + return change_c0_status(ST0_CU2 | ST0_IE, ST0_CU2); +} + +static inline void nlm_restore_flags(uint32_t sr) +{ + write_c0_status(sr); +} + +/* + * The n64 implementations are simple, the o32 implementations when they + * are added, will have to disable interrupts and enable KX before doing + * 64 bit ops. + */ +static inline uint32_t +nlm_read_reg(uint64_t base, uint32_t reg) +{ + volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg; + + return *addr; +} + +static inline void +nlm_write_reg(uint64_t base, uint32_t reg, uint32_t val) +{ + volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg; + + *addr = val; +} + +static inline uint64_t +nlm_read_reg64(uint64_t base, uint32_t reg) +{ + uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); + volatile uint64_t *ptr = (volatile uint64_t *)(long)addr; + + return *ptr; +} + +static inline void +nlm_write_reg64(uint64_t base, uint32_t reg, uint64_t val) +{ + uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); + volatile uint64_t *ptr = (volatile uint64_t *)(long)addr; + + *ptr = val; +} + +/* + * Routines to store 32/64 bit values to 64 bit addresses, + * used when going thru XKPHYS to access registers + */ +static inline uint32_t +nlm_read_reg_xkphys(uint64_t base, uint32_t reg) +{ + return nlm_read_reg(base, reg); +} + +static inline void +nlm_write_reg_xkphys(uint64_t base, uint32_t reg, uint32_t val) +{ + nlm_write_reg(base, reg, val); +} + +static inline uint64_t +nlm_read_reg64_xkphys(uint64_t base, uint32_t reg) +{ + return nlm_read_reg64(base, reg); +} + +static inline void +nlm_write_reg64_xkphys(uint64_t base, uint32_t reg, uint64_t val) +{ + nlm_write_reg64(base, reg, val); +} + +/* Location where IO base is mapped */ +extern uint64_t nlm_io_base; + +#if defined(CONFIG_CPU_XLP) +static inline uint64_t +nlm_pcicfg_base(uint32_t devoffset) +{ + return nlm_io_base + devoffset; +} + +static inline uint64_t +nlm_xkphys_map_pcibar0(uint64_t pcibase) +{ + uint64_t paddr; + + paddr = nlm_read_reg(pcibase, 0x4) & ~0xfu; + return (uint64_t)0x9000000000000000 | paddr; +} +#elif defined(CONFIG_CPU_XLR) + +static inline uint64_t +nlm_mmio_base(uint32_t devoffset) +{ + return nlm_io_base + devoffset; +} +#endif + +#endif diff --git a/arch/mips/include/asm/netlogic/xlp-hal/bridge.h b/arch/mips/include/asm/netlogic/xlp-hal/bridge.h new file mode 100644 index 000000000000..ca95133f1ad1 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlp-hal/bridge.h @@ -0,0 +1,187 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NLM_HAL_BRIDGE_H__ +#define __NLM_HAL_BRIDGE_H__ + +/** +* @file_name mio.h +* @author Netlogic Microsystems +* @brief Basic definitions of XLP memory and io subsystem +*/ + +/* + * BRIDGE specific registers + * + * These registers start after the PCIe header, which has 0x40 + * standard entries + */ +#define BRIDGE_MODE 0x00 +#define BRIDGE_PCI_CFG_BASE 0x01 +#define BRIDGE_PCI_CFG_LIMIT 0x02 +#define BRIDGE_PCIE_CFG_BASE 0x03 +#define BRIDGE_PCIE_CFG_LIMIT 0x04 +#define BRIDGE_BUSNUM_BAR0 0x05 +#define BRIDGE_BUSNUM_BAR1 0x06 +#define BRIDGE_BUSNUM_BAR2 0x07 +#define BRIDGE_BUSNUM_BAR3 0x08 +#define BRIDGE_BUSNUM_BAR4 0x09 +#define BRIDGE_BUSNUM_BAR5 0x0a +#define BRIDGE_BUSNUM_BAR6 0x0b +#define BRIDGE_FLASH_BAR0 0x0c +#define BRIDGE_FLASH_BAR1 0x0d +#define BRIDGE_FLASH_BAR2 0x0e +#define BRIDGE_FLASH_BAR3 0x0f +#define BRIDGE_FLASH_LIMIT0 0x10 +#define BRIDGE_FLASH_LIMIT1 0x11 +#define BRIDGE_FLASH_LIMIT2 0x12 +#define BRIDGE_FLASH_LIMIT3 0x13 + +#define BRIDGE_DRAM_BAR(i) (0x14 + (i)) +#define BRIDGE_DRAM_BAR0 0x14 +#define BRIDGE_DRAM_BAR1 0x15 +#define BRIDGE_DRAM_BAR2 0x16 +#define BRIDGE_DRAM_BAR3 0x17 +#define BRIDGE_DRAM_BAR4 0x18 +#define BRIDGE_DRAM_BAR5 0x19 +#define BRIDGE_DRAM_BAR6 0x1a +#define BRIDGE_DRAM_BAR7 0x1b + +#define BRIDGE_DRAM_LIMIT(i) (0x1c + (i)) +#define BRIDGE_DRAM_LIMIT0 0x1c +#define BRIDGE_DRAM_LIMIT1 0x1d +#define BRIDGE_DRAM_LIMIT2 0x1e +#define BRIDGE_DRAM_LIMIT3 0x1f +#define BRIDGE_DRAM_LIMIT4 0x20 +#define BRIDGE_DRAM_LIMIT5 0x21 +#define BRIDGE_DRAM_LIMIT6 0x22 +#define BRIDGE_DRAM_LIMIT7 0x23 + +#define BRIDGE_DRAM_NODE_TRANSLN0 0x24 +#define BRIDGE_DRAM_NODE_TRANSLN1 0x25 +#define BRIDGE_DRAM_NODE_TRANSLN2 0x26 +#define BRIDGE_DRAM_NODE_TRANSLN3 0x27 +#define BRIDGE_DRAM_NODE_TRANSLN4 0x28 +#define BRIDGE_DRAM_NODE_TRANSLN5 0x29 +#define BRIDGE_DRAM_NODE_TRANSLN6 0x2a +#define BRIDGE_DRAM_NODE_TRANSLN7 0x2b +#define BRIDGE_DRAM_CHNL_TRANSLN0 0x2c +#define BRIDGE_DRAM_CHNL_TRANSLN1 0x2d +#define BRIDGE_DRAM_CHNL_TRANSLN2 0x2e +#define BRIDGE_DRAM_CHNL_TRANSLN3 0x2f +#define BRIDGE_DRAM_CHNL_TRANSLN4 0x30 +#define BRIDGE_DRAM_CHNL_TRANSLN5 0x31 +#define BRIDGE_DRAM_CHNL_TRANSLN6 0x32 +#define BRIDGE_DRAM_CHNL_TRANSLN7 0x33 +#define BRIDGE_PCIEMEM_BASE0 0x34 +#define BRIDGE_PCIEMEM_BASE1 0x35 +#define BRIDGE_PCIEMEM_BASE2 0x36 +#define BRIDGE_PCIEMEM_BASE3 0x37 +#define BRIDGE_PCIEMEM_LIMIT0 0x38 +#define BRIDGE_PCIEMEM_LIMIT1 0x39 +#define BRIDGE_PCIEMEM_LIMIT2 0x3a +#define BRIDGE_PCIEMEM_LIMIT3 0x3b +#define BRIDGE_PCIEIO_BASE0 0x3c +#define BRIDGE_PCIEIO_BASE1 0x3d +#define BRIDGE_PCIEIO_BASE2 0x3e +#define BRIDGE_PCIEIO_BASE3 0x3f +#define BRIDGE_PCIEIO_LIMIT0 0x40 +#define BRIDGE_PCIEIO_LIMIT1 0x41 +#define BRIDGE_PCIEIO_LIMIT2 0x42 +#define BRIDGE_PCIEIO_LIMIT3 0x43 +#define BRIDGE_PCIEMEM_BASE4 0x44 +#define BRIDGE_PCIEMEM_BASE5 0x45 +#define BRIDGE_PCIEMEM_BASE6 0x46 +#define BRIDGE_PCIEMEM_LIMIT4 0x47 +#define BRIDGE_PCIEMEM_LIMIT5 0x48 +#define BRIDGE_PCIEMEM_LIMIT6 0x49 +#define BRIDGE_PCIEIO_BASE4 0x4a +#define BRIDGE_PCIEIO_BASE5 0x4b +#define BRIDGE_PCIEIO_BASE6 0x4c +#define BRIDGE_PCIEIO_LIMIT4 0x4d +#define BRIDGE_PCIEIO_LIMIT5 0x4e +#define BRIDGE_PCIEIO_LIMIT6 0x4f +#define BRIDGE_NBU_EVENT_CNT_CTL 0x50 +#define BRIDGE_EVNTCTR1_LOW 0x51 +#define BRIDGE_EVNTCTR1_HI 0x52 +#define BRIDGE_EVNT_CNT_CTL2 0x53 +#define BRIDGE_EVNTCTR2_LOW 0x54 +#define BRIDGE_EVNTCTR2_HI 0x55 +#define BRIDGE_TRACEBUF_MATCH0 0x56 +#define BRIDGE_TRACEBUF_MATCH1 0x57 +#define BRIDGE_TRACEBUF_MATCH_LOW 0x58 +#define BRIDGE_TRACEBUF_MATCH_HI 0x59 +#define BRIDGE_TRACEBUF_CTRL 0x5a +#define BRIDGE_TRACEBUF_INIT 0x5b +#define BRIDGE_TRACEBUF_ACCESS 0x5c +#define BRIDGE_TRACEBUF_READ_DATA0 0x5d +#define BRIDGE_TRACEBUF_READ_DATA1 0x5d +#define BRIDGE_TRACEBUF_READ_DATA2 0x5f +#define BRIDGE_TRACEBUF_READ_DATA3 0x60 +#define BRIDGE_TRACEBUF_STATUS 0x61 +#define BRIDGE_ADDRESS_ERROR0 0x62 +#define BRIDGE_ADDRESS_ERROR1 0x63 +#define BRIDGE_ADDRESS_ERROR2 0x64 +#define BRIDGE_TAG_ECC_ADDR_ERROR0 0x65 +#define BRIDGE_TAG_ECC_ADDR_ERROR1 0x66 +#define BRIDGE_TAG_ECC_ADDR_ERROR2 0x67 +#define BRIDGE_LINE_FLUSH0 0x68 +#define BRIDGE_LINE_FLUSH1 0x69 +#define BRIDGE_NODE_ID 0x6a +#define BRIDGE_ERROR_INTERRUPT_EN 0x6b +#define BRIDGE_PCIE0_WEIGHT 0x2c0 +#define BRIDGE_PCIE1_WEIGHT 0x2c1 +#define BRIDGE_PCIE2_WEIGHT 0x2c2 +#define BRIDGE_PCIE3_WEIGHT 0x2c3 +#define BRIDGE_USB_WEIGHT 0x2c4 +#define BRIDGE_NET_WEIGHT 0x2c5 +#define BRIDGE_POE_WEIGHT 0x2c6 +#define BRIDGE_CMS_WEIGHT 0x2c7 +#define BRIDGE_DMAENG_WEIGHT 0x2c8 +#define BRIDGE_SEC_WEIGHT 0x2c9 +#define BRIDGE_COMP_WEIGHT 0x2ca +#define BRIDGE_GIO_WEIGHT 0x2cb +#define BRIDGE_FLASH_WEIGHT 0x2cc + +#ifndef __ASSEMBLY__ + +#define nlm_read_bridge_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_bridge_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_bridge_pcibase(node) \ + nlm_pcicfg_base(XLP_IO_BRIDGE_OFFSET(node)) +#define nlm_get_bridge_regbase(node) \ + (nlm_get_bridge_pcibase(node) + XLP_IO_PCI_HDRSZ) + +#endif /* __ASSEMBLY__ */ +#endif /* __NLM_HAL_BRIDGE_H__ */ diff --git a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h new file mode 100644 index 000000000000..bf7d41deb9be --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h @@ -0,0 +1,83 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NLM_HAL_CPUCONTROL_H__ +#define __NLM_HAL_CPUCONTROL_H__ + +#define CPU_BLOCKID_IFU 0 +#define CPU_BLOCKID_ICU 1 +#define CPU_BLOCKID_IEU 2 +#define CPU_BLOCKID_LSU 3 +#define CPU_BLOCKID_MMU 4 +#define CPU_BLOCKID_PRF 5 +#define CPU_BLOCKID_SCH 7 +#define CPU_BLOCKID_SCU 8 +#define CPU_BLOCKID_FPU 9 +#define CPU_BLOCKID_MAP 10 + +#define LSU_DEFEATURE 0x304 +#define LSU_CERRLOG_REGID 0x09 +#define SCHED_DEFEATURE 0x700 + +/* Offsets of interest from the 'MAP' Block */ +#define MAP_THREADMODE 0x00 +#define MAP_EXT_EBASE_ENABLE 0x04 +#define MAP_CCDI_CONFIG 0x08 +#define MAP_THRD0_CCDI_STATUS 0x0c +#define MAP_THRD1_CCDI_STATUS 0x10 +#define MAP_THRD2_CCDI_STATUS 0x14 +#define MAP_THRD3_CCDI_STATUS 0x18 +#define MAP_THRD0_DEBUG_MODE 0x1c +#define MAP_THRD1_DEBUG_MODE 0x20 +#define MAP_THRD2_DEBUG_MODE 0x24 +#define MAP_THRD3_DEBUG_MODE 0x28 +#define MAP_MISC_STATE 0x60 +#define MAP_DEBUG_READ_CTL 0x64 +#define MAP_DEBUG_READ_REG0 0x68 +#define MAP_DEBUG_READ_REG1 0x6c + +#define MMU_SETUP 0x400 +#define MMU_LFSRSEED 0x401 +#define MMU_HPW_NUM_PAGE_LVL 0x410 +#define MMU_PGWKR_PGDBASE 0x411 +#define MMU_PGWKR_PGDSHFT 0x412 +#define MMU_PGWKR_PGDMASK 0x413 +#define MMU_PGWKR_PUDSHFT 0x414 +#define MMU_PGWKR_PUDMASK 0x415 +#define MMU_PGWKR_PMDSHFT 0x416 +#define MMU_PGWKR_PMDMASK 0x417 +#define MMU_PGWKR_PTESHFT 0x418 +#define MMU_PGWKR_PTEMASK 0x419 + +#endif /* __NLM_CPUCONTROL_H__ */ diff --git a/arch/mips/include/asm/netlogic/xlp-hal/iomap.h b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h new file mode 100644 index 000000000000..86cc3391e50c --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlp-hal/iomap.h @@ -0,0 +1,153 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NLM_HAL_IOMAP_H__ +#define __NLM_HAL_IOMAP_H__ + +#define XLP_DEFAULT_IO_BASE 0x18000000 +#define NMI_BASE 0xbfc00000 +#define XLP_IO_CLK 133333333 + +#define XLP_PCIE_CFG_SIZE 0x1000 /* 4K */ +#define XLP_PCIE_DEV_BLK_SIZE (8 * XLP_PCIE_CFG_SIZE) +#define XLP_PCIE_BUS_BLK_SIZE (256 * XLP_PCIE_DEV_BLK_SIZE) +#define XLP_IO_SIZE (64 << 20) /* ECFG space size */ +#define XLP_IO_PCI_HDRSZ 0x100 +#define XLP_IO_DEV(node, dev) ((dev) + (node) * 8) +#define XLP_HDR_OFFSET(node, bus, dev, fn) (((bus) << 20) | \ + ((XLP_IO_DEV(node, dev)) << 15) | ((fn) << 12)) + +#define XLP_IO_BRIDGE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 0) +/* coherent inter chip */ +#define XLP_IO_CIC0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 1) +#define XLP_IO_CIC1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 2) +#define XLP_IO_CIC2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 3) +#define XLP_IO_PIC_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 4) + +#define XLP_IO_PCIE_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 1, i) +#define XLP_IO_PCIE0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 0) +#define XLP_IO_PCIE1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 1) +#define XLP_IO_PCIE2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 2) +#define XLP_IO_PCIE3_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 3) + +#define XLP_IO_USB_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 2, i) +#define XLP_IO_USB_EHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 0) +#define XLP_IO_USB_OHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 1) +#define XLP_IO_USB_OHCI1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 2) +#define XLP_IO_USB_EHCI1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 3) +#define XLP_IO_USB_OHCI2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 4) +#define XLP_IO_USB_OHCI3_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 5) + +#define XLP_IO_NAE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 3, 0) +#define XLP_IO_POE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 3, 1) + +#define XLP_IO_CMS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 4, 0) + +#define XLP_IO_DMA_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 1) +#define XLP_IO_SEC_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 2) +#define XLP_IO_CMP_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 3) + +#define XLP_IO_UART_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 6, i) +#define XLP_IO_UART0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 0) +#define XLP_IO_UART1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 1) +#define XLP_IO_I2C_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 6, 2 + i) +#define XLP_IO_I2C0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 2) +#define XLP_IO_I2C1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 3) +#define XLP_IO_GPIO_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 4) +/* system management */ +#define XLP_IO_SYS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 5) +#define XLP_IO_JTAG_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 6) + +#define XLP_IO_NOR_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 0) +#define XLP_IO_NAND_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 1) +#define XLP_IO_SPI_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 2) +/* SD flash */ +#define XLP_IO_SD_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 3) +#define XLP_IO_MMC_OFFSET(node, slot) \ + ((XLP_IO_SD_OFFSET(node))+(slot*0x100)+XLP_IO_PCI_HDRSZ) + +/* PCI config header register id's */ +#define XLP_PCI_CFGREG0 0x00 +#define XLP_PCI_CFGREG1 0x01 +#define XLP_PCI_CFGREG2 0x02 +#define XLP_PCI_CFGREG3 0x03 +#define XLP_PCI_CFGREG4 0x04 +#define XLP_PCI_CFGREG5 0x05 +#define XLP_PCI_DEVINFO_REG0 0x30 +#define XLP_PCI_DEVINFO_REG1 0x31 +#define XLP_PCI_DEVINFO_REG2 0x32 +#define XLP_PCI_DEVINFO_REG3 0x33 +#define XLP_PCI_DEVINFO_REG4 0x34 +#define XLP_PCI_DEVINFO_REG5 0x35 +#define XLP_PCI_DEVINFO_REG6 0x36 +#define XLP_PCI_DEVINFO_REG7 0x37 +#define XLP_PCI_DEVSCRATCH_REG0 0x38 +#define XLP_PCI_DEVSCRATCH_REG1 0x39 +#define XLP_PCI_DEVSCRATCH_REG2 0x3a +#define XLP_PCI_DEVSCRATCH_REG3 0x3b +#define XLP_PCI_MSGSTN_REG 0x3c +#define XLP_PCI_IRTINFO_REG 0x3d +#define XLP_PCI_UCODEINFO_REG 0x3e +#define XLP_PCI_SBB_WT_REG 0x3f + +/* PCI IDs for SoC device */ +#define PCI_VENDOR_NETLOGIC 0x184e + +#define PCI_DEVICE_ID_NLM_ROOT 0x1001 +#define PCI_DEVICE_ID_NLM_ICI 0x1002 +#define PCI_DEVICE_ID_NLM_PIC 0x1003 +#define PCI_DEVICE_ID_NLM_PCIE 0x1004 +#define PCI_DEVICE_ID_NLM_EHCI 0x1007 +#define PCI_DEVICE_ID_NLM_ILK 0x1008 +#define PCI_DEVICE_ID_NLM_NAE 0x1009 +#define PCI_DEVICE_ID_NLM_POE 0x100A +#define PCI_DEVICE_ID_NLM_FMN 0x100B +#define PCI_DEVICE_ID_NLM_RAID 0x100D +#define PCI_DEVICE_ID_NLM_SAE 0x100D +#define PCI_DEVICE_ID_NLM_RSA 0x100E +#define PCI_DEVICE_ID_NLM_CMP 0x100F +#define PCI_DEVICE_ID_NLM_UART 0x1010 +#define PCI_DEVICE_ID_NLM_I2C 0x1011 +#define PCI_DEVICE_ID_NLM_NOR 0x1015 +#define PCI_DEVICE_ID_NLM_NAND 0x1016 +#define PCI_DEVICE_ID_NLM_MMC 0x1018 + +#ifndef __ASSEMBLY__ + +#define nlm_read_pci_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_pci_reg(b, r, v) nlm_write_reg(b, r, v) + +#endif /* !__ASSEMBLY */ + +#endif /* __NLM_HAL_IOMAP_H__ */ diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pic.h b/arch/mips/include/asm/netlogic/xlp-hal/pic.h new file mode 100644 index 000000000000..b6628f7ccf74 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlp-hal/pic.h @@ -0,0 +1,411 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NLM_HAL_PIC_H +#define _NLM_HAL_PIC_H + +/* PIC Specific registers */ +#define PIC_CTRL 0x00 + +/* PIC control register defines */ +#define PIC_CTRL_ITV 32 /* interrupt timeout value */ +#define PIC_CTRL_ICI 19 /* ICI interrupt timeout enable */ +#define PIC_CTRL_ITE 18 /* interrupt timeout enable */ +#define PIC_CTRL_STE 10 /* system timer interrupt enable */ +#define PIC_CTRL_WWR1 8 /* watchdog 1 wraparound count for reset */ +#define PIC_CTRL_WWR0 6 /* watchdog 0 wraparound count for reset */ +#define PIC_CTRL_WWN1 4 /* watchdog 1 wraparound count for NMI */ +#define PIC_CTRL_WWN0 2 /* watchdog 0 wraparound count for NMI */ +#define PIC_CTRL_WTE 0 /* watchdog timer enable */ + +/* PIC Status register defines */ +#define PIC_ICI_STATUS 33 /* ICI interrupt timeout status */ +#define PIC_ITE_STATUS 32 /* interrupt timeout status */ +#define PIC_STS_STATUS 4 /* System timer interrupt status */ +#define PIC_WNS_STATUS 2 /* NMI status for watchdog timers */ +#define PIC_WIS_STATUS 0 /* Interrupt status for watchdog timers */ + +/* PIC IPI control register offsets */ +#define PIC_IPICTRL_NMI 32 +#define PIC_IPICTRL_RIV 20 /* received interrupt vector */ +#define PIC_IPICTRL_IDB 16 /* interrupt destination base */ +#define PIC_IPICTRL_DTE 0 /* interrupt destination thread enables */ + +/* PIC IRT register offsets */ +#define PIC_IRT_ENABLE 31 +#define PIC_IRT_NMI 29 +#define PIC_IRT_SCH 28 /* Scheduling scheme */ +#define PIC_IRT_RVEC 20 /* Interrupt receive vectors */ +#define PIC_IRT_DT 19 /* Destination type */ +#define PIC_IRT_DB 16 /* Destination base */ +#define PIC_IRT_DTE 0 /* Destination thread enables */ + +#define PIC_BYTESWAP 0x02 +#define PIC_STATUS 0x04 +#define PIC_INTR_TIMEOUT 0x06 +#define PIC_ICI0_INTR_TIMEOUT 0x08 +#define PIC_ICI1_INTR_TIMEOUT 0x0a +#define PIC_ICI2_INTR_TIMEOUT 0x0c +#define PIC_IPI_CTL 0x0e +#define PIC_INT_ACK 0x10 +#define PIC_INT_PENDING0 0x12 +#define PIC_INT_PENDING1 0x14 +#define PIC_INT_PENDING2 0x16 + +#define PIC_WDOG0_MAXVAL 0x18 +#define PIC_WDOG0_COUNT 0x1a +#define PIC_WDOG0_ENABLE0 0x1c +#define PIC_WDOG0_ENABLE1 0x1e +#define PIC_WDOG0_BEATCMD 0x20 +#define PIC_WDOG0_BEAT0 0x22 +#define PIC_WDOG0_BEAT1 0x24 + +#define PIC_WDOG1_MAXVAL 0x26 +#define PIC_WDOG1_COUNT 0x28 +#define PIC_WDOG1_ENABLE0 0x2a +#define PIC_WDOG1_ENABLE1 0x2c +#define PIC_WDOG1_BEATCMD 0x2e +#define PIC_WDOG1_BEAT0 0x30 +#define PIC_WDOG1_BEAT1 0x32 + +#define PIC_WDOG_MAXVAL(i) (PIC_WDOG0_MAXVAL + ((i) ? 7 : 0)) +#define PIC_WDOG_COUNT(i) (PIC_WDOG0_COUNT + ((i) ? 7 : 0)) +#define PIC_WDOG_ENABLE0(i) (PIC_WDOG0_ENABLE0 + ((i) ? 7 : 0)) +#define PIC_WDOG_ENABLE1(i) (PIC_WDOG0_ENABLE1 + ((i) ? 7 : 0)) +#define PIC_WDOG_BEATCMD(i) (PIC_WDOG0_BEATCMD + ((i) ? 7 : 0)) +#define PIC_WDOG_BEAT0(i) (PIC_WDOG0_BEAT0 + ((i) ? 7 : 0)) +#define PIC_WDOG_BEAT1(i) (PIC_WDOG0_BEAT1 + ((i) ? 7 : 0)) + +#define PIC_TIMER0_MAXVAL 0x34 +#define PIC_TIMER1_MAXVAL 0x36 +#define PIC_TIMER2_MAXVAL 0x38 +#define PIC_TIMER3_MAXVAL 0x3a +#define PIC_TIMER4_MAXVAL 0x3c +#define PIC_TIMER5_MAXVAL 0x3e +#define PIC_TIMER6_MAXVAL 0x40 +#define PIC_TIMER7_MAXVAL 0x42 +#define PIC_TIMER_MAXVAL(i) (PIC_TIMER0_MAXVAL + ((i) * 2)) + +#define PIC_TIMER0_COUNT 0x44 +#define PIC_TIMER1_COUNT 0x46 +#define PIC_TIMER2_COUNT 0x48 +#define PIC_TIMER3_COUNT 0x4a +#define PIC_TIMER4_COUNT 0x4c +#define PIC_TIMER5_COUNT 0x4e +#define PIC_TIMER6_COUNT 0x50 +#define PIC_TIMER7_COUNT 0x52 +#define PIC_TIMER_COUNT(i) (PIC_TIMER0_COUNT + ((i) * 2)) + +#define PIC_ITE0_N0_N1 0x54 +#define PIC_ITE1_N0_N1 0x58 +#define PIC_ITE2_N0_N1 0x5c +#define PIC_ITE3_N0_N1 0x60 +#define PIC_ITE4_N0_N1 0x64 +#define PIC_ITE5_N0_N1 0x68 +#define PIC_ITE6_N0_N1 0x6c +#define PIC_ITE7_N0_N1 0x70 +#define PIC_ITE_N0_N1(i) (PIC_ITE0_N0_N1 + ((i) * 4)) + +#define PIC_ITE0_N2_N3 0x56 +#define PIC_ITE1_N2_N3 0x5a +#define PIC_ITE2_N2_N3 0x5e +#define PIC_ITE3_N2_N3 0x62 +#define PIC_ITE4_N2_N3 0x66 +#define PIC_ITE5_N2_N3 0x6a +#define PIC_ITE6_N2_N3 0x6e +#define PIC_ITE7_N2_N3 0x72 +#define PIC_ITE_N2_N3(i) (PIC_ITE0_N2_N3 + ((i) * 4)) + +#define PIC_IRT0 0x74 +#define PIC_IRT(i) (PIC_IRT0 + ((i) * 2)) + +#define TIMER_CYCLES_MAXVAL 0xffffffffffffffffULL + +/* + * IRT Map + */ +#define PIC_NUM_IRTS 160 + +#define PIC_IRT_WD_0_INDEX 0 +#define PIC_IRT_WD_1_INDEX 1 +#define PIC_IRT_WD_NMI_0_INDEX 2 +#define PIC_IRT_WD_NMI_1_INDEX 3 +#define PIC_IRT_TIMER_0_INDEX 4 +#define PIC_IRT_TIMER_1_INDEX 5 +#define PIC_IRT_TIMER_2_INDEX 6 +#define PIC_IRT_TIMER_3_INDEX 7 +#define PIC_IRT_TIMER_4_INDEX 8 +#define PIC_IRT_TIMER_5_INDEX 9 +#define PIC_IRT_TIMER_6_INDEX 10 +#define PIC_IRT_TIMER_7_INDEX 11 +#define PIC_IRT_CLOCK_INDEX PIC_IRT_TIMER_7_INDEX +#define PIC_IRT_TIMER_INDEX(num) ((num) + PIC_IRT_TIMER_0_INDEX) + + +/* 11 and 12 */ +#define PIC_NUM_MSG_Q_IRTS 32 +#define PIC_IRT_MSG_Q0_INDEX 12 +#define PIC_IRT_MSG_Q_INDEX(qid) ((qid) + PIC_IRT_MSG_Q0_INDEX) +/* 12 to 43 */ +#define PIC_IRT_MSG_0_INDEX 44 +#define PIC_IRT_MSG_1_INDEX 45 +/* 44 and 45 */ +#define PIC_NUM_PCIE_MSIX_IRTS 32 +#define PIC_IRT_PCIE_MSIX_0_INDEX 46 +#define PIC_IRT_PCIE_MSIX_INDEX(num) ((num) + PIC_IRT_PCIE_MSIX_0_INDEX) +/* 46 to 77 */ +#define PIC_NUM_PCIE_LINK_IRTS 4 +#define PIC_IRT_PCIE_LINK_0_INDEX 78 +#define PIC_IRT_PCIE_LINK_1_INDEX 79 +#define PIC_IRT_PCIE_LINK_2_INDEX 80 +#define PIC_IRT_PCIE_LINK_3_INDEX 81 +#define PIC_IRT_PCIE_LINK_INDEX(num) ((num) + PIC_IRT_PCIE_LINK_0_INDEX) +/* 78 to 81 */ +#define PIC_NUM_NA_IRTS 32 +/* 82 to 113 */ +#define PIC_IRT_NA_0_INDEX 82 +#define PIC_IRT_NA_INDEX(num) ((num) + PIC_IRT_NA_0_INDEX) +#define PIC_IRT_POE_INDEX 114 + +#define PIC_NUM_USB_IRTS 6 +#define PIC_IRT_USB_0_INDEX 115 +#define PIC_IRT_EHCI_0_INDEX 115 +#define PIC_IRT_EHCI_1_INDEX 118 +#define PIC_IRT_USB_INDEX(num) ((num) + PIC_IRT_USB_0_INDEX) +/* 115 to 120 */ +#define PIC_IRT_GDX_INDEX 121 +#define PIC_IRT_SEC_INDEX 122 +#define PIC_IRT_RSA_INDEX 123 + +#define PIC_NUM_COMP_IRTS 4 +#define PIC_IRT_COMP_0_INDEX 124 +#define PIC_IRT_COMP_INDEX(num) ((num) + PIC_IRT_COMP_0_INDEX) +/* 124 to 127 */ +#define PIC_IRT_GBU_INDEX 128 +#define PIC_IRT_ICC_0_INDEX 129 /* ICC - Inter Chip Coherency */ +#define PIC_IRT_ICC_1_INDEX 130 +#define PIC_IRT_ICC_2_INDEX 131 +#define PIC_IRT_CAM_INDEX 132 +#define PIC_IRT_UART_0_INDEX 133 +#define PIC_IRT_UART_1_INDEX 134 +#define PIC_IRT_I2C_0_INDEX 135 +#define PIC_IRT_I2C_1_INDEX 136 +#define PIC_IRT_SYS_0_INDEX 137 +#define PIC_IRT_SYS_1_INDEX 138 +#define PIC_IRT_JTAG_INDEX 139 +#define PIC_IRT_PIC_INDEX 140 +#define PIC_IRT_NBU_INDEX 141 +#define PIC_IRT_TCU_INDEX 142 +#define PIC_IRT_GCU_INDEX 143 /* GBC - Global Coherency */ +#define PIC_IRT_DMC_0_INDEX 144 +#define PIC_IRT_DMC_1_INDEX 145 + +#define PIC_NUM_GPIO_IRTS 4 +#define PIC_IRT_GPIO_0_INDEX 146 +#define PIC_IRT_GPIO_INDEX(num) ((num) + PIC_IRT_GPIO_0_INDEX) + +/* 146 to 149 */ +#define PIC_IRT_NOR_INDEX 150 +#define PIC_IRT_NAND_INDEX 151 +#define PIC_IRT_SPI_INDEX 152 +#define PIC_IRT_MMC_INDEX 153 + +#define PIC_CLOCK_TIMER 7 +#define PIC_IRQ_BASE 8 + +#if !defined(LOCORE) && !defined(__ASSEMBLY__) + +#define PIC_IRT_FIRST_IRQ (PIC_IRQ_BASE) +#define PIC_IRT_LAST_IRQ 63 +#define PIC_IRQ_IS_IRT(irq) ((irq) >= PIC_IRT_FIRST_IRQ) + +/* + * Misc + */ +#define PIC_IRT_VALID 1 +#define PIC_LOCAL_SCHEDULING 1 +#define PIC_GLOBAL_SCHEDULING 0 + +#define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r) +#define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v) +#define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node)) +#define nlm_get_pic_regbase(node) (nlm_get_pic_pcibase(node) + XLP_IO_PCI_HDRSZ) + +/* IRT and h/w interrupt routines */ +static inline int +nlm_pic_read_irt(uint64_t base, int irt_index) +{ + return nlm_read_pic_reg(base, PIC_IRT(irt_index)); +} + +static inline uint64_t +nlm_pic_read_control(uint64_t base) +{ + return nlm_read_pic_reg(base, PIC_CTRL); +} + +static inline void +nlm_pic_write_control(uint64_t base, uint64_t control) +{ + nlm_write_pic_reg(base, PIC_CTRL, control); +} + +static inline void +nlm_pic_update_control(uint64_t base, uint64_t control) +{ + uint64_t val; + + val = nlm_read_pic_reg(base, PIC_CTRL); + nlm_write_pic_reg(base, PIC_CTRL, control | val); +} + +static inline void +nlm_set_irt_to_cpu(uint64_t base, int irt, int cpu) +{ + uint64_t val; + + val = nlm_read_pic_reg(base, PIC_IRT(irt)); + val |= cpu & 0xf; + if (cpu > 15) + val |= 1 << 16; + nlm_write_pic_reg(base, PIC_IRT(irt), val); +} + +static inline void +nlm_pic_write_irt(uint64_t base, int irt_num, int en, int nmi, + int sch, int vec, int dt, int db, int dte) +{ + uint64_t val; + + val = (((uint64_t)en & 0x1) << 31) | ((nmi & 0x1) << 29) | + ((sch & 0x1) << 28) | ((vec & 0x3f) << 20) | + ((dt & 0x1) << 19) | ((db & 0x7) << 16) | + (dte & 0xffff); + + nlm_write_pic_reg(base, PIC_IRT(irt_num), val); +} + +static inline void +nlm_pic_write_irt_direct(uint64_t base, int irt_num, int en, int nmi, + int sch, int vec, int cpu) +{ + nlm_pic_write_irt(base, irt_num, en, nmi, sch, vec, 1, + (cpu >> 4), /* thread group */ + 1 << (cpu & 0xf)); /* thread mask */ +} + +static inline uint64_t +nlm_pic_read_timer(uint64_t base, int timer) +{ + return nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer)); +} + +static inline void +nlm_pic_write_timer(uint64_t base, int timer, uint64_t value) +{ + nlm_write_pic_reg(base, PIC_TIMER_COUNT(timer), value); +} + +static inline void +nlm_pic_set_timer(uint64_t base, int timer, uint64_t value, int irq, int cpu) +{ + uint64_t pic_ctrl = nlm_read_pic_reg(base, PIC_CTRL); + int en; + + en = (irq > 0); + nlm_write_pic_reg(base, PIC_TIMER_MAXVAL(timer), value); + nlm_pic_write_irt_direct(base, PIC_IRT_TIMER_INDEX(timer), + en, 0, 0, irq, cpu); + + /* enable the timer */ + pic_ctrl |= (1 << (PIC_CTRL_STE + timer)); + nlm_write_pic_reg(base, PIC_CTRL, pic_ctrl); +} + +static inline void +nlm_pic_enable_irt(uint64_t base, int irt) +{ + uint64_t reg; + + reg = nlm_read_pic_reg(base, PIC_IRT(irt)); + nlm_write_pic_reg(base, PIC_IRT(irt), reg | (1u << 31)); +} + +static inline void +nlm_pic_disable_irt(uint64_t base, int irt) +{ + uint32_t reg; + + reg = nlm_read_pic_reg(base, PIC_IRT(irt)); + nlm_write_pic_reg(base, PIC_IRT(irt), reg & ~((uint64_t)1 << 31)); +} + +static inline void +nlm_pic_send_ipi(uint64_t base, int hwt, int irq, int nmi) +{ + uint64_t ipi; + int node, ncpu; + + node = hwt / 32; + ncpu = hwt & 0x1f; + ipi = ((uint64_t)nmi << 31) | (irq << 20) | (node << 17) | + (1 << (ncpu & 0xf)); + if (ncpu > 15) + ipi |= 0x10000; /* Setting bit 16 to select cpus 16-31 */ + + nlm_write_pic_reg(base, PIC_IPI_CTL, ipi); +} + +static inline void +nlm_pic_ack(uint64_t base, int irt_num) +{ + nlm_write_pic_reg(base, PIC_INT_ACK, irt_num); + + /* Ack the Status register for Watchdog & System timers */ + if (irt_num < 12) + nlm_write_pic_reg(base, PIC_STATUS, (1 << irt_num)); +} + +static inline void +nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt) +{ + nlm_pic_write_irt_direct(base, irt, 0, 0, 0, irq, 0); +} + +extern uint64_t nlm_pic_base; +int nlm_irq_to_irt(int irq); +int nlm_irt_to_irq(int irt); + +#endif /* __ASSEMBLY__ */ +#endif /* _NLM_HAL_PIC_H */ diff --git a/arch/mips/include/asm/netlogic/xlp-hal/sys.h b/arch/mips/include/asm/netlogic/xlp-hal/sys.h new file mode 100644 index 000000000000..21432f7d89b9 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlp-hal/sys.h @@ -0,0 +1,129 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NLM_HAL_SYS_H__ +#define __NLM_HAL_SYS_H__ + +/** +* @file_name sys.h +* @author Netlogic Microsystems +* @brief HAL for System configuration registers +*/ +#define SYS_CHIP_RESET 0x00 +#define SYS_POWER_ON_RESET_CFG 0x01 +#define SYS_EFUSE_DEVICE_CFG_STATUS0 0x02 +#define SYS_EFUSE_DEVICE_CFG_STATUS1 0x03 +#define SYS_EFUSE_DEVICE_CFG_STATUS2 0x04 +#define SYS_EFUSE_DEVICE_CFG3 0x05 +#define SYS_EFUSE_DEVICE_CFG4 0x06 +#define SYS_EFUSE_DEVICE_CFG5 0x07 +#define SYS_EFUSE_DEVICE_CFG6 0x08 +#define SYS_EFUSE_DEVICE_CFG7 0x09 +#define SYS_PLL_CTRL 0x0a +#define SYS_CPU_RESET 0x0b +#define SYS_CPU_NONCOHERENT_MODE 0x0d +#define SYS_CORE_DFS_DIS_CTRL 0x0e +#define SYS_CORE_DFS_RST_CTRL 0x0f +#define SYS_CORE_DFS_BYP_CTRL 0x10 +#define SYS_CORE_DFS_PHA_CTRL 0x11 +#define SYS_CORE_DFS_DIV_INC_CTRL 0x12 +#define SYS_CORE_DFS_DIV_DEC_CTRL 0x13 +#define SYS_CORE_DFS_DIV_VALUE 0x14 +#define SYS_RESET 0x15 +#define SYS_DFS_DIS_CTRL 0x16 +#define SYS_DFS_RST_CTRL 0x17 +#define SYS_DFS_BYP_CTRL 0x18 +#define SYS_DFS_DIV_INC_CTRL 0x19 +#define SYS_DFS_DIV_DEC_CTRL 0x1a +#define SYS_DFS_DIV_VALUE0 0x1b +#define SYS_DFS_DIV_VALUE1 0x1c +#define SYS_SENSE_AMP_DLY 0x1d +#define SYS_SOC_SENSE_AMP_DLY 0x1e +#define SYS_CTRL0 0x1f +#define SYS_CTRL1 0x20 +#define SYS_TIMEOUT_BS1 0x21 +#define SYS_BYTE_SWAP 0x22 +#define SYS_VRM_VID 0x23 +#define SYS_PWR_RAM_CMD 0x24 +#define SYS_PWR_RAM_ADDR 0x25 +#define SYS_PWR_RAM_DATA0 0x26 +#define SYS_PWR_RAM_DATA1 0x27 +#define SYS_PWR_RAM_DATA2 0x28 +#define SYS_PWR_UCODE 0x29 +#define SYS_CPU0_PWR_STATUS 0x2a +#define SYS_CPU1_PWR_STATUS 0x2b +#define SYS_CPU2_PWR_STATUS 0x2c +#define SYS_CPU3_PWR_STATUS 0x2d +#define SYS_CPU4_PWR_STATUS 0x2e +#define SYS_CPU5_PWR_STATUS 0x2f +#define SYS_CPU6_PWR_STATUS 0x30 +#define SYS_CPU7_PWR_STATUS 0x31 +#define SYS_STATUS 0x32 +#define SYS_INT_POL 0x33 +#define SYS_INT_TYPE 0x34 +#define SYS_INT_STATUS 0x35 +#define SYS_INT_MASK0 0x36 +#define SYS_INT_MASK1 0x37 +#define SYS_UCO_S_ECC 0x38 +#define SYS_UCO_M_ECC 0x39 +#define SYS_UCO_ADDR 0x3a +#define SYS_UCO_INSTR 0x3b +#define SYS_MEM_BIST0 0x3c +#define SYS_MEM_BIST1 0x3d +#define SYS_MEM_BIST2 0x3e +#define SYS_MEM_BIST3 0x3f +#define SYS_MEM_BIST4 0x40 +#define SYS_MEM_BIST5 0x41 +#define SYS_MEM_BIST6 0x42 +#define SYS_MEM_BIST7 0x43 +#define SYS_MEM_BIST8 0x44 +#define SYS_MEM_BIST9 0x45 +#define SYS_MEM_BIST10 0x46 +#define SYS_MEM_BIST11 0x47 +#define SYS_MEM_BIST12 0x48 +#define SYS_SCRTCH0 0x49 +#define SYS_SCRTCH1 0x4a +#define SYS_SCRTCH2 0x4b +#define SYS_SCRTCH3 0x4c + +#ifndef __ASSEMBLY__ + +#define nlm_read_sys_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_sys_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_sys_pcibase(node) nlm_pcicfg_base(XLP_IO_SYS_OFFSET(node)) +#define nlm_get_sys_regbase(node) (nlm_get_sys_pcibase(node) + XLP_IO_PCI_HDRSZ) + +extern uint64_t nlm_sys_base; +#endif +#endif diff --git a/arch/mips/include/asm/netlogic/xlp-hal/uart.h b/arch/mips/include/asm/netlogic/xlp-hal/uart.h new file mode 100644 index 000000000000..6a7046ca094d --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlp-hal/uart.h @@ -0,0 +1,191 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __XLP_HAL_UART_H__ +#define __XLP_HAL_UART_H__ + +/* UART Specific registers */ +#define UART_RX_DATA 0x00 +#define UART_TX_DATA 0x00 + +#define UART_INT_EN 0x01 +#define UART_INT_ID 0x02 +#define UART_FIFO_CTL 0x02 +#define UART_LINE_CTL 0x03 +#define UART_MODEM_CTL 0x04 +#define UART_LINE_STS 0x05 +#define UART_MODEM_STS 0x06 + +#define UART_DIVISOR0 0x00 +#define UART_DIVISOR1 0x01 + +#define BASE_BAUD (XLP_IO_CLK/16) +#define BAUD_DIVISOR(baud) (BASE_BAUD / baud) + +/* LCR mask values */ +#define LCR_5BITS 0x00 +#define LCR_6BITS 0x01 +#define LCR_7BITS 0x02 +#define LCR_8BITS 0x03 +#define LCR_STOPB 0x04 +#define LCR_PENAB 0x08 +#define LCR_PODD 0x00 +#define LCR_PEVEN 0x10 +#define LCR_PONE 0x20 +#define LCR_PZERO 0x30 +#define LCR_SBREAK 0x40 +#define LCR_EFR_ENABLE 0xbf +#define LCR_DLAB 0x80 + +/* MCR mask values */ +#define MCR_DTR 0x01 +#define MCR_RTS 0x02 +#define MCR_DRS 0x04 +#define MCR_IE 0x08 +#define MCR_LOOPBACK 0x10 + +/* FCR mask values */ +#define FCR_RCV_RST 0x02 +#define FCR_XMT_RST 0x04 +#define FCR_RX_LOW 0x00 +#define FCR_RX_MEDL 0x40 +#define FCR_RX_MEDH 0x80 +#define FCR_RX_HIGH 0xc0 + +/* IER mask values */ +#define IER_ERXRDY 0x1 +#define IER_ETXRDY 0x2 +#define IER_ERLS 0x4 +#define IER_EMSC 0x8 + +#if !defined(LOCORE) && !defined(__ASSEMBLY__) + +#define nlm_read_uart_reg(b, r) nlm_read_reg(b, r) +#define nlm_write_uart_reg(b, r, v) nlm_write_reg(b, r, v) +#define nlm_get_uart_pcibase(node, inst) \ + nlm_pcicfg_base(XLP_IO_UART_OFFSET(node, inst)) +#define nlm_get_uart_regbase(node, inst) \ + (nlm_get_uart_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) + +static inline void +nlm_uart_set_baudrate(uint64_t base, int baud) +{ + uint32_t lcr; + + lcr = nlm_read_uart_reg(base, UART_LINE_CTL); + + /* enable divisor register, and write baud values */ + nlm_write_uart_reg(base, UART_LINE_CTL, lcr | (1 << 7)); + nlm_write_uart_reg(base, UART_DIVISOR0, + (BAUD_DIVISOR(baud) & 0xff)); + nlm_write_uart_reg(base, UART_DIVISOR1, + ((BAUD_DIVISOR(baud) >> 8) & 0xff)); + + /* restore default lcr */ + nlm_write_uart_reg(base, UART_LINE_CTL, lcr); +} + +static inline void +nlm_uart_outbyte(uint64_t base, char c) +{ + uint32_t lsr; + + for (;;) { + lsr = nlm_read_uart_reg(base, UART_LINE_STS); + if (lsr & 0x20) + break; + } + + nlm_write_uart_reg(base, UART_TX_DATA, (int)c); +} + +static inline char +nlm_uart_inbyte(uint64_t base) +{ + int data, lsr; + + for (;;) { + lsr = nlm_read_uart_reg(base, UART_LINE_STS); + if (lsr & 0x80) { /* parity/frame/break-error - push a zero */ + data = 0; + break; + } + if (lsr & 0x01) { /* Rx data */ + data = nlm_read_uart_reg(base, UART_RX_DATA); + break; + } + } + + return (char)data; +} + +static inline int +nlm_uart_init(uint64_t base, int baud, int databits, int stopbits, + int parity, int int_en, int loopback) +{ + uint32_t lcr; + + lcr = 0; + if (databits >= 8) + lcr |= LCR_8BITS; + else if (databits == 7) + lcr |= LCR_7BITS; + else if (databits == 6) + lcr |= LCR_6BITS; + else + lcr |= LCR_5BITS; + + if (stopbits > 1) + lcr |= LCR_STOPB; + + lcr |= parity << 3; + + /* setup default lcr */ + nlm_write_uart_reg(base, UART_LINE_CTL, lcr); + + /* Reset the FIFOs */ + nlm_write_uart_reg(base, UART_LINE_CTL, FCR_RCV_RST | FCR_XMT_RST); + + nlm_uart_set_baudrate(base, baud); + + if (loopback) + nlm_write_uart_reg(base, UART_MODEM_CTL, 0x1f); + + if (int_en) + nlm_write_uart_reg(base, UART_INT_EN, IER_ERXRDY | IER_ETXRDY); + + return 0; +} +#endif /* !LOCORE && !__ASSEMBLY__ */ +#endif /* __XLP_HAL_UART_H__ */ diff --git a/arch/mips/netlogic/xlr/xlr_console.c b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h index 759df0692201..1540588e396d 100644 --- a/arch/mips/netlogic/xlr/xlr_console.c +++ b/arch/mips/include/asm/netlogic/xlp-hal/xlp.h @@ -32,15 +32,20 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <linux/types.h> -#include <asm/netlogic/xlr/iomap.h> +#ifndef _NLM_HAL_XLP_H +#define _NLM_HAL_XLP_H -void prom_putchar(char c) -{ - nlm_reg_t *mmio; +#define PIC_UART_0_IRQ 17 +#define PIC_UART_1_IRQ 18 - mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); - while (netlogic_read_reg(mmio, 0x5) == 0) - ; - netlogic_write_reg(mmio, 0x0, c); -} +#ifndef __ASSEMBLY__ + +/* SMP support functions */ +void xlp_boot_core0_siblings(void); +void xlp_wakeup_secondary_cpus(void); + +void xlp_mmu_init(void); +void nlm_hal_init(void); + +#endif /* !__ASSEMBLY__ */ +#endif /* _ASM_NLM_XLP_H */ diff --git a/arch/mips/include/asm/netlogic/xlr/iomap.h b/arch/mips/include/asm/netlogic/xlr/iomap.h index 2e3a4dd53045..2e768f032e83 100644 --- a/arch/mips/include/asm/netlogic/xlr/iomap.h +++ b/arch/mips/include/asm/netlogic/xlr/iomap.h @@ -106,26 +106,4 @@ #define DEFAULT_HT_TYPE0_CFG_BASE 0x16000000 #define DEFAULT_HT_TYPE1_CFG_BASE 0x17000000 -#ifndef __ASSEMBLY__ -#include <linux/types.h> -#include <asm/byteorder.h> - -typedef volatile __u32 nlm_reg_t; -extern unsigned long netlogic_io_base; - -/* FIXME read once in write_reg */ -#ifdef CONFIG_CPU_LITTLE_ENDIAN -#define netlogic_read_reg(base, offset) ((base)[(offset)]) -#define netlogic_write_reg(base, offset, value) ((base)[(offset)] = (value)) -#else -#define netlogic_read_reg(base, offset) (be32_to_cpu((base)[(offset)])) -#define netlogic_write_reg(base, offset, value) \ - ((base)[(offset)] = cpu_to_be32((value))) -#endif - -#define netlogic_read_reg_le32(base, offset) (le32_to_cpu((base)[(offset)])) -#define netlogic_write_reg_le32(base, offset, value) \ - ((base)[(offset)] = cpu_to_le32((value))) -#define netlogic_io_mmio(offset) ((nlm_reg_t *)(netlogic_io_base+(offset))) -#endif /* __ASSEMBLY__ */ #endif diff --git a/arch/mips/include/asm/netlogic/xlr/msidef.h b/arch/mips/include/asm/netlogic/xlr/msidef.h new file mode 100644 index 000000000000..7e39d40be4f5 --- /dev/null +++ b/arch/mips/include/asm/netlogic/xlr/msidef.h @@ -0,0 +1,84 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ASM_RMI_MSIDEF_H +#define ASM_RMI_MSIDEF_H + +/* + * Constants for Intel APIC based MSI messages. + * Adapted for the RMI XLR using identical defines + */ + +/* + * Shifts for MSI data + */ + +#define MSI_DATA_VECTOR_SHIFT 0 +#define MSI_DATA_VECTOR_MASK 0x000000ff +#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & \ + MSI_DATA_VECTOR_MASK) + +#define MSI_DATA_DELIVERY_MODE_SHIFT 8 +#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT) +#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT) + +#define MSI_DATA_LEVEL_SHIFT 14 +#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) +#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) + +#define MSI_DATA_TRIGGER_SHIFT 15 +#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) +#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) + +/* + * Shift/mask fields for msi address + */ + +#define MSI_ADDR_BASE_HI 0 +#define MSI_ADDR_BASE_LO 0xfee00000 + +#define MSI_ADDR_DEST_MODE_SHIFT 2 +#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT) +#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT) + +#define MSI_ADDR_REDIRECTION_SHIFT 3 +#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) +#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) + +#define MSI_ADDR_DEST_ID_SHIFT 12 +#define MSI_ADDR_DEST_ID_MASK 0x00ffff0 +#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & \ + MSI_ADDR_DEST_ID_MASK) + +#endif /* ASM_RMI_MSIDEF_H */ diff --git a/arch/mips/include/asm/netlogic/xlr/pic.h b/arch/mips/include/asm/netlogic/xlr/pic.h index 5cceb746f080..868013e62f32 100644 --- a/arch/mips/include/asm/netlogic/xlr/pic.h +++ b/arch/mips/include/asm/netlogic/xlr/pic.h @@ -193,39 +193,72 @@ /* end XLS */ #ifndef __ASSEMBLY__ -static inline void pic_send_ipi(u32 ipi) + +#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_0_IRQ) && \ + ((irq) <= PIC_TIMER_7_IRQ)) +#define PIC_IRQ_IS_IRT(irq) (((irq) >= PIC_IRT_FIRST_IRQ) && \ + ((irq) <= PIC_IRT_LAST_IRQ)) + +static inline int +nlm_irq_to_irt(int irq) { - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + if (PIC_IRQ_IS_IRT(irq) == 0) + return -1; - netlogic_write_reg(mmio, PIC_IPI, ipi); + return PIC_IRQ_TO_INTR(irq); } -static inline u32 pic_read_control(void) +static inline int +nlm_irt_to_irq(int irt) { - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - return netlogic_read_reg(mmio, PIC_CTRL); + return PIC_INTR_TO_IRQ(irt); } -static inline void pic_write_control(u32 control) +static inline void +nlm_pic_enable_irt(uint64_t base, int irt) { - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + uint32_t reg; - netlogic_write_reg(mmio, PIC_CTRL, control); + reg = nlm_read_reg(base, PIC_IRT_1(irt)); + nlm_write_reg(base, PIC_IRT_1(irt), reg | (1u << 31)); } -static inline void pic_update_control(u32 control) +static inline void +nlm_pic_disable_irt(uint64_t base, int irt) { - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); + uint32_t reg; - netlogic_write_reg(mmio, PIC_CTRL, - (control | netlogic_read_reg(mmio, PIC_CTRL))); + reg = nlm_read_reg(base, PIC_IRT_1(irt)); + nlm_write_reg(base, PIC_IRT_1(irt), reg & ~(1u << 31)); } -#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_0_IRQ) && \ - ((irq) <= PIC_TIMER_7_IRQ)) -#define PIC_IRQ_IS_IRT(irq) (((irq) >= PIC_IRT_FIRST_IRQ) && \ - ((irq) <= PIC_IRT_LAST_IRQ)) -#endif +static inline void +nlm_pic_send_ipi(uint64_t base, int hwt, int irq, int nmi) +{ + unsigned int tid, pid; + + tid = hwt & 0x3; + pid = (hwt >> 2) & 0x07; + nlm_write_reg(base, PIC_IPI, + (pid << 20) | (tid << 16) | (nmi << 8) | irq); +} + +static inline void +nlm_pic_ack(uint64_t base, int irt) +{ + nlm_write_reg(base, PIC_INT_ACK, 1u << irt); +} +static inline void +nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt) +{ + nlm_write_reg(base, PIC_IRT_0(irt), (1u << hwt)); + /* local scheduling, invalid, level by default */ + nlm_write_reg(base, PIC_IRT_1(irt), + (1 << 30) | (1 << 6) | irq); +} + +extern uint64_t nlm_pic_base; +#endif #endif /* _ASM_NLM_XLR_PIC_H */ diff --git a/arch/mips/include/asm/netlogic/xlr/xlr.h b/arch/mips/include/asm/netlogic/xlr/xlr.h index 3e6372692a04..ff4a17b0bf78 100644 --- a/arch/mips/include/asm/netlogic/xlr/xlr.h +++ b/arch/mips/include/asm/netlogic/xlr/xlr.h @@ -40,17 +40,8 @@ struct uart_port; unsigned int nlm_xlr_uart_in(struct uart_port *, int); void nlm_xlr_uart_out(struct uart_port *, int, int); -/* SMP support functions */ -struct irq_desc; -void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc); -void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc); -int nlm_wakeup_secondary_cpus(u32 wakeup_mask); -void nlm_smp_irq_init(void); -void nlm_boot_smp_nmi(void); -void prom_pre_boot_secondary_cpus(void); - -extern struct plat_smp_ops nlm_smp_ops; -extern unsigned long nlm_common_ebase; +/* SMP helpers */ +void xlr_wakeup_secondary_cpus(void); /* XLS B silicon "Rook" */ static inline unsigned int nlm_chip_is_xls_b(void) diff --git a/drivers/staging/octeon/cvmx-address.h b/arch/mips/include/asm/octeon/cvmx-address.h index 3c74d826e2e6..3c74d826e2e6 100644 --- a/drivers/staging/octeon/cvmx-address.h +++ b/arch/mips/include/asm/octeon/cvmx-address.h diff --git a/drivers/staging/octeon/cvmx-asxx-defs.h b/arch/mips/include/asm/octeon/cvmx-asxx-defs.h index 91415a85e8d2..91415a85e8d2 100644 --- a/drivers/staging/octeon/cvmx-asxx-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-asxx-defs.h diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h index 4e4c3a8282d6..1db1dc2724cb 100644 --- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h @@ -39,7 +39,7 @@ * versions. */ #define CVMX_BOOTINFO_MAJ_VER 1 -#define CVMX_BOOTINFO_MIN_VER 2 +#define CVMX_BOOTINFO_MIN_VER 3 #if (CVMX_BOOTINFO_MAJ_VER == 1) #define CVMX_BOOTINFO_OCTEON_SERIAL_LEN 20 @@ -116,7 +116,13 @@ struct cvmx_bootinfo { */ uint32_t config_flags; #endif - +#if (CVMX_BOOTINFO_MIN_VER >= 3) + /* + * Address of the OF Flattened Device Tree structure + * describing the board. + */ + uint64_t fdt_addr; +#endif }; #define CVMX_BOOTINFO_CFG_FLAG_PCI_HOST (1ull << 0) @@ -164,6 +170,22 @@ enum cvmx_board_types_enum { /* Special 'generic' board type, supports many boards */ CVMX_BOARD_TYPE_GENERIC = 28, CVMX_BOARD_TYPE_EBH5610 = 29, + CVMX_BOARD_TYPE_LANAI2_A = 30, + CVMX_BOARD_TYPE_LANAI2_U = 31, + CVMX_BOARD_TYPE_EBB5600 = 32, + CVMX_BOARD_TYPE_EBB6300 = 33, + CVMX_BOARD_TYPE_NIC_XLE_10G = 34, + CVMX_BOARD_TYPE_LANAI2_G = 35, + CVMX_BOARD_TYPE_EBT5810 = 36, + CVMX_BOARD_TYPE_NIC10E = 37, + CVMX_BOARD_TYPE_EP6300C = 38, + CVMX_BOARD_TYPE_EBB6800 = 39, + CVMX_BOARD_TYPE_NIC4E = 40, + CVMX_BOARD_TYPE_NIC2E = 41, + CVMX_BOARD_TYPE_EBB6600 = 42, + CVMX_BOARD_TYPE_REDWING = 43, + CVMX_BOARD_TYPE_NIC68_4 = 44, + CVMX_BOARD_TYPE_NIC10E_66 = 45, CVMX_BOARD_TYPE_MAX, /* @@ -181,6 +203,23 @@ enum cvmx_board_types_enum { CVMX_BOARD_TYPE_CUST_NS0216 = 10002, CVMX_BOARD_TYPE_CUST_NB5 = 10003, CVMX_BOARD_TYPE_CUST_WMR500 = 10004, + CVMX_BOARD_TYPE_CUST_ITB101 = 10005, + CVMX_BOARD_TYPE_CUST_NTE102 = 10006, + CVMX_BOARD_TYPE_CUST_AGS103 = 10007, + CVMX_BOARD_TYPE_CUST_GST104 = 10008, + CVMX_BOARD_TYPE_CUST_GCT105 = 10009, + CVMX_BOARD_TYPE_CUST_AGS106 = 10010, + CVMX_BOARD_TYPE_CUST_SGM107 = 10011, + CVMX_BOARD_TYPE_CUST_GCT108 = 10012, + CVMX_BOARD_TYPE_CUST_AGS109 = 10013, + CVMX_BOARD_TYPE_CUST_GCT110 = 10014, + CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER = 10015, + CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER = 10016, + CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX = 10017, + CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX = 10018, + CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX = 10019, + CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX = 10020, + CVMX_BOARD_TYPE_CUST_L2_ZINWELL = 10021, CVMX_BOARD_TYPE_CUST_DEFINED_MAX = 20000, /* @@ -241,6 +280,22 @@ static inline const char *cvmx_board_type_to_string(enum ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5200) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_GENERIC) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5610) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_A) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_U) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB5600) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6300) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_10G) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_G) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5810) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EP6300C) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6800) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC4E) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC2E) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6600) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_REDWING) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC68_4) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E_66) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX) /* Customer boards listed here */ @@ -249,6 +304,23 @@ static inline const char *cvmx_board_type_to_string(enum ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NS0216) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NB5) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WMR500) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_ITB101) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NTE102) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS103) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GST104) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT105) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS106) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_SGM107) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT108) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS109) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT110) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ZINWELL) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MAX) /* Customer private range */ @@ -265,9 +337,9 @@ static inline const char *cvmx_chip_type_to_string(enum { switch (type) { ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_NULL) - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_SIM_TYPE_DEPRECATED) - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_OCTEON_SAMPLE) - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_MAX) + ENUM_CHIP_TYPE_CASE(CVMX_CHIP_SIM_TYPE_DEPRECATED) + ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_OCTEON_SAMPLE) + ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_MAX) } return "Unsupported Chip"; } diff --git a/drivers/staging/octeon/cvmx-cmd-queue.h b/arch/mips/include/asm/octeon/cvmx-cmd-queue.h index 614653b686a0..614653b686a0 100644 --- a/drivers/staging/octeon/cvmx-cmd-queue.h +++ b/arch/mips/include/asm/octeon/cvmx-cmd-queue.h diff --git a/drivers/staging/octeon/cvmx-config.h b/arch/mips/include/asm/octeon/cvmx-config.h index 078a520481cf..26835d1b43b8 100644 --- a/drivers/staging/octeon/cvmx-config.h +++ b/arch/mips/include/asm/octeon/cvmx-config.h @@ -166,4 +166,3 @@ typedef enum { #define CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE 0 #endif /* __CVMX_CONFIG_H__ */ - diff --git a/drivers/staging/octeon/cvmx-dbg-defs.h b/arch/mips/include/asm/octeon/cvmx-dbg-defs.h index abbf42d05e5a..abbf42d05e5a 100644 --- a/drivers/staging/octeon/cvmx-dbg-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-dbg-defs.h diff --git a/arch/mips/include/asm/octeon/cvmx-dpi-defs.h b/arch/mips/include/asm/octeon/cvmx-dpi-defs.h new file mode 100644 index 000000000000..c34ad04789ce --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-dpi-defs.h @@ -0,0 +1,643 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2011 Cavium Networks + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, Version 2, as + * published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_DPI_DEFS_H__ +#define __CVMX_DPI_DEFS_H__ + +#define CVMX_DPI_BIST_STATUS (CVMX_ADD_IO_SEG(0x0001DF0000000000ull)) +#define CVMX_DPI_CTL (CVMX_ADD_IO_SEG(0x0001DF0000000040ull)) +#define CVMX_DPI_DMAX_COUNTS(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000300ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMAX_DBELL(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000200ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMAX_ERR_RSP_STATUS(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000A80ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMAX_IBUFF_SADDR(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000280ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMAX_IFLIGHT(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000A00ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMAX_NADDR(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000380ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMAX_REQBNK0(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000400ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMAX_REQBNK1(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000480ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMA_CONTROL (CVMX_ADD_IO_SEG(0x0001DF0000000048ull)) +#define CVMX_DPI_DMA_ENGX_EN(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000080ull) + ((offset) & 7) * 8) +#define CVMX_DPI_DMA_PPX_CNT(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000B00ull) + ((offset) & 31) * 8) +#define CVMX_DPI_ENGX_BUF(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000880ull) + ((offset) & 7) * 8) +#define CVMX_DPI_INFO_REG (CVMX_ADD_IO_SEG(0x0001DF0000000980ull)) +#define CVMX_DPI_INT_EN (CVMX_ADD_IO_SEG(0x0001DF0000000010ull)) +#define CVMX_DPI_INT_REG (CVMX_ADD_IO_SEG(0x0001DF0000000008ull)) +#define CVMX_DPI_NCBX_CFG(block_id) (CVMX_ADD_IO_SEG(0x0001DF0000000800ull)) +#define CVMX_DPI_PINT_INFO (CVMX_ADD_IO_SEG(0x0001DF0000000830ull)) +#define CVMX_DPI_PKT_ERR_RSP (CVMX_ADD_IO_SEG(0x0001DF0000000078ull)) +#define CVMX_DPI_REQ_ERR_RSP (CVMX_ADD_IO_SEG(0x0001DF0000000058ull)) +#define CVMX_DPI_REQ_ERR_RSP_EN (CVMX_ADD_IO_SEG(0x0001DF0000000068ull)) +#define CVMX_DPI_REQ_ERR_RST (CVMX_ADD_IO_SEG(0x0001DF0000000060ull)) +#define CVMX_DPI_REQ_ERR_RST_EN (CVMX_ADD_IO_SEG(0x0001DF0000000070ull)) +#define CVMX_DPI_REQ_ERR_SKIP_COMP (CVMX_ADD_IO_SEG(0x0001DF0000000838ull)) +#define CVMX_DPI_REQ_GBL_EN (CVMX_ADD_IO_SEG(0x0001DF0000000050ull)) +#define CVMX_DPI_SLI_PRTX_CFG(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000900ull) + ((offset) & 3) * 8) +#define CVMX_DPI_SLI_PRTX_ERR_INFO(offset) (CVMX_ADD_IO_SEG(0x0001DF0000000940ull) + ((offset) & 3) * 8) + +union cvmx_dpi_bist_status { + uint64_t u64; + struct cvmx_dpi_bist_status_s { + uint64_t reserved_47_63:17; + uint64_t bist:47; + } s; + struct cvmx_dpi_bist_status_s cn61xx; + struct cvmx_dpi_bist_status_cn63xx { + uint64_t reserved_45_63:19; + uint64_t bist:45; + } cn63xx; + struct cvmx_dpi_bist_status_cn63xxp1 { + uint64_t reserved_37_63:27; + uint64_t bist:37; + } cn63xxp1; + struct cvmx_dpi_bist_status_s cn66xx; + struct cvmx_dpi_bist_status_cn63xx cn68xx; + struct cvmx_dpi_bist_status_cn63xx cn68xxp1; +}; + +union cvmx_dpi_ctl { + uint64_t u64; + struct cvmx_dpi_ctl_s { + uint64_t reserved_2_63:62; + uint64_t clk:1; + uint64_t en:1; + } s; + struct cvmx_dpi_ctl_cn61xx { + uint64_t reserved_1_63:63; + uint64_t en:1; + } cn61xx; + struct cvmx_dpi_ctl_s cn63xx; + struct cvmx_dpi_ctl_s cn63xxp1; + struct cvmx_dpi_ctl_s cn66xx; + struct cvmx_dpi_ctl_s cn68xx; + struct cvmx_dpi_ctl_s cn68xxp1; +}; + +union cvmx_dpi_dmax_counts { + uint64_t u64; + struct cvmx_dpi_dmax_counts_s { + uint64_t reserved_39_63:25; + uint64_t fcnt:7; + uint64_t dbell:32; + } s; + struct cvmx_dpi_dmax_counts_s cn61xx; + struct cvmx_dpi_dmax_counts_s cn63xx; + struct cvmx_dpi_dmax_counts_s cn63xxp1; + struct cvmx_dpi_dmax_counts_s cn66xx; + struct cvmx_dpi_dmax_counts_s cn68xx; + struct cvmx_dpi_dmax_counts_s cn68xxp1; +}; + +union cvmx_dpi_dmax_dbell { + uint64_t u64; + struct cvmx_dpi_dmax_dbell_s { + uint64_t reserved_16_63:48; + uint64_t dbell:16; + } s; + struct cvmx_dpi_dmax_dbell_s cn61xx; + struct cvmx_dpi_dmax_dbell_s cn63xx; + struct cvmx_dpi_dmax_dbell_s cn63xxp1; + struct cvmx_dpi_dmax_dbell_s cn66xx; + struct cvmx_dpi_dmax_dbell_s cn68xx; + struct cvmx_dpi_dmax_dbell_s cn68xxp1; +}; + +union cvmx_dpi_dmax_err_rsp_status { + uint64_t u64; + struct cvmx_dpi_dmax_err_rsp_status_s { + uint64_t reserved_6_63:58; + uint64_t status:6; + } s; + struct cvmx_dpi_dmax_err_rsp_status_s cn61xx; + struct cvmx_dpi_dmax_err_rsp_status_s cn66xx; + struct cvmx_dpi_dmax_err_rsp_status_s cn68xx; + struct cvmx_dpi_dmax_err_rsp_status_s cn68xxp1; +}; + +union cvmx_dpi_dmax_ibuff_saddr { + uint64_t u64; + struct cvmx_dpi_dmax_ibuff_saddr_s { + uint64_t reserved_62_63:2; + uint64_t csize:14; + uint64_t reserved_41_47:7; + uint64_t idle:1; + uint64_t saddr:33; + uint64_t reserved_0_6:7; + } s; + struct cvmx_dpi_dmax_ibuff_saddr_cn61xx { + uint64_t reserved_62_63:2; + uint64_t csize:14; + uint64_t reserved_41_47:7; + uint64_t idle:1; + uint64_t reserved_36_39:4; + uint64_t saddr:29; + uint64_t reserved_0_6:7; + } cn61xx; + struct cvmx_dpi_dmax_ibuff_saddr_cn61xx cn63xx; + struct cvmx_dpi_dmax_ibuff_saddr_cn61xx cn63xxp1; + struct cvmx_dpi_dmax_ibuff_saddr_cn61xx cn66xx; + struct cvmx_dpi_dmax_ibuff_saddr_s cn68xx; + struct cvmx_dpi_dmax_ibuff_saddr_s cn68xxp1; +}; + +union cvmx_dpi_dmax_iflight { + uint64_t u64; + struct cvmx_dpi_dmax_iflight_s { + uint64_t reserved_3_63:61; + uint64_t cnt:3; + } s; + struct cvmx_dpi_dmax_iflight_s cn61xx; + struct cvmx_dpi_dmax_iflight_s cn66xx; + struct cvmx_dpi_dmax_iflight_s cn68xx; + struct cvmx_dpi_dmax_iflight_s cn68xxp1; +}; + +union cvmx_dpi_dmax_naddr { + uint64_t u64; + struct cvmx_dpi_dmax_naddr_s { + uint64_t reserved_40_63:24; + uint64_t addr:40; + } s; + struct cvmx_dpi_dmax_naddr_cn61xx { + uint64_t reserved_36_63:28; + uint64_t addr:36; + } cn61xx; + struct cvmx_dpi_dmax_naddr_cn61xx cn63xx; + struct cvmx_dpi_dmax_naddr_cn61xx cn63xxp1; + struct cvmx_dpi_dmax_naddr_cn61xx cn66xx; + struct cvmx_dpi_dmax_naddr_s cn68xx; + struct cvmx_dpi_dmax_naddr_s cn68xxp1; +}; + +union cvmx_dpi_dmax_reqbnk0 { + uint64_t u64; + struct cvmx_dpi_dmax_reqbnk0_s { + uint64_t state:64; + } s; + struct cvmx_dpi_dmax_reqbnk0_s cn61xx; + struct cvmx_dpi_dmax_reqbnk0_s cn63xx; + struct cvmx_dpi_dmax_reqbnk0_s cn63xxp1; + struct cvmx_dpi_dmax_reqbnk0_s cn66xx; + struct cvmx_dpi_dmax_reqbnk0_s cn68xx; + struct cvmx_dpi_dmax_reqbnk0_s cn68xxp1; +}; + +union cvmx_dpi_dmax_reqbnk1 { + uint64_t u64; + struct cvmx_dpi_dmax_reqbnk1_s { + uint64_t state:64; + } s; + struct cvmx_dpi_dmax_reqbnk1_s cn61xx; + struct cvmx_dpi_dmax_reqbnk1_s cn63xx; + struct cvmx_dpi_dmax_reqbnk1_s cn63xxp1; + struct cvmx_dpi_dmax_reqbnk1_s cn66xx; + struct cvmx_dpi_dmax_reqbnk1_s cn68xx; + struct cvmx_dpi_dmax_reqbnk1_s cn68xxp1; +}; + +union cvmx_dpi_dma_control { + uint64_t u64; + struct cvmx_dpi_dma_control_s { + uint64_t reserved_62_63:2; + uint64_t dici_mode:1; + uint64_t pkt_en1:1; + uint64_t ffp_dis:1; + uint64_t commit_mode:1; + uint64_t pkt_hp:1; + uint64_t pkt_en:1; + uint64_t reserved_54_55:2; + uint64_t dma_enb:6; + uint64_t reserved_34_47:14; + uint64_t b0_lend:1; + uint64_t dwb_denb:1; + uint64_t dwb_ichk:9; + uint64_t fpa_que:3; + uint64_t o_add1:1; + uint64_t o_ro:1; + uint64_t o_ns:1; + uint64_t o_es:2; + uint64_t o_mode:1; + uint64_t reserved_0_13:14; + } s; + struct cvmx_dpi_dma_control_s cn61xx; + struct cvmx_dpi_dma_control_cn63xx { + uint64_t reserved_61_63:3; + uint64_t pkt_en1:1; + uint64_t ffp_dis:1; + uint64_t commit_mode:1; + uint64_t pkt_hp:1; + uint64_t pkt_en:1; + uint64_t reserved_54_55:2; + uint64_t dma_enb:6; + uint64_t reserved_34_47:14; + uint64_t b0_lend:1; + uint64_t dwb_denb:1; + uint64_t dwb_ichk:9; + uint64_t fpa_que:3; + uint64_t o_add1:1; + uint64_t o_ro:1; + uint64_t o_ns:1; + uint64_t o_es:2; + uint64_t o_mode:1; + uint64_t reserved_0_13:14; + } cn63xx; + struct cvmx_dpi_dma_control_cn63xxp1 { + uint64_t reserved_59_63:5; + uint64_t commit_mode:1; + uint64_t pkt_hp:1; + uint64_t pkt_en:1; + uint64_t reserved_54_55:2; + uint64_t dma_enb:6; + uint64_t reserved_34_47:14; + uint64_t b0_lend:1; + uint64_t dwb_denb:1; + uint64_t dwb_ichk:9; + uint64_t fpa_que:3; + uint64_t o_add1:1; + uint64_t o_ro:1; + uint64_t o_ns:1; + uint64_t o_es:2; + uint64_t o_mode:1; + uint64_t reserved_0_13:14; + } cn63xxp1; + struct cvmx_dpi_dma_control_cn63xx cn66xx; + struct cvmx_dpi_dma_control_s cn68xx; + struct cvmx_dpi_dma_control_cn63xx cn68xxp1; +}; + +union cvmx_dpi_dma_engx_en { + uint64_t u64; + struct cvmx_dpi_dma_engx_en_s { + uint64_t reserved_8_63:56; + uint64_t qen:8; + } s; + struct cvmx_dpi_dma_engx_en_s cn61xx; + struct cvmx_dpi_dma_engx_en_s cn63xx; + struct cvmx_dpi_dma_engx_en_s cn63xxp1; + struct cvmx_dpi_dma_engx_en_s cn66xx; + struct cvmx_dpi_dma_engx_en_s cn68xx; + struct cvmx_dpi_dma_engx_en_s cn68xxp1; +}; + +union cvmx_dpi_dma_ppx_cnt { + uint64_t u64; + struct cvmx_dpi_dma_ppx_cnt_s { + uint64_t reserved_16_63:48; + uint64_t cnt:16; + } s; + struct cvmx_dpi_dma_ppx_cnt_s cn61xx; + struct cvmx_dpi_dma_ppx_cnt_s cn68xx; +}; + +union cvmx_dpi_engx_buf { + uint64_t u64; + struct cvmx_dpi_engx_buf_s { + uint64_t reserved_37_63:27; + uint64_t compblks:5; + uint64_t reserved_9_31:23; + uint64_t base:5; + uint64_t blks:4; + } s; + struct cvmx_dpi_engx_buf_s cn61xx; + struct cvmx_dpi_engx_buf_cn63xx { + uint64_t reserved_8_63:56; + uint64_t base:4; + uint64_t blks:4; + } cn63xx; + struct cvmx_dpi_engx_buf_cn63xx cn63xxp1; + struct cvmx_dpi_engx_buf_s cn66xx; + struct cvmx_dpi_engx_buf_s cn68xx; + struct cvmx_dpi_engx_buf_s cn68xxp1; +}; + +union cvmx_dpi_info_reg { + uint64_t u64; + struct cvmx_dpi_info_reg_s { + uint64_t reserved_8_63:56; + uint64_t ffp:4; + uint64_t reserved_2_3:2; + uint64_t ncb:1; + uint64_t rsl:1; + } s; + struct cvmx_dpi_info_reg_s cn61xx; + struct cvmx_dpi_info_reg_s cn63xx; + struct cvmx_dpi_info_reg_cn63xxp1 { + uint64_t reserved_2_63:62; + uint64_t ncb:1; + uint64_t rsl:1; + } cn63xxp1; + struct cvmx_dpi_info_reg_s cn66xx; + struct cvmx_dpi_info_reg_s cn68xx; + struct cvmx_dpi_info_reg_s cn68xxp1; +}; + +union cvmx_dpi_int_en { + uint64_t u64; + struct cvmx_dpi_int_en_s { + uint64_t reserved_28_63:36; + uint64_t sprt3_rst:1; + uint64_t sprt2_rst:1; + uint64_t sprt1_rst:1; + uint64_t sprt0_rst:1; + uint64_t reserved_23_23:1; + uint64_t req_badfil:1; + uint64_t req_inull:1; + uint64_t req_anull:1; + uint64_t req_undflw:1; + uint64_t req_ovrflw:1; + uint64_t req_badlen:1; + uint64_t req_badadr:1; + uint64_t dmadbo:8; + uint64_t reserved_2_7:6; + uint64_t nfovr:1; + uint64_t nderr:1; + } s; + struct cvmx_dpi_int_en_s cn61xx; + struct cvmx_dpi_int_en_cn63xx { + uint64_t reserved_26_63:38; + uint64_t sprt1_rst:1; + uint64_t sprt0_rst:1; + uint64_t reserved_23_23:1; + uint64_t req_badfil:1; + uint64_t req_inull:1; + uint64_t req_anull:1; + uint64_t req_undflw:1; + uint64_t req_ovrflw:1; + uint64_t req_badlen:1; + uint64_t req_badadr:1; + uint64_t dmadbo:8; + uint64_t reserved_2_7:6; + uint64_t nfovr:1; + uint64_t nderr:1; + } cn63xx; + struct cvmx_dpi_int_en_cn63xx cn63xxp1; + struct cvmx_dpi_int_en_s cn66xx; + struct cvmx_dpi_int_en_cn63xx cn68xx; + struct cvmx_dpi_int_en_cn63xx cn68xxp1; +}; + +union cvmx_dpi_int_reg { + uint64_t u64; + struct cvmx_dpi_int_reg_s { + uint64_t reserved_28_63:36; + uint64_t sprt3_rst:1; + uint64_t sprt2_rst:1; + uint64_t sprt1_rst:1; + uint64_t sprt0_rst:1; + uint64_t reserved_23_23:1; + uint64_t req_badfil:1; + uint64_t req_inull:1; + uint64_t req_anull:1; + uint64_t req_undflw:1; + uint64_t req_ovrflw:1; + uint64_t req_badlen:1; + uint64_t req_badadr:1; + uint64_t dmadbo:8; + uint64_t reserved_2_7:6; + uint64_t nfovr:1; + uint64_t nderr:1; + } s; + struct cvmx_dpi_int_reg_s cn61xx; + struct cvmx_dpi_int_reg_cn63xx { + uint64_t reserved_26_63:38; + uint64_t sprt1_rst:1; + uint64_t sprt0_rst:1; + uint64_t reserved_23_23:1; + uint64_t req_badfil:1; + uint64_t req_inull:1; + uint64_t req_anull:1; + uint64_t req_undflw:1; + uint64_t req_ovrflw:1; + uint64_t req_badlen:1; + uint64_t req_badadr:1; + uint64_t dmadbo:8; + uint64_t reserved_2_7:6; + uint64_t nfovr:1; + uint64_t nderr:1; + } cn63xx; + struct cvmx_dpi_int_reg_cn63xx cn63xxp1; + struct cvmx_dpi_int_reg_s cn66xx; + struct cvmx_dpi_int_reg_cn63xx cn68xx; + struct cvmx_dpi_int_reg_cn63xx cn68xxp1; +}; + +union cvmx_dpi_ncbx_cfg { + uint64_t u64; + struct cvmx_dpi_ncbx_cfg_s { + uint64_t reserved_6_63:58; + uint64_t molr:6; + } s; + struct cvmx_dpi_ncbx_cfg_s cn61xx; + struct cvmx_dpi_ncbx_cfg_s cn66xx; + struct cvmx_dpi_ncbx_cfg_s cn68xx; +}; + +union cvmx_dpi_pint_info { + uint64_t u64; + struct cvmx_dpi_pint_info_s { + uint64_t reserved_14_63:50; + uint64_t iinfo:6; + uint64_t reserved_6_7:2; + uint64_t sinfo:6; + } s; + struct cvmx_dpi_pint_info_s cn61xx; + struct cvmx_dpi_pint_info_s cn63xx; + struct cvmx_dpi_pint_info_s cn63xxp1; + struct cvmx_dpi_pint_info_s cn66xx; + struct cvmx_dpi_pint_info_s cn68xx; + struct cvmx_dpi_pint_info_s cn68xxp1; +}; + +union cvmx_dpi_pkt_err_rsp { + uint64_t u64; + struct cvmx_dpi_pkt_err_rsp_s { + uint64_t reserved_1_63:63; + uint64_t pkterr:1; + } s; + struct cvmx_dpi_pkt_err_rsp_s cn61xx; + struct cvmx_dpi_pkt_err_rsp_s cn63xx; + struct cvmx_dpi_pkt_err_rsp_s cn63xxp1; + struct cvmx_dpi_pkt_err_rsp_s cn66xx; + struct cvmx_dpi_pkt_err_rsp_s cn68xx; + struct cvmx_dpi_pkt_err_rsp_s cn68xxp1; +}; + +union cvmx_dpi_req_err_rsp { + uint64_t u64; + struct cvmx_dpi_req_err_rsp_s { + uint64_t reserved_8_63:56; + uint64_t qerr:8; + } s; + struct cvmx_dpi_req_err_rsp_s cn61xx; + struct cvmx_dpi_req_err_rsp_s cn63xx; + struct cvmx_dpi_req_err_rsp_s cn63xxp1; + struct cvmx_dpi_req_err_rsp_s cn66xx; + struct cvmx_dpi_req_err_rsp_s cn68xx; + struct cvmx_dpi_req_err_rsp_s cn68xxp1; +}; + +union cvmx_dpi_req_err_rsp_en { + uint64_t u64; + struct cvmx_dpi_req_err_rsp_en_s { + uint64_t reserved_8_63:56; + uint64_t en:8; + } s; + struct cvmx_dpi_req_err_rsp_en_s cn61xx; + struct cvmx_dpi_req_err_rsp_en_s cn63xx; + struct cvmx_dpi_req_err_rsp_en_s cn63xxp1; + struct cvmx_dpi_req_err_rsp_en_s cn66xx; + struct cvmx_dpi_req_err_rsp_en_s cn68xx; + struct cvmx_dpi_req_err_rsp_en_s cn68xxp1; +}; + +union cvmx_dpi_req_err_rst { + uint64_t u64; + struct cvmx_dpi_req_err_rst_s { + uint64_t reserved_8_63:56; + uint64_t qerr:8; + } s; + struct cvmx_dpi_req_err_rst_s cn61xx; + struct cvmx_dpi_req_err_rst_s cn63xx; + struct cvmx_dpi_req_err_rst_s cn63xxp1; + struct cvmx_dpi_req_err_rst_s cn66xx; + struct cvmx_dpi_req_err_rst_s cn68xx; + struct cvmx_dpi_req_err_rst_s cn68xxp1; +}; + +union cvmx_dpi_req_err_rst_en { + uint64_t u64; + struct cvmx_dpi_req_err_rst_en_s { + uint64_t reserved_8_63:56; + uint64_t en:8; + } s; + struct cvmx_dpi_req_err_rst_en_s cn61xx; + struct cvmx_dpi_req_err_rst_en_s cn63xx; + struct cvmx_dpi_req_err_rst_en_s cn63xxp1; + struct cvmx_dpi_req_err_rst_en_s cn66xx; + struct cvmx_dpi_req_err_rst_en_s cn68xx; + struct cvmx_dpi_req_err_rst_en_s cn68xxp1; +}; + +union cvmx_dpi_req_err_skip_comp { + uint64_t u64; + struct cvmx_dpi_req_err_skip_comp_s { + uint64_t reserved_24_63:40; + uint64_t en_rst:8; + uint64_t reserved_8_15:8; + uint64_t en_rsp:8; + } s; + struct cvmx_dpi_req_err_skip_comp_s cn61xx; + struct cvmx_dpi_req_err_skip_comp_s cn66xx; + struct cvmx_dpi_req_err_skip_comp_s cn68xx; + struct cvmx_dpi_req_err_skip_comp_s cn68xxp1; +}; + +union cvmx_dpi_req_gbl_en { + uint64_t u64; + struct cvmx_dpi_req_gbl_en_s { + uint64_t reserved_8_63:56; + uint64_t qen:8; + } s; + struct cvmx_dpi_req_gbl_en_s cn61xx; + struct cvmx_dpi_req_gbl_en_s cn63xx; + struct cvmx_dpi_req_gbl_en_s cn63xxp1; + struct cvmx_dpi_req_gbl_en_s cn66xx; + struct cvmx_dpi_req_gbl_en_s cn68xx; + struct cvmx_dpi_req_gbl_en_s cn68xxp1; +}; + +union cvmx_dpi_sli_prtx_cfg { + uint64_t u64; + struct cvmx_dpi_sli_prtx_cfg_s { + uint64_t reserved_25_63:39; + uint64_t halt:1; + uint64_t qlm_cfg:4; + uint64_t reserved_17_19:3; + uint64_t rd_mode:1; + uint64_t reserved_14_15:2; + uint64_t molr:6; + uint64_t mps_lim:1; + uint64_t reserved_5_6:2; + uint64_t mps:1; + uint64_t mrrs_lim:1; + uint64_t reserved_2_2:1; + uint64_t mrrs:2; + } s; + struct cvmx_dpi_sli_prtx_cfg_s cn61xx; + struct cvmx_dpi_sli_prtx_cfg_cn63xx { + uint64_t reserved_25_63:39; + uint64_t halt:1; + uint64_t reserved_21_23:3; + uint64_t qlm_cfg:1; + uint64_t reserved_17_19:3; + uint64_t rd_mode:1; + uint64_t reserved_14_15:2; + uint64_t molr:6; + uint64_t mps_lim:1; + uint64_t reserved_5_6:2; + uint64_t mps:1; + uint64_t mrrs_lim:1; + uint64_t reserved_2_2:1; + uint64_t mrrs:2; + } cn63xx; + struct cvmx_dpi_sli_prtx_cfg_cn63xx cn63xxp1; + struct cvmx_dpi_sli_prtx_cfg_s cn66xx; + struct cvmx_dpi_sli_prtx_cfg_cn63xx cn68xx; + struct cvmx_dpi_sli_prtx_cfg_cn63xx cn68xxp1; +}; + +union cvmx_dpi_sli_prtx_err { + uint64_t u64; + struct cvmx_dpi_sli_prtx_err_s { + uint64_t addr:61; + uint64_t reserved_0_2:3; + } s; + struct cvmx_dpi_sli_prtx_err_s cn61xx; + struct cvmx_dpi_sli_prtx_err_s cn63xx; + struct cvmx_dpi_sli_prtx_err_s cn63xxp1; + struct cvmx_dpi_sli_prtx_err_s cn66xx; + struct cvmx_dpi_sli_prtx_err_s cn68xx; + struct cvmx_dpi_sli_prtx_err_s cn68xxp1; +}; + +union cvmx_dpi_sli_prtx_err_info { + uint64_t u64; + struct cvmx_dpi_sli_prtx_err_info_s { + uint64_t reserved_9_63:55; + uint64_t lock:1; + uint64_t reserved_5_7:3; + uint64_t type:1; + uint64_t reserved_3_3:1; + uint64_t reqq:3; + } s; + struct cvmx_dpi_sli_prtx_err_info_s cn61xx; + struct cvmx_dpi_sli_prtx_err_info_s cn63xx; + struct cvmx_dpi_sli_prtx_err_info_s cn63xxp1; + struct cvmx_dpi_sli_prtx_err_info_s cn66xx; + struct cvmx_dpi_sli_prtx_err_info_s cn68xx; + struct cvmx_dpi_sli_prtx_err_info_s cn68xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-fau.h b/arch/mips/include/asm/octeon/cvmx-fau.h index a6939fc8ba18..a6939fc8ba18 100644 --- a/drivers/staging/octeon/cvmx-fau.h +++ b/arch/mips/include/asm/octeon/cvmx-fau.h diff --git a/drivers/staging/octeon/cvmx-fpa-defs.h b/arch/mips/include/asm/octeon/cvmx-fpa-defs.h index bf5546b90110..bf5546b90110 100644 --- a/drivers/staging/octeon/cvmx-fpa-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-fpa-defs.h diff --git a/drivers/staging/octeon/cvmx-fpa.h b/arch/mips/include/asm/octeon/cvmx-fpa.h index 1f04f9658736..1f04f9658736 100644 --- a/drivers/staging/octeon/cvmx-fpa.h +++ b/arch/mips/include/asm/octeon/cvmx-fpa.h diff --git a/drivers/staging/octeon/cvmx-gmxx-defs.h b/arch/mips/include/asm/octeon/cvmx-gmxx-defs.h index 946a43a73fd7..946a43a73fd7 100644 --- a/drivers/staging/octeon/cvmx-gmxx-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-gmxx-defs.h diff --git a/drivers/staging/octeon/cvmx-helper-board.h b/arch/mips/include/asm/octeon/cvmx-helper-board.h index b465bec43553..88527fa835c9 100644 --- a/drivers/staging/octeon/cvmx-helper-board.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-board.h @@ -44,6 +44,12 @@ typedef enum { set_phy_link_flags_flow_control_mask = 0x3 << 1, /* Mask for 2 bit wide flow control field */ } cvmx_helper_board_set_phy_link_flags_types_t; +/* + * Fake IPD port, the RGMII/MII interface may use different PHY, use + * this macro to return appropriate MIX address to read the PHY. + */ +#define CVMX_HELPER_BOARD_MGMT_IPD_PORT -10 + /** * cvmx_override_board_link_get(int ipd_port) is a function * pointer. It is meant to allow customization of the process of diff --git a/drivers/staging/octeon/cvmx-helper-fpa.h b/arch/mips/include/asm/octeon/cvmx-helper-fpa.h index 5ff8c93198de..5ff8c93198de 100644 --- a/drivers/staging/octeon/cvmx-helper-fpa.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-fpa.h diff --git a/drivers/staging/octeon/cvmx-helper-loop.h b/arch/mips/include/asm/octeon/cvmx-helper-loop.h index e646a6ccce75..077f0e9d3b2d 100644 --- a/drivers/staging/octeon/cvmx-helper-loop.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-loop.h @@ -44,6 +44,7 @@ * Returns Number of ports on the interface. Zero to disable. */ extern int __cvmx_helper_loop_probe(int interface); +static inline int __cvmx_helper_loop_enumerate(int interface) {return 4; } /** * Bringup and enable a LOOP interface. After this call packet diff --git a/drivers/staging/octeon/cvmx-helper-npi.h b/arch/mips/include/asm/octeon/cvmx-helper-npi.h index 908e7b08c214..8df4c7fafdba 100644 --- a/drivers/staging/octeon/cvmx-helper-npi.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-npi.h @@ -45,6 +45,7 @@ * Returns Number of ports on the interface. Zero to disable. */ extern int __cvmx_helper_npi_probe(int interface); +#define __cvmx_helper_npi_enumerate __cvmx_helper_npi_probe /** * Bringup and enable a NPI interface. After this call packet diff --git a/drivers/staging/octeon/cvmx-helper-rgmii.h b/arch/mips/include/asm/octeon/cvmx-helper-rgmii.h index ea2652604a57..78295ba0050f 100644 --- a/drivers/staging/octeon/cvmx-helper-rgmii.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-rgmii.h @@ -43,6 +43,7 @@ * Returns Number of RGMII/GMII/MII ports (0-4). */ extern int __cvmx_helper_rgmii_probe(int interface); +#define __cvmx_helper_rgmii_enumerate __cvmx_helper_rgmii_probe /** * Put an RGMII interface in loopback mode. Internal packets sent diff --git a/drivers/staging/octeon/cvmx-helper-sgmii.h b/arch/mips/include/asm/octeon/cvmx-helper-sgmii.h index 19b48d60857f..9a9b6c103ede 100644 --- a/drivers/staging/octeon/cvmx-helper-sgmii.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-sgmii.h @@ -45,6 +45,7 @@ * Returns Number of ports on the interface. Zero to disable. */ extern int __cvmx_helper_sgmii_probe(int interface); +extern int __cvmx_helper_sgmii_enumerate(int interface); /** * Bringup and enable a SGMII interface. After this call packet diff --git a/drivers/staging/octeon/cvmx-helper-spi.h b/arch/mips/include/asm/octeon/cvmx-helper-spi.h index 69bac036d10e..9f1c6b968f91 100644 --- a/drivers/staging/octeon/cvmx-helper-spi.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-spi.h @@ -42,6 +42,7 @@ * Returns Number of ports on the interface. Zero to disable. */ extern int __cvmx_helper_spi_probe(int interface); +extern int __cvmx_helper_spi_enumerate(int interface); /** * Bringup and enable a SPI interface. After this call packet I/O diff --git a/drivers/staging/octeon/cvmx-helper-util.h b/arch/mips/include/asm/octeon/cvmx-helper-util.h index 6a6e52fc22c1..6a6e52fc22c1 100644 --- a/drivers/staging/octeon/cvmx-helper-util.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-util.h diff --git a/drivers/staging/octeon/cvmx-helper-xaui.h b/arch/mips/include/asm/octeon/cvmx-helper-xaui.h index 4b4db2f93cd4..f6fbc4f45b56 100644 --- a/drivers/staging/octeon/cvmx-helper-xaui.h +++ b/arch/mips/include/asm/octeon/cvmx-helper-xaui.h @@ -45,6 +45,7 @@ * Returns Number of ports on the interface. Zero to disable. */ extern int __cvmx_helper_xaui_probe(int interface); +extern int __cvmx_helper_xaui_enumerate(int interface); /** * Bringup and enable a XAUI interface. After this call packet diff --git a/drivers/staging/octeon/cvmx-helper.h b/arch/mips/include/asm/octeon/cvmx-helper.h index 51916f3cc40c..3169cd79f2ac 100644 --- a/drivers/staging/octeon/cvmx-helper.h +++ b/arch/mips/include/asm/octeon/cvmx-helper.h @@ -207,6 +207,7 @@ extern int cvmx_helper_link_set(int ipd_port, * Returns Zero on success, negative on failure */ extern int cvmx_helper_interface_probe(int interface); +extern int cvmx_helper_interface_enumerate(int interface); /** * Configure a port for internal and/or external loopback. Internal loopback diff --git a/drivers/staging/octeon/cvmx-ipd.h b/arch/mips/include/asm/octeon/cvmx-ipd.h index 115a552c5c7f..115a552c5c7f 100644 --- a/drivers/staging/octeon/cvmx-ipd.h +++ b/arch/mips/include/asm/octeon/cvmx-ipd.h diff --git a/drivers/staging/octeon/cvmx-mdio.h b/arch/mips/include/asm/octeon/cvmx-mdio.h index d88ab8d8e37d..d88ab8d8e37d 100644 --- a/drivers/staging/octeon/cvmx-mdio.h +++ b/arch/mips/include/asm/octeon/cvmx-mdio.h diff --git a/arch/mips/include/asm/octeon/cvmx-mio-defs.h b/arch/mips/include/asm/octeon/cvmx-mio-defs.h index 52b14a333ad4..b1774126736d 100644 --- a/arch/mips/include/asm/octeon/cvmx-mio-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-mio-defs.h @@ -43,6 +43,22 @@ #define CVMX_MIO_BOOT_REG_CFGX(offset) (CVMX_ADD_IO_SEG(0x0001180000000000ull) + ((offset) & 7) * 8) #define CVMX_MIO_BOOT_REG_TIMX(offset) (CVMX_ADD_IO_SEG(0x0001180000000040ull) + ((offset) & 7) * 8) #define CVMX_MIO_BOOT_THR (CVMX_ADD_IO_SEG(0x00011800000000B0ull)) +#define CVMX_MIO_EMM_BUF_DAT (CVMX_ADD_IO_SEG(0x00011800000020E8ull)) +#define CVMX_MIO_EMM_BUF_IDX (CVMX_ADD_IO_SEG(0x00011800000020E0ull)) +#define CVMX_MIO_EMM_CFG (CVMX_ADD_IO_SEG(0x0001180000002000ull)) +#define CVMX_MIO_EMM_CMD (CVMX_ADD_IO_SEG(0x0001180000002058ull)) +#define CVMX_MIO_EMM_DMA (CVMX_ADD_IO_SEG(0x0001180000002050ull)) +#define CVMX_MIO_EMM_INT (CVMX_ADD_IO_SEG(0x0001180000002078ull)) +#define CVMX_MIO_EMM_INT_EN (CVMX_ADD_IO_SEG(0x0001180000002080ull)) +#define CVMX_MIO_EMM_MODEX(offset) (CVMX_ADD_IO_SEG(0x0001180000002008ull) + ((offset) & 3) * 8) +#define CVMX_MIO_EMM_RCA (CVMX_ADD_IO_SEG(0x00011800000020A0ull)) +#define CVMX_MIO_EMM_RSP_HI (CVMX_ADD_IO_SEG(0x0001180000002070ull)) +#define CVMX_MIO_EMM_RSP_LO (CVMX_ADD_IO_SEG(0x0001180000002068ull)) +#define CVMX_MIO_EMM_RSP_STS (CVMX_ADD_IO_SEG(0x0001180000002060ull)) +#define CVMX_MIO_EMM_SAMPLE (CVMX_ADD_IO_SEG(0x0001180000002090ull)) +#define CVMX_MIO_EMM_STS_MASK (CVMX_ADD_IO_SEG(0x0001180000002098ull)) +#define CVMX_MIO_EMM_SWITCH (CVMX_ADD_IO_SEG(0x0001180000002048ull)) +#define CVMX_MIO_EMM_WDOG (CVMX_ADD_IO_SEG(0x0001180000002088ull)) #define CVMX_MIO_FUS_BNK_DATX(offset) (CVMX_ADD_IO_SEG(0x0001180000001520ull) + ((offset) & 3) * 8) #define CVMX_MIO_FUS_DAT0 (CVMX_ADD_IO_SEG(0x0001180000001400ull)) #define CVMX_MIO_FUS_DAT1 (CVMX_ADD_IO_SEG(0x0001180000001408ull)) @@ -60,6 +76,7 @@ #define CVMX_MIO_FUS_REPAIR_RES2 (CVMX_ADD_IO_SEG(0x0001180000001568ull)) #define CVMX_MIO_FUS_SPR_REPAIR_RES (CVMX_ADD_IO_SEG(0x0001180000001548ull)) #define CVMX_MIO_FUS_SPR_REPAIR_SUM (CVMX_ADD_IO_SEG(0x0001180000001540ull)) +#define CVMX_MIO_FUS_TGG (CVMX_ADD_IO_SEG(0x0001180000001428ull)) #define CVMX_MIO_FUS_UNLOCK (CVMX_ADD_IO_SEG(0x0001180000001578ull)) #define CVMX_MIO_FUS_WADR (CVMX_ADD_IO_SEG(0x0001180000001508ull)) #define CVMX_MIO_GPIO_COMP (CVMX_ADD_IO_SEG(0x00011800000000C8ull)) @@ -68,14 +85,25 @@ #define CVMX_MIO_NDF_DMA_INT_EN (CVMX_ADD_IO_SEG(0x0001180000000178ull)) #define CVMX_MIO_PLL_CTL (CVMX_ADD_IO_SEG(0x0001180000001448ull)) #define CVMX_MIO_PLL_SETTING (CVMX_ADD_IO_SEG(0x0001180000001440ull)) +#define CVMX_MIO_PTP_CKOUT_HI_INCR (CVMX_ADD_IO_SEG(0x0001070000000F40ull)) +#define CVMX_MIO_PTP_CKOUT_LO_INCR (CVMX_ADD_IO_SEG(0x0001070000000F48ull)) +#define CVMX_MIO_PTP_CKOUT_THRESH_HI (CVMX_ADD_IO_SEG(0x0001070000000F38ull)) +#define CVMX_MIO_PTP_CKOUT_THRESH_LO (CVMX_ADD_IO_SEG(0x0001070000000F30ull)) #define CVMX_MIO_PTP_CLOCK_CFG (CVMX_ADD_IO_SEG(0x0001070000000F00ull)) #define CVMX_MIO_PTP_CLOCK_COMP (CVMX_ADD_IO_SEG(0x0001070000000F18ull)) #define CVMX_MIO_PTP_CLOCK_HI (CVMX_ADD_IO_SEG(0x0001070000000F10ull)) #define CVMX_MIO_PTP_CLOCK_LO (CVMX_ADD_IO_SEG(0x0001070000000F08ull)) #define CVMX_MIO_PTP_EVT_CNT (CVMX_ADD_IO_SEG(0x0001070000000F28ull)) +#define CVMX_MIO_PTP_PPS_HI_INCR (CVMX_ADD_IO_SEG(0x0001070000000F60ull)) +#define CVMX_MIO_PTP_PPS_LO_INCR (CVMX_ADD_IO_SEG(0x0001070000000F68ull)) +#define CVMX_MIO_PTP_PPS_THRESH_HI (CVMX_ADD_IO_SEG(0x0001070000000F58ull)) +#define CVMX_MIO_PTP_PPS_THRESH_LO (CVMX_ADD_IO_SEG(0x0001070000000F50ull)) #define CVMX_MIO_PTP_TIMESTAMP (CVMX_ADD_IO_SEG(0x0001070000000F20ull)) +#define CVMX_MIO_QLMX_CFG(offset) (CVMX_ADD_IO_SEG(0x0001180000001590ull) + ((offset) & 7) * 8) #define CVMX_MIO_RST_BOOT (CVMX_ADD_IO_SEG(0x0001180000001600ull)) #define CVMX_MIO_RST_CFG (CVMX_ADD_IO_SEG(0x0001180000001610ull)) +#define CVMX_MIO_RST_CKILL (CVMX_ADD_IO_SEG(0x0001180000001638ull)) +#define CVMX_MIO_RST_CNTLX(offset) (CVMX_ADD_IO_SEG(0x0001180000001648ull) + ((offset) & 3) * 8) #define CVMX_MIO_RST_CTLX(offset) (CVMX_ADD_IO_SEG(0x0001180000001618ull) + ((offset) & 1) * 8) #define CVMX_MIO_RST_DELAY (CVMX_ADD_IO_SEG(0x0001180000001608ull)) #define CVMX_MIO_RST_INT (CVMX_ADD_IO_SEG(0x0001180000001628ull)) @@ -183,11 +211,21 @@ union cvmx_mio_boot_bist_stat { struct cvmx_mio_boot_bist_stat_cn52xxp1 cn56xxp1; struct cvmx_mio_boot_bist_stat_cn38xx cn58xx; struct cvmx_mio_boot_bist_stat_cn38xx cn58xxp1; + struct cvmx_mio_boot_bist_stat_cn61xx { + uint64_t reserved_12_63:52; + uint64_t stat:12; + } cn61xx; struct cvmx_mio_boot_bist_stat_cn63xx { uint64_t reserved_9_63:55; uint64_t stat:9; } cn63xx; struct cvmx_mio_boot_bist_stat_cn63xx cn63xxp1; + struct cvmx_mio_boot_bist_stat_cn66xx { + uint64_t reserved_10_63:54; + uint64_t stat:10; + } cn66xx; + struct cvmx_mio_boot_bist_stat_cn66xx cn68xx; + struct cvmx_mio_boot_bist_stat_cn66xx cn68xxp1; }; union cvmx_mio_boot_comp { @@ -204,12 +242,16 @@ union cvmx_mio_boot_comp { struct cvmx_mio_boot_comp_cn50xx cn52xxp1; struct cvmx_mio_boot_comp_cn50xx cn56xx; struct cvmx_mio_boot_comp_cn50xx cn56xxp1; - struct cvmx_mio_boot_comp_cn63xx { + struct cvmx_mio_boot_comp_cn61xx { uint64_t reserved_12_63:52; uint64_t pctl:6; uint64_t nctl:6; - } cn63xx; - struct cvmx_mio_boot_comp_cn63xx cn63xxp1; + } cn61xx; + struct cvmx_mio_boot_comp_cn61xx cn63xx; + struct cvmx_mio_boot_comp_cn61xx cn63xxp1; + struct cvmx_mio_boot_comp_cn61xx cn66xx; + struct cvmx_mio_boot_comp_cn61xx cn68xx; + struct cvmx_mio_boot_comp_cn61xx cn68xxp1; }; union cvmx_mio_boot_dma_cfgx { @@ -230,8 +272,12 @@ union cvmx_mio_boot_dma_cfgx { struct cvmx_mio_boot_dma_cfgx_s cn52xxp1; struct cvmx_mio_boot_dma_cfgx_s cn56xx; struct cvmx_mio_boot_dma_cfgx_s cn56xxp1; + struct cvmx_mio_boot_dma_cfgx_s cn61xx; struct cvmx_mio_boot_dma_cfgx_s cn63xx; struct cvmx_mio_boot_dma_cfgx_s cn63xxp1; + struct cvmx_mio_boot_dma_cfgx_s cn66xx; + struct cvmx_mio_boot_dma_cfgx_s cn68xx; + struct cvmx_mio_boot_dma_cfgx_s cn68xxp1; }; union cvmx_mio_boot_dma_intx { @@ -245,8 +291,12 @@ union cvmx_mio_boot_dma_intx { struct cvmx_mio_boot_dma_intx_s cn52xxp1; struct cvmx_mio_boot_dma_intx_s cn56xx; struct cvmx_mio_boot_dma_intx_s cn56xxp1; + struct cvmx_mio_boot_dma_intx_s cn61xx; struct cvmx_mio_boot_dma_intx_s cn63xx; struct cvmx_mio_boot_dma_intx_s cn63xxp1; + struct cvmx_mio_boot_dma_intx_s cn66xx; + struct cvmx_mio_boot_dma_intx_s cn68xx; + struct cvmx_mio_boot_dma_intx_s cn68xxp1; }; union cvmx_mio_boot_dma_int_enx { @@ -260,8 +310,12 @@ union cvmx_mio_boot_dma_int_enx { struct cvmx_mio_boot_dma_int_enx_s cn52xxp1; struct cvmx_mio_boot_dma_int_enx_s cn56xx; struct cvmx_mio_boot_dma_int_enx_s cn56xxp1; + struct cvmx_mio_boot_dma_int_enx_s cn61xx; struct cvmx_mio_boot_dma_int_enx_s cn63xx; struct cvmx_mio_boot_dma_int_enx_s cn63xxp1; + struct cvmx_mio_boot_dma_int_enx_s cn66xx; + struct cvmx_mio_boot_dma_int_enx_s cn68xx; + struct cvmx_mio_boot_dma_int_enx_s cn68xxp1; }; union cvmx_mio_boot_dma_timx { @@ -287,8 +341,12 @@ union cvmx_mio_boot_dma_timx { struct cvmx_mio_boot_dma_timx_s cn52xxp1; struct cvmx_mio_boot_dma_timx_s cn56xx; struct cvmx_mio_boot_dma_timx_s cn56xxp1; + struct cvmx_mio_boot_dma_timx_s cn61xx; struct cvmx_mio_boot_dma_timx_s cn63xx; struct cvmx_mio_boot_dma_timx_s cn63xxp1; + struct cvmx_mio_boot_dma_timx_s cn66xx; + struct cvmx_mio_boot_dma_timx_s cn68xx; + struct cvmx_mio_boot_dma_timx_s cn68xxp1; }; union cvmx_mio_boot_err { @@ -309,8 +367,12 @@ union cvmx_mio_boot_err { struct cvmx_mio_boot_err_s cn56xxp1; struct cvmx_mio_boot_err_s cn58xx; struct cvmx_mio_boot_err_s cn58xxp1; + struct cvmx_mio_boot_err_s cn61xx; struct cvmx_mio_boot_err_s cn63xx; struct cvmx_mio_boot_err_s cn63xxp1; + struct cvmx_mio_boot_err_s cn66xx; + struct cvmx_mio_boot_err_s cn68xx; + struct cvmx_mio_boot_err_s cn68xxp1; }; union cvmx_mio_boot_int { @@ -331,8 +393,12 @@ union cvmx_mio_boot_int { struct cvmx_mio_boot_int_s cn56xxp1; struct cvmx_mio_boot_int_s cn58xx; struct cvmx_mio_boot_int_s cn58xxp1; + struct cvmx_mio_boot_int_s cn61xx; struct cvmx_mio_boot_int_s cn63xx; struct cvmx_mio_boot_int_s cn63xxp1; + struct cvmx_mio_boot_int_s cn66xx; + struct cvmx_mio_boot_int_s cn68xx; + struct cvmx_mio_boot_int_s cn68xxp1; }; union cvmx_mio_boot_loc_adr { @@ -353,8 +419,12 @@ union cvmx_mio_boot_loc_adr { struct cvmx_mio_boot_loc_adr_s cn56xxp1; struct cvmx_mio_boot_loc_adr_s cn58xx; struct cvmx_mio_boot_loc_adr_s cn58xxp1; + struct cvmx_mio_boot_loc_adr_s cn61xx; struct cvmx_mio_boot_loc_adr_s cn63xx; struct cvmx_mio_boot_loc_adr_s cn63xxp1; + struct cvmx_mio_boot_loc_adr_s cn66xx; + struct cvmx_mio_boot_loc_adr_s cn68xx; + struct cvmx_mio_boot_loc_adr_s cn68xxp1; }; union cvmx_mio_boot_loc_cfgx { @@ -377,8 +447,12 @@ union cvmx_mio_boot_loc_cfgx { struct cvmx_mio_boot_loc_cfgx_s cn56xxp1; struct cvmx_mio_boot_loc_cfgx_s cn58xx; struct cvmx_mio_boot_loc_cfgx_s cn58xxp1; + struct cvmx_mio_boot_loc_cfgx_s cn61xx; struct cvmx_mio_boot_loc_cfgx_s cn63xx; struct cvmx_mio_boot_loc_cfgx_s cn63xxp1; + struct cvmx_mio_boot_loc_cfgx_s cn66xx; + struct cvmx_mio_boot_loc_cfgx_s cn68xx; + struct cvmx_mio_boot_loc_cfgx_s cn68xxp1; }; union cvmx_mio_boot_loc_dat { @@ -397,14 +471,19 @@ union cvmx_mio_boot_loc_dat { struct cvmx_mio_boot_loc_dat_s cn56xxp1; struct cvmx_mio_boot_loc_dat_s cn58xx; struct cvmx_mio_boot_loc_dat_s cn58xxp1; + struct cvmx_mio_boot_loc_dat_s cn61xx; struct cvmx_mio_boot_loc_dat_s cn63xx; struct cvmx_mio_boot_loc_dat_s cn63xxp1; + struct cvmx_mio_boot_loc_dat_s cn66xx; + struct cvmx_mio_boot_loc_dat_s cn68xx; + struct cvmx_mio_boot_loc_dat_s cn68xxp1; }; union cvmx_mio_boot_pin_defs { uint64_t u64; struct cvmx_mio_boot_pin_defs_s { - uint64_t reserved_16_63:48; + uint64_t reserved_32_63:32; + uint64_t user1:16; uint64_t ale:1; uint64_t width:1; uint64_t dmack_p2:1; @@ -412,7 +491,7 @@ union cvmx_mio_boot_pin_defs { uint64_t dmack_p0:1; uint64_t term:2; uint64_t nand:1; - uint64_t reserved_0_7:8; + uint64_t user0:8; } s; struct cvmx_mio_boot_pin_defs_cn52xx { uint64_t reserved_16_63:48; @@ -435,8 +514,23 @@ union cvmx_mio_boot_pin_defs { uint64_t term:2; uint64_t reserved_0_8:9; } cn56xx; + struct cvmx_mio_boot_pin_defs_cn61xx { + uint64_t reserved_32_63:32; + uint64_t user1:16; + uint64_t ale:1; + uint64_t width:1; + uint64_t reserved_13_13:1; + uint64_t dmack_p1:1; + uint64_t dmack_p0:1; + uint64_t term:2; + uint64_t nand:1; + uint64_t user0:8; + } cn61xx; struct cvmx_mio_boot_pin_defs_cn52xx cn63xx; struct cvmx_mio_boot_pin_defs_cn52xx cn63xxp1; + struct cvmx_mio_boot_pin_defs_cn52xx cn66xx; + struct cvmx_mio_boot_pin_defs_cn52xx cn68xx; + struct cvmx_mio_boot_pin_defs_cn52xx cn68xxp1; }; union cvmx_mio_boot_reg_cfgx { @@ -498,8 +592,12 @@ union cvmx_mio_boot_reg_cfgx { struct cvmx_mio_boot_reg_cfgx_s cn56xxp1; struct cvmx_mio_boot_reg_cfgx_cn30xx cn58xx; struct cvmx_mio_boot_reg_cfgx_cn30xx cn58xxp1; + struct cvmx_mio_boot_reg_cfgx_s cn61xx; struct cvmx_mio_boot_reg_cfgx_s cn63xx; struct cvmx_mio_boot_reg_cfgx_s cn63xxp1; + struct cvmx_mio_boot_reg_cfgx_s cn66xx; + struct cvmx_mio_boot_reg_cfgx_s cn68xx; + struct cvmx_mio_boot_reg_cfgx_s cn68xxp1; }; union cvmx_mio_boot_reg_timx { @@ -544,8 +642,12 @@ union cvmx_mio_boot_reg_timx { struct cvmx_mio_boot_reg_timx_s cn56xxp1; struct cvmx_mio_boot_reg_timx_s cn58xx; struct cvmx_mio_boot_reg_timx_s cn58xxp1; + struct cvmx_mio_boot_reg_timx_s cn61xx; struct cvmx_mio_boot_reg_timx_s cn63xx; struct cvmx_mio_boot_reg_timx_s cn63xxp1; + struct cvmx_mio_boot_reg_timx_s cn66xx; + struct cvmx_mio_boot_reg_timx_s cn68xx; + struct cvmx_mio_boot_reg_timx_s cn68xxp1; }; union cvmx_mio_boot_thr { @@ -574,8 +676,231 @@ union cvmx_mio_boot_thr { struct cvmx_mio_boot_thr_s cn56xxp1; struct cvmx_mio_boot_thr_cn30xx cn58xx; struct cvmx_mio_boot_thr_cn30xx cn58xxp1; + struct cvmx_mio_boot_thr_s cn61xx; struct cvmx_mio_boot_thr_s cn63xx; struct cvmx_mio_boot_thr_s cn63xxp1; + struct cvmx_mio_boot_thr_s cn66xx; + struct cvmx_mio_boot_thr_s cn68xx; + struct cvmx_mio_boot_thr_s cn68xxp1; +}; + +union cvmx_mio_emm_buf_dat { + uint64_t u64; + struct cvmx_mio_emm_buf_dat_s { + uint64_t dat:64; + } s; + struct cvmx_mio_emm_buf_dat_s cn61xx; +}; + +union cvmx_mio_emm_buf_idx { + uint64_t u64; + struct cvmx_mio_emm_buf_idx_s { + uint64_t reserved_17_63:47; + uint64_t inc:1; + uint64_t reserved_7_15:9; + uint64_t buf_num:1; + uint64_t offset:6; + } s; + struct cvmx_mio_emm_buf_idx_s cn61xx; +}; + +union cvmx_mio_emm_cfg { + uint64_t u64; + struct cvmx_mio_emm_cfg_s { + uint64_t reserved_17_63:47; + uint64_t boot_fail:1; + uint64_t reserved_4_15:12; + uint64_t bus_ena:4; + } s; + struct cvmx_mio_emm_cfg_s cn61xx; +}; + +union cvmx_mio_emm_cmd { + uint64_t u64; + struct cvmx_mio_emm_cmd_s { + uint64_t reserved_62_63:2; + uint64_t bus_id:2; + uint64_t cmd_val:1; + uint64_t reserved_56_58:3; + uint64_t dbuf:1; + uint64_t offset:6; + uint64_t reserved_43_48:6; + uint64_t ctype_xor:2; + uint64_t rtype_xor:3; + uint64_t cmd_idx:6; + uint64_t arg:32; + } s; + struct cvmx_mio_emm_cmd_s cn61xx; +}; + +union cvmx_mio_emm_dma { + uint64_t u64; + struct cvmx_mio_emm_dma_s { + uint64_t reserved_62_63:2; + uint64_t bus_id:2; + uint64_t dma_val:1; + uint64_t sector:1; + uint64_t dat_null:1; + uint64_t thres:6; + uint64_t rel_wr:1; + uint64_t rw:1; + uint64_t multi:1; + uint64_t block_cnt:16; + uint64_t card_addr:32; + } s; + struct cvmx_mio_emm_dma_s cn61xx; +}; + +union cvmx_mio_emm_int { + uint64_t u64; + struct cvmx_mio_emm_int_s { + uint64_t reserved_7_63:57; + uint64_t switch_err:1; + uint64_t switch_done:1; + uint64_t dma_err:1; + uint64_t cmd_err:1; + uint64_t dma_done:1; + uint64_t cmd_done:1; + uint64_t buf_done:1; + } s; + struct cvmx_mio_emm_int_s cn61xx; +}; + +union cvmx_mio_emm_int_en { + uint64_t u64; + struct cvmx_mio_emm_int_en_s { + uint64_t reserved_7_63:57; + uint64_t switch_err:1; + uint64_t switch_done:1; + uint64_t dma_err:1; + uint64_t cmd_err:1; + uint64_t dma_done:1; + uint64_t cmd_done:1; + uint64_t buf_done:1; + } s; + struct cvmx_mio_emm_int_en_s cn61xx; +}; + +union cvmx_mio_emm_modex { + uint64_t u64; + struct cvmx_mio_emm_modex_s { + uint64_t reserved_49_63:15; + uint64_t hs_timing:1; + uint64_t reserved_43_47:5; + uint64_t bus_width:3; + uint64_t reserved_36_39:4; + uint64_t power_class:4; + uint64_t clk_hi:16; + uint64_t clk_lo:16; + } s; + struct cvmx_mio_emm_modex_s cn61xx; +}; + +union cvmx_mio_emm_rca { + uint64_t u64; + struct cvmx_mio_emm_rca_s { + uint64_t reserved_16_63:48; + uint64_t card_rca:16; + } s; + struct cvmx_mio_emm_rca_s cn61xx; +}; + +union cvmx_mio_emm_rsp_hi { + uint64_t u64; + struct cvmx_mio_emm_rsp_hi_s { + uint64_t dat:64; + } s; + struct cvmx_mio_emm_rsp_hi_s cn61xx; +}; + +union cvmx_mio_emm_rsp_lo { + uint64_t u64; + struct cvmx_mio_emm_rsp_lo_s { + uint64_t dat:64; + } s; + struct cvmx_mio_emm_rsp_lo_s cn61xx; +}; + +union cvmx_mio_emm_rsp_sts { + uint64_t u64; + struct cvmx_mio_emm_rsp_sts_s { + uint64_t reserved_62_63:2; + uint64_t bus_id:2; + uint64_t cmd_val:1; + uint64_t switch_val:1; + uint64_t dma_val:1; + uint64_t dma_pend:1; + uint64_t reserved_29_55:27; + uint64_t dbuf_err:1; + uint64_t reserved_24_27:4; + uint64_t dbuf:1; + uint64_t blk_timeout:1; + uint64_t blk_crc_err:1; + uint64_t rsp_busybit:1; + uint64_t stp_timeout:1; + uint64_t stp_crc_err:1; + uint64_t stp_bad_sts:1; + uint64_t stp_val:1; + uint64_t rsp_timeout:1; + uint64_t rsp_crc_err:1; + uint64_t rsp_bad_sts:1; + uint64_t rsp_val:1; + uint64_t rsp_type:3; + uint64_t cmd_type:2; + uint64_t cmd_idx:6; + uint64_t cmd_done:1; + } s; + struct cvmx_mio_emm_rsp_sts_s cn61xx; +}; + +union cvmx_mio_emm_sample { + uint64_t u64; + struct cvmx_mio_emm_sample_s { + uint64_t reserved_26_63:38; + uint64_t cmd_cnt:10; + uint64_t reserved_10_15:6; + uint64_t dat_cnt:10; + } s; + struct cvmx_mio_emm_sample_s cn61xx; +}; + +union cvmx_mio_emm_sts_mask { + uint64_t u64; + struct cvmx_mio_emm_sts_mask_s { + uint64_t reserved_32_63:32; + uint64_t sts_msk:32; + } s; + struct cvmx_mio_emm_sts_mask_s cn61xx; +}; + +union cvmx_mio_emm_switch { + uint64_t u64; + struct cvmx_mio_emm_switch_s { + uint64_t reserved_62_63:2; + uint64_t bus_id:2; + uint64_t switch_exe:1; + uint64_t switch_err0:1; + uint64_t switch_err1:1; + uint64_t switch_err2:1; + uint64_t reserved_49_55:7; + uint64_t hs_timing:1; + uint64_t reserved_43_47:5; + uint64_t bus_width:3; + uint64_t reserved_36_39:4; + uint64_t power_class:4; + uint64_t clk_hi:16; + uint64_t clk_lo:16; + } s; + struct cvmx_mio_emm_switch_s cn61xx; +}; + +union cvmx_mio_emm_wdog { + uint64_t u64; + struct cvmx_mio_emm_wdog_s { + uint64_t reserved_26_63:38; + uint64_t clk_cnt:26; + } s; + struct cvmx_mio_emm_wdog_s cn61xx; }; union cvmx_mio_fus_bnk_datx { @@ -590,8 +915,12 @@ union cvmx_mio_fus_bnk_datx { struct cvmx_mio_fus_bnk_datx_s cn56xxp1; struct cvmx_mio_fus_bnk_datx_s cn58xx; struct cvmx_mio_fus_bnk_datx_s cn58xxp1; + struct cvmx_mio_fus_bnk_datx_s cn61xx; struct cvmx_mio_fus_bnk_datx_s cn63xx; struct cvmx_mio_fus_bnk_datx_s cn63xxp1; + struct cvmx_mio_fus_bnk_datx_s cn66xx; + struct cvmx_mio_fus_bnk_datx_s cn68xx; + struct cvmx_mio_fus_bnk_datx_s cn68xxp1; }; union cvmx_mio_fus_dat0 { @@ -611,8 +940,12 @@ union cvmx_mio_fus_dat0 { struct cvmx_mio_fus_dat0_s cn56xxp1; struct cvmx_mio_fus_dat0_s cn58xx; struct cvmx_mio_fus_dat0_s cn58xxp1; + struct cvmx_mio_fus_dat0_s cn61xx; struct cvmx_mio_fus_dat0_s cn63xx; struct cvmx_mio_fus_dat0_s cn63xxp1; + struct cvmx_mio_fus_dat0_s cn66xx; + struct cvmx_mio_fus_dat0_s cn68xx; + struct cvmx_mio_fus_dat0_s cn68xxp1; }; union cvmx_mio_fus_dat1 { @@ -632,14 +965,21 @@ union cvmx_mio_fus_dat1 { struct cvmx_mio_fus_dat1_s cn56xxp1; struct cvmx_mio_fus_dat1_s cn58xx; struct cvmx_mio_fus_dat1_s cn58xxp1; + struct cvmx_mio_fus_dat1_s cn61xx; struct cvmx_mio_fus_dat1_s cn63xx; struct cvmx_mio_fus_dat1_s cn63xxp1; + struct cvmx_mio_fus_dat1_s cn66xx; + struct cvmx_mio_fus_dat1_s cn68xx; + struct cvmx_mio_fus_dat1_s cn68xxp1; }; union cvmx_mio_fus_dat2 { uint64_t u64; struct cvmx_mio_fus_dat2_s { - uint64_t reserved_35_63:29; + uint64_t reserved_48_63:16; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; uint64_t dorm_crypto:1; uint64_t fus318:1; uint64_t raid_en:1; @@ -747,6 +1087,23 @@ union cvmx_mio_fus_dat2 { uint64_t pp_dis:16; } cn58xx; struct cvmx_mio_fus_dat2_cn58xx cn58xxp1; + struct cvmx_mio_fus_dat2_cn61xx { + uint64_t reserved_48_63:16; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_29_31:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_24_25:2; + uint64_t chip_id:8; + uint64_t reserved_4_15:12; + uint64_t pp_dis:4; + } cn61xx; struct cvmx_mio_fus_dat2_cn63xx { uint64_t reserved_35_63:29; uint64_t dorm_crypto:1; @@ -762,6 +1119,38 @@ union cvmx_mio_fus_dat2 { uint64_t pp_dis:6; } cn63xx; struct cvmx_mio_fus_dat2_cn63xx cn63xxp1; + struct cvmx_mio_fus_dat2_cn66xx { + uint64_t reserved_48_63:16; + uint64_t fus118:1; + uint64_t rom_info:10; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_29_31:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_24_25:2; + uint64_t chip_id:8; + uint64_t reserved_10_15:6; + uint64_t pp_dis:10; + } cn66xx; + struct cvmx_mio_fus_dat2_cn68xx { + uint64_t reserved_37_63:27; + uint64_t power_limit:2; + uint64_t dorm_crypto:1; + uint64_t fus318:1; + uint64_t raid_en:1; + uint64_t reserved_29_31:3; + uint64_t nodfa_cp2:1; + uint64_t nomul:1; + uint64_t nocrypto:1; + uint64_t reserved_24_25:2; + uint64_t chip_id:8; + uint64_t reserved_0_15:16; + } cn68xx; + struct cvmx_mio_fus_dat2_cn68xx cn68xxp1; }; union cvmx_mio_fus_dat3 { @@ -834,7 +1223,7 @@ union cvmx_mio_fus_dat3 { struct cvmx_mio_fus_dat3_cn38xx cn56xxp1; struct cvmx_mio_fus_dat3_cn38xx cn58xx; struct cvmx_mio_fus_dat3_cn38xx cn58xxp1; - struct cvmx_mio_fus_dat3_cn63xx { + struct cvmx_mio_fus_dat3_cn61xx { uint64_t reserved_58_63:6; uint64_t pll_ctl:10; uint64_t dfa_info_dte:3; @@ -853,8 +1242,12 @@ union cvmx_mio_fus_dat3 { uint64_t nozip:1; uint64_t nodfa_dte:1; uint64_t reserved_0_23:24; - } cn63xx; - struct cvmx_mio_fus_dat3_cn63xx cn63xxp1; + } cn61xx; + struct cvmx_mio_fus_dat3_cn61xx cn63xx; + struct cvmx_mio_fus_dat3_cn61xx cn63xxp1; + struct cvmx_mio_fus_dat3_cn61xx cn66xx; + struct cvmx_mio_fus_dat3_cn61xx cn68xx; + struct cvmx_mio_fus_dat3_cn61xx cn68xxp1; }; union cvmx_mio_fus_ema { @@ -875,8 +1268,12 @@ union cvmx_mio_fus_ema { uint64_t ema:2; } cn58xx; struct cvmx_mio_fus_ema_cn58xx cn58xxp1; + struct cvmx_mio_fus_ema_s cn61xx; struct cvmx_mio_fus_ema_s cn63xx; struct cvmx_mio_fus_ema_s cn63xxp1; + struct cvmx_mio_fus_ema_s cn66xx; + struct cvmx_mio_fus_ema_s cn68xx; + struct cvmx_mio_fus_ema_s cn68xxp1; }; union cvmx_mio_fus_pdf { @@ -890,14 +1287,21 @@ union cvmx_mio_fus_pdf { struct cvmx_mio_fus_pdf_s cn56xx; struct cvmx_mio_fus_pdf_s cn56xxp1; struct cvmx_mio_fus_pdf_s cn58xx; + struct cvmx_mio_fus_pdf_s cn61xx; struct cvmx_mio_fus_pdf_s cn63xx; struct cvmx_mio_fus_pdf_s cn63xxp1; + struct cvmx_mio_fus_pdf_s cn66xx; + struct cvmx_mio_fus_pdf_s cn68xx; + struct cvmx_mio_fus_pdf_s cn68xxp1; }; union cvmx_mio_fus_pll { uint64_t u64; struct cvmx_mio_fus_pll_s { - uint64_t reserved_8_63:56; + uint64_t reserved_48_63:16; + uint64_t rclk_align_r:8; + uint64_t rclk_align_l:8; + uint64_t reserved_8_31:24; uint64_t c_cout_rst:1; uint64_t c_cout_sel:2; uint64_t pnr_cout_rst:1; @@ -916,8 +1320,20 @@ union cvmx_mio_fus_pll { struct cvmx_mio_fus_pll_cn50xx cn56xxp1; struct cvmx_mio_fus_pll_cn50xx cn58xx; struct cvmx_mio_fus_pll_cn50xx cn58xxp1; - struct cvmx_mio_fus_pll_s cn63xx; - struct cvmx_mio_fus_pll_s cn63xxp1; + struct cvmx_mio_fus_pll_cn61xx { + uint64_t reserved_8_63:56; + uint64_t c_cout_rst:1; + uint64_t c_cout_sel:2; + uint64_t pnr_cout_rst:1; + uint64_t pnr_cout_sel:2; + uint64_t rfslip:1; + uint64_t fbslip:1; + } cn61xx; + struct cvmx_mio_fus_pll_cn61xx cn63xx; + struct cvmx_mio_fus_pll_cn61xx cn63xxp1; + struct cvmx_mio_fus_pll_cn61xx cn66xx; + struct cvmx_mio_fus_pll_s cn68xx; + struct cvmx_mio_fus_pll_s cn68xxp1; }; union cvmx_mio_fus_prog { @@ -941,8 +1357,12 @@ union cvmx_mio_fus_prog { struct cvmx_mio_fus_prog_cn30xx cn56xxp1; struct cvmx_mio_fus_prog_cn30xx cn58xx; struct cvmx_mio_fus_prog_cn30xx cn58xxp1; + struct cvmx_mio_fus_prog_s cn61xx; struct cvmx_mio_fus_prog_s cn63xx; struct cvmx_mio_fus_prog_s cn63xxp1; + struct cvmx_mio_fus_prog_s cn66xx; + struct cvmx_mio_fus_prog_s cn68xx; + struct cvmx_mio_fus_prog_s cn68xxp1; }; union cvmx_mio_fus_prog_times { @@ -969,7 +1389,7 @@ union cvmx_mio_fus_prog_times { struct cvmx_mio_fus_prog_times_cn50xx cn56xxp1; struct cvmx_mio_fus_prog_times_cn50xx cn58xx; struct cvmx_mio_fus_prog_times_cn50xx cn58xxp1; - struct cvmx_mio_fus_prog_times_cn63xx { + struct cvmx_mio_fus_prog_times_cn61xx { uint64_t reserved_35_63:29; uint64_t vgate_pin:1; uint64_t fsrc_pin:1; @@ -978,8 +1398,12 @@ union cvmx_mio_fus_prog_times { uint64_t sclk_lo:4; uint64_t sclk_hi:15; uint64_t setup:6; - } cn63xx; - struct cvmx_mio_fus_prog_times_cn63xx cn63xxp1; + } cn61xx; + struct cvmx_mio_fus_prog_times_cn61xx cn63xx; + struct cvmx_mio_fus_prog_times_cn61xx cn63xxp1; + struct cvmx_mio_fus_prog_times_cn61xx cn66xx; + struct cvmx_mio_fus_prog_times_cn61xx cn68xx; + struct cvmx_mio_fus_prog_times_cn61xx cn68xxp1; }; union cvmx_mio_fus_rcmd { @@ -1013,8 +1437,12 @@ union cvmx_mio_fus_rcmd { struct cvmx_mio_fus_rcmd_s cn56xxp1; struct cvmx_mio_fus_rcmd_cn30xx cn58xx; struct cvmx_mio_fus_rcmd_cn30xx cn58xxp1; + struct cvmx_mio_fus_rcmd_s cn61xx; struct cvmx_mio_fus_rcmd_s cn63xx; struct cvmx_mio_fus_rcmd_s cn63xxp1; + struct cvmx_mio_fus_rcmd_s cn66xx; + struct cvmx_mio_fus_rcmd_s cn68xx; + struct cvmx_mio_fus_rcmd_s cn68xxp1; }; union cvmx_mio_fus_read_times { @@ -1027,8 +1455,12 @@ union cvmx_mio_fus_read_times { uint64_t sdh:4; uint64_t setup:10; } s; + struct cvmx_mio_fus_read_times_s cn61xx; struct cvmx_mio_fus_read_times_s cn63xx; struct cvmx_mio_fus_read_times_s cn63xxp1; + struct cvmx_mio_fus_read_times_s cn66xx; + struct cvmx_mio_fus_read_times_s cn68xx; + struct cvmx_mio_fus_read_times_s cn68xxp1; }; union cvmx_mio_fus_repair_res0 { @@ -1040,8 +1472,12 @@ union cvmx_mio_fus_repair_res0 { uint64_t repair1:18; uint64_t repair0:18; } s; + struct cvmx_mio_fus_repair_res0_s cn61xx; struct cvmx_mio_fus_repair_res0_s cn63xx; struct cvmx_mio_fus_repair_res0_s cn63xxp1; + struct cvmx_mio_fus_repair_res0_s cn66xx; + struct cvmx_mio_fus_repair_res0_s cn68xx; + struct cvmx_mio_fus_repair_res0_s cn68xxp1; }; union cvmx_mio_fus_repair_res1 { @@ -1052,8 +1488,12 @@ union cvmx_mio_fus_repair_res1 { uint64_t repair4:18; uint64_t repair3:18; } s; + struct cvmx_mio_fus_repair_res1_s cn61xx; struct cvmx_mio_fus_repair_res1_s cn63xx; struct cvmx_mio_fus_repair_res1_s cn63xxp1; + struct cvmx_mio_fus_repair_res1_s cn66xx; + struct cvmx_mio_fus_repair_res1_s cn68xx; + struct cvmx_mio_fus_repair_res1_s cn68xxp1; }; union cvmx_mio_fus_repair_res2 { @@ -1062,8 +1502,12 @@ union cvmx_mio_fus_repair_res2 { uint64_t reserved_18_63:46; uint64_t repair6:18; } s; + struct cvmx_mio_fus_repair_res2_s cn61xx; struct cvmx_mio_fus_repair_res2_s cn63xx; struct cvmx_mio_fus_repair_res2_s cn63xxp1; + struct cvmx_mio_fus_repair_res2_s cn66xx; + struct cvmx_mio_fus_repair_res2_s cn68xx; + struct cvmx_mio_fus_repair_res2_s cn68xxp1; }; union cvmx_mio_fus_spr_repair_res { @@ -1084,8 +1528,12 @@ union cvmx_mio_fus_spr_repair_res { struct cvmx_mio_fus_spr_repair_res_s cn56xxp1; struct cvmx_mio_fus_spr_repair_res_s cn58xx; struct cvmx_mio_fus_spr_repair_res_s cn58xxp1; + struct cvmx_mio_fus_spr_repair_res_s cn61xx; struct cvmx_mio_fus_spr_repair_res_s cn63xx; struct cvmx_mio_fus_spr_repair_res_s cn63xxp1; + struct cvmx_mio_fus_spr_repair_res_s cn66xx; + struct cvmx_mio_fus_spr_repair_res_s cn68xx; + struct cvmx_mio_fus_spr_repair_res_s cn68xxp1; }; union cvmx_mio_fus_spr_repair_sum { @@ -1104,8 +1552,22 @@ union cvmx_mio_fus_spr_repair_sum { struct cvmx_mio_fus_spr_repair_sum_s cn56xxp1; struct cvmx_mio_fus_spr_repair_sum_s cn58xx; struct cvmx_mio_fus_spr_repair_sum_s cn58xxp1; + struct cvmx_mio_fus_spr_repair_sum_s cn61xx; struct cvmx_mio_fus_spr_repair_sum_s cn63xx; struct cvmx_mio_fus_spr_repair_sum_s cn63xxp1; + struct cvmx_mio_fus_spr_repair_sum_s cn66xx; + struct cvmx_mio_fus_spr_repair_sum_s cn68xx; + struct cvmx_mio_fus_spr_repair_sum_s cn68xxp1; +}; + +union cvmx_mio_fus_tgg { + uint64_t u64; + struct cvmx_mio_fus_tgg_s { + uint64_t val:1; + uint64_t dat:63; + } s; + struct cvmx_mio_fus_tgg_s cn61xx; + struct cvmx_mio_fus_tgg_s cn66xx; }; union cvmx_mio_fus_unlock { @@ -1141,11 +1603,15 @@ union cvmx_mio_fus_wadr { struct cvmx_mio_fus_wadr_cn52xx cn56xxp1; struct cvmx_mio_fus_wadr_cn50xx cn58xx; struct cvmx_mio_fus_wadr_cn50xx cn58xxp1; - struct cvmx_mio_fus_wadr_cn63xx { + struct cvmx_mio_fus_wadr_cn61xx { uint64_t reserved_4_63:60; uint64_t addr:4; - } cn63xx; - struct cvmx_mio_fus_wadr_cn63xx cn63xxp1; + } cn61xx; + struct cvmx_mio_fus_wadr_cn61xx cn63xx; + struct cvmx_mio_fus_wadr_cn61xx cn63xxp1; + struct cvmx_mio_fus_wadr_cn61xx cn66xx; + struct cvmx_mio_fus_wadr_cn61xx cn68xx; + struct cvmx_mio_fus_wadr_cn61xx cn68xxp1; }; union cvmx_mio_gpio_comp { @@ -1155,8 +1621,12 @@ union cvmx_mio_gpio_comp { uint64_t pctl:6; uint64_t nctl:6; } s; + struct cvmx_mio_gpio_comp_s cn61xx; struct cvmx_mio_gpio_comp_s cn63xx; struct cvmx_mio_gpio_comp_s cn63xxp1; + struct cvmx_mio_gpio_comp_s cn66xx; + struct cvmx_mio_gpio_comp_s cn68xx; + struct cvmx_mio_gpio_comp_s cn68xxp1; }; union cvmx_mio_ndf_dma_cfg { @@ -1174,8 +1644,12 @@ union cvmx_mio_ndf_dma_cfg { uint64_t adr:36; } s; struct cvmx_mio_ndf_dma_cfg_s cn52xx; + struct cvmx_mio_ndf_dma_cfg_s cn61xx; struct cvmx_mio_ndf_dma_cfg_s cn63xx; struct cvmx_mio_ndf_dma_cfg_s cn63xxp1; + struct cvmx_mio_ndf_dma_cfg_s cn66xx; + struct cvmx_mio_ndf_dma_cfg_s cn68xx; + struct cvmx_mio_ndf_dma_cfg_s cn68xxp1; }; union cvmx_mio_ndf_dma_int { @@ -1185,8 +1659,12 @@ union cvmx_mio_ndf_dma_int { uint64_t done:1; } s; struct cvmx_mio_ndf_dma_int_s cn52xx; + struct cvmx_mio_ndf_dma_int_s cn61xx; struct cvmx_mio_ndf_dma_int_s cn63xx; struct cvmx_mio_ndf_dma_int_s cn63xxp1; + struct cvmx_mio_ndf_dma_int_s cn66xx; + struct cvmx_mio_ndf_dma_int_s cn68xx; + struct cvmx_mio_ndf_dma_int_s cn68xxp1; }; union cvmx_mio_ndf_dma_int_en { @@ -1196,8 +1674,12 @@ union cvmx_mio_ndf_dma_int_en { uint64_t done:1; } s; struct cvmx_mio_ndf_dma_int_en_s cn52xx; + struct cvmx_mio_ndf_dma_int_en_s cn61xx; struct cvmx_mio_ndf_dma_int_en_s cn63xx; struct cvmx_mio_ndf_dma_int_en_s cn63xxp1; + struct cvmx_mio_ndf_dma_int_en_s cn66xx; + struct cvmx_mio_ndf_dma_int_en_s cn68xx; + struct cvmx_mio_ndf_dma_int_en_s cn68xxp1; }; union cvmx_mio_pll_ctl { @@ -1220,10 +1702,63 @@ union cvmx_mio_pll_setting { struct cvmx_mio_pll_setting_s cn31xx; }; +union cvmx_mio_ptp_ckout_hi_incr { + uint64_t u64; + struct cvmx_mio_ptp_ckout_hi_incr_s { + uint64_t nanosec:32; + uint64_t frnanosec:32; + } s; + struct cvmx_mio_ptp_ckout_hi_incr_s cn61xx; + struct cvmx_mio_ptp_ckout_hi_incr_s cn66xx; + struct cvmx_mio_ptp_ckout_hi_incr_s cn68xx; +}; + +union cvmx_mio_ptp_ckout_lo_incr { + uint64_t u64; + struct cvmx_mio_ptp_ckout_lo_incr_s { + uint64_t nanosec:32; + uint64_t frnanosec:32; + } s; + struct cvmx_mio_ptp_ckout_lo_incr_s cn61xx; + struct cvmx_mio_ptp_ckout_lo_incr_s cn66xx; + struct cvmx_mio_ptp_ckout_lo_incr_s cn68xx; +}; + +union cvmx_mio_ptp_ckout_thresh_hi { + uint64_t u64; + struct cvmx_mio_ptp_ckout_thresh_hi_s { + uint64_t nanosec:64; + } s; + struct cvmx_mio_ptp_ckout_thresh_hi_s cn61xx; + struct cvmx_mio_ptp_ckout_thresh_hi_s cn66xx; + struct cvmx_mio_ptp_ckout_thresh_hi_s cn68xx; +}; + +union cvmx_mio_ptp_ckout_thresh_lo { + uint64_t u64; + struct cvmx_mio_ptp_ckout_thresh_lo_s { + uint64_t reserved_32_63:32; + uint64_t frnanosec:32; + } s; + struct cvmx_mio_ptp_ckout_thresh_lo_s cn61xx; + struct cvmx_mio_ptp_ckout_thresh_lo_s cn66xx; + struct cvmx_mio_ptp_ckout_thresh_lo_s cn68xx; +}; + union cvmx_mio_ptp_clock_cfg { uint64_t u64; struct cvmx_mio_ptp_clock_cfg_s { - uint64_t reserved_24_63:40; + uint64_t reserved_42_63:22; + uint64_t pps:1; + uint64_t ckout:1; + uint64_t ext_clk_edge:2; + uint64_t ckout_out4:1; + uint64_t pps_out:5; + uint64_t pps_inv:1; + uint64_t pps_en:1; + uint64_t ckout_out:4; + uint64_t ckout_inv:1; + uint64_t ckout_en:1; uint64_t evcnt_in:6; uint64_t evcnt_edge:1; uint64_t evcnt_en:1; @@ -1234,8 +1769,42 @@ union cvmx_mio_ptp_clock_cfg { uint64_t ext_clk_en:1; uint64_t ptp_en:1; } s; - struct cvmx_mio_ptp_clock_cfg_s cn63xx; - struct cvmx_mio_ptp_clock_cfg_s cn63xxp1; + struct cvmx_mio_ptp_clock_cfg_s cn61xx; + struct cvmx_mio_ptp_clock_cfg_cn63xx { + uint64_t reserved_24_63:40; + uint64_t evcnt_in:6; + uint64_t evcnt_edge:1; + uint64_t evcnt_en:1; + uint64_t tstmp_in:6; + uint64_t tstmp_edge:1; + uint64_t tstmp_en:1; + uint64_t ext_clk_in:6; + uint64_t ext_clk_en:1; + uint64_t ptp_en:1; + } cn63xx; + struct cvmx_mio_ptp_clock_cfg_cn63xx cn63xxp1; + struct cvmx_mio_ptp_clock_cfg_cn66xx { + uint64_t reserved_40_63:24; + uint64_t ext_clk_edge:2; + uint64_t ckout_out4:1; + uint64_t pps_out:5; + uint64_t pps_inv:1; + uint64_t pps_en:1; + uint64_t ckout_out:4; + uint64_t ckout_inv:1; + uint64_t ckout_en:1; + uint64_t evcnt_in:6; + uint64_t evcnt_edge:1; + uint64_t evcnt_en:1; + uint64_t tstmp_in:6; + uint64_t tstmp_edge:1; + uint64_t tstmp_en:1; + uint64_t ext_clk_in:6; + uint64_t ext_clk_en:1; + uint64_t ptp_en:1; + } cn66xx; + struct cvmx_mio_ptp_clock_cfg_s cn68xx; + struct cvmx_mio_ptp_clock_cfg_cn63xx cn68xxp1; }; union cvmx_mio_ptp_clock_comp { @@ -1244,8 +1813,12 @@ union cvmx_mio_ptp_clock_comp { uint64_t nanosec:32; uint64_t frnanosec:32; } s; + struct cvmx_mio_ptp_clock_comp_s cn61xx; struct cvmx_mio_ptp_clock_comp_s cn63xx; struct cvmx_mio_ptp_clock_comp_s cn63xxp1; + struct cvmx_mio_ptp_clock_comp_s cn66xx; + struct cvmx_mio_ptp_clock_comp_s cn68xx; + struct cvmx_mio_ptp_clock_comp_s cn68xxp1; }; union cvmx_mio_ptp_clock_hi { @@ -1253,8 +1826,12 @@ union cvmx_mio_ptp_clock_hi { struct cvmx_mio_ptp_clock_hi_s { uint64_t nanosec:64; } s; + struct cvmx_mio_ptp_clock_hi_s cn61xx; struct cvmx_mio_ptp_clock_hi_s cn63xx; struct cvmx_mio_ptp_clock_hi_s cn63xxp1; + struct cvmx_mio_ptp_clock_hi_s cn66xx; + struct cvmx_mio_ptp_clock_hi_s cn68xx; + struct cvmx_mio_ptp_clock_hi_s cn68xxp1; }; union cvmx_mio_ptp_clock_lo { @@ -1263,8 +1840,12 @@ union cvmx_mio_ptp_clock_lo { uint64_t reserved_32_63:32; uint64_t frnanosec:32; } s; + struct cvmx_mio_ptp_clock_lo_s cn61xx; struct cvmx_mio_ptp_clock_lo_s cn63xx; struct cvmx_mio_ptp_clock_lo_s cn63xxp1; + struct cvmx_mio_ptp_clock_lo_s cn66xx; + struct cvmx_mio_ptp_clock_lo_s cn68xx; + struct cvmx_mio_ptp_clock_lo_s cn68xxp1; }; union cvmx_mio_ptp_evt_cnt { @@ -1272,8 +1853,55 @@ union cvmx_mio_ptp_evt_cnt { struct cvmx_mio_ptp_evt_cnt_s { uint64_t cntr:64; } s; + struct cvmx_mio_ptp_evt_cnt_s cn61xx; struct cvmx_mio_ptp_evt_cnt_s cn63xx; struct cvmx_mio_ptp_evt_cnt_s cn63xxp1; + struct cvmx_mio_ptp_evt_cnt_s cn66xx; + struct cvmx_mio_ptp_evt_cnt_s cn68xx; + struct cvmx_mio_ptp_evt_cnt_s cn68xxp1; +}; + +union cvmx_mio_ptp_pps_hi_incr { + uint64_t u64; + struct cvmx_mio_ptp_pps_hi_incr_s { + uint64_t nanosec:32; + uint64_t frnanosec:32; + } s; + struct cvmx_mio_ptp_pps_hi_incr_s cn61xx; + struct cvmx_mio_ptp_pps_hi_incr_s cn66xx; + struct cvmx_mio_ptp_pps_hi_incr_s cn68xx; +}; + +union cvmx_mio_ptp_pps_lo_incr { + uint64_t u64; + struct cvmx_mio_ptp_pps_lo_incr_s { + uint64_t nanosec:32; + uint64_t frnanosec:32; + } s; + struct cvmx_mio_ptp_pps_lo_incr_s cn61xx; + struct cvmx_mio_ptp_pps_lo_incr_s cn66xx; + struct cvmx_mio_ptp_pps_lo_incr_s cn68xx; +}; + +union cvmx_mio_ptp_pps_thresh_hi { + uint64_t u64; + struct cvmx_mio_ptp_pps_thresh_hi_s { + uint64_t nanosec:64; + } s; + struct cvmx_mio_ptp_pps_thresh_hi_s cn61xx; + struct cvmx_mio_ptp_pps_thresh_hi_s cn66xx; + struct cvmx_mio_ptp_pps_thresh_hi_s cn68xx; +}; + +union cvmx_mio_ptp_pps_thresh_lo { + uint64_t u64; + struct cvmx_mio_ptp_pps_thresh_lo_s { + uint64_t reserved_32_63:32; + uint64_t frnanosec:32; + } s; + struct cvmx_mio_ptp_pps_thresh_lo_s cn61xx; + struct cvmx_mio_ptp_pps_thresh_lo_s cn66xx; + struct cvmx_mio_ptp_pps_thresh_lo_s cn68xx; }; union cvmx_mio_ptp_timestamp { @@ -1281,14 +1909,52 @@ union cvmx_mio_ptp_timestamp { struct cvmx_mio_ptp_timestamp_s { uint64_t nanosec:64; } s; + struct cvmx_mio_ptp_timestamp_s cn61xx; struct cvmx_mio_ptp_timestamp_s cn63xx; struct cvmx_mio_ptp_timestamp_s cn63xxp1; + struct cvmx_mio_ptp_timestamp_s cn66xx; + struct cvmx_mio_ptp_timestamp_s cn68xx; + struct cvmx_mio_ptp_timestamp_s cn68xxp1; +}; + +union cvmx_mio_qlmx_cfg { + uint64_t u64; + struct cvmx_mio_qlmx_cfg_s { + uint64_t reserved_12_63:52; + uint64_t qlm_spd:4; + uint64_t reserved_4_7:4; + uint64_t qlm_cfg:4; + } s; + struct cvmx_mio_qlmx_cfg_cn61xx { + uint64_t reserved_12_63:52; + uint64_t qlm_spd:4; + uint64_t reserved_2_7:6; + uint64_t qlm_cfg:2; + } cn61xx; + struct cvmx_mio_qlmx_cfg_s cn66xx; + struct cvmx_mio_qlmx_cfg_cn68xx { + uint64_t reserved_12_63:52; + uint64_t qlm_spd:4; + uint64_t reserved_3_7:5; + uint64_t qlm_cfg:3; + } cn68xx; + struct cvmx_mio_qlmx_cfg_cn68xx cn68xxp1; }; union cvmx_mio_rst_boot { uint64_t u64; struct cvmx_mio_rst_boot_s { - uint64_t reserved_36_63:28; + uint64_t chipkill:1; + uint64_t jtcsrdis:1; + uint64_t ejtagdis:1; + uint64_t romen:1; + uint64_t ckill_ppdis:1; + uint64_t jt_tstmode:1; + uint64_t reserved_50_57:8; + uint64_t lboot_ext:2; + uint64_t reserved_44_47:4; + uint64_t qlm4_spd:4; + uint64_t qlm3_spd:4; uint64_t c_mul:6; uint64_t pnr_mul:6; uint64_t qlm2_spd:4; @@ -1298,32 +1964,168 @@ union cvmx_mio_rst_boot { uint64_t rboot:1; uint64_t rboot_pin:1; } s; - struct cvmx_mio_rst_boot_s cn63xx; - struct cvmx_mio_rst_boot_s cn63xxp1; + struct cvmx_mio_rst_boot_cn61xx { + uint64_t chipkill:1; + uint64_t jtcsrdis:1; + uint64_t ejtagdis:1; + uint64_t romen:1; + uint64_t ckill_ppdis:1; + uint64_t jt_tstmode:1; + uint64_t reserved_50_57:8; + uint64_t lboot_ext:2; + uint64_t reserved_36_47:12; + uint64_t c_mul:6; + uint64_t pnr_mul:6; + uint64_t qlm2_spd:4; + uint64_t qlm1_spd:4; + uint64_t qlm0_spd:4; + uint64_t lboot:10; + uint64_t rboot:1; + uint64_t rboot_pin:1; + } cn61xx; + struct cvmx_mio_rst_boot_cn63xx { + uint64_t reserved_36_63:28; + uint64_t c_mul:6; + uint64_t pnr_mul:6; + uint64_t qlm2_spd:4; + uint64_t qlm1_spd:4; + uint64_t qlm0_spd:4; + uint64_t lboot:10; + uint64_t rboot:1; + uint64_t rboot_pin:1; + } cn63xx; + struct cvmx_mio_rst_boot_cn63xx cn63xxp1; + struct cvmx_mio_rst_boot_cn66xx { + uint64_t chipkill:1; + uint64_t jtcsrdis:1; + uint64_t ejtagdis:1; + uint64_t romen:1; + uint64_t ckill_ppdis:1; + uint64_t reserved_50_58:9; + uint64_t lboot_ext:2; + uint64_t reserved_36_47:12; + uint64_t c_mul:6; + uint64_t pnr_mul:6; + uint64_t qlm2_spd:4; + uint64_t qlm1_spd:4; + uint64_t qlm0_spd:4; + uint64_t lboot:10; + uint64_t rboot:1; + uint64_t rboot_pin:1; + } cn66xx; + struct cvmx_mio_rst_boot_cn68xx { + uint64_t reserved_59_63:5; + uint64_t jt_tstmode:1; + uint64_t reserved_44_57:14; + uint64_t qlm4_spd:4; + uint64_t qlm3_spd:4; + uint64_t c_mul:6; + uint64_t pnr_mul:6; + uint64_t qlm2_spd:4; + uint64_t qlm1_spd:4; + uint64_t qlm0_spd:4; + uint64_t lboot:10; + uint64_t rboot:1; + uint64_t rboot_pin:1; + } cn68xx; + struct cvmx_mio_rst_boot_cn68xxp1 { + uint64_t reserved_44_63:20; + uint64_t qlm4_spd:4; + uint64_t qlm3_spd:4; + uint64_t c_mul:6; + uint64_t pnr_mul:6; + uint64_t qlm2_spd:4; + uint64_t qlm1_spd:4; + uint64_t qlm0_spd:4; + uint64_t lboot:10; + uint64_t rboot:1; + uint64_t rboot_pin:1; + } cn68xxp1; }; union cvmx_mio_rst_cfg { uint64_t u64; struct cvmx_mio_rst_cfg_s { + uint64_t reserved_3_63:61; + uint64_t cntl_clr_bist:1; + uint64_t warm_clr_bist:1; + uint64_t soft_clr_bist:1; + } s; + struct cvmx_mio_rst_cfg_cn61xx { uint64_t bist_delay:58; uint64_t reserved_3_5:3; uint64_t cntl_clr_bist:1; uint64_t warm_clr_bist:1; uint64_t soft_clr_bist:1; - } s; - struct cvmx_mio_rst_cfg_s cn63xx; + } cn61xx; + struct cvmx_mio_rst_cfg_cn61xx cn63xx; struct cvmx_mio_rst_cfg_cn63xxp1 { uint64_t bist_delay:58; uint64_t reserved_2_5:4; uint64_t warm_clr_bist:1; uint64_t soft_clr_bist:1; } cn63xxp1; + struct cvmx_mio_rst_cfg_cn61xx cn66xx; + struct cvmx_mio_rst_cfg_cn68xx { + uint64_t bist_delay:56; + uint64_t reserved_3_7:5; + uint64_t cntl_clr_bist:1; + uint64_t warm_clr_bist:1; + uint64_t soft_clr_bist:1; + } cn68xx; + struct cvmx_mio_rst_cfg_cn68xx cn68xxp1; +}; + +union cvmx_mio_rst_ckill { + uint64_t u64; + struct cvmx_mio_rst_ckill_s { + uint64_t reserved_47_63:17; + uint64_t timer:47; + } s; + struct cvmx_mio_rst_ckill_s cn61xx; + struct cvmx_mio_rst_ckill_s cn66xx; +}; + +union cvmx_mio_rst_cntlx { + uint64_t u64; + struct cvmx_mio_rst_cntlx_s { + uint64_t reserved_13_63:51; + uint64_t in_rev_ln:1; + uint64_t rev_lanes:1; + uint64_t gen1_only:1; + uint64_t prst_link:1; + uint64_t rst_done:1; + uint64_t rst_link:1; + uint64_t host_mode:1; + uint64_t prtmode:2; + uint64_t rst_drv:1; + uint64_t rst_rcv:1; + uint64_t rst_chip:1; + uint64_t rst_val:1; + } s; + struct cvmx_mio_rst_cntlx_s cn61xx; + struct cvmx_mio_rst_cntlx_cn66xx { + uint64_t reserved_10_63:54; + uint64_t prst_link:1; + uint64_t rst_done:1; + uint64_t rst_link:1; + uint64_t host_mode:1; + uint64_t prtmode:2; + uint64_t rst_drv:1; + uint64_t rst_rcv:1; + uint64_t rst_chip:1; + uint64_t rst_val:1; + } cn66xx; + struct cvmx_mio_rst_cntlx_cn66xx cn68xx; }; union cvmx_mio_rst_ctlx { uint64_t u64; struct cvmx_mio_rst_ctlx_s { - uint64_t reserved_10_63:54; + uint64_t reserved_13_63:51; + uint64_t in_rev_ln:1; + uint64_t rev_lanes:1; + uint64_t gen1_only:1; uint64_t prst_link:1; uint64_t rst_done:1; uint64_t rst_link:1; @@ -1334,7 +2136,19 @@ union cvmx_mio_rst_ctlx { uint64_t rst_chip:1; uint64_t rst_val:1; } s; - struct cvmx_mio_rst_ctlx_s cn63xx; + struct cvmx_mio_rst_ctlx_s cn61xx; + struct cvmx_mio_rst_ctlx_cn63xx { + uint64_t reserved_10_63:54; + uint64_t prst_link:1; + uint64_t rst_done:1; + uint64_t rst_link:1; + uint64_t host_mode:1; + uint64_t prtmode:2; + uint64_t rst_drv:1; + uint64_t rst_rcv:1; + uint64_t rst_chip:1; + uint64_t rst_val:1; + } cn63xx; struct cvmx_mio_rst_ctlx_cn63xxp1 { uint64_t reserved_9_63:55; uint64_t rst_done:1; @@ -1346,17 +2160,24 @@ union cvmx_mio_rst_ctlx { uint64_t rst_chip:1; uint64_t rst_val:1; } cn63xxp1; + struct cvmx_mio_rst_ctlx_cn63xx cn66xx; + struct cvmx_mio_rst_ctlx_cn63xx cn68xx; + struct cvmx_mio_rst_ctlx_cn63xx cn68xxp1; }; union cvmx_mio_rst_delay { uint64_t u64; struct cvmx_mio_rst_delay_s { uint64_t reserved_32_63:32; - uint64_t soft_rst_dly:16; uint64_t warm_rst_dly:16; + uint64_t soft_rst_dly:16; } s; + struct cvmx_mio_rst_delay_s cn61xx; struct cvmx_mio_rst_delay_s cn63xx; struct cvmx_mio_rst_delay_s cn63xxp1; + struct cvmx_mio_rst_delay_s cn66xx; + struct cvmx_mio_rst_delay_s cn68xx; + struct cvmx_mio_rst_delay_s cn68xxp1; }; union cvmx_mio_rst_int { @@ -1365,12 +2186,25 @@ union cvmx_mio_rst_int { uint64_t reserved_10_63:54; uint64_t perst1:1; uint64_t perst0:1; - uint64_t reserved_2_7:6; + uint64_t reserved_4_7:4; + uint64_t rst_link3:1; + uint64_t rst_link2:1; uint64_t rst_link1:1; uint64_t rst_link0:1; } s; - struct cvmx_mio_rst_int_s cn63xx; - struct cvmx_mio_rst_int_s cn63xxp1; + struct cvmx_mio_rst_int_cn61xx { + uint64_t reserved_10_63:54; + uint64_t perst1:1; + uint64_t perst0:1; + uint64_t reserved_2_7:6; + uint64_t rst_link1:1; + uint64_t rst_link0:1; + } cn61xx; + struct cvmx_mio_rst_int_cn61xx cn63xx; + struct cvmx_mio_rst_int_cn61xx cn63xxp1; + struct cvmx_mio_rst_int_s cn66xx; + struct cvmx_mio_rst_int_cn61xx cn68xx; + struct cvmx_mio_rst_int_cn61xx cn68xxp1; }; union cvmx_mio_rst_int_en { @@ -1379,12 +2213,25 @@ union cvmx_mio_rst_int_en { uint64_t reserved_10_63:54; uint64_t perst1:1; uint64_t perst0:1; - uint64_t reserved_2_7:6; + uint64_t reserved_4_7:4; + uint64_t rst_link3:1; + uint64_t rst_link2:1; uint64_t rst_link1:1; uint64_t rst_link0:1; } s; - struct cvmx_mio_rst_int_en_s cn63xx; - struct cvmx_mio_rst_int_en_s cn63xxp1; + struct cvmx_mio_rst_int_en_cn61xx { + uint64_t reserved_10_63:54; + uint64_t perst1:1; + uint64_t perst0:1; + uint64_t reserved_2_7:6; + uint64_t rst_link1:1; + uint64_t rst_link0:1; + } cn61xx; + struct cvmx_mio_rst_int_en_cn61xx cn63xx; + struct cvmx_mio_rst_int_en_cn61xx cn63xxp1; + struct cvmx_mio_rst_int_en_s cn66xx; + struct cvmx_mio_rst_int_en_cn61xx cn68xx; + struct cvmx_mio_rst_int_en_cn61xx cn68xxp1; }; union cvmx_mio_twsx_int { @@ -1424,8 +2271,12 @@ union cvmx_mio_twsx_int { struct cvmx_mio_twsx_int_s cn56xxp1; struct cvmx_mio_twsx_int_s cn58xx; struct cvmx_mio_twsx_int_s cn58xxp1; + struct cvmx_mio_twsx_int_s cn61xx; struct cvmx_mio_twsx_int_s cn63xx; struct cvmx_mio_twsx_int_s cn63xxp1; + struct cvmx_mio_twsx_int_s cn66xx; + struct cvmx_mio_twsx_int_s cn68xx; + struct cvmx_mio_twsx_int_s cn68xxp1; }; union cvmx_mio_twsx_sw_twsi { @@ -1455,8 +2306,12 @@ union cvmx_mio_twsx_sw_twsi { struct cvmx_mio_twsx_sw_twsi_s cn56xxp1; struct cvmx_mio_twsx_sw_twsi_s cn58xx; struct cvmx_mio_twsx_sw_twsi_s cn58xxp1; + struct cvmx_mio_twsx_sw_twsi_s cn61xx; struct cvmx_mio_twsx_sw_twsi_s cn63xx; struct cvmx_mio_twsx_sw_twsi_s cn63xxp1; + struct cvmx_mio_twsx_sw_twsi_s cn66xx; + struct cvmx_mio_twsx_sw_twsi_s cn68xx; + struct cvmx_mio_twsx_sw_twsi_s cn68xxp1; }; union cvmx_mio_twsx_sw_twsi_ext { @@ -1477,8 +2332,12 @@ union cvmx_mio_twsx_sw_twsi_ext { struct cvmx_mio_twsx_sw_twsi_ext_s cn56xxp1; struct cvmx_mio_twsx_sw_twsi_ext_s cn58xx; struct cvmx_mio_twsx_sw_twsi_ext_s cn58xxp1; + struct cvmx_mio_twsx_sw_twsi_ext_s cn61xx; struct cvmx_mio_twsx_sw_twsi_ext_s cn63xx; struct cvmx_mio_twsx_sw_twsi_ext_s cn63xxp1; + struct cvmx_mio_twsx_sw_twsi_ext_s cn66xx; + struct cvmx_mio_twsx_sw_twsi_ext_s cn68xx; + struct cvmx_mio_twsx_sw_twsi_ext_s cn68xxp1; }; union cvmx_mio_twsx_twsi_sw { @@ -1499,8 +2358,12 @@ union cvmx_mio_twsx_twsi_sw { struct cvmx_mio_twsx_twsi_sw_s cn56xxp1; struct cvmx_mio_twsx_twsi_sw_s cn58xx; struct cvmx_mio_twsx_twsi_sw_s cn58xxp1; + struct cvmx_mio_twsx_twsi_sw_s cn61xx; struct cvmx_mio_twsx_twsi_sw_s cn63xx; struct cvmx_mio_twsx_twsi_sw_s cn63xxp1; + struct cvmx_mio_twsx_twsi_sw_s cn66xx; + struct cvmx_mio_twsx_twsi_sw_s cn68xx; + struct cvmx_mio_twsx_twsi_sw_s cn68xxp1; }; union cvmx_mio_uartx_dlh { @@ -1520,8 +2383,12 @@ union cvmx_mio_uartx_dlh { struct cvmx_mio_uartx_dlh_s cn56xxp1; struct cvmx_mio_uartx_dlh_s cn58xx; struct cvmx_mio_uartx_dlh_s cn58xxp1; + struct cvmx_mio_uartx_dlh_s cn61xx; struct cvmx_mio_uartx_dlh_s cn63xx; struct cvmx_mio_uartx_dlh_s cn63xxp1; + struct cvmx_mio_uartx_dlh_s cn66xx; + struct cvmx_mio_uartx_dlh_s cn68xx; + struct cvmx_mio_uartx_dlh_s cn68xxp1; }; union cvmx_mio_uartx_dll { @@ -1541,8 +2408,12 @@ union cvmx_mio_uartx_dll { struct cvmx_mio_uartx_dll_s cn56xxp1; struct cvmx_mio_uartx_dll_s cn58xx; struct cvmx_mio_uartx_dll_s cn58xxp1; + struct cvmx_mio_uartx_dll_s cn61xx; struct cvmx_mio_uartx_dll_s cn63xx; struct cvmx_mio_uartx_dll_s cn63xxp1; + struct cvmx_mio_uartx_dll_s cn66xx; + struct cvmx_mio_uartx_dll_s cn68xx; + struct cvmx_mio_uartx_dll_s cn68xxp1; }; union cvmx_mio_uartx_far { @@ -1562,8 +2433,12 @@ union cvmx_mio_uartx_far { struct cvmx_mio_uartx_far_s cn56xxp1; struct cvmx_mio_uartx_far_s cn58xx; struct cvmx_mio_uartx_far_s cn58xxp1; + struct cvmx_mio_uartx_far_s cn61xx; struct cvmx_mio_uartx_far_s cn63xx; struct cvmx_mio_uartx_far_s cn63xxp1; + struct cvmx_mio_uartx_far_s cn66xx; + struct cvmx_mio_uartx_far_s cn68xx; + struct cvmx_mio_uartx_far_s cn68xxp1; }; union cvmx_mio_uartx_fcr { @@ -1588,8 +2463,12 @@ union cvmx_mio_uartx_fcr { struct cvmx_mio_uartx_fcr_s cn56xxp1; struct cvmx_mio_uartx_fcr_s cn58xx; struct cvmx_mio_uartx_fcr_s cn58xxp1; + struct cvmx_mio_uartx_fcr_s cn61xx; struct cvmx_mio_uartx_fcr_s cn63xx; struct cvmx_mio_uartx_fcr_s cn63xxp1; + struct cvmx_mio_uartx_fcr_s cn66xx; + struct cvmx_mio_uartx_fcr_s cn68xx; + struct cvmx_mio_uartx_fcr_s cn68xxp1; }; union cvmx_mio_uartx_htx { @@ -1609,8 +2488,12 @@ union cvmx_mio_uartx_htx { struct cvmx_mio_uartx_htx_s cn56xxp1; struct cvmx_mio_uartx_htx_s cn58xx; struct cvmx_mio_uartx_htx_s cn58xxp1; + struct cvmx_mio_uartx_htx_s cn61xx; struct cvmx_mio_uartx_htx_s cn63xx; struct cvmx_mio_uartx_htx_s cn63xxp1; + struct cvmx_mio_uartx_htx_s cn66xx; + struct cvmx_mio_uartx_htx_s cn68xx; + struct cvmx_mio_uartx_htx_s cn68xxp1; }; union cvmx_mio_uartx_ier { @@ -1635,8 +2518,12 @@ union cvmx_mio_uartx_ier { struct cvmx_mio_uartx_ier_s cn56xxp1; struct cvmx_mio_uartx_ier_s cn58xx; struct cvmx_mio_uartx_ier_s cn58xxp1; + struct cvmx_mio_uartx_ier_s cn61xx; struct cvmx_mio_uartx_ier_s cn63xx; struct cvmx_mio_uartx_ier_s cn63xxp1; + struct cvmx_mio_uartx_ier_s cn66xx; + struct cvmx_mio_uartx_ier_s cn68xx; + struct cvmx_mio_uartx_ier_s cn68xxp1; }; union cvmx_mio_uartx_iir { @@ -1658,8 +2545,12 @@ union cvmx_mio_uartx_iir { struct cvmx_mio_uartx_iir_s cn56xxp1; struct cvmx_mio_uartx_iir_s cn58xx; struct cvmx_mio_uartx_iir_s cn58xxp1; + struct cvmx_mio_uartx_iir_s cn61xx; struct cvmx_mio_uartx_iir_s cn63xx; struct cvmx_mio_uartx_iir_s cn63xxp1; + struct cvmx_mio_uartx_iir_s cn66xx; + struct cvmx_mio_uartx_iir_s cn68xx; + struct cvmx_mio_uartx_iir_s cn68xxp1; }; union cvmx_mio_uartx_lcr { @@ -1685,8 +2576,12 @@ union cvmx_mio_uartx_lcr { struct cvmx_mio_uartx_lcr_s cn56xxp1; struct cvmx_mio_uartx_lcr_s cn58xx; struct cvmx_mio_uartx_lcr_s cn58xxp1; + struct cvmx_mio_uartx_lcr_s cn61xx; struct cvmx_mio_uartx_lcr_s cn63xx; struct cvmx_mio_uartx_lcr_s cn63xxp1; + struct cvmx_mio_uartx_lcr_s cn66xx; + struct cvmx_mio_uartx_lcr_s cn68xx; + struct cvmx_mio_uartx_lcr_s cn68xxp1; }; union cvmx_mio_uartx_lsr { @@ -1713,8 +2608,12 @@ union cvmx_mio_uartx_lsr { struct cvmx_mio_uartx_lsr_s cn56xxp1; struct cvmx_mio_uartx_lsr_s cn58xx; struct cvmx_mio_uartx_lsr_s cn58xxp1; + struct cvmx_mio_uartx_lsr_s cn61xx; struct cvmx_mio_uartx_lsr_s cn63xx; struct cvmx_mio_uartx_lsr_s cn63xxp1; + struct cvmx_mio_uartx_lsr_s cn66xx; + struct cvmx_mio_uartx_lsr_s cn68xx; + struct cvmx_mio_uartx_lsr_s cn68xxp1; }; union cvmx_mio_uartx_mcr { @@ -1739,8 +2638,12 @@ union cvmx_mio_uartx_mcr { struct cvmx_mio_uartx_mcr_s cn56xxp1; struct cvmx_mio_uartx_mcr_s cn58xx; struct cvmx_mio_uartx_mcr_s cn58xxp1; + struct cvmx_mio_uartx_mcr_s cn61xx; struct cvmx_mio_uartx_mcr_s cn63xx; struct cvmx_mio_uartx_mcr_s cn63xxp1; + struct cvmx_mio_uartx_mcr_s cn66xx; + struct cvmx_mio_uartx_mcr_s cn68xx; + struct cvmx_mio_uartx_mcr_s cn68xxp1; }; union cvmx_mio_uartx_msr { @@ -1767,8 +2670,12 @@ union cvmx_mio_uartx_msr { struct cvmx_mio_uartx_msr_s cn56xxp1; struct cvmx_mio_uartx_msr_s cn58xx; struct cvmx_mio_uartx_msr_s cn58xxp1; + struct cvmx_mio_uartx_msr_s cn61xx; struct cvmx_mio_uartx_msr_s cn63xx; struct cvmx_mio_uartx_msr_s cn63xxp1; + struct cvmx_mio_uartx_msr_s cn66xx; + struct cvmx_mio_uartx_msr_s cn68xx; + struct cvmx_mio_uartx_msr_s cn68xxp1; }; union cvmx_mio_uartx_rbr { @@ -1788,8 +2695,12 @@ union cvmx_mio_uartx_rbr { struct cvmx_mio_uartx_rbr_s cn56xxp1; struct cvmx_mio_uartx_rbr_s cn58xx; struct cvmx_mio_uartx_rbr_s cn58xxp1; + struct cvmx_mio_uartx_rbr_s cn61xx; struct cvmx_mio_uartx_rbr_s cn63xx; struct cvmx_mio_uartx_rbr_s cn63xxp1; + struct cvmx_mio_uartx_rbr_s cn66xx; + struct cvmx_mio_uartx_rbr_s cn68xx; + struct cvmx_mio_uartx_rbr_s cn68xxp1; }; union cvmx_mio_uartx_rfl { @@ -1809,8 +2720,12 @@ union cvmx_mio_uartx_rfl { struct cvmx_mio_uartx_rfl_s cn56xxp1; struct cvmx_mio_uartx_rfl_s cn58xx; struct cvmx_mio_uartx_rfl_s cn58xxp1; + struct cvmx_mio_uartx_rfl_s cn61xx; struct cvmx_mio_uartx_rfl_s cn63xx; struct cvmx_mio_uartx_rfl_s cn63xxp1; + struct cvmx_mio_uartx_rfl_s cn66xx; + struct cvmx_mio_uartx_rfl_s cn68xx; + struct cvmx_mio_uartx_rfl_s cn68xxp1; }; union cvmx_mio_uartx_rfw { @@ -1832,8 +2747,12 @@ union cvmx_mio_uartx_rfw { struct cvmx_mio_uartx_rfw_s cn56xxp1; struct cvmx_mio_uartx_rfw_s cn58xx; struct cvmx_mio_uartx_rfw_s cn58xxp1; + struct cvmx_mio_uartx_rfw_s cn61xx; struct cvmx_mio_uartx_rfw_s cn63xx; struct cvmx_mio_uartx_rfw_s cn63xxp1; + struct cvmx_mio_uartx_rfw_s cn66xx; + struct cvmx_mio_uartx_rfw_s cn68xx; + struct cvmx_mio_uartx_rfw_s cn68xxp1; }; union cvmx_mio_uartx_sbcr { @@ -1853,8 +2772,12 @@ union cvmx_mio_uartx_sbcr { struct cvmx_mio_uartx_sbcr_s cn56xxp1; struct cvmx_mio_uartx_sbcr_s cn58xx; struct cvmx_mio_uartx_sbcr_s cn58xxp1; + struct cvmx_mio_uartx_sbcr_s cn61xx; struct cvmx_mio_uartx_sbcr_s cn63xx; struct cvmx_mio_uartx_sbcr_s cn63xxp1; + struct cvmx_mio_uartx_sbcr_s cn66xx; + struct cvmx_mio_uartx_sbcr_s cn68xx; + struct cvmx_mio_uartx_sbcr_s cn68xxp1; }; union cvmx_mio_uartx_scr { @@ -1874,8 +2797,12 @@ union cvmx_mio_uartx_scr { struct cvmx_mio_uartx_scr_s cn56xxp1; struct cvmx_mio_uartx_scr_s cn58xx; struct cvmx_mio_uartx_scr_s cn58xxp1; + struct cvmx_mio_uartx_scr_s cn61xx; struct cvmx_mio_uartx_scr_s cn63xx; struct cvmx_mio_uartx_scr_s cn63xxp1; + struct cvmx_mio_uartx_scr_s cn66xx; + struct cvmx_mio_uartx_scr_s cn68xx; + struct cvmx_mio_uartx_scr_s cn68xxp1; }; union cvmx_mio_uartx_sfe { @@ -1895,8 +2822,12 @@ union cvmx_mio_uartx_sfe { struct cvmx_mio_uartx_sfe_s cn56xxp1; struct cvmx_mio_uartx_sfe_s cn58xx; struct cvmx_mio_uartx_sfe_s cn58xxp1; + struct cvmx_mio_uartx_sfe_s cn61xx; struct cvmx_mio_uartx_sfe_s cn63xx; struct cvmx_mio_uartx_sfe_s cn63xxp1; + struct cvmx_mio_uartx_sfe_s cn66xx; + struct cvmx_mio_uartx_sfe_s cn68xx; + struct cvmx_mio_uartx_sfe_s cn68xxp1; }; union cvmx_mio_uartx_srr { @@ -1918,8 +2849,12 @@ union cvmx_mio_uartx_srr { struct cvmx_mio_uartx_srr_s cn56xxp1; struct cvmx_mio_uartx_srr_s cn58xx; struct cvmx_mio_uartx_srr_s cn58xxp1; + struct cvmx_mio_uartx_srr_s cn61xx; struct cvmx_mio_uartx_srr_s cn63xx; struct cvmx_mio_uartx_srr_s cn63xxp1; + struct cvmx_mio_uartx_srr_s cn66xx; + struct cvmx_mio_uartx_srr_s cn68xx; + struct cvmx_mio_uartx_srr_s cn68xxp1; }; union cvmx_mio_uartx_srt { @@ -1939,8 +2874,12 @@ union cvmx_mio_uartx_srt { struct cvmx_mio_uartx_srt_s cn56xxp1; struct cvmx_mio_uartx_srt_s cn58xx; struct cvmx_mio_uartx_srt_s cn58xxp1; + struct cvmx_mio_uartx_srt_s cn61xx; struct cvmx_mio_uartx_srt_s cn63xx; struct cvmx_mio_uartx_srt_s cn63xxp1; + struct cvmx_mio_uartx_srt_s cn66xx; + struct cvmx_mio_uartx_srt_s cn68xx; + struct cvmx_mio_uartx_srt_s cn68xxp1; }; union cvmx_mio_uartx_srts { @@ -1960,8 +2899,12 @@ union cvmx_mio_uartx_srts { struct cvmx_mio_uartx_srts_s cn56xxp1; struct cvmx_mio_uartx_srts_s cn58xx; struct cvmx_mio_uartx_srts_s cn58xxp1; + struct cvmx_mio_uartx_srts_s cn61xx; struct cvmx_mio_uartx_srts_s cn63xx; struct cvmx_mio_uartx_srts_s cn63xxp1; + struct cvmx_mio_uartx_srts_s cn66xx; + struct cvmx_mio_uartx_srts_s cn68xx; + struct cvmx_mio_uartx_srts_s cn68xxp1; }; union cvmx_mio_uartx_stt { @@ -1981,8 +2924,12 @@ union cvmx_mio_uartx_stt { struct cvmx_mio_uartx_stt_s cn56xxp1; struct cvmx_mio_uartx_stt_s cn58xx; struct cvmx_mio_uartx_stt_s cn58xxp1; + struct cvmx_mio_uartx_stt_s cn61xx; struct cvmx_mio_uartx_stt_s cn63xx; struct cvmx_mio_uartx_stt_s cn63xxp1; + struct cvmx_mio_uartx_stt_s cn66xx; + struct cvmx_mio_uartx_stt_s cn68xx; + struct cvmx_mio_uartx_stt_s cn68xxp1; }; union cvmx_mio_uartx_tfl { @@ -2002,8 +2949,12 @@ union cvmx_mio_uartx_tfl { struct cvmx_mio_uartx_tfl_s cn56xxp1; struct cvmx_mio_uartx_tfl_s cn58xx; struct cvmx_mio_uartx_tfl_s cn58xxp1; + struct cvmx_mio_uartx_tfl_s cn61xx; struct cvmx_mio_uartx_tfl_s cn63xx; struct cvmx_mio_uartx_tfl_s cn63xxp1; + struct cvmx_mio_uartx_tfl_s cn66xx; + struct cvmx_mio_uartx_tfl_s cn68xx; + struct cvmx_mio_uartx_tfl_s cn68xxp1; }; union cvmx_mio_uartx_tfr { @@ -2023,8 +2974,12 @@ union cvmx_mio_uartx_tfr { struct cvmx_mio_uartx_tfr_s cn56xxp1; struct cvmx_mio_uartx_tfr_s cn58xx; struct cvmx_mio_uartx_tfr_s cn58xxp1; + struct cvmx_mio_uartx_tfr_s cn61xx; struct cvmx_mio_uartx_tfr_s cn63xx; struct cvmx_mio_uartx_tfr_s cn63xxp1; + struct cvmx_mio_uartx_tfr_s cn66xx; + struct cvmx_mio_uartx_tfr_s cn68xx; + struct cvmx_mio_uartx_tfr_s cn68xxp1; }; union cvmx_mio_uartx_thr { @@ -2044,8 +2999,12 @@ union cvmx_mio_uartx_thr { struct cvmx_mio_uartx_thr_s cn56xxp1; struct cvmx_mio_uartx_thr_s cn58xx; struct cvmx_mio_uartx_thr_s cn58xxp1; + struct cvmx_mio_uartx_thr_s cn61xx; struct cvmx_mio_uartx_thr_s cn63xx; struct cvmx_mio_uartx_thr_s cn63xxp1; + struct cvmx_mio_uartx_thr_s cn66xx; + struct cvmx_mio_uartx_thr_s cn68xx; + struct cvmx_mio_uartx_thr_s cn68xxp1; }; union cvmx_mio_uartx_usr { @@ -2069,8 +3028,12 @@ union cvmx_mio_uartx_usr { struct cvmx_mio_uartx_usr_s cn56xxp1; struct cvmx_mio_uartx_usr_s cn58xx; struct cvmx_mio_uartx_usr_s cn58xxp1; + struct cvmx_mio_uartx_usr_s cn61xx; struct cvmx_mio_uartx_usr_s cn63xx; struct cvmx_mio_uartx_usr_s cn63xxp1; + struct cvmx_mio_uartx_usr_s cn66xx; + struct cvmx_mio_uartx_usr_s cn68xx; + struct cvmx_mio_uartx_usr_s cn68xxp1; }; union cvmx_mio_uart2_dlh { diff --git a/arch/mips/include/asm/octeon/cvmx-npei-defs.h b/arch/mips/include/asm/octeon/cvmx-npei-defs.h index 9899a9d2ba72..a3075f733ca5 100644 --- a/arch/mips/include/asm/octeon/cvmx-npei-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-npei-defs.h @@ -4,7 +4,7 @@ * Contact: support@caviumnetworks.com * This file is part of the OCTEON SDK * - * Copyright (c) 2003-2010 Cavium Networks + * Copyright (c) 2003-2011 Cavium Networks * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as @@ -65,7 +65,7 @@ #define CVMX_NPEI_LAST_WIN_RDATA0 (0x0000000000000600ull) #define CVMX_NPEI_LAST_WIN_RDATA1 (0x0000000000000610ull) #define CVMX_NPEI_MEM_ACCESS_CTL (0x00000000000004F0ull) -#define CVMX_NPEI_MEM_ACCESS_SUBIDX(offset) (0x0000000000000340ull + ((offset) & 31) * 16 - 16*12) +#define CVMX_NPEI_MEM_ACCESS_SUBIDX(offset) (0x0000000000000280ull + ((offset) & 31) * 16 - 16*12) #define CVMX_NPEI_MSI_ENB0 (0x0000000000003C50ull) #define CVMX_NPEI_MSI_ENB1 (0x0000000000003C60ull) #define CVMX_NPEI_MSI_ENB2 (0x0000000000003C70ull) diff --git a/arch/mips/include/asm/octeon/cvmx-pciercx-defs.h b/arch/mips/include/asm/octeon/cvmx-pciercx-defs.h index f8cb88902efb..7b1dc8b74e5b 100644 --- a/arch/mips/include/asm/octeon/cvmx-pciercx-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-pciercx-defs.h @@ -4,7 +4,7 @@ * Contact: support@caviumnetworks.com * This file is part of the OCTEON SDK * - * Copyright (c) 2003-2010 Cavium Networks + * Copyright (c) 2003-2011 Cavium Networks * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as @@ -116,8 +116,12 @@ union cvmx_pciercx_cfg000 { struct cvmx_pciercx_cfg000_s cn52xxp1; struct cvmx_pciercx_cfg000_s cn56xx; struct cvmx_pciercx_cfg000_s cn56xxp1; + struct cvmx_pciercx_cfg000_s cn61xx; struct cvmx_pciercx_cfg000_s cn63xx; struct cvmx_pciercx_cfg000_s cn63xxp1; + struct cvmx_pciercx_cfg000_s cn66xx; + struct cvmx_pciercx_cfg000_s cn68xx; + struct cvmx_pciercx_cfg000_s cn68xxp1; }; union cvmx_pciercx_cfg001 { @@ -152,8 +156,12 @@ union cvmx_pciercx_cfg001 { struct cvmx_pciercx_cfg001_s cn52xxp1; struct cvmx_pciercx_cfg001_s cn56xx; struct cvmx_pciercx_cfg001_s cn56xxp1; + struct cvmx_pciercx_cfg001_s cn61xx; struct cvmx_pciercx_cfg001_s cn63xx; struct cvmx_pciercx_cfg001_s cn63xxp1; + struct cvmx_pciercx_cfg001_s cn66xx; + struct cvmx_pciercx_cfg001_s cn68xx; + struct cvmx_pciercx_cfg001_s cn68xxp1; }; union cvmx_pciercx_cfg002 { @@ -168,8 +176,12 @@ union cvmx_pciercx_cfg002 { struct cvmx_pciercx_cfg002_s cn52xxp1; struct cvmx_pciercx_cfg002_s cn56xx; struct cvmx_pciercx_cfg002_s cn56xxp1; + struct cvmx_pciercx_cfg002_s cn61xx; struct cvmx_pciercx_cfg002_s cn63xx; struct cvmx_pciercx_cfg002_s cn63xxp1; + struct cvmx_pciercx_cfg002_s cn66xx; + struct cvmx_pciercx_cfg002_s cn68xx; + struct cvmx_pciercx_cfg002_s cn68xxp1; }; union cvmx_pciercx_cfg003 { @@ -185,8 +197,12 @@ union cvmx_pciercx_cfg003 { struct cvmx_pciercx_cfg003_s cn52xxp1; struct cvmx_pciercx_cfg003_s cn56xx; struct cvmx_pciercx_cfg003_s cn56xxp1; + struct cvmx_pciercx_cfg003_s cn61xx; struct cvmx_pciercx_cfg003_s cn63xx; struct cvmx_pciercx_cfg003_s cn63xxp1; + struct cvmx_pciercx_cfg003_s cn66xx; + struct cvmx_pciercx_cfg003_s cn68xx; + struct cvmx_pciercx_cfg003_s cn68xxp1; }; union cvmx_pciercx_cfg004 { @@ -198,8 +214,12 @@ union cvmx_pciercx_cfg004 { struct cvmx_pciercx_cfg004_s cn52xxp1; struct cvmx_pciercx_cfg004_s cn56xx; struct cvmx_pciercx_cfg004_s cn56xxp1; + struct cvmx_pciercx_cfg004_s cn61xx; struct cvmx_pciercx_cfg004_s cn63xx; struct cvmx_pciercx_cfg004_s cn63xxp1; + struct cvmx_pciercx_cfg004_s cn66xx; + struct cvmx_pciercx_cfg004_s cn68xx; + struct cvmx_pciercx_cfg004_s cn68xxp1; }; union cvmx_pciercx_cfg005 { @@ -211,8 +231,12 @@ union cvmx_pciercx_cfg005 { struct cvmx_pciercx_cfg005_s cn52xxp1; struct cvmx_pciercx_cfg005_s cn56xx; struct cvmx_pciercx_cfg005_s cn56xxp1; + struct cvmx_pciercx_cfg005_s cn61xx; struct cvmx_pciercx_cfg005_s cn63xx; struct cvmx_pciercx_cfg005_s cn63xxp1; + struct cvmx_pciercx_cfg005_s cn66xx; + struct cvmx_pciercx_cfg005_s cn68xx; + struct cvmx_pciercx_cfg005_s cn68xxp1; }; union cvmx_pciercx_cfg006 { @@ -227,8 +251,12 @@ union cvmx_pciercx_cfg006 { struct cvmx_pciercx_cfg006_s cn52xxp1; struct cvmx_pciercx_cfg006_s cn56xx; struct cvmx_pciercx_cfg006_s cn56xxp1; + struct cvmx_pciercx_cfg006_s cn61xx; struct cvmx_pciercx_cfg006_s cn63xx; struct cvmx_pciercx_cfg006_s cn63xxp1; + struct cvmx_pciercx_cfg006_s cn66xx; + struct cvmx_pciercx_cfg006_s cn68xx; + struct cvmx_pciercx_cfg006_s cn68xxp1; }; union cvmx_pciercx_cfg007 { @@ -256,8 +284,12 @@ union cvmx_pciercx_cfg007 { struct cvmx_pciercx_cfg007_s cn52xxp1; struct cvmx_pciercx_cfg007_s cn56xx; struct cvmx_pciercx_cfg007_s cn56xxp1; + struct cvmx_pciercx_cfg007_s cn61xx; struct cvmx_pciercx_cfg007_s cn63xx; struct cvmx_pciercx_cfg007_s cn63xxp1; + struct cvmx_pciercx_cfg007_s cn66xx; + struct cvmx_pciercx_cfg007_s cn68xx; + struct cvmx_pciercx_cfg007_s cn68xxp1; }; union cvmx_pciercx_cfg008 { @@ -272,8 +304,12 @@ union cvmx_pciercx_cfg008 { struct cvmx_pciercx_cfg008_s cn52xxp1; struct cvmx_pciercx_cfg008_s cn56xx; struct cvmx_pciercx_cfg008_s cn56xxp1; + struct cvmx_pciercx_cfg008_s cn61xx; struct cvmx_pciercx_cfg008_s cn63xx; struct cvmx_pciercx_cfg008_s cn63xxp1; + struct cvmx_pciercx_cfg008_s cn66xx; + struct cvmx_pciercx_cfg008_s cn68xx; + struct cvmx_pciercx_cfg008_s cn68xxp1; }; union cvmx_pciercx_cfg009 { @@ -290,8 +326,12 @@ union cvmx_pciercx_cfg009 { struct cvmx_pciercx_cfg009_s cn52xxp1; struct cvmx_pciercx_cfg009_s cn56xx; struct cvmx_pciercx_cfg009_s cn56xxp1; + struct cvmx_pciercx_cfg009_s cn61xx; struct cvmx_pciercx_cfg009_s cn63xx; struct cvmx_pciercx_cfg009_s cn63xxp1; + struct cvmx_pciercx_cfg009_s cn66xx; + struct cvmx_pciercx_cfg009_s cn68xx; + struct cvmx_pciercx_cfg009_s cn68xxp1; }; union cvmx_pciercx_cfg010 { @@ -303,8 +343,12 @@ union cvmx_pciercx_cfg010 { struct cvmx_pciercx_cfg010_s cn52xxp1; struct cvmx_pciercx_cfg010_s cn56xx; struct cvmx_pciercx_cfg010_s cn56xxp1; + struct cvmx_pciercx_cfg010_s cn61xx; struct cvmx_pciercx_cfg010_s cn63xx; struct cvmx_pciercx_cfg010_s cn63xxp1; + struct cvmx_pciercx_cfg010_s cn66xx; + struct cvmx_pciercx_cfg010_s cn68xx; + struct cvmx_pciercx_cfg010_s cn68xxp1; }; union cvmx_pciercx_cfg011 { @@ -316,8 +360,12 @@ union cvmx_pciercx_cfg011 { struct cvmx_pciercx_cfg011_s cn52xxp1; struct cvmx_pciercx_cfg011_s cn56xx; struct cvmx_pciercx_cfg011_s cn56xxp1; + struct cvmx_pciercx_cfg011_s cn61xx; struct cvmx_pciercx_cfg011_s cn63xx; struct cvmx_pciercx_cfg011_s cn63xxp1; + struct cvmx_pciercx_cfg011_s cn66xx; + struct cvmx_pciercx_cfg011_s cn68xx; + struct cvmx_pciercx_cfg011_s cn68xxp1; }; union cvmx_pciercx_cfg012 { @@ -330,8 +378,12 @@ union cvmx_pciercx_cfg012 { struct cvmx_pciercx_cfg012_s cn52xxp1; struct cvmx_pciercx_cfg012_s cn56xx; struct cvmx_pciercx_cfg012_s cn56xxp1; + struct cvmx_pciercx_cfg012_s cn61xx; struct cvmx_pciercx_cfg012_s cn63xx; struct cvmx_pciercx_cfg012_s cn63xxp1; + struct cvmx_pciercx_cfg012_s cn66xx; + struct cvmx_pciercx_cfg012_s cn68xx; + struct cvmx_pciercx_cfg012_s cn68xxp1; }; union cvmx_pciercx_cfg013 { @@ -344,8 +396,12 @@ union cvmx_pciercx_cfg013 { struct cvmx_pciercx_cfg013_s cn52xxp1; struct cvmx_pciercx_cfg013_s cn56xx; struct cvmx_pciercx_cfg013_s cn56xxp1; + struct cvmx_pciercx_cfg013_s cn61xx; struct cvmx_pciercx_cfg013_s cn63xx; struct cvmx_pciercx_cfg013_s cn63xxp1; + struct cvmx_pciercx_cfg013_s cn66xx; + struct cvmx_pciercx_cfg013_s cn68xx; + struct cvmx_pciercx_cfg013_s cn68xxp1; }; union cvmx_pciercx_cfg014 { @@ -357,8 +413,12 @@ union cvmx_pciercx_cfg014 { struct cvmx_pciercx_cfg014_s cn52xxp1; struct cvmx_pciercx_cfg014_s cn56xx; struct cvmx_pciercx_cfg014_s cn56xxp1; + struct cvmx_pciercx_cfg014_s cn61xx; struct cvmx_pciercx_cfg014_s cn63xx; struct cvmx_pciercx_cfg014_s cn63xxp1; + struct cvmx_pciercx_cfg014_s cn66xx; + struct cvmx_pciercx_cfg014_s cn68xx; + struct cvmx_pciercx_cfg014_s cn68xxp1; }; union cvmx_pciercx_cfg015 { @@ -384,8 +444,12 @@ union cvmx_pciercx_cfg015 { struct cvmx_pciercx_cfg015_s cn52xxp1; struct cvmx_pciercx_cfg015_s cn56xx; struct cvmx_pciercx_cfg015_s cn56xxp1; + struct cvmx_pciercx_cfg015_s cn61xx; struct cvmx_pciercx_cfg015_s cn63xx; struct cvmx_pciercx_cfg015_s cn63xxp1; + struct cvmx_pciercx_cfg015_s cn66xx; + struct cvmx_pciercx_cfg015_s cn68xx; + struct cvmx_pciercx_cfg015_s cn68xxp1; }; union cvmx_pciercx_cfg016 { @@ -406,8 +470,12 @@ union cvmx_pciercx_cfg016 { struct cvmx_pciercx_cfg016_s cn52xxp1; struct cvmx_pciercx_cfg016_s cn56xx; struct cvmx_pciercx_cfg016_s cn56xxp1; + struct cvmx_pciercx_cfg016_s cn61xx; struct cvmx_pciercx_cfg016_s cn63xx; struct cvmx_pciercx_cfg016_s cn63xxp1; + struct cvmx_pciercx_cfg016_s cn66xx; + struct cvmx_pciercx_cfg016_s cn68xx; + struct cvmx_pciercx_cfg016_s cn68xxp1; }; union cvmx_pciercx_cfg017 { @@ -430,14 +498,19 @@ union cvmx_pciercx_cfg017 { struct cvmx_pciercx_cfg017_s cn52xxp1; struct cvmx_pciercx_cfg017_s cn56xx; struct cvmx_pciercx_cfg017_s cn56xxp1; + struct cvmx_pciercx_cfg017_s cn61xx; struct cvmx_pciercx_cfg017_s cn63xx; struct cvmx_pciercx_cfg017_s cn63xxp1; + struct cvmx_pciercx_cfg017_s cn66xx; + struct cvmx_pciercx_cfg017_s cn68xx; + struct cvmx_pciercx_cfg017_s cn68xxp1; }; union cvmx_pciercx_cfg020 { uint32_t u32; struct cvmx_pciercx_cfg020_s { - uint32_t reserved_24_31:8; + uint32_t reserved_25_31:7; + uint32_t pvm:1; uint32_t m64:1; uint32_t mme:3; uint32_t mmc:3; @@ -445,12 +518,24 @@ union cvmx_pciercx_cfg020 { uint32_t ncp:8; uint32_t msicid:8; } s; - struct cvmx_pciercx_cfg020_s cn52xx; - struct cvmx_pciercx_cfg020_s cn52xxp1; - struct cvmx_pciercx_cfg020_s cn56xx; - struct cvmx_pciercx_cfg020_s cn56xxp1; - struct cvmx_pciercx_cfg020_s cn63xx; - struct cvmx_pciercx_cfg020_s cn63xxp1; + struct cvmx_pciercx_cfg020_cn52xx { + uint32_t reserved_24_31:8; + uint32_t m64:1; + uint32_t mme:3; + uint32_t mmc:3; + uint32_t msien:1; + uint32_t ncp:8; + uint32_t msicid:8; + } cn52xx; + struct cvmx_pciercx_cfg020_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg020_cn52xx cn56xx; + struct cvmx_pciercx_cfg020_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg020_s cn61xx; + struct cvmx_pciercx_cfg020_cn52xx cn63xx; + struct cvmx_pciercx_cfg020_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg020_cn52xx cn66xx; + struct cvmx_pciercx_cfg020_cn52xx cn68xx; + struct cvmx_pciercx_cfg020_cn52xx cn68xxp1; }; union cvmx_pciercx_cfg021 { @@ -463,8 +548,12 @@ union cvmx_pciercx_cfg021 { struct cvmx_pciercx_cfg021_s cn52xxp1; struct cvmx_pciercx_cfg021_s cn56xx; struct cvmx_pciercx_cfg021_s cn56xxp1; + struct cvmx_pciercx_cfg021_s cn61xx; struct cvmx_pciercx_cfg021_s cn63xx; struct cvmx_pciercx_cfg021_s cn63xxp1; + struct cvmx_pciercx_cfg021_s cn66xx; + struct cvmx_pciercx_cfg021_s cn68xx; + struct cvmx_pciercx_cfg021_s cn68xxp1; }; union cvmx_pciercx_cfg022 { @@ -476,8 +565,12 @@ union cvmx_pciercx_cfg022 { struct cvmx_pciercx_cfg022_s cn52xxp1; struct cvmx_pciercx_cfg022_s cn56xx; struct cvmx_pciercx_cfg022_s cn56xxp1; + struct cvmx_pciercx_cfg022_s cn61xx; struct cvmx_pciercx_cfg022_s cn63xx; struct cvmx_pciercx_cfg022_s cn63xxp1; + struct cvmx_pciercx_cfg022_s cn66xx; + struct cvmx_pciercx_cfg022_s cn68xx; + struct cvmx_pciercx_cfg022_s cn68xxp1; }; union cvmx_pciercx_cfg023 { @@ -490,8 +583,12 @@ union cvmx_pciercx_cfg023 { struct cvmx_pciercx_cfg023_s cn52xxp1; struct cvmx_pciercx_cfg023_s cn56xx; struct cvmx_pciercx_cfg023_s cn56xxp1; + struct cvmx_pciercx_cfg023_s cn61xx; struct cvmx_pciercx_cfg023_s cn63xx; struct cvmx_pciercx_cfg023_s cn63xxp1; + struct cvmx_pciercx_cfg023_s cn66xx; + struct cvmx_pciercx_cfg023_s cn68xx; + struct cvmx_pciercx_cfg023_s cn68xxp1; }; union cvmx_pciercx_cfg028 { @@ -509,8 +606,12 @@ union cvmx_pciercx_cfg028 { struct cvmx_pciercx_cfg028_s cn52xxp1; struct cvmx_pciercx_cfg028_s cn56xx; struct cvmx_pciercx_cfg028_s cn56xxp1; + struct cvmx_pciercx_cfg028_s cn61xx; struct cvmx_pciercx_cfg028_s cn63xx; struct cvmx_pciercx_cfg028_s cn63xxp1; + struct cvmx_pciercx_cfg028_s cn66xx; + struct cvmx_pciercx_cfg028_s cn68xx; + struct cvmx_pciercx_cfg028_s cn68xxp1; }; union cvmx_pciercx_cfg029 { @@ -532,8 +633,12 @@ union cvmx_pciercx_cfg029 { struct cvmx_pciercx_cfg029_s cn52xxp1; struct cvmx_pciercx_cfg029_s cn56xx; struct cvmx_pciercx_cfg029_s cn56xxp1; + struct cvmx_pciercx_cfg029_s cn61xx; struct cvmx_pciercx_cfg029_s cn63xx; struct cvmx_pciercx_cfg029_s cn63xxp1; + struct cvmx_pciercx_cfg029_s cn66xx; + struct cvmx_pciercx_cfg029_s cn68xx; + struct cvmx_pciercx_cfg029_s cn68xxp1; }; union cvmx_pciercx_cfg030 { @@ -563,15 +668,20 @@ union cvmx_pciercx_cfg030 { struct cvmx_pciercx_cfg030_s cn52xxp1; struct cvmx_pciercx_cfg030_s cn56xx; struct cvmx_pciercx_cfg030_s cn56xxp1; + struct cvmx_pciercx_cfg030_s cn61xx; struct cvmx_pciercx_cfg030_s cn63xx; struct cvmx_pciercx_cfg030_s cn63xxp1; + struct cvmx_pciercx_cfg030_s cn66xx; + struct cvmx_pciercx_cfg030_s cn68xx; + struct cvmx_pciercx_cfg030_s cn68xxp1; }; union cvmx_pciercx_cfg031 { uint32_t u32; struct cvmx_pciercx_cfg031_s { uint32_t pnum:8; - uint32_t reserved_22_23:2; + uint32_t reserved_23_23:1; + uint32_t aspm:1; uint32_t lbnc:1; uint32_t dllarc:1; uint32_t sderc:1; @@ -582,12 +692,28 @@ union cvmx_pciercx_cfg031 { uint32_t mlw:6; uint32_t mls:4; } s; - struct cvmx_pciercx_cfg031_s cn52xx; - struct cvmx_pciercx_cfg031_s cn52xxp1; - struct cvmx_pciercx_cfg031_s cn56xx; - struct cvmx_pciercx_cfg031_s cn56xxp1; - struct cvmx_pciercx_cfg031_s cn63xx; - struct cvmx_pciercx_cfg031_s cn63xxp1; + struct cvmx_pciercx_cfg031_cn52xx { + uint32_t pnum:8; + uint32_t reserved_22_23:2; + uint32_t lbnc:1; + uint32_t dllarc:1; + uint32_t sderc:1; + uint32_t cpm:1; + uint32_t l1el:3; + uint32_t l0el:3; + uint32_t aslpms:2; + uint32_t mlw:6; + uint32_t mls:4; + } cn52xx; + struct cvmx_pciercx_cfg031_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg031_cn52xx cn56xx; + struct cvmx_pciercx_cfg031_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg031_s cn61xx; + struct cvmx_pciercx_cfg031_cn52xx cn63xx; + struct cvmx_pciercx_cfg031_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg031_s cn66xx; + struct cvmx_pciercx_cfg031_s cn68xx; + struct cvmx_pciercx_cfg031_cn52xx cn68xxp1; }; union cvmx_pciercx_cfg032 { @@ -618,8 +744,12 @@ union cvmx_pciercx_cfg032 { struct cvmx_pciercx_cfg032_s cn52xxp1; struct cvmx_pciercx_cfg032_s cn56xx; struct cvmx_pciercx_cfg032_s cn56xxp1; + struct cvmx_pciercx_cfg032_s cn61xx; struct cvmx_pciercx_cfg032_s cn63xx; struct cvmx_pciercx_cfg032_s cn63xxp1; + struct cvmx_pciercx_cfg032_s cn66xx; + struct cvmx_pciercx_cfg032_s cn68xx; + struct cvmx_pciercx_cfg032_s cn68xxp1; }; union cvmx_pciercx_cfg033 { @@ -642,8 +772,12 @@ union cvmx_pciercx_cfg033 { struct cvmx_pciercx_cfg033_s cn52xxp1; struct cvmx_pciercx_cfg033_s cn56xx; struct cvmx_pciercx_cfg033_s cn56xxp1; + struct cvmx_pciercx_cfg033_s cn61xx; struct cvmx_pciercx_cfg033_s cn63xx; struct cvmx_pciercx_cfg033_s cn63xxp1; + struct cvmx_pciercx_cfg033_s cn66xx; + struct cvmx_pciercx_cfg033_s cn68xx; + struct cvmx_pciercx_cfg033_s cn68xxp1; }; union cvmx_pciercx_cfg034 { @@ -676,8 +810,12 @@ union cvmx_pciercx_cfg034 { struct cvmx_pciercx_cfg034_s cn52xxp1; struct cvmx_pciercx_cfg034_s cn56xx; struct cvmx_pciercx_cfg034_s cn56xxp1; + struct cvmx_pciercx_cfg034_s cn61xx; struct cvmx_pciercx_cfg034_s cn63xx; struct cvmx_pciercx_cfg034_s cn63xxp1; + struct cvmx_pciercx_cfg034_s cn66xx; + struct cvmx_pciercx_cfg034_s cn68xx; + struct cvmx_pciercx_cfg034_s cn68xxp1; }; union cvmx_pciercx_cfg035 { @@ -696,8 +834,12 @@ union cvmx_pciercx_cfg035 { struct cvmx_pciercx_cfg035_s cn52xxp1; struct cvmx_pciercx_cfg035_s cn56xx; struct cvmx_pciercx_cfg035_s cn56xxp1; + struct cvmx_pciercx_cfg035_s cn61xx; struct cvmx_pciercx_cfg035_s cn63xx; struct cvmx_pciercx_cfg035_s cn63xxp1; + struct cvmx_pciercx_cfg035_s cn66xx; + struct cvmx_pciercx_cfg035_s cn68xx; + struct cvmx_pciercx_cfg035_s cn68xxp1; }; union cvmx_pciercx_cfg036 { @@ -712,38 +854,95 @@ union cvmx_pciercx_cfg036 { struct cvmx_pciercx_cfg036_s cn52xxp1; struct cvmx_pciercx_cfg036_s cn56xx; struct cvmx_pciercx_cfg036_s cn56xxp1; + struct cvmx_pciercx_cfg036_s cn61xx; struct cvmx_pciercx_cfg036_s cn63xx; struct cvmx_pciercx_cfg036_s cn63xxp1; + struct cvmx_pciercx_cfg036_s cn66xx; + struct cvmx_pciercx_cfg036_s cn68xx; + struct cvmx_pciercx_cfg036_s cn68xxp1; }; union cvmx_pciercx_cfg037 { uint32_t u32; struct cvmx_pciercx_cfg037_s { - uint32_t reserved_5_31:27; + uint32_t reserved_14_31:18; + uint32_t tph:2; + uint32_t reserved_11_11:1; + uint32_t noroprpr:1; + uint32_t atom128s:1; + uint32_t atom64s:1; + uint32_t atom32s:1; + uint32_t atom_ops:1; + uint32_t reserved_5_5:1; uint32_t ctds:1; uint32_t ctrs:4; } s; - struct cvmx_pciercx_cfg037_s cn52xx; - struct cvmx_pciercx_cfg037_s cn52xxp1; - struct cvmx_pciercx_cfg037_s cn56xx; - struct cvmx_pciercx_cfg037_s cn56xxp1; - struct cvmx_pciercx_cfg037_s cn63xx; - struct cvmx_pciercx_cfg037_s cn63xxp1; + struct cvmx_pciercx_cfg037_cn52xx { + uint32_t reserved_5_31:27; + uint32_t ctds:1; + uint32_t ctrs:4; + } cn52xx; + struct cvmx_pciercx_cfg037_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg037_cn52xx cn56xx; + struct cvmx_pciercx_cfg037_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg037_cn61xx { + uint32_t reserved_14_31:18; + uint32_t tph:2; + uint32_t reserved_11_11:1; + uint32_t noroprpr:1; + uint32_t atom128s:1; + uint32_t atom64s:1; + uint32_t atom32s:1; + uint32_t atom_ops:1; + uint32_t ari_fw:1; + uint32_t ctds:1; + uint32_t ctrs:4; + } cn61xx; + struct cvmx_pciercx_cfg037_cn52xx cn63xx; + struct cvmx_pciercx_cfg037_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg037_cn66xx { + uint32_t reserved_14_31:18; + uint32_t tph:2; + uint32_t reserved_11_11:1; + uint32_t noroprpr:1; + uint32_t atom128s:1; + uint32_t atom64s:1; + uint32_t atom32s:1; + uint32_t atom_ops:1; + uint32_t ari:1; + uint32_t ctds:1; + uint32_t ctrs:4; + } cn66xx; + struct cvmx_pciercx_cfg037_cn66xx cn68xx; + struct cvmx_pciercx_cfg037_cn66xx cn68xxp1; }; union cvmx_pciercx_cfg038 { uint32_t u32; struct cvmx_pciercx_cfg038_s { - uint32_t reserved_5_31:27; + uint32_t reserved_10_31:22; + uint32_t id0_cp:1; + uint32_t id0_rq:1; + uint32_t atom_op_eb:1; + uint32_t atom_op:1; + uint32_t ari:1; uint32_t ctd:1; uint32_t ctv:4; } s; - struct cvmx_pciercx_cfg038_s cn52xx; - struct cvmx_pciercx_cfg038_s cn52xxp1; - struct cvmx_pciercx_cfg038_s cn56xx; - struct cvmx_pciercx_cfg038_s cn56xxp1; - struct cvmx_pciercx_cfg038_s cn63xx; - struct cvmx_pciercx_cfg038_s cn63xxp1; + struct cvmx_pciercx_cfg038_cn52xx { + uint32_t reserved_5_31:27; + uint32_t ctd:1; + uint32_t ctv:4; + } cn52xx; + struct cvmx_pciercx_cfg038_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg038_cn52xx cn56xx; + struct cvmx_pciercx_cfg038_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg038_s cn61xx; + struct cvmx_pciercx_cfg038_cn52xx cn63xx; + struct cvmx_pciercx_cfg038_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg038_s cn66xx; + struct cvmx_pciercx_cfg038_s cn68xx; + struct cvmx_pciercx_cfg038_s cn68xxp1; }; union cvmx_pciercx_cfg039 { @@ -760,8 +959,12 @@ union cvmx_pciercx_cfg039 { struct cvmx_pciercx_cfg039_cn52xx cn52xxp1; struct cvmx_pciercx_cfg039_cn52xx cn56xx; struct cvmx_pciercx_cfg039_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg039_s cn61xx; struct cvmx_pciercx_cfg039_s cn63xx; struct cvmx_pciercx_cfg039_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg039_s cn66xx; + struct cvmx_pciercx_cfg039_s cn68xx; + struct cvmx_pciercx_cfg039_s cn68xxp1; }; union cvmx_pciercx_cfg040 { @@ -785,8 +988,12 @@ union cvmx_pciercx_cfg040 { struct cvmx_pciercx_cfg040_cn52xx cn52xxp1; struct cvmx_pciercx_cfg040_cn52xx cn56xx; struct cvmx_pciercx_cfg040_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg040_s cn61xx; struct cvmx_pciercx_cfg040_s cn63xx; struct cvmx_pciercx_cfg040_s cn63xxp1; + struct cvmx_pciercx_cfg040_s cn66xx; + struct cvmx_pciercx_cfg040_s cn68xx; + struct cvmx_pciercx_cfg040_s cn68xxp1; }; union cvmx_pciercx_cfg041 { @@ -798,8 +1005,12 @@ union cvmx_pciercx_cfg041 { struct cvmx_pciercx_cfg041_s cn52xxp1; struct cvmx_pciercx_cfg041_s cn56xx; struct cvmx_pciercx_cfg041_s cn56xxp1; + struct cvmx_pciercx_cfg041_s cn61xx; struct cvmx_pciercx_cfg041_s cn63xx; struct cvmx_pciercx_cfg041_s cn63xxp1; + struct cvmx_pciercx_cfg041_s cn66xx; + struct cvmx_pciercx_cfg041_s cn68xx; + struct cvmx_pciercx_cfg041_s cn68xxp1; }; union cvmx_pciercx_cfg042 { @@ -811,8 +1022,12 @@ union cvmx_pciercx_cfg042 { struct cvmx_pciercx_cfg042_s cn52xxp1; struct cvmx_pciercx_cfg042_s cn56xx; struct cvmx_pciercx_cfg042_s cn56xxp1; + struct cvmx_pciercx_cfg042_s cn61xx; struct cvmx_pciercx_cfg042_s cn63xx; struct cvmx_pciercx_cfg042_s cn63xxp1; + struct cvmx_pciercx_cfg042_s cn66xx; + struct cvmx_pciercx_cfg042_s cn68xx; + struct cvmx_pciercx_cfg042_s cn68xxp1; }; union cvmx_pciercx_cfg064 { @@ -826,14 +1041,20 @@ union cvmx_pciercx_cfg064 { struct cvmx_pciercx_cfg064_s cn52xxp1; struct cvmx_pciercx_cfg064_s cn56xx; struct cvmx_pciercx_cfg064_s cn56xxp1; + struct cvmx_pciercx_cfg064_s cn61xx; struct cvmx_pciercx_cfg064_s cn63xx; struct cvmx_pciercx_cfg064_s cn63xxp1; + struct cvmx_pciercx_cfg064_s cn66xx; + struct cvmx_pciercx_cfg064_s cn68xx; + struct cvmx_pciercx_cfg064_s cn68xxp1; }; union cvmx_pciercx_cfg065 { uint32_t u32; struct cvmx_pciercx_cfg065_s { - uint32_t reserved_21_31:11; + uint32_t reserved_25_31:7; + uint32_t uatombs:1; + uint32_t reserved_21_23:3; uint32_t ures:1; uint32_t ecrces:1; uint32_t mtlps:1; @@ -848,18 +1069,39 @@ union cvmx_pciercx_cfg065 { uint32_t dlpes:1; uint32_t reserved_0_3:4; } s; - struct cvmx_pciercx_cfg065_s cn52xx; - struct cvmx_pciercx_cfg065_s cn52xxp1; - struct cvmx_pciercx_cfg065_s cn56xx; - struct cvmx_pciercx_cfg065_s cn56xxp1; - struct cvmx_pciercx_cfg065_s cn63xx; - struct cvmx_pciercx_cfg065_s cn63xxp1; + struct cvmx_pciercx_cfg065_cn52xx { + uint32_t reserved_21_31:11; + uint32_t ures:1; + uint32_t ecrces:1; + uint32_t mtlps:1; + uint32_t ros:1; + uint32_t ucs:1; + uint32_t cas:1; + uint32_t cts:1; + uint32_t fcpes:1; + uint32_t ptlps:1; + uint32_t reserved_6_11:6; + uint32_t sdes:1; + uint32_t dlpes:1; + uint32_t reserved_0_3:4; + } cn52xx; + struct cvmx_pciercx_cfg065_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg065_cn52xx cn56xx; + struct cvmx_pciercx_cfg065_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg065_s cn61xx; + struct cvmx_pciercx_cfg065_cn52xx cn63xx; + struct cvmx_pciercx_cfg065_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg065_s cn66xx; + struct cvmx_pciercx_cfg065_s cn68xx; + struct cvmx_pciercx_cfg065_cn52xx cn68xxp1; }; union cvmx_pciercx_cfg066 { uint32_t u32; struct cvmx_pciercx_cfg066_s { - uint32_t reserved_21_31:11; + uint32_t reserved_25_31:7; + uint32_t uatombm:1; + uint32_t reserved_21_23:3; uint32_t urem:1; uint32_t ecrcem:1; uint32_t mtlpm:1; @@ -874,18 +1116,39 @@ union cvmx_pciercx_cfg066 { uint32_t dlpem:1; uint32_t reserved_0_3:4; } s; - struct cvmx_pciercx_cfg066_s cn52xx; - struct cvmx_pciercx_cfg066_s cn52xxp1; - struct cvmx_pciercx_cfg066_s cn56xx; - struct cvmx_pciercx_cfg066_s cn56xxp1; - struct cvmx_pciercx_cfg066_s cn63xx; - struct cvmx_pciercx_cfg066_s cn63xxp1; + struct cvmx_pciercx_cfg066_cn52xx { + uint32_t reserved_21_31:11; + uint32_t urem:1; + uint32_t ecrcem:1; + uint32_t mtlpm:1; + uint32_t rom:1; + uint32_t ucm:1; + uint32_t cam:1; + uint32_t ctm:1; + uint32_t fcpem:1; + uint32_t ptlpm:1; + uint32_t reserved_6_11:6; + uint32_t sdem:1; + uint32_t dlpem:1; + uint32_t reserved_0_3:4; + } cn52xx; + struct cvmx_pciercx_cfg066_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg066_cn52xx cn56xx; + struct cvmx_pciercx_cfg066_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg066_s cn61xx; + struct cvmx_pciercx_cfg066_cn52xx cn63xx; + struct cvmx_pciercx_cfg066_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg066_s cn66xx; + struct cvmx_pciercx_cfg066_s cn68xx; + struct cvmx_pciercx_cfg066_cn52xx cn68xxp1; }; union cvmx_pciercx_cfg067 { uint32_t u32; struct cvmx_pciercx_cfg067_s { - uint32_t reserved_21_31:11; + uint32_t reserved_25_31:7; + uint32_t uatombs:1; + uint32_t reserved_21_23:3; uint32_t ures:1; uint32_t ecrces:1; uint32_t mtlps:1; @@ -900,12 +1163,31 @@ union cvmx_pciercx_cfg067 { uint32_t dlpes:1; uint32_t reserved_0_3:4; } s; - struct cvmx_pciercx_cfg067_s cn52xx; - struct cvmx_pciercx_cfg067_s cn52xxp1; - struct cvmx_pciercx_cfg067_s cn56xx; - struct cvmx_pciercx_cfg067_s cn56xxp1; - struct cvmx_pciercx_cfg067_s cn63xx; - struct cvmx_pciercx_cfg067_s cn63xxp1; + struct cvmx_pciercx_cfg067_cn52xx { + uint32_t reserved_21_31:11; + uint32_t ures:1; + uint32_t ecrces:1; + uint32_t mtlps:1; + uint32_t ros:1; + uint32_t ucs:1; + uint32_t cas:1; + uint32_t cts:1; + uint32_t fcpes:1; + uint32_t ptlps:1; + uint32_t reserved_6_11:6; + uint32_t sdes:1; + uint32_t dlpes:1; + uint32_t reserved_0_3:4; + } cn52xx; + struct cvmx_pciercx_cfg067_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg067_cn52xx cn56xx; + struct cvmx_pciercx_cfg067_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg067_s cn61xx; + struct cvmx_pciercx_cfg067_cn52xx cn63xx; + struct cvmx_pciercx_cfg067_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg067_s cn66xx; + struct cvmx_pciercx_cfg067_s cn68xx; + struct cvmx_pciercx_cfg067_cn52xx cn68xxp1; }; union cvmx_pciercx_cfg068 { @@ -925,8 +1207,12 @@ union cvmx_pciercx_cfg068 { struct cvmx_pciercx_cfg068_s cn52xxp1; struct cvmx_pciercx_cfg068_s cn56xx; struct cvmx_pciercx_cfg068_s cn56xxp1; + struct cvmx_pciercx_cfg068_s cn61xx; struct cvmx_pciercx_cfg068_s cn63xx; struct cvmx_pciercx_cfg068_s cn63xxp1; + struct cvmx_pciercx_cfg068_s cn66xx; + struct cvmx_pciercx_cfg068_s cn68xx; + struct cvmx_pciercx_cfg068_s cn68xxp1; }; union cvmx_pciercx_cfg069 { @@ -946,8 +1232,12 @@ union cvmx_pciercx_cfg069 { struct cvmx_pciercx_cfg069_s cn52xxp1; struct cvmx_pciercx_cfg069_s cn56xx; struct cvmx_pciercx_cfg069_s cn56xxp1; + struct cvmx_pciercx_cfg069_s cn61xx; struct cvmx_pciercx_cfg069_s cn63xx; struct cvmx_pciercx_cfg069_s cn63xxp1; + struct cvmx_pciercx_cfg069_s cn66xx; + struct cvmx_pciercx_cfg069_s cn68xx; + struct cvmx_pciercx_cfg069_s cn68xxp1; }; union cvmx_pciercx_cfg070 { @@ -964,8 +1254,12 @@ union cvmx_pciercx_cfg070 { struct cvmx_pciercx_cfg070_s cn52xxp1; struct cvmx_pciercx_cfg070_s cn56xx; struct cvmx_pciercx_cfg070_s cn56xxp1; + struct cvmx_pciercx_cfg070_s cn61xx; struct cvmx_pciercx_cfg070_s cn63xx; struct cvmx_pciercx_cfg070_s cn63xxp1; + struct cvmx_pciercx_cfg070_s cn66xx; + struct cvmx_pciercx_cfg070_s cn68xx; + struct cvmx_pciercx_cfg070_s cn68xxp1; }; union cvmx_pciercx_cfg071 { @@ -977,8 +1271,12 @@ union cvmx_pciercx_cfg071 { struct cvmx_pciercx_cfg071_s cn52xxp1; struct cvmx_pciercx_cfg071_s cn56xx; struct cvmx_pciercx_cfg071_s cn56xxp1; + struct cvmx_pciercx_cfg071_s cn61xx; struct cvmx_pciercx_cfg071_s cn63xx; struct cvmx_pciercx_cfg071_s cn63xxp1; + struct cvmx_pciercx_cfg071_s cn66xx; + struct cvmx_pciercx_cfg071_s cn68xx; + struct cvmx_pciercx_cfg071_s cn68xxp1; }; union cvmx_pciercx_cfg072 { @@ -990,8 +1288,12 @@ union cvmx_pciercx_cfg072 { struct cvmx_pciercx_cfg072_s cn52xxp1; struct cvmx_pciercx_cfg072_s cn56xx; struct cvmx_pciercx_cfg072_s cn56xxp1; + struct cvmx_pciercx_cfg072_s cn61xx; struct cvmx_pciercx_cfg072_s cn63xx; struct cvmx_pciercx_cfg072_s cn63xxp1; + struct cvmx_pciercx_cfg072_s cn66xx; + struct cvmx_pciercx_cfg072_s cn68xx; + struct cvmx_pciercx_cfg072_s cn68xxp1; }; union cvmx_pciercx_cfg073 { @@ -1003,8 +1305,12 @@ union cvmx_pciercx_cfg073 { struct cvmx_pciercx_cfg073_s cn52xxp1; struct cvmx_pciercx_cfg073_s cn56xx; struct cvmx_pciercx_cfg073_s cn56xxp1; + struct cvmx_pciercx_cfg073_s cn61xx; struct cvmx_pciercx_cfg073_s cn63xx; struct cvmx_pciercx_cfg073_s cn63xxp1; + struct cvmx_pciercx_cfg073_s cn66xx; + struct cvmx_pciercx_cfg073_s cn68xx; + struct cvmx_pciercx_cfg073_s cn68xxp1; }; union cvmx_pciercx_cfg074 { @@ -1016,8 +1322,12 @@ union cvmx_pciercx_cfg074 { struct cvmx_pciercx_cfg074_s cn52xxp1; struct cvmx_pciercx_cfg074_s cn56xx; struct cvmx_pciercx_cfg074_s cn56xxp1; + struct cvmx_pciercx_cfg074_s cn61xx; struct cvmx_pciercx_cfg074_s cn63xx; struct cvmx_pciercx_cfg074_s cn63xxp1; + struct cvmx_pciercx_cfg074_s cn66xx; + struct cvmx_pciercx_cfg074_s cn68xx; + struct cvmx_pciercx_cfg074_s cn68xxp1; }; union cvmx_pciercx_cfg075 { @@ -1032,8 +1342,12 @@ union cvmx_pciercx_cfg075 { struct cvmx_pciercx_cfg075_s cn52xxp1; struct cvmx_pciercx_cfg075_s cn56xx; struct cvmx_pciercx_cfg075_s cn56xxp1; + struct cvmx_pciercx_cfg075_s cn61xx; struct cvmx_pciercx_cfg075_s cn63xx; struct cvmx_pciercx_cfg075_s cn63xxp1; + struct cvmx_pciercx_cfg075_s cn66xx; + struct cvmx_pciercx_cfg075_s cn68xx; + struct cvmx_pciercx_cfg075_s cn68xxp1; }; union cvmx_pciercx_cfg076 { @@ -1053,8 +1367,12 @@ union cvmx_pciercx_cfg076 { struct cvmx_pciercx_cfg076_s cn52xxp1; struct cvmx_pciercx_cfg076_s cn56xx; struct cvmx_pciercx_cfg076_s cn56xxp1; + struct cvmx_pciercx_cfg076_s cn61xx; struct cvmx_pciercx_cfg076_s cn63xx; struct cvmx_pciercx_cfg076_s cn63xxp1; + struct cvmx_pciercx_cfg076_s cn66xx; + struct cvmx_pciercx_cfg076_s cn68xx; + struct cvmx_pciercx_cfg076_s cn68xxp1; }; union cvmx_pciercx_cfg077 { @@ -1067,8 +1385,12 @@ union cvmx_pciercx_cfg077 { struct cvmx_pciercx_cfg077_s cn52xxp1; struct cvmx_pciercx_cfg077_s cn56xx; struct cvmx_pciercx_cfg077_s cn56xxp1; + struct cvmx_pciercx_cfg077_s cn61xx; struct cvmx_pciercx_cfg077_s cn63xx; struct cvmx_pciercx_cfg077_s cn63xxp1; + struct cvmx_pciercx_cfg077_s cn66xx; + struct cvmx_pciercx_cfg077_s cn68xx; + struct cvmx_pciercx_cfg077_s cn68xxp1; }; union cvmx_pciercx_cfg448 { @@ -1081,8 +1403,12 @@ union cvmx_pciercx_cfg448 { struct cvmx_pciercx_cfg448_s cn52xxp1; struct cvmx_pciercx_cfg448_s cn56xx; struct cvmx_pciercx_cfg448_s cn56xxp1; + struct cvmx_pciercx_cfg448_s cn61xx; struct cvmx_pciercx_cfg448_s cn63xx; struct cvmx_pciercx_cfg448_s cn63xxp1; + struct cvmx_pciercx_cfg448_s cn66xx; + struct cvmx_pciercx_cfg448_s cn68xx; + struct cvmx_pciercx_cfg448_s cn68xxp1; }; union cvmx_pciercx_cfg449 { @@ -1094,8 +1420,12 @@ union cvmx_pciercx_cfg449 { struct cvmx_pciercx_cfg449_s cn52xxp1; struct cvmx_pciercx_cfg449_s cn56xx; struct cvmx_pciercx_cfg449_s cn56xxp1; + struct cvmx_pciercx_cfg449_s cn61xx; struct cvmx_pciercx_cfg449_s cn63xx; struct cvmx_pciercx_cfg449_s cn63xxp1; + struct cvmx_pciercx_cfg449_s cn66xx; + struct cvmx_pciercx_cfg449_s cn68xx; + struct cvmx_pciercx_cfg449_s cn68xxp1; }; union cvmx_pciercx_cfg450 { @@ -1112,26 +1442,42 @@ union cvmx_pciercx_cfg450 { struct cvmx_pciercx_cfg450_s cn52xxp1; struct cvmx_pciercx_cfg450_s cn56xx; struct cvmx_pciercx_cfg450_s cn56xxp1; + struct cvmx_pciercx_cfg450_s cn61xx; struct cvmx_pciercx_cfg450_s cn63xx; struct cvmx_pciercx_cfg450_s cn63xxp1; + struct cvmx_pciercx_cfg450_s cn66xx; + struct cvmx_pciercx_cfg450_s cn68xx; + struct cvmx_pciercx_cfg450_s cn68xxp1; }; union cvmx_pciercx_cfg451 { uint32_t u32; struct cvmx_pciercx_cfg451_s { - uint32_t reserved_30_31:2; + uint32_t reserved_31_31:1; + uint32_t easpml1:1; uint32_t l1el:3; uint32_t l0el:3; uint32_t n_fts_cc:8; uint32_t n_fts:8; uint32_t ack_freq:8; } s; - struct cvmx_pciercx_cfg451_s cn52xx; - struct cvmx_pciercx_cfg451_s cn52xxp1; - struct cvmx_pciercx_cfg451_s cn56xx; - struct cvmx_pciercx_cfg451_s cn56xxp1; - struct cvmx_pciercx_cfg451_s cn63xx; - struct cvmx_pciercx_cfg451_s cn63xxp1; + struct cvmx_pciercx_cfg451_cn52xx { + uint32_t reserved_30_31:2; + uint32_t l1el:3; + uint32_t l0el:3; + uint32_t n_fts_cc:8; + uint32_t n_fts:8; + uint32_t ack_freq:8; + } cn52xx; + struct cvmx_pciercx_cfg451_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg451_cn52xx cn56xx; + struct cvmx_pciercx_cfg451_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg451_s cn61xx; + struct cvmx_pciercx_cfg451_cn52xx cn63xx; + struct cvmx_pciercx_cfg451_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg451_s cn66xx; + struct cvmx_pciercx_cfg451_s cn68xx; + struct cvmx_pciercx_cfg451_s cn68xxp1; }; union cvmx_pciercx_cfg452 { @@ -1155,8 +1501,24 @@ union cvmx_pciercx_cfg452 { struct cvmx_pciercx_cfg452_s cn52xxp1; struct cvmx_pciercx_cfg452_s cn56xx; struct cvmx_pciercx_cfg452_s cn56xxp1; + struct cvmx_pciercx_cfg452_cn61xx { + uint32_t reserved_22_31:10; + uint32_t lme:6; + uint32_t reserved_8_15:8; + uint32_t flm:1; + uint32_t reserved_6_6:1; + uint32_t dllle:1; + uint32_t reserved_4_4:1; + uint32_t ra:1; + uint32_t le:1; + uint32_t sd:1; + uint32_t omr:1; + } cn61xx; struct cvmx_pciercx_cfg452_s cn63xx; struct cvmx_pciercx_cfg452_s cn63xxp1; + struct cvmx_pciercx_cfg452_cn61xx cn66xx; + struct cvmx_pciercx_cfg452_cn61xx cn68xx; + struct cvmx_pciercx_cfg452_cn61xx cn68xxp1; }; union cvmx_pciercx_cfg453 { @@ -1172,13 +1534,26 @@ union cvmx_pciercx_cfg453 { struct cvmx_pciercx_cfg453_s cn52xxp1; struct cvmx_pciercx_cfg453_s cn56xx; struct cvmx_pciercx_cfg453_s cn56xxp1; + struct cvmx_pciercx_cfg453_s cn61xx; struct cvmx_pciercx_cfg453_s cn63xx; struct cvmx_pciercx_cfg453_s cn63xxp1; + struct cvmx_pciercx_cfg453_s cn66xx; + struct cvmx_pciercx_cfg453_s cn68xx; + struct cvmx_pciercx_cfg453_s cn68xxp1; }; union cvmx_pciercx_cfg454 { uint32_t u32; struct cvmx_pciercx_cfg454_s { + uint32_t cx_nfunc:3; + uint32_t tmfcwt:5; + uint32_t tmanlt:5; + uint32_t tmrt:5; + uint32_t reserved_11_13:3; + uint32_t nskps:3; + uint32_t reserved_0_7:8; + } s; + struct cvmx_pciercx_cfg454_cn52xx { uint32_t reserved_29_31:3; uint32_t tmfcwt:5; uint32_t tmanlt:5; @@ -1187,13 +1562,23 @@ union cvmx_pciercx_cfg454 { uint32_t nskps:3; uint32_t reserved_4_7:4; uint32_t ntss:4; - } s; - struct cvmx_pciercx_cfg454_s cn52xx; - struct cvmx_pciercx_cfg454_s cn52xxp1; - struct cvmx_pciercx_cfg454_s cn56xx; - struct cvmx_pciercx_cfg454_s cn56xxp1; - struct cvmx_pciercx_cfg454_s cn63xx; - struct cvmx_pciercx_cfg454_s cn63xxp1; + } cn52xx; + struct cvmx_pciercx_cfg454_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg454_cn52xx cn56xx; + struct cvmx_pciercx_cfg454_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg454_cn61xx { + uint32_t cx_nfunc:3; + uint32_t tmfcwt:5; + uint32_t tmanlt:5; + uint32_t tmrt:5; + uint32_t reserved_8_13:6; + uint32_t mfuncn:8; + } cn61xx; + struct cvmx_pciercx_cfg454_cn52xx cn63xx; + struct cvmx_pciercx_cfg454_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg454_cn61xx cn66xx; + struct cvmx_pciercx_cfg454_cn61xx cn68xx; + struct cvmx_pciercx_cfg454_cn52xx cn68xxp1; }; union cvmx_pciercx_cfg455 { @@ -1223,23 +1608,37 @@ union cvmx_pciercx_cfg455 { struct cvmx_pciercx_cfg455_s cn52xxp1; struct cvmx_pciercx_cfg455_s cn56xx; struct cvmx_pciercx_cfg455_s cn56xxp1; + struct cvmx_pciercx_cfg455_s cn61xx; struct cvmx_pciercx_cfg455_s cn63xx; struct cvmx_pciercx_cfg455_s cn63xxp1; + struct cvmx_pciercx_cfg455_s cn66xx; + struct cvmx_pciercx_cfg455_s cn68xx; + struct cvmx_pciercx_cfg455_s cn68xxp1; }; union cvmx_pciercx_cfg456 { uint32_t u32; struct cvmx_pciercx_cfg456_s { - uint32_t reserved_2_31:30; + uint32_t reserved_4_31:28; + uint32_t m_handle_flush:1; + uint32_t m_dabort_4ucpl:1; uint32_t m_vend1_drp:1; uint32_t m_vend0_drp:1; } s; - struct cvmx_pciercx_cfg456_s cn52xx; - struct cvmx_pciercx_cfg456_s cn52xxp1; - struct cvmx_pciercx_cfg456_s cn56xx; - struct cvmx_pciercx_cfg456_s cn56xxp1; - struct cvmx_pciercx_cfg456_s cn63xx; - struct cvmx_pciercx_cfg456_s cn63xxp1; + struct cvmx_pciercx_cfg456_cn52xx { + uint32_t reserved_2_31:30; + uint32_t m_vend1_drp:1; + uint32_t m_vend0_drp:1; + } cn52xx; + struct cvmx_pciercx_cfg456_cn52xx cn52xxp1; + struct cvmx_pciercx_cfg456_cn52xx cn56xx; + struct cvmx_pciercx_cfg456_cn52xx cn56xxp1; + struct cvmx_pciercx_cfg456_s cn61xx; + struct cvmx_pciercx_cfg456_cn52xx cn63xx; + struct cvmx_pciercx_cfg456_cn52xx cn63xxp1; + struct cvmx_pciercx_cfg456_s cn66xx; + struct cvmx_pciercx_cfg456_s cn68xx; + struct cvmx_pciercx_cfg456_cn52xx cn68xxp1; }; union cvmx_pciercx_cfg458 { @@ -1251,8 +1650,12 @@ union cvmx_pciercx_cfg458 { struct cvmx_pciercx_cfg458_s cn52xxp1; struct cvmx_pciercx_cfg458_s cn56xx; struct cvmx_pciercx_cfg458_s cn56xxp1; + struct cvmx_pciercx_cfg458_s cn61xx; struct cvmx_pciercx_cfg458_s cn63xx; struct cvmx_pciercx_cfg458_s cn63xxp1; + struct cvmx_pciercx_cfg458_s cn66xx; + struct cvmx_pciercx_cfg458_s cn68xx; + struct cvmx_pciercx_cfg458_s cn68xxp1; }; union cvmx_pciercx_cfg459 { @@ -1264,8 +1667,12 @@ union cvmx_pciercx_cfg459 { struct cvmx_pciercx_cfg459_s cn52xxp1; struct cvmx_pciercx_cfg459_s cn56xx; struct cvmx_pciercx_cfg459_s cn56xxp1; + struct cvmx_pciercx_cfg459_s cn61xx; struct cvmx_pciercx_cfg459_s cn63xx; struct cvmx_pciercx_cfg459_s cn63xxp1; + struct cvmx_pciercx_cfg459_s cn66xx; + struct cvmx_pciercx_cfg459_s cn68xx; + struct cvmx_pciercx_cfg459_s cn68xxp1; }; union cvmx_pciercx_cfg460 { @@ -1279,8 +1686,12 @@ union cvmx_pciercx_cfg460 { struct cvmx_pciercx_cfg460_s cn52xxp1; struct cvmx_pciercx_cfg460_s cn56xx; struct cvmx_pciercx_cfg460_s cn56xxp1; + struct cvmx_pciercx_cfg460_s cn61xx; struct cvmx_pciercx_cfg460_s cn63xx; struct cvmx_pciercx_cfg460_s cn63xxp1; + struct cvmx_pciercx_cfg460_s cn66xx; + struct cvmx_pciercx_cfg460_s cn68xx; + struct cvmx_pciercx_cfg460_s cn68xxp1; }; union cvmx_pciercx_cfg461 { @@ -1294,8 +1705,12 @@ union cvmx_pciercx_cfg461 { struct cvmx_pciercx_cfg461_s cn52xxp1; struct cvmx_pciercx_cfg461_s cn56xx; struct cvmx_pciercx_cfg461_s cn56xxp1; + struct cvmx_pciercx_cfg461_s cn61xx; struct cvmx_pciercx_cfg461_s cn63xx; struct cvmx_pciercx_cfg461_s cn63xxp1; + struct cvmx_pciercx_cfg461_s cn66xx; + struct cvmx_pciercx_cfg461_s cn68xx; + struct cvmx_pciercx_cfg461_s cn68xxp1; }; union cvmx_pciercx_cfg462 { @@ -1309,8 +1724,12 @@ union cvmx_pciercx_cfg462 { struct cvmx_pciercx_cfg462_s cn52xxp1; struct cvmx_pciercx_cfg462_s cn56xx; struct cvmx_pciercx_cfg462_s cn56xxp1; + struct cvmx_pciercx_cfg462_s cn61xx; struct cvmx_pciercx_cfg462_s cn63xx; struct cvmx_pciercx_cfg462_s cn63xxp1; + struct cvmx_pciercx_cfg462_s cn66xx; + struct cvmx_pciercx_cfg462_s cn68xx; + struct cvmx_pciercx_cfg462_s cn68xxp1; }; union cvmx_pciercx_cfg463 { @@ -1325,8 +1744,12 @@ union cvmx_pciercx_cfg463 { struct cvmx_pciercx_cfg463_s cn52xxp1; struct cvmx_pciercx_cfg463_s cn56xx; struct cvmx_pciercx_cfg463_s cn56xxp1; + struct cvmx_pciercx_cfg463_s cn61xx; struct cvmx_pciercx_cfg463_s cn63xx; struct cvmx_pciercx_cfg463_s cn63xxp1; + struct cvmx_pciercx_cfg463_s cn66xx; + struct cvmx_pciercx_cfg463_s cn68xx; + struct cvmx_pciercx_cfg463_s cn68xxp1; }; union cvmx_pciercx_cfg464 { @@ -1341,8 +1764,12 @@ union cvmx_pciercx_cfg464 { struct cvmx_pciercx_cfg464_s cn52xxp1; struct cvmx_pciercx_cfg464_s cn56xx; struct cvmx_pciercx_cfg464_s cn56xxp1; + struct cvmx_pciercx_cfg464_s cn61xx; struct cvmx_pciercx_cfg464_s cn63xx; struct cvmx_pciercx_cfg464_s cn63xxp1; + struct cvmx_pciercx_cfg464_s cn66xx; + struct cvmx_pciercx_cfg464_s cn68xx; + struct cvmx_pciercx_cfg464_s cn68xxp1; }; union cvmx_pciercx_cfg465 { @@ -1357,8 +1784,12 @@ union cvmx_pciercx_cfg465 { struct cvmx_pciercx_cfg465_s cn52xxp1; struct cvmx_pciercx_cfg465_s cn56xx; struct cvmx_pciercx_cfg465_s cn56xxp1; + struct cvmx_pciercx_cfg465_s cn61xx; struct cvmx_pciercx_cfg465_s cn63xx; struct cvmx_pciercx_cfg465_s cn63xxp1; + struct cvmx_pciercx_cfg465_s cn66xx; + struct cvmx_pciercx_cfg465_s cn68xx; + struct cvmx_pciercx_cfg465_s cn68xxp1; }; union cvmx_pciercx_cfg466 { @@ -1376,8 +1807,12 @@ union cvmx_pciercx_cfg466 { struct cvmx_pciercx_cfg466_s cn52xxp1; struct cvmx_pciercx_cfg466_s cn56xx; struct cvmx_pciercx_cfg466_s cn56xxp1; + struct cvmx_pciercx_cfg466_s cn61xx; struct cvmx_pciercx_cfg466_s cn63xx; struct cvmx_pciercx_cfg466_s cn63xxp1; + struct cvmx_pciercx_cfg466_s cn66xx; + struct cvmx_pciercx_cfg466_s cn68xx; + struct cvmx_pciercx_cfg466_s cn68xxp1; }; union cvmx_pciercx_cfg467 { @@ -1393,8 +1828,12 @@ union cvmx_pciercx_cfg467 { struct cvmx_pciercx_cfg467_s cn52xxp1; struct cvmx_pciercx_cfg467_s cn56xx; struct cvmx_pciercx_cfg467_s cn56xxp1; + struct cvmx_pciercx_cfg467_s cn61xx; struct cvmx_pciercx_cfg467_s cn63xx; struct cvmx_pciercx_cfg467_s cn63xxp1; + struct cvmx_pciercx_cfg467_s cn66xx; + struct cvmx_pciercx_cfg467_s cn68xx; + struct cvmx_pciercx_cfg467_s cn68xxp1; }; union cvmx_pciercx_cfg468 { @@ -1410,8 +1849,12 @@ union cvmx_pciercx_cfg468 { struct cvmx_pciercx_cfg468_s cn52xxp1; struct cvmx_pciercx_cfg468_s cn56xx; struct cvmx_pciercx_cfg468_s cn56xxp1; + struct cvmx_pciercx_cfg468_s cn61xx; struct cvmx_pciercx_cfg468_s cn63xx; struct cvmx_pciercx_cfg468_s cn63xxp1; + struct cvmx_pciercx_cfg468_s cn66xx; + struct cvmx_pciercx_cfg468_s cn68xx; + struct cvmx_pciercx_cfg468_s cn68xxp1; }; union cvmx_pciercx_cfg490 { @@ -1426,8 +1869,12 @@ union cvmx_pciercx_cfg490 { struct cvmx_pciercx_cfg490_s cn52xxp1; struct cvmx_pciercx_cfg490_s cn56xx; struct cvmx_pciercx_cfg490_s cn56xxp1; + struct cvmx_pciercx_cfg490_s cn61xx; struct cvmx_pciercx_cfg490_s cn63xx; struct cvmx_pciercx_cfg490_s cn63xxp1; + struct cvmx_pciercx_cfg490_s cn66xx; + struct cvmx_pciercx_cfg490_s cn68xx; + struct cvmx_pciercx_cfg490_s cn68xxp1; }; union cvmx_pciercx_cfg491 { @@ -1442,8 +1889,12 @@ union cvmx_pciercx_cfg491 { struct cvmx_pciercx_cfg491_s cn52xxp1; struct cvmx_pciercx_cfg491_s cn56xx; struct cvmx_pciercx_cfg491_s cn56xxp1; + struct cvmx_pciercx_cfg491_s cn61xx; struct cvmx_pciercx_cfg491_s cn63xx; struct cvmx_pciercx_cfg491_s cn63xxp1; + struct cvmx_pciercx_cfg491_s cn66xx; + struct cvmx_pciercx_cfg491_s cn68xx; + struct cvmx_pciercx_cfg491_s cn68xxp1; }; union cvmx_pciercx_cfg492 { @@ -1458,8 +1909,12 @@ union cvmx_pciercx_cfg492 { struct cvmx_pciercx_cfg492_s cn52xxp1; struct cvmx_pciercx_cfg492_s cn56xx; struct cvmx_pciercx_cfg492_s cn56xxp1; + struct cvmx_pciercx_cfg492_s cn61xx; struct cvmx_pciercx_cfg492_s cn63xx; struct cvmx_pciercx_cfg492_s cn63xxp1; + struct cvmx_pciercx_cfg492_s cn66xx; + struct cvmx_pciercx_cfg492_s cn68xx; + struct cvmx_pciercx_cfg492_s cn68xxp1; }; union cvmx_pciercx_cfg515 { @@ -1473,8 +1928,12 @@ union cvmx_pciercx_cfg515 { uint32_t le:9; uint32_t n_fts:8; } s; + struct cvmx_pciercx_cfg515_s cn61xx; struct cvmx_pciercx_cfg515_s cn63xx; struct cvmx_pciercx_cfg515_s cn63xxp1; + struct cvmx_pciercx_cfg515_s cn66xx; + struct cvmx_pciercx_cfg515_s cn68xx; + struct cvmx_pciercx_cfg515_s cn68xxp1; }; union cvmx_pciercx_cfg516 { @@ -1486,8 +1945,12 @@ union cvmx_pciercx_cfg516 { struct cvmx_pciercx_cfg516_s cn52xxp1; struct cvmx_pciercx_cfg516_s cn56xx; struct cvmx_pciercx_cfg516_s cn56xxp1; + struct cvmx_pciercx_cfg516_s cn61xx; struct cvmx_pciercx_cfg516_s cn63xx; struct cvmx_pciercx_cfg516_s cn63xxp1; + struct cvmx_pciercx_cfg516_s cn66xx; + struct cvmx_pciercx_cfg516_s cn68xx; + struct cvmx_pciercx_cfg516_s cn68xxp1; }; union cvmx_pciercx_cfg517 { @@ -1499,8 +1962,12 @@ union cvmx_pciercx_cfg517 { struct cvmx_pciercx_cfg517_s cn52xxp1; struct cvmx_pciercx_cfg517_s cn56xx; struct cvmx_pciercx_cfg517_s cn56xxp1; + struct cvmx_pciercx_cfg517_s cn61xx; struct cvmx_pciercx_cfg517_s cn63xx; struct cvmx_pciercx_cfg517_s cn63xxp1; + struct cvmx_pciercx_cfg517_s cn66xx; + struct cvmx_pciercx_cfg517_s cn68xx; + struct cvmx_pciercx_cfg517_s cn68xxp1; }; #endif diff --git a/drivers/staging/octeon/cvmx-pcsx-defs.h b/arch/mips/include/asm/octeon/cvmx-pcsx-defs.h index d45952df5f5b..d45952df5f5b 100644 --- a/drivers/staging/octeon/cvmx-pcsx-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-pcsx-defs.h diff --git a/drivers/staging/octeon/cvmx-pcsxx-defs.h b/arch/mips/include/asm/octeon/cvmx-pcsxx-defs.h index 55d120fe8aed..55d120fe8aed 100644 --- a/drivers/staging/octeon/cvmx-pcsxx-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-pcsxx-defs.h diff --git a/arch/mips/include/asm/octeon/cvmx-pemx-defs.h b/arch/mips/include/asm/octeon/cvmx-pemx-defs.h new file mode 100644 index 000000000000..be189a2585e0 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-pemx-defs.h @@ -0,0 +1,509 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2011 Cavium Networks + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, Version 2, as + * published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_PEMX_DEFS_H__ +#define __CVMX_PEMX_DEFS_H__ + +#define CVMX_PEMX_BAR1_INDEXX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C00000A8ull) + (((offset) & 15) + ((block_id) & 1) * 0x200000ull) * 8) +#define CVMX_PEMX_BAR2_MASK(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000130ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_BAR_CTL(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000128ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_BIST_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000018ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_BIST_STATUS2(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000420ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_CFG_RD(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000030ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_CFG_WR(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000028ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_CPL_LUT_VALID(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000098ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_CTL_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000000ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_DBG_INFO(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000008ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_DBG_INFO_EN(block_id) (CVMX_ADD_IO_SEG(0x00011800C00000A0ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_DIAG_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000020ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_INB_READ_CREDITS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000138ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_INT_ENB(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000410ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_INT_ENB_INT(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000418ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_INT_SUM(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000408ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_P2N_BAR0_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000080ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_P2N_BAR1_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000088ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_P2N_BAR2_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000090ull) + ((block_id) & 1) * 0x1000000ull) +#define CVMX_PEMX_P2P_BARX_END(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C0000048ull) + (((offset) & 3) + ((block_id) & 1) * 0x100000ull) * 16) +#define CVMX_PEMX_P2P_BARX_START(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C0000040ull) + (((offset) & 3) + ((block_id) & 1) * 0x100000ull) * 16) +#define CVMX_PEMX_TLP_CREDITS(block_id) (CVMX_ADD_IO_SEG(0x00011800C0000038ull) + ((block_id) & 1) * 0x1000000ull) + +union cvmx_pemx_bar1_indexx { + uint64_t u64; + struct cvmx_pemx_bar1_indexx_s { + uint64_t reserved_20_63:44; + uint64_t addr_idx:16; + uint64_t ca:1; + uint64_t end_swp:2; + uint64_t addr_v:1; + } s; + struct cvmx_pemx_bar1_indexx_s cn61xx; + struct cvmx_pemx_bar1_indexx_s cn63xx; + struct cvmx_pemx_bar1_indexx_s cn63xxp1; + struct cvmx_pemx_bar1_indexx_s cn66xx; + struct cvmx_pemx_bar1_indexx_s cn68xx; + struct cvmx_pemx_bar1_indexx_s cn68xxp1; +}; + +union cvmx_pemx_bar2_mask { + uint64_t u64; + struct cvmx_pemx_bar2_mask_s { + uint64_t reserved_38_63:26; + uint64_t mask:35; + uint64_t reserved_0_2:3; + } s; + struct cvmx_pemx_bar2_mask_s cn61xx; + struct cvmx_pemx_bar2_mask_s cn66xx; + struct cvmx_pemx_bar2_mask_s cn68xx; + struct cvmx_pemx_bar2_mask_s cn68xxp1; +}; + +union cvmx_pemx_bar_ctl { + uint64_t u64; + struct cvmx_pemx_bar_ctl_s { + uint64_t reserved_7_63:57; + uint64_t bar1_siz:3; + uint64_t bar2_enb:1; + uint64_t bar2_esx:2; + uint64_t bar2_cax:1; + } s; + struct cvmx_pemx_bar_ctl_s cn61xx; + struct cvmx_pemx_bar_ctl_s cn63xx; + struct cvmx_pemx_bar_ctl_s cn63xxp1; + struct cvmx_pemx_bar_ctl_s cn66xx; + struct cvmx_pemx_bar_ctl_s cn68xx; + struct cvmx_pemx_bar_ctl_s cn68xxp1; +}; + +union cvmx_pemx_bist_status { + uint64_t u64; + struct cvmx_pemx_bist_status_s { + uint64_t reserved_8_63:56; + uint64_t retry:1; + uint64_t rqdata0:1; + uint64_t rqdata1:1; + uint64_t rqdata2:1; + uint64_t rqdata3:1; + uint64_t rqhdr1:1; + uint64_t rqhdr0:1; + uint64_t sot:1; + } s; + struct cvmx_pemx_bist_status_s cn61xx; + struct cvmx_pemx_bist_status_s cn63xx; + struct cvmx_pemx_bist_status_s cn63xxp1; + struct cvmx_pemx_bist_status_s cn66xx; + struct cvmx_pemx_bist_status_s cn68xx; + struct cvmx_pemx_bist_status_s cn68xxp1; +}; + +union cvmx_pemx_bist_status2 { + uint64_t u64; + struct cvmx_pemx_bist_status2_s { + uint64_t reserved_10_63:54; + uint64_t e2p_cpl:1; + uint64_t e2p_n:1; + uint64_t e2p_p:1; + uint64_t peai_p2e:1; + uint64_t pef_tpf1:1; + uint64_t pef_tpf0:1; + uint64_t pef_tnf:1; + uint64_t pef_tcf1:1; + uint64_t pef_tc0:1; + uint64_t ppf:1; + } s; + struct cvmx_pemx_bist_status2_s cn61xx; + struct cvmx_pemx_bist_status2_s cn63xx; + struct cvmx_pemx_bist_status2_s cn63xxp1; + struct cvmx_pemx_bist_status2_s cn66xx; + struct cvmx_pemx_bist_status2_s cn68xx; + struct cvmx_pemx_bist_status2_s cn68xxp1; +}; + +union cvmx_pemx_cfg_rd { + uint64_t u64; + struct cvmx_pemx_cfg_rd_s { + uint64_t data:32; + uint64_t addr:32; + } s; + struct cvmx_pemx_cfg_rd_s cn61xx; + struct cvmx_pemx_cfg_rd_s cn63xx; + struct cvmx_pemx_cfg_rd_s cn63xxp1; + struct cvmx_pemx_cfg_rd_s cn66xx; + struct cvmx_pemx_cfg_rd_s cn68xx; + struct cvmx_pemx_cfg_rd_s cn68xxp1; +}; + +union cvmx_pemx_cfg_wr { + uint64_t u64; + struct cvmx_pemx_cfg_wr_s { + uint64_t data:32; + uint64_t addr:32; + } s; + struct cvmx_pemx_cfg_wr_s cn61xx; + struct cvmx_pemx_cfg_wr_s cn63xx; + struct cvmx_pemx_cfg_wr_s cn63xxp1; + struct cvmx_pemx_cfg_wr_s cn66xx; + struct cvmx_pemx_cfg_wr_s cn68xx; + struct cvmx_pemx_cfg_wr_s cn68xxp1; +}; + +union cvmx_pemx_cpl_lut_valid { + uint64_t u64; + struct cvmx_pemx_cpl_lut_valid_s { + uint64_t reserved_32_63:32; + uint64_t tag:32; + } s; + struct cvmx_pemx_cpl_lut_valid_s cn61xx; + struct cvmx_pemx_cpl_lut_valid_s cn63xx; + struct cvmx_pemx_cpl_lut_valid_s cn63xxp1; + struct cvmx_pemx_cpl_lut_valid_s cn66xx; + struct cvmx_pemx_cpl_lut_valid_s cn68xx; + struct cvmx_pemx_cpl_lut_valid_s cn68xxp1; +}; + +union cvmx_pemx_ctl_status { + uint64_t u64; + struct cvmx_pemx_ctl_status_s { + uint64_t reserved_48_63:16; + uint64_t auto_sd:1; + uint64_t dnum:5; + uint64_t pbus:8; + uint64_t reserved_32_33:2; + uint64_t cfg_rtry:16; + uint64_t reserved_12_15:4; + uint64_t pm_xtoff:1; + uint64_t pm_xpme:1; + uint64_t ob_p_cmd:1; + uint64_t reserved_7_8:2; + uint64_t nf_ecrc:1; + uint64_t dly_one:1; + uint64_t lnk_enb:1; + uint64_t ro_ctlp:1; + uint64_t fast_lm:1; + uint64_t inv_ecrc:1; + uint64_t inv_lcrc:1; + } s; + struct cvmx_pemx_ctl_status_s cn61xx; + struct cvmx_pemx_ctl_status_s cn63xx; + struct cvmx_pemx_ctl_status_s cn63xxp1; + struct cvmx_pemx_ctl_status_s cn66xx; + struct cvmx_pemx_ctl_status_s cn68xx; + struct cvmx_pemx_ctl_status_s cn68xxp1; +}; + +union cvmx_pemx_dbg_info { + uint64_t u64; + struct cvmx_pemx_dbg_info_s { + uint64_t reserved_31_63:33; + uint64_t ecrc_e:1; + uint64_t rawwpp:1; + uint64_t racpp:1; + uint64_t ramtlp:1; + uint64_t rarwdns:1; + uint64_t caar:1; + uint64_t racca:1; + uint64_t racur:1; + uint64_t rauc:1; + uint64_t rqo:1; + uint64_t fcuv:1; + uint64_t rpe:1; + uint64_t fcpvwt:1; + uint64_t dpeoosd:1; + uint64_t rtwdle:1; + uint64_t rdwdle:1; + uint64_t mre:1; + uint64_t rte:1; + uint64_t acto:1; + uint64_t rvdm:1; + uint64_t rumep:1; + uint64_t rptamrc:1; + uint64_t rpmerc:1; + uint64_t rfemrc:1; + uint64_t rnfemrc:1; + uint64_t rcemrc:1; + uint64_t rpoison:1; + uint64_t recrce:1; + uint64_t rtlplle:1; + uint64_t rtlpmal:1; + uint64_t spoison:1; + } s; + struct cvmx_pemx_dbg_info_s cn61xx; + struct cvmx_pemx_dbg_info_s cn63xx; + struct cvmx_pemx_dbg_info_s cn63xxp1; + struct cvmx_pemx_dbg_info_s cn66xx; + struct cvmx_pemx_dbg_info_s cn68xx; + struct cvmx_pemx_dbg_info_s cn68xxp1; +}; + +union cvmx_pemx_dbg_info_en { + uint64_t u64; + struct cvmx_pemx_dbg_info_en_s { + uint64_t reserved_31_63:33; + uint64_t ecrc_e:1; + uint64_t rawwpp:1; + uint64_t racpp:1; + uint64_t ramtlp:1; + uint64_t rarwdns:1; + uint64_t caar:1; + uint64_t racca:1; + uint64_t racur:1; + uint64_t rauc:1; + uint64_t rqo:1; + uint64_t fcuv:1; + uint64_t rpe:1; + uint64_t fcpvwt:1; + uint64_t dpeoosd:1; + uint64_t rtwdle:1; + uint64_t rdwdle:1; + uint64_t mre:1; + uint64_t rte:1; + uint64_t acto:1; + uint64_t rvdm:1; + uint64_t rumep:1; + uint64_t rptamrc:1; + uint64_t rpmerc:1; + uint64_t rfemrc:1; + uint64_t rnfemrc:1; + uint64_t rcemrc:1; + uint64_t rpoison:1; + uint64_t recrce:1; + uint64_t rtlplle:1; + uint64_t rtlpmal:1; + uint64_t spoison:1; + } s; + struct cvmx_pemx_dbg_info_en_s cn61xx; + struct cvmx_pemx_dbg_info_en_s cn63xx; + struct cvmx_pemx_dbg_info_en_s cn63xxp1; + struct cvmx_pemx_dbg_info_en_s cn66xx; + struct cvmx_pemx_dbg_info_en_s cn68xx; + struct cvmx_pemx_dbg_info_en_s cn68xxp1; +}; + +union cvmx_pemx_diag_status { + uint64_t u64; + struct cvmx_pemx_diag_status_s { + uint64_t reserved_4_63:60; + uint64_t pm_dst:1; + uint64_t pm_stat:1; + uint64_t pm_en:1; + uint64_t aux_en:1; + } s; + struct cvmx_pemx_diag_status_s cn61xx; + struct cvmx_pemx_diag_status_s cn63xx; + struct cvmx_pemx_diag_status_s cn63xxp1; + struct cvmx_pemx_diag_status_s cn66xx; + struct cvmx_pemx_diag_status_s cn68xx; + struct cvmx_pemx_diag_status_s cn68xxp1; +}; + +union cvmx_pemx_inb_read_credits { + uint64_t u64; + struct cvmx_pemx_inb_read_credits_s { + uint64_t reserved_6_63:58; + uint64_t num:6; + } s; + struct cvmx_pemx_inb_read_credits_s cn61xx; + struct cvmx_pemx_inb_read_credits_s cn66xx; + struct cvmx_pemx_inb_read_credits_s cn68xx; +}; + +union cvmx_pemx_int_enb { + uint64_t u64; + struct cvmx_pemx_int_enb_s { + uint64_t reserved_14_63:50; + uint64_t crs_dr:1; + uint64_t crs_er:1; + uint64_t rdlk:1; + uint64_t exc:1; + uint64_t un_bx:1; + uint64_t un_b2:1; + uint64_t un_b1:1; + uint64_t up_bx:1; + uint64_t up_b2:1; + uint64_t up_b1:1; + uint64_t pmem:1; + uint64_t pmei:1; + uint64_t se:1; + uint64_t aeri:1; + } s; + struct cvmx_pemx_int_enb_s cn61xx; + struct cvmx_pemx_int_enb_s cn63xx; + struct cvmx_pemx_int_enb_s cn63xxp1; + struct cvmx_pemx_int_enb_s cn66xx; + struct cvmx_pemx_int_enb_s cn68xx; + struct cvmx_pemx_int_enb_s cn68xxp1; +}; + +union cvmx_pemx_int_enb_int { + uint64_t u64; + struct cvmx_pemx_int_enb_int_s { + uint64_t reserved_14_63:50; + uint64_t crs_dr:1; + uint64_t crs_er:1; + uint64_t rdlk:1; + uint64_t exc:1; + uint64_t un_bx:1; + uint64_t un_b2:1; + uint64_t un_b1:1; + uint64_t up_bx:1; + uint64_t up_b2:1; + uint64_t up_b1:1; + uint64_t pmem:1; + uint64_t pmei:1; + uint64_t se:1; + uint64_t aeri:1; + } s; + struct cvmx_pemx_int_enb_int_s cn61xx; + struct cvmx_pemx_int_enb_int_s cn63xx; + struct cvmx_pemx_int_enb_int_s cn63xxp1; + struct cvmx_pemx_int_enb_int_s cn66xx; + struct cvmx_pemx_int_enb_int_s cn68xx; + struct cvmx_pemx_int_enb_int_s cn68xxp1; +}; + +union cvmx_pemx_int_sum { + uint64_t u64; + struct cvmx_pemx_int_sum_s { + uint64_t reserved_14_63:50; + uint64_t crs_dr:1; + uint64_t crs_er:1; + uint64_t rdlk:1; + uint64_t exc:1; + uint64_t un_bx:1; + uint64_t un_b2:1; + uint64_t un_b1:1; + uint64_t up_bx:1; + uint64_t up_b2:1; + uint64_t up_b1:1; + uint64_t pmem:1; + uint64_t pmei:1; + uint64_t se:1; + uint64_t aeri:1; + } s; + struct cvmx_pemx_int_sum_s cn61xx; + struct cvmx_pemx_int_sum_s cn63xx; + struct cvmx_pemx_int_sum_s cn63xxp1; + struct cvmx_pemx_int_sum_s cn66xx; + struct cvmx_pemx_int_sum_s cn68xx; + struct cvmx_pemx_int_sum_s cn68xxp1; +}; + +union cvmx_pemx_p2n_bar0_start { + uint64_t u64; + struct cvmx_pemx_p2n_bar0_start_s { + uint64_t addr:50; + uint64_t reserved_0_13:14; + } s; + struct cvmx_pemx_p2n_bar0_start_s cn61xx; + struct cvmx_pemx_p2n_bar0_start_s cn63xx; + struct cvmx_pemx_p2n_bar0_start_s cn63xxp1; + struct cvmx_pemx_p2n_bar0_start_s cn66xx; + struct cvmx_pemx_p2n_bar0_start_s cn68xx; + struct cvmx_pemx_p2n_bar0_start_s cn68xxp1; +}; + +union cvmx_pemx_p2n_bar1_start { + uint64_t u64; + struct cvmx_pemx_p2n_bar1_start_s { + uint64_t addr:38; + uint64_t reserved_0_25:26; + } s; + struct cvmx_pemx_p2n_bar1_start_s cn61xx; + struct cvmx_pemx_p2n_bar1_start_s cn63xx; + struct cvmx_pemx_p2n_bar1_start_s cn63xxp1; + struct cvmx_pemx_p2n_bar1_start_s cn66xx; + struct cvmx_pemx_p2n_bar1_start_s cn68xx; + struct cvmx_pemx_p2n_bar1_start_s cn68xxp1; +}; + +union cvmx_pemx_p2n_bar2_start { + uint64_t u64; + struct cvmx_pemx_p2n_bar2_start_s { + uint64_t addr:23; + uint64_t reserved_0_40:41; + } s; + struct cvmx_pemx_p2n_bar2_start_s cn61xx; + struct cvmx_pemx_p2n_bar2_start_s cn63xx; + struct cvmx_pemx_p2n_bar2_start_s cn63xxp1; + struct cvmx_pemx_p2n_bar2_start_s cn66xx; + struct cvmx_pemx_p2n_bar2_start_s cn68xx; + struct cvmx_pemx_p2n_bar2_start_s cn68xxp1; +}; + +union cvmx_pemx_p2p_barx_end { + uint64_t u64; + struct cvmx_pemx_p2p_barx_end_s { + uint64_t addr:52; + uint64_t reserved_0_11:12; + } s; + struct cvmx_pemx_p2p_barx_end_s cn63xx; + struct cvmx_pemx_p2p_barx_end_s cn63xxp1; + struct cvmx_pemx_p2p_barx_end_s cn66xx; + struct cvmx_pemx_p2p_barx_end_s cn68xx; + struct cvmx_pemx_p2p_barx_end_s cn68xxp1; +}; + +union cvmx_pemx_p2p_barx_start { + uint64_t u64; + struct cvmx_pemx_p2p_barx_start_s { + uint64_t addr:52; + uint64_t reserved_0_11:12; + } s; + struct cvmx_pemx_p2p_barx_start_s cn63xx; + struct cvmx_pemx_p2p_barx_start_s cn63xxp1; + struct cvmx_pemx_p2p_barx_start_s cn66xx; + struct cvmx_pemx_p2p_barx_start_s cn68xx; + struct cvmx_pemx_p2p_barx_start_s cn68xxp1; +}; + +union cvmx_pemx_tlp_credits { + uint64_t u64; + struct cvmx_pemx_tlp_credits_s { + uint64_t reserved_56_63:8; + uint64_t peai_ppf:8; + uint64_t pem_cpl:8; + uint64_t pem_np:8; + uint64_t pem_p:8; + uint64_t sli_cpl:8; + uint64_t sli_np:8; + uint64_t sli_p:8; + } s; + struct cvmx_pemx_tlp_credits_cn61xx { + uint64_t reserved_56_63:8; + uint64_t peai_ppf:8; + uint64_t reserved_24_47:24; + uint64_t sli_cpl:8; + uint64_t sli_np:8; + uint64_t sli_p:8; + } cn61xx; + struct cvmx_pemx_tlp_credits_s cn63xx; + struct cvmx_pemx_tlp_credits_s cn63xxp1; + struct cvmx_pemx_tlp_credits_s cn66xx; + struct cvmx_pemx_tlp_credits_s cn68xx; + struct cvmx_pemx_tlp_credits_s cn68xxp1; +}; + +#endif diff --git a/arch/mips/include/asm/octeon/cvmx-pexp-defs.h b/arch/mips/include/asm/octeon/cvmx-pexp-defs.h index 5ab8679d89af..4438d211988b 100644 --- a/arch/mips/include/asm/octeon/cvmx-pexp-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-pexp-defs.h @@ -4,7 +4,7 @@ * Contact: support@caviumnetworks.com * This file is part of the OCTEON SDK * - * Copyright (c) 2003-2010 Cavium Networks + * Copyright (c) 2003-2011 Cavium Networks * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as @@ -25,13 +25,6 @@ * Contact Cavium Networks for more information ***********************license end**************************************/ -/** - * cvmx-pexp-defs.h - * - * Configuration and status register (CSR) definitions for - * OCTEON PEXP. - * - */ #ifndef __CVMX_PEXP_DEFS_H__ #define __CVMX_PEXP_DEFS_H__ @@ -139,7 +132,7 @@ #define CVMX_PEXP_NPEI_STATE3 (CVMX_ADD_IO_SEG(0x00011F0000008640ull)) #define CVMX_PEXP_NPEI_WINDOW_CTL (CVMX_ADD_IO_SEG(0x00011F0000008380ull)) #define CVMX_PEXP_SLI_BIST_STATUS (CVMX_ADD_IO_SEG(0x00011F0000010580ull)) -#define CVMX_PEXP_SLI_CTL_PORTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000010050ull) + ((offset) & 1) * 16) +#define CVMX_PEXP_SLI_CTL_PORTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000010050ull) + ((offset) & 3) * 16) #define CVMX_PEXP_SLI_CTL_STATUS (CVMX_ADD_IO_SEG(0x00011F0000010570ull)) #define CVMX_PEXP_SLI_DATA_OUT_CNT (CVMX_ADD_IO_SEG(0x00011F00000105F0ull)) #define CVMX_PEXP_SLI_DBG_DATA (CVMX_ADD_IO_SEG(0x00011F0000010310ull)) @@ -152,7 +145,10 @@ #define CVMX_PEXP_SLI_INT_SUM (CVMX_ADD_IO_SEG(0x00011F0000010330ull)) #define CVMX_PEXP_SLI_LAST_WIN_RDATA0 (CVMX_ADD_IO_SEG(0x00011F0000010600ull)) #define CVMX_PEXP_SLI_LAST_WIN_RDATA1 (CVMX_ADD_IO_SEG(0x00011F0000010610ull)) +#define CVMX_PEXP_SLI_LAST_WIN_RDATA2 (CVMX_ADD_IO_SEG(0x00011F00000106C0ull)) +#define CVMX_PEXP_SLI_LAST_WIN_RDATA3 (CVMX_ADD_IO_SEG(0x00011F00000106D0ull)) #define CVMX_PEXP_SLI_MAC_CREDIT_CNT (CVMX_ADD_IO_SEG(0x00011F0000013D70ull)) +#define CVMX_PEXP_SLI_MAC_CREDIT_CNT2 (CVMX_ADD_IO_SEG(0x00011F0000013E10ull)) #define CVMX_PEXP_SLI_MEM_ACCESS_CTL (CVMX_ADD_IO_SEG(0x00011F00000102F0ull)) #define CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(offset) (CVMX_ADD_IO_SEG(0x00011F00000100E0ull) + ((offset) & 31) * 16 - 16*12) #define CVMX_PEXP_SLI_MSI_ENB0 (CVMX_ADD_IO_SEG(0x00011F0000013C50ull)) @@ -206,6 +202,7 @@ #define CVMX_PEXP_SLI_PKT_IPTR (CVMX_ADD_IO_SEG(0x00011F0000011070ull)) #define CVMX_PEXP_SLI_PKT_OUTPUT_WMARK (CVMX_ADD_IO_SEG(0x00011F0000011180ull)) #define CVMX_PEXP_SLI_PKT_OUT_BMODE (CVMX_ADD_IO_SEG(0x00011F00000110D0ull)) +#define CVMX_PEXP_SLI_PKT_OUT_BP_EN (CVMX_ADD_IO_SEG(0x00011F0000011240ull)) #define CVMX_PEXP_SLI_PKT_OUT_ENB (CVMX_ADD_IO_SEG(0x00011F0000011010ull)) #define CVMX_PEXP_SLI_PKT_PCIE_PORT (CVMX_ADD_IO_SEG(0x00011F00000110E0ull)) #define CVMX_PEXP_SLI_PKT_PORT_IN_RST (CVMX_ADD_IO_SEG(0x00011F00000111F0ull)) @@ -214,12 +211,14 @@ #define CVMX_PEXP_SLI_PKT_SLIST_ROR (CVMX_ADD_IO_SEG(0x00011F0000011030ull)) #define CVMX_PEXP_SLI_PKT_TIME_INT (CVMX_ADD_IO_SEG(0x00011F0000011140ull)) #define CVMX_PEXP_SLI_PKT_TIME_INT_ENB (CVMX_ADD_IO_SEG(0x00011F0000011160ull)) -#define CVMX_PEXP_SLI_S2M_PORTX_CTL(offset) (CVMX_ADD_IO_SEG(0x00011F0000013D80ull) + ((offset) & 1) * 16) +#define CVMX_PEXP_SLI_PORTX_PKIND(offset) (CVMX_ADD_IO_SEG(0x00011F0000010800ull) + ((offset) & 31) * 16) +#define CVMX_PEXP_SLI_S2M_PORTX_CTL(offset) (CVMX_ADD_IO_SEG(0x00011F0000013D80ull) + ((offset) & 3) * 16) #define CVMX_PEXP_SLI_SCRATCH_1 (CVMX_ADD_IO_SEG(0x00011F00000103C0ull)) #define CVMX_PEXP_SLI_SCRATCH_2 (CVMX_ADD_IO_SEG(0x00011F00000103D0ull)) #define CVMX_PEXP_SLI_STATE1 (CVMX_ADD_IO_SEG(0x00011F0000010620ull)) #define CVMX_PEXP_SLI_STATE2 (CVMX_ADD_IO_SEG(0x00011F0000010630ull)) #define CVMX_PEXP_SLI_STATE3 (CVMX_ADD_IO_SEG(0x00011F0000010640ull)) +#define CVMX_PEXP_SLI_TX_PIPE (CVMX_ADD_IO_SEG(0x00011F0000011230ull)) #define CVMX_PEXP_SLI_WINDOW_CTL (CVMX_ADD_IO_SEG(0x00011F00000102E0ull)) #endif diff --git a/drivers/staging/octeon/cvmx-pip-defs.h b/arch/mips/include/asm/octeon/cvmx-pip-defs.h index 5a369100ca68..5a369100ca68 100644 --- a/drivers/staging/octeon/cvmx-pip-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-pip-defs.h diff --git a/drivers/staging/octeon/cvmx-pip.h b/arch/mips/include/asm/octeon/cvmx-pip.h index 78dbce8f2c5e..78dbce8f2c5e 100644 --- a/drivers/staging/octeon/cvmx-pip.h +++ b/arch/mips/include/asm/octeon/cvmx-pip.h diff --git a/drivers/staging/octeon/cvmx-pko-defs.h b/arch/mips/include/asm/octeon/cvmx-pko-defs.h index 50e779cf1ad8..50e779cf1ad8 100644 --- a/drivers/staging/octeon/cvmx-pko-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-pko-defs.h diff --git a/drivers/staging/octeon/cvmx-pko.h b/arch/mips/include/asm/octeon/cvmx-pko.h index de3412aada5d..de3412aada5d 100644 --- a/drivers/staging/octeon/cvmx-pko.h +++ b/arch/mips/include/asm/octeon/cvmx-pko.h diff --git a/drivers/staging/octeon/cvmx-pow.h b/arch/mips/include/asm/octeon/cvmx-pow.h index 999aefe3274c..999aefe3274c 100644 --- a/drivers/staging/octeon/cvmx-pow.h +++ b/arch/mips/include/asm/octeon/cvmx-pow.h diff --git a/drivers/staging/octeon/cvmx-scratch.h b/arch/mips/include/asm/octeon/cvmx-scratch.h index 96b70cfd6245..96b70cfd6245 100644 --- a/drivers/staging/octeon/cvmx-scratch.h +++ b/arch/mips/include/asm/octeon/cvmx-scratch.h diff --git a/arch/mips/include/asm/octeon/cvmx-sli-defs.h b/arch/mips/include/asm/octeon/cvmx-sli-defs.h new file mode 100644 index 000000000000..7c6c901d3d28 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-sli-defs.h @@ -0,0 +1,2172 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2011 Cavium Networks + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, Version 2, as + * published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_SLI_DEFS_H__ +#define __CVMX_SLI_DEFS_H__ + +#define CVMX_SLI_BIST_STATUS (0x0000000000000580ull) +#define CVMX_SLI_CTL_PORTX(offset) (0x0000000000000050ull + ((offset) & 3) * 16) +#define CVMX_SLI_CTL_STATUS (0x0000000000000570ull) +#define CVMX_SLI_DATA_OUT_CNT (0x00000000000005F0ull) +#define CVMX_SLI_DBG_DATA (0x0000000000000310ull) +#define CVMX_SLI_DBG_SELECT (0x0000000000000300ull) +#define CVMX_SLI_DMAX_CNT(offset) (0x0000000000000400ull + ((offset) & 1) * 16) +#define CVMX_SLI_DMAX_INT_LEVEL(offset) (0x00000000000003E0ull + ((offset) & 1) * 16) +#define CVMX_SLI_DMAX_TIM(offset) (0x0000000000000420ull + ((offset) & 1) * 16) +#define CVMX_SLI_INT_ENB_CIU (0x0000000000003CD0ull) +#define CVMX_SLI_INT_ENB_PORTX(offset) (0x0000000000000340ull + ((offset) & 1) * 16) +#define CVMX_SLI_INT_SUM (0x0000000000000330ull) +#define CVMX_SLI_LAST_WIN_RDATA0 (0x0000000000000600ull) +#define CVMX_SLI_LAST_WIN_RDATA1 (0x0000000000000610ull) +#define CVMX_SLI_LAST_WIN_RDATA2 (0x00000000000006C0ull) +#define CVMX_SLI_LAST_WIN_RDATA3 (0x00000000000006D0ull) +#define CVMX_SLI_MAC_CREDIT_CNT (0x0000000000003D70ull) +#define CVMX_SLI_MAC_CREDIT_CNT2 (0x0000000000003E10ull) +#define CVMX_SLI_MAC_NUMBER (0x0000000000003E00ull) +#define CVMX_SLI_MEM_ACCESS_CTL (0x00000000000002F0ull) +#define CVMX_SLI_MEM_ACCESS_SUBIDX(offset) (0x00000000000000E0ull + ((offset) & 31) * 16 - 16*12) +#define CVMX_SLI_MSI_ENB0 (0x0000000000003C50ull) +#define CVMX_SLI_MSI_ENB1 (0x0000000000003C60ull) +#define CVMX_SLI_MSI_ENB2 (0x0000000000003C70ull) +#define CVMX_SLI_MSI_ENB3 (0x0000000000003C80ull) +#define CVMX_SLI_MSI_RCV0 (0x0000000000003C10ull) +#define CVMX_SLI_MSI_RCV1 (0x0000000000003C20ull) +#define CVMX_SLI_MSI_RCV2 (0x0000000000003C30ull) +#define CVMX_SLI_MSI_RCV3 (0x0000000000003C40ull) +#define CVMX_SLI_MSI_RD_MAP (0x0000000000003CA0ull) +#define CVMX_SLI_MSI_W1C_ENB0 (0x0000000000003CF0ull) +#define CVMX_SLI_MSI_W1C_ENB1 (0x0000000000003D00ull) +#define CVMX_SLI_MSI_W1C_ENB2 (0x0000000000003D10ull) +#define CVMX_SLI_MSI_W1C_ENB3 (0x0000000000003D20ull) +#define CVMX_SLI_MSI_W1S_ENB0 (0x0000000000003D30ull) +#define CVMX_SLI_MSI_W1S_ENB1 (0x0000000000003D40ull) +#define CVMX_SLI_MSI_W1S_ENB2 (0x0000000000003D50ull) +#define CVMX_SLI_MSI_W1S_ENB3 (0x0000000000003D60ull) +#define CVMX_SLI_MSI_WR_MAP (0x0000000000003C90ull) +#define CVMX_SLI_PCIE_MSI_RCV (0x0000000000003CB0ull) +#define CVMX_SLI_PCIE_MSI_RCV_B1 (0x0000000000000650ull) +#define CVMX_SLI_PCIE_MSI_RCV_B2 (0x0000000000000660ull) +#define CVMX_SLI_PCIE_MSI_RCV_B3 (0x0000000000000670ull) +#define CVMX_SLI_PKTX_CNTS(offset) (0x0000000000002400ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_INSTR_BADDR(offset) (0x0000000000002800ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_INSTR_BAOFF_DBELL(offset) (0x0000000000002C00ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_INSTR_FIFO_RSIZE(offset) (0x0000000000003000ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_INSTR_HEADER(offset) (0x0000000000003400ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_IN_BP(offset) (0x0000000000003800ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_OUT_SIZE(offset) (0x0000000000000C00ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_SLIST_BADDR(offset) (0x0000000000001400ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_SLIST_BAOFF_DBELL(offset) (0x0000000000001800ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKTX_SLIST_FIFO_RSIZE(offset) (0x0000000000001C00ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKT_CNT_INT (0x0000000000001130ull) +#define CVMX_SLI_PKT_CNT_INT_ENB (0x0000000000001150ull) +#define CVMX_SLI_PKT_CTL (0x0000000000001220ull) +#define CVMX_SLI_PKT_DATA_OUT_ES (0x00000000000010B0ull) +#define CVMX_SLI_PKT_DATA_OUT_NS (0x00000000000010A0ull) +#define CVMX_SLI_PKT_DATA_OUT_ROR (0x0000000000001090ull) +#define CVMX_SLI_PKT_DPADDR (0x0000000000001080ull) +#define CVMX_SLI_PKT_INPUT_CONTROL (0x0000000000001170ull) +#define CVMX_SLI_PKT_INSTR_ENB (0x0000000000001000ull) +#define CVMX_SLI_PKT_INSTR_RD_SIZE (0x00000000000011A0ull) +#define CVMX_SLI_PKT_INSTR_SIZE (0x0000000000001020ull) +#define CVMX_SLI_PKT_INT_LEVELS (0x0000000000001120ull) +#define CVMX_SLI_PKT_IN_BP (0x0000000000001210ull) +#define CVMX_SLI_PKT_IN_DONEX_CNTS(offset) (0x0000000000002000ull + ((offset) & 31) * 16) +#define CVMX_SLI_PKT_IN_INSTR_COUNTS (0x0000000000001200ull) +#define CVMX_SLI_PKT_IN_PCIE_PORT (0x00000000000011B0ull) +#define CVMX_SLI_PKT_IPTR (0x0000000000001070ull) +#define CVMX_SLI_PKT_OUTPUT_WMARK (0x0000000000001180ull) +#define CVMX_SLI_PKT_OUT_BMODE (0x00000000000010D0ull) +#define CVMX_SLI_PKT_OUT_BP_EN (0x0000000000001240ull) +#define CVMX_SLI_PKT_OUT_ENB (0x0000000000001010ull) +#define CVMX_SLI_PKT_PCIE_PORT (0x00000000000010E0ull) +#define CVMX_SLI_PKT_PORT_IN_RST (0x00000000000011F0ull) +#define CVMX_SLI_PKT_SLIST_ES (0x0000000000001050ull) +#define CVMX_SLI_PKT_SLIST_NS (0x0000000000001040ull) +#define CVMX_SLI_PKT_SLIST_ROR (0x0000000000001030ull) +#define CVMX_SLI_PKT_TIME_INT (0x0000000000001140ull) +#define CVMX_SLI_PKT_TIME_INT_ENB (0x0000000000001160ull) +#define CVMX_SLI_PORTX_PKIND(offset) (0x0000000000000800ull + ((offset) & 31) * 16) +#define CVMX_SLI_S2M_PORTX_CTL(offset) (0x0000000000003D80ull + ((offset) & 3) * 16) +#define CVMX_SLI_SCRATCH_1 (0x00000000000003C0ull) +#define CVMX_SLI_SCRATCH_2 (0x00000000000003D0ull) +#define CVMX_SLI_STATE1 (0x0000000000000620ull) +#define CVMX_SLI_STATE2 (0x0000000000000630ull) +#define CVMX_SLI_STATE3 (0x0000000000000640ull) +#define CVMX_SLI_TX_PIPE (0x0000000000001230ull) +#define CVMX_SLI_WINDOW_CTL (0x00000000000002E0ull) +#define CVMX_SLI_WIN_RD_ADDR (0x0000000000000010ull) +#define CVMX_SLI_WIN_RD_DATA (0x0000000000000040ull) +#define CVMX_SLI_WIN_WR_ADDR (0x0000000000000000ull) +#define CVMX_SLI_WIN_WR_DATA (0x0000000000000020ull) +#define CVMX_SLI_WIN_WR_MASK (0x0000000000000030ull) + +union cvmx_sli_bist_status { + uint64_t u64; + struct cvmx_sli_bist_status_s { + uint64_t reserved_32_63:32; + uint64_t ncb_req:1; + uint64_t n2p0_c:1; + uint64_t n2p0_o:1; + uint64_t n2p1_c:1; + uint64_t n2p1_o:1; + uint64_t cpl_p0:1; + uint64_t cpl_p1:1; + uint64_t reserved_19_24:6; + uint64_t p2n0_c0:1; + uint64_t p2n0_c1:1; + uint64_t p2n0_n:1; + uint64_t p2n0_p0:1; + uint64_t p2n0_p1:1; + uint64_t p2n1_c0:1; + uint64_t p2n1_c1:1; + uint64_t p2n1_n:1; + uint64_t p2n1_p0:1; + uint64_t p2n1_p1:1; + uint64_t reserved_6_8:3; + uint64_t dsi1_1:1; + uint64_t dsi1_0:1; + uint64_t dsi0_1:1; + uint64_t dsi0_0:1; + uint64_t msi:1; + uint64_t ncb_cmd:1; + } s; + struct cvmx_sli_bist_status_cn61xx { + uint64_t reserved_31_63:33; + uint64_t n2p0_c:1; + uint64_t n2p0_o:1; + uint64_t reserved_27_28:2; + uint64_t cpl_p0:1; + uint64_t cpl_p1:1; + uint64_t reserved_19_24:6; + uint64_t p2n0_c0:1; + uint64_t p2n0_c1:1; + uint64_t p2n0_n:1; + uint64_t p2n0_p0:1; + uint64_t p2n0_p1:1; + uint64_t p2n1_c0:1; + uint64_t p2n1_c1:1; + uint64_t p2n1_n:1; + uint64_t p2n1_p0:1; + uint64_t p2n1_p1:1; + uint64_t reserved_6_8:3; + uint64_t dsi1_1:1; + uint64_t dsi1_0:1; + uint64_t dsi0_1:1; + uint64_t dsi0_0:1; + uint64_t msi:1; + uint64_t ncb_cmd:1; + } cn61xx; + struct cvmx_sli_bist_status_cn63xx { + uint64_t reserved_31_63:33; + uint64_t n2p0_c:1; + uint64_t n2p0_o:1; + uint64_t n2p1_c:1; + uint64_t n2p1_o:1; + uint64_t cpl_p0:1; + uint64_t cpl_p1:1; + uint64_t reserved_19_24:6; + uint64_t p2n0_c0:1; + uint64_t p2n0_c1:1; + uint64_t p2n0_n:1; + uint64_t p2n0_p0:1; + uint64_t p2n0_p1:1; + uint64_t p2n1_c0:1; + uint64_t p2n1_c1:1; + uint64_t p2n1_n:1; + uint64_t p2n1_p0:1; + uint64_t p2n1_p1:1; + uint64_t reserved_6_8:3; + uint64_t dsi1_1:1; + uint64_t dsi1_0:1; + uint64_t dsi0_1:1; + uint64_t dsi0_0:1; + uint64_t msi:1; + uint64_t ncb_cmd:1; + } cn63xx; + struct cvmx_sli_bist_status_cn63xx cn63xxp1; + struct cvmx_sli_bist_status_cn61xx cn66xx; + struct cvmx_sli_bist_status_s cn68xx; + struct cvmx_sli_bist_status_s cn68xxp1; +}; + +union cvmx_sli_ctl_portx { + uint64_t u64; + struct cvmx_sli_ctl_portx_s { + uint64_t reserved_22_63:42; + uint64_t intd:1; + uint64_t intc:1; + uint64_t intb:1; + uint64_t inta:1; + uint64_t dis_port:1; + uint64_t waitl_com:1; + uint64_t intd_map:2; + uint64_t intc_map:2; + uint64_t intb_map:2; + uint64_t inta_map:2; + uint64_t ctlp_ro:1; + uint64_t reserved_6_6:1; + uint64_t ptlp_ro:1; + uint64_t reserved_1_4:4; + uint64_t wait_com:1; + } s; + struct cvmx_sli_ctl_portx_s cn61xx; + struct cvmx_sli_ctl_portx_s cn63xx; + struct cvmx_sli_ctl_portx_s cn63xxp1; + struct cvmx_sli_ctl_portx_s cn66xx; + struct cvmx_sli_ctl_portx_s cn68xx; + struct cvmx_sli_ctl_portx_s cn68xxp1; +}; + +union cvmx_sli_ctl_status { + uint64_t u64; + struct cvmx_sli_ctl_status_s { + uint64_t reserved_20_63:44; + uint64_t p1_ntags:6; + uint64_t p0_ntags:6; + uint64_t chip_rev:8; + } s; + struct cvmx_sli_ctl_status_cn61xx { + uint64_t reserved_14_63:50; + uint64_t p0_ntags:6; + uint64_t chip_rev:8; + } cn61xx; + struct cvmx_sli_ctl_status_s cn63xx; + struct cvmx_sli_ctl_status_s cn63xxp1; + struct cvmx_sli_ctl_status_cn61xx cn66xx; + struct cvmx_sli_ctl_status_s cn68xx; + struct cvmx_sli_ctl_status_s cn68xxp1; +}; + +union cvmx_sli_data_out_cnt { + uint64_t u64; + struct cvmx_sli_data_out_cnt_s { + uint64_t reserved_44_63:20; + uint64_t p1_ucnt:16; + uint64_t p1_fcnt:6; + uint64_t p0_ucnt:16; + uint64_t p0_fcnt:6; + } s; + struct cvmx_sli_data_out_cnt_s cn61xx; + struct cvmx_sli_data_out_cnt_s cn63xx; + struct cvmx_sli_data_out_cnt_s cn63xxp1; + struct cvmx_sli_data_out_cnt_s cn66xx; + struct cvmx_sli_data_out_cnt_s cn68xx; + struct cvmx_sli_data_out_cnt_s cn68xxp1; +}; + +union cvmx_sli_dbg_data { + uint64_t u64; + struct cvmx_sli_dbg_data_s { + uint64_t reserved_18_63:46; + uint64_t dsel_ext:1; + uint64_t data:17; + } s; + struct cvmx_sli_dbg_data_s cn61xx; + struct cvmx_sli_dbg_data_s cn63xx; + struct cvmx_sli_dbg_data_s cn63xxp1; + struct cvmx_sli_dbg_data_s cn66xx; + struct cvmx_sli_dbg_data_s cn68xx; + struct cvmx_sli_dbg_data_s cn68xxp1; +}; + +union cvmx_sli_dbg_select { + uint64_t u64; + struct cvmx_sli_dbg_select_s { + uint64_t reserved_33_63:31; + uint64_t adbg_sel:1; + uint64_t dbg_sel:32; + } s; + struct cvmx_sli_dbg_select_s cn61xx; + struct cvmx_sli_dbg_select_s cn63xx; + struct cvmx_sli_dbg_select_s cn63xxp1; + struct cvmx_sli_dbg_select_s cn66xx; + struct cvmx_sli_dbg_select_s cn68xx; + struct cvmx_sli_dbg_select_s cn68xxp1; +}; + +union cvmx_sli_dmax_cnt { + uint64_t u64; + struct cvmx_sli_dmax_cnt_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_sli_dmax_cnt_s cn61xx; + struct cvmx_sli_dmax_cnt_s cn63xx; + struct cvmx_sli_dmax_cnt_s cn63xxp1; + struct cvmx_sli_dmax_cnt_s cn66xx; + struct cvmx_sli_dmax_cnt_s cn68xx; + struct cvmx_sli_dmax_cnt_s cn68xxp1; +}; + +union cvmx_sli_dmax_int_level { + uint64_t u64; + struct cvmx_sli_dmax_int_level_s { + uint64_t time:32; + uint64_t cnt:32; + } s; + struct cvmx_sli_dmax_int_level_s cn61xx; + struct cvmx_sli_dmax_int_level_s cn63xx; + struct cvmx_sli_dmax_int_level_s cn63xxp1; + struct cvmx_sli_dmax_int_level_s cn66xx; + struct cvmx_sli_dmax_int_level_s cn68xx; + struct cvmx_sli_dmax_int_level_s cn68xxp1; +}; + +union cvmx_sli_dmax_tim { + uint64_t u64; + struct cvmx_sli_dmax_tim_s { + uint64_t reserved_32_63:32; + uint64_t tim:32; + } s; + struct cvmx_sli_dmax_tim_s cn61xx; + struct cvmx_sli_dmax_tim_s cn63xx; + struct cvmx_sli_dmax_tim_s cn63xxp1; + struct cvmx_sli_dmax_tim_s cn66xx; + struct cvmx_sli_dmax_tim_s cn68xx; + struct cvmx_sli_dmax_tim_s cn68xxp1; +}; + +union cvmx_sli_int_enb_ciu { + uint64_t u64; + struct cvmx_sli_int_enb_ciu_s { + uint64_t reserved_62_63:2; + uint64_t pipe_err:1; + uint64_t ill_pad:1; + uint64_t sprt3_err:1; + uint64_t sprt2_err:1; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_28_31:4; + uint64_t m3_un_wi:1; + uint64_t m3_un_b0:1; + uint64_t m3_up_wi:1; + uint64_t m3_up_b0:1; + uint64_t m2_un_wi:1; + uint64_t m2_un_b0:1; + uint64_t m2_up_wi:1; + uint64_t m2_up_b0:1; + uint64_t reserved_18_19:2; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } s; + struct cvmx_sli_int_enb_ciu_cn61xx { + uint64_t reserved_61_63:3; + uint64_t ill_pad:1; + uint64_t sprt3_err:1; + uint64_t sprt2_err:1; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_28_31:4; + uint64_t m3_un_wi:1; + uint64_t m3_un_b0:1; + uint64_t m3_up_wi:1; + uint64_t m3_up_b0:1; + uint64_t m2_un_wi:1; + uint64_t m2_un_b0:1; + uint64_t m2_up_wi:1; + uint64_t m2_up_b0:1; + uint64_t reserved_18_19:2; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn61xx; + struct cvmx_sli_int_enb_ciu_cn63xx { + uint64_t reserved_61_63:3; + uint64_t ill_pad:1; + uint64_t reserved_58_59:2; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_18_31:14; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn63xx; + struct cvmx_sli_int_enb_ciu_cn63xx cn63xxp1; + struct cvmx_sli_int_enb_ciu_cn61xx cn66xx; + struct cvmx_sli_int_enb_ciu_cn68xx { + uint64_t reserved_62_63:2; + uint64_t pipe_err:1; + uint64_t ill_pad:1; + uint64_t reserved_58_59:2; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t reserved_51_51:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_18_31:14; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn68xx; + struct cvmx_sli_int_enb_ciu_cn68xx cn68xxp1; +}; + +union cvmx_sli_int_enb_portx { + uint64_t u64; + struct cvmx_sli_int_enb_portx_s { + uint64_t reserved_62_63:2; + uint64_t pipe_err:1; + uint64_t ill_pad:1; + uint64_t sprt3_err:1; + uint64_t sprt2_err:1; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_28_31:4; + uint64_t m3_un_wi:1; + uint64_t m3_un_b0:1; + uint64_t m3_up_wi:1; + uint64_t m3_up_b0:1; + uint64_t m2_un_wi:1; + uint64_t m2_un_b0:1; + uint64_t m2_up_wi:1; + uint64_t m2_up_b0:1; + uint64_t mac1_int:1; + uint64_t mac0_int:1; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } s; + struct cvmx_sli_int_enb_portx_cn61xx { + uint64_t reserved_61_63:3; + uint64_t ill_pad:1; + uint64_t sprt3_err:1; + uint64_t sprt2_err:1; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_28_31:4; + uint64_t m3_un_wi:1; + uint64_t m3_un_b0:1; + uint64_t m3_up_wi:1; + uint64_t m3_up_b0:1; + uint64_t m2_un_wi:1; + uint64_t m2_un_b0:1; + uint64_t m2_up_wi:1; + uint64_t m2_up_b0:1; + uint64_t mac1_int:1; + uint64_t mac0_int:1; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn61xx; + struct cvmx_sli_int_enb_portx_cn63xx { + uint64_t reserved_61_63:3; + uint64_t ill_pad:1; + uint64_t reserved_58_59:2; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_20_31:12; + uint64_t mac1_int:1; + uint64_t mac0_int:1; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn63xx; + struct cvmx_sli_int_enb_portx_cn63xx cn63xxp1; + struct cvmx_sli_int_enb_portx_cn61xx cn66xx; + struct cvmx_sli_int_enb_portx_cn68xx { + uint64_t reserved_62_63:2; + uint64_t pipe_err:1; + uint64_t ill_pad:1; + uint64_t reserved_58_59:2; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t reserved_51_51:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_20_31:12; + uint64_t mac1_int:1; + uint64_t mac0_int:1; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn68xx; + struct cvmx_sli_int_enb_portx_cn68xx cn68xxp1; +}; + +union cvmx_sli_int_sum { + uint64_t u64; + struct cvmx_sli_int_sum_s { + uint64_t reserved_62_63:2; + uint64_t pipe_err:1; + uint64_t ill_pad:1; + uint64_t sprt3_err:1; + uint64_t sprt2_err:1; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_28_31:4; + uint64_t m3_un_wi:1; + uint64_t m3_un_b0:1; + uint64_t m3_up_wi:1; + uint64_t m3_up_b0:1; + uint64_t m2_un_wi:1; + uint64_t m2_un_b0:1; + uint64_t m2_up_wi:1; + uint64_t m2_up_b0:1; + uint64_t mac1_int:1; + uint64_t mac0_int:1; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } s; + struct cvmx_sli_int_sum_cn61xx { + uint64_t reserved_61_63:3; + uint64_t ill_pad:1; + uint64_t sprt3_err:1; + uint64_t sprt2_err:1; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_28_31:4; + uint64_t m3_un_wi:1; + uint64_t m3_un_b0:1; + uint64_t m3_up_wi:1; + uint64_t m3_up_b0:1; + uint64_t m2_un_wi:1; + uint64_t m2_un_b0:1; + uint64_t m2_up_wi:1; + uint64_t m2_up_b0:1; + uint64_t mac1_int:1; + uint64_t mac0_int:1; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn61xx; + struct cvmx_sli_int_sum_cn63xx { + uint64_t reserved_61_63:3; + uint64_t ill_pad:1; + uint64_t reserved_58_59:2; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t pin_bp:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_20_31:12; + uint64_t mac1_int:1; + uint64_t mac0_int:1; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn63xx; + struct cvmx_sli_int_sum_cn63xx cn63xxp1; + struct cvmx_sli_int_sum_cn61xx cn66xx; + struct cvmx_sli_int_sum_cn68xx { + uint64_t reserved_62_63:2; + uint64_t pipe_err:1; + uint64_t ill_pad:1; + uint64_t reserved_58_59:2; + uint64_t sprt1_err:1; + uint64_t sprt0_err:1; + uint64_t pins_err:1; + uint64_t pop_err:1; + uint64_t pdi_err:1; + uint64_t pgl_err:1; + uint64_t reserved_51_51:1; + uint64_t pout_err:1; + uint64_t psldbof:1; + uint64_t pidbof:1; + uint64_t reserved_38_47:10; + uint64_t dtime:2; + uint64_t dcnt:2; + uint64_t dmafi:2; + uint64_t reserved_20_31:12; + uint64_t mac1_int:1; + uint64_t mac0_int:1; + uint64_t mio_int1:1; + uint64_t mio_int0:1; + uint64_t m1_un_wi:1; + uint64_t m1_un_b0:1; + uint64_t m1_up_wi:1; + uint64_t m1_up_b0:1; + uint64_t m0_un_wi:1; + uint64_t m0_un_b0:1; + uint64_t m0_up_wi:1; + uint64_t m0_up_b0:1; + uint64_t reserved_6_7:2; + uint64_t ptime:1; + uint64_t pcnt:1; + uint64_t iob2big:1; + uint64_t bar0_to:1; + uint64_t reserved_1_1:1; + uint64_t rml_to:1; + } cn68xx; + struct cvmx_sli_int_sum_cn68xx cn68xxp1; +}; + +union cvmx_sli_last_win_rdata0 { + uint64_t u64; + struct cvmx_sli_last_win_rdata0_s { + uint64_t data:64; + } s; + struct cvmx_sli_last_win_rdata0_s cn61xx; + struct cvmx_sli_last_win_rdata0_s cn63xx; + struct cvmx_sli_last_win_rdata0_s cn63xxp1; + struct cvmx_sli_last_win_rdata0_s cn66xx; + struct cvmx_sli_last_win_rdata0_s cn68xx; + struct cvmx_sli_last_win_rdata0_s cn68xxp1; +}; + +union cvmx_sli_last_win_rdata1 { + uint64_t u64; + struct cvmx_sli_last_win_rdata1_s { + uint64_t data:64; + } s; + struct cvmx_sli_last_win_rdata1_s cn61xx; + struct cvmx_sli_last_win_rdata1_s cn63xx; + struct cvmx_sli_last_win_rdata1_s cn63xxp1; + struct cvmx_sli_last_win_rdata1_s cn66xx; + struct cvmx_sli_last_win_rdata1_s cn68xx; + struct cvmx_sli_last_win_rdata1_s cn68xxp1; +}; + +union cvmx_sli_last_win_rdata2 { + uint64_t u64; + struct cvmx_sli_last_win_rdata2_s { + uint64_t data:64; + } s; + struct cvmx_sli_last_win_rdata2_s cn61xx; + struct cvmx_sli_last_win_rdata2_s cn66xx; +}; + +union cvmx_sli_last_win_rdata3 { + uint64_t u64; + struct cvmx_sli_last_win_rdata3_s { + uint64_t data:64; + } s; + struct cvmx_sli_last_win_rdata3_s cn61xx; + struct cvmx_sli_last_win_rdata3_s cn66xx; +}; + +union cvmx_sli_mac_credit_cnt { + uint64_t u64; + struct cvmx_sli_mac_credit_cnt_s { + uint64_t reserved_54_63:10; + uint64_t p1_c_d:1; + uint64_t p1_n_d:1; + uint64_t p1_p_d:1; + uint64_t p0_c_d:1; + uint64_t p0_n_d:1; + uint64_t p0_p_d:1; + uint64_t p1_ccnt:8; + uint64_t p1_ncnt:8; + uint64_t p1_pcnt:8; + uint64_t p0_ccnt:8; + uint64_t p0_ncnt:8; + uint64_t p0_pcnt:8; + } s; + struct cvmx_sli_mac_credit_cnt_s cn61xx; + struct cvmx_sli_mac_credit_cnt_s cn63xx; + struct cvmx_sli_mac_credit_cnt_cn63xxp1 { + uint64_t reserved_48_63:16; + uint64_t p1_ccnt:8; + uint64_t p1_ncnt:8; + uint64_t p1_pcnt:8; + uint64_t p0_ccnt:8; + uint64_t p0_ncnt:8; + uint64_t p0_pcnt:8; + } cn63xxp1; + struct cvmx_sli_mac_credit_cnt_s cn66xx; + struct cvmx_sli_mac_credit_cnt_s cn68xx; + struct cvmx_sli_mac_credit_cnt_s cn68xxp1; +}; + +union cvmx_sli_mac_credit_cnt2 { + uint64_t u64; + struct cvmx_sli_mac_credit_cnt2_s { + uint64_t reserved_54_63:10; + uint64_t p3_c_d:1; + uint64_t p3_n_d:1; + uint64_t p3_p_d:1; + uint64_t p2_c_d:1; + uint64_t p2_n_d:1; + uint64_t p2_p_d:1; + uint64_t p3_ccnt:8; + uint64_t p3_ncnt:8; + uint64_t p3_pcnt:8; + uint64_t p2_ccnt:8; + uint64_t p2_ncnt:8; + uint64_t p2_pcnt:8; + } s; + struct cvmx_sli_mac_credit_cnt2_s cn61xx; + struct cvmx_sli_mac_credit_cnt2_s cn66xx; +}; + +union cvmx_sli_mac_number { + uint64_t u64; + struct cvmx_sli_mac_number_s { + uint64_t reserved_9_63:55; + uint64_t a_mode:1; + uint64_t num:8; + } s; + struct cvmx_sli_mac_number_s cn61xx; + struct cvmx_sli_mac_number_cn63xx { + uint64_t reserved_8_63:56; + uint64_t num:8; + } cn63xx; + struct cvmx_sli_mac_number_s cn66xx; + struct cvmx_sli_mac_number_cn63xx cn68xx; + struct cvmx_sli_mac_number_cn63xx cn68xxp1; +}; + +union cvmx_sli_mem_access_ctl { + uint64_t u64; + struct cvmx_sli_mem_access_ctl_s { + uint64_t reserved_14_63:50; + uint64_t max_word:4; + uint64_t timer:10; + } s; + struct cvmx_sli_mem_access_ctl_s cn61xx; + struct cvmx_sli_mem_access_ctl_s cn63xx; + struct cvmx_sli_mem_access_ctl_s cn63xxp1; + struct cvmx_sli_mem_access_ctl_s cn66xx; + struct cvmx_sli_mem_access_ctl_s cn68xx; + struct cvmx_sli_mem_access_ctl_s cn68xxp1; +}; + +union cvmx_sli_mem_access_subidx { + uint64_t u64; + struct cvmx_sli_mem_access_subidx_s { + uint64_t reserved_43_63:21; + uint64_t zero:1; + uint64_t port:3; + uint64_t nmerge:1; + uint64_t esr:2; + uint64_t esw:2; + uint64_t wtype:2; + uint64_t rtype:2; + uint64_t reserved_0_29:30; + } s; + struct cvmx_sli_mem_access_subidx_cn61xx { + uint64_t reserved_43_63:21; + uint64_t zero:1; + uint64_t port:3; + uint64_t nmerge:1; + uint64_t esr:2; + uint64_t esw:2; + uint64_t wtype:2; + uint64_t rtype:2; + uint64_t ba:30; + } cn61xx; + struct cvmx_sli_mem_access_subidx_cn61xx cn63xx; + struct cvmx_sli_mem_access_subidx_cn61xx cn63xxp1; + struct cvmx_sli_mem_access_subidx_cn61xx cn66xx; + struct cvmx_sli_mem_access_subidx_cn68xx { + uint64_t reserved_43_63:21; + uint64_t zero:1; + uint64_t port:3; + uint64_t nmerge:1; + uint64_t esr:2; + uint64_t esw:2; + uint64_t wtype:2; + uint64_t rtype:2; + uint64_t ba:28; + uint64_t reserved_0_1:2; + } cn68xx; + struct cvmx_sli_mem_access_subidx_cn68xx cn68xxp1; +}; + +union cvmx_sli_msi_enb0 { + uint64_t u64; + struct cvmx_sli_msi_enb0_s { + uint64_t enb:64; + } s; + struct cvmx_sli_msi_enb0_s cn61xx; + struct cvmx_sli_msi_enb0_s cn63xx; + struct cvmx_sli_msi_enb0_s cn63xxp1; + struct cvmx_sli_msi_enb0_s cn66xx; + struct cvmx_sli_msi_enb0_s cn68xx; + struct cvmx_sli_msi_enb0_s cn68xxp1; +}; + +union cvmx_sli_msi_enb1 { + uint64_t u64; + struct cvmx_sli_msi_enb1_s { + uint64_t enb:64; + } s; + struct cvmx_sli_msi_enb1_s cn61xx; + struct cvmx_sli_msi_enb1_s cn63xx; + struct cvmx_sli_msi_enb1_s cn63xxp1; + struct cvmx_sli_msi_enb1_s cn66xx; + struct cvmx_sli_msi_enb1_s cn68xx; + struct cvmx_sli_msi_enb1_s cn68xxp1; +}; + +union cvmx_sli_msi_enb2 { + uint64_t u64; + struct cvmx_sli_msi_enb2_s { + uint64_t enb:64; + } s; + struct cvmx_sli_msi_enb2_s cn61xx; + struct cvmx_sli_msi_enb2_s cn63xx; + struct cvmx_sli_msi_enb2_s cn63xxp1; + struct cvmx_sli_msi_enb2_s cn66xx; + struct cvmx_sli_msi_enb2_s cn68xx; + struct cvmx_sli_msi_enb2_s cn68xxp1; +}; + +union cvmx_sli_msi_enb3 { + uint64_t u64; + struct cvmx_sli_msi_enb3_s { + uint64_t enb:64; + } s; + struct cvmx_sli_msi_enb3_s cn61xx; + struct cvmx_sli_msi_enb3_s cn63xx; + struct cvmx_sli_msi_enb3_s cn63xxp1; + struct cvmx_sli_msi_enb3_s cn66xx; + struct cvmx_sli_msi_enb3_s cn68xx; + struct cvmx_sli_msi_enb3_s cn68xxp1; +}; + +union cvmx_sli_msi_rcv0 { + uint64_t u64; + struct cvmx_sli_msi_rcv0_s { + uint64_t intr:64; + } s; + struct cvmx_sli_msi_rcv0_s cn61xx; + struct cvmx_sli_msi_rcv0_s cn63xx; + struct cvmx_sli_msi_rcv0_s cn63xxp1; + struct cvmx_sli_msi_rcv0_s cn66xx; + struct cvmx_sli_msi_rcv0_s cn68xx; + struct cvmx_sli_msi_rcv0_s cn68xxp1; +}; + +union cvmx_sli_msi_rcv1 { + uint64_t u64; + struct cvmx_sli_msi_rcv1_s { + uint64_t intr:64; + } s; + struct cvmx_sli_msi_rcv1_s cn61xx; + struct cvmx_sli_msi_rcv1_s cn63xx; + struct cvmx_sli_msi_rcv1_s cn63xxp1; + struct cvmx_sli_msi_rcv1_s cn66xx; + struct cvmx_sli_msi_rcv1_s cn68xx; + struct cvmx_sli_msi_rcv1_s cn68xxp1; +}; + +union cvmx_sli_msi_rcv2 { + uint64_t u64; + struct cvmx_sli_msi_rcv2_s { + uint64_t intr:64; + } s; + struct cvmx_sli_msi_rcv2_s cn61xx; + struct cvmx_sli_msi_rcv2_s cn63xx; + struct cvmx_sli_msi_rcv2_s cn63xxp1; + struct cvmx_sli_msi_rcv2_s cn66xx; + struct cvmx_sli_msi_rcv2_s cn68xx; + struct cvmx_sli_msi_rcv2_s cn68xxp1; +}; + +union cvmx_sli_msi_rcv3 { + uint64_t u64; + struct cvmx_sli_msi_rcv3_s { + uint64_t intr:64; + } s; + struct cvmx_sli_msi_rcv3_s cn61xx; + struct cvmx_sli_msi_rcv3_s cn63xx; + struct cvmx_sli_msi_rcv3_s cn63xxp1; + struct cvmx_sli_msi_rcv3_s cn66xx; + struct cvmx_sli_msi_rcv3_s cn68xx; + struct cvmx_sli_msi_rcv3_s cn68xxp1; +}; + +union cvmx_sli_msi_rd_map { + uint64_t u64; + struct cvmx_sli_msi_rd_map_s { + uint64_t reserved_16_63:48; + uint64_t rd_int:8; + uint64_t msi_int:8; + } s; + struct cvmx_sli_msi_rd_map_s cn61xx; + struct cvmx_sli_msi_rd_map_s cn63xx; + struct cvmx_sli_msi_rd_map_s cn63xxp1; + struct cvmx_sli_msi_rd_map_s cn66xx; + struct cvmx_sli_msi_rd_map_s cn68xx; + struct cvmx_sli_msi_rd_map_s cn68xxp1; +}; + +union cvmx_sli_msi_w1c_enb0 { + uint64_t u64; + struct cvmx_sli_msi_w1c_enb0_s { + uint64_t clr:64; + } s; + struct cvmx_sli_msi_w1c_enb0_s cn61xx; + struct cvmx_sli_msi_w1c_enb0_s cn63xx; + struct cvmx_sli_msi_w1c_enb0_s cn63xxp1; + struct cvmx_sli_msi_w1c_enb0_s cn66xx; + struct cvmx_sli_msi_w1c_enb0_s cn68xx; + struct cvmx_sli_msi_w1c_enb0_s cn68xxp1; +}; + +union cvmx_sli_msi_w1c_enb1 { + uint64_t u64; + struct cvmx_sli_msi_w1c_enb1_s { + uint64_t clr:64; + } s; + struct cvmx_sli_msi_w1c_enb1_s cn61xx; + struct cvmx_sli_msi_w1c_enb1_s cn63xx; + struct cvmx_sli_msi_w1c_enb1_s cn63xxp1; + struct cvmx_sli_msi_w1c_enb1_s cn66xx; + struct cvmx_sli_msi_w1c_enb1_s cn68xx; + struct cvmx_sli_msi_w1c_enb1_s cn68xxp1; +}; + +union cvmx_sli_msi_w1c_enb2 { + uint64_t u64; + struct cvmx_sli_msi_w1c_enb2_s { + uint64_t clr:64; + } s; + struct cvmx_sli_msi_w1c_enb2_s cn61xx; + struct cvmx_sli_msi_w1c_enb2_s cn63xx; + struct cvmx_sli_msi_w1c_enb2_s cn63xxp1; + struct cvmx_sli_msi_w1c_enb2_s cn66xx; + struct cvmx_sli_msi_w1c_enb2_s cn68xx; + struct cvmx_sli_msi_w1c_enb2_s cn68xxp1; +}; + +union cvmx_sli_msi_w1c_enb3 { + uint64_t u64; + struct cvmx_sli_msi_w1c_enb3_s { + uint64_t clr:64; + } s; + struct cvmx_sli_msi_w1c_enb3_s cn61xx; + struct cvmx_sli_msi_w1c_enb3_s cn63xx; + struct cvmx_sli_msi_w1c_enb3_s cn63xxp1; + struct cvmx_sli_msi_w1c_enb3_s cn66xx; + struct cvmx_sli_msi_w1c_enb3_s cn68xx; + struct cvmx_sli_msi_w1c_enb3_s cn68xxp1; +}; + +union cvmx_sli_msi_w1s_enb0 { + uint64_t u64; + struct cvmx_sli_msi_w1s_enb0_s { + uint64_t set:64; + } s; + struct cvmx_sli_msi_w1s_enb0_s cn61xx; + struct cvmx_sli_msi_w1s_enb0_s cn63xx; + struct cvmx_sli_msi_w1s_enb0_s cn63xxp1; + struct cvmx_sli_msi_w1s_enb0_s cn66xx; + struct cvmx_sli_msi_w1s_enb0_s cn68xx; + struct cvmx_sli_msi_w1s_enb0_s cn68xxp1; +}; + +union cvmx_sli_msi_w1s_enb1 { + uint64_t u64; + struct cvmx_sli_msi_w1s_enb1_s { + uint64_t set:64; + } s; + struct cvmx_sli_msi_w1s_enb1_s cn61xx; + struct cvmx_sli_msi_w1s_enb1_s cn63xx; + struct cvmx_sli_msi_w1s_enb1_s cn63xxp1; + struct cvmx_sli_msi_w1s_enb1_s cn66xx; + struct cvmx_sli_msi_w1s_enb1_s cn68xx; + struct cvmx_sli_msi_w1s_enb1_s cn68xxp1; +}; + +union cvmx_sli_msi_w1s_enb2 { + uint64_t u64; + struct cvmx_sli_msi_w1s_enb2_s { + uint64_t set:64; + } s; + struct cvmx_sli_msi_w1s_enb2_s cn61xx; + struct cvmx_sli_msi_w1s_enb2_s cn63xx; + struct cvmx_sli_msi_w1s_enb2_s cn63xxp1; + struct cvmx_sli_msi_w1s_enb2_s cn66xx; + struct cvmx_sli_msi_w1s_enb2_s cn68xx; + struct cvmx_sli_msi_w1s_enb2_s cn68xxp1; +}; + +union cvmx_sli_msi_w1s_enb3 { + uint64_t u64; + struct cvmx_sli_msi_w1s_enb3_s { + uint64_t set:64; + } s; + struct cvmx_sli_msi_w1s_enb3_s cn61xx; + struct cvmx_sli_msi_w1s_enb3_s cn63xx; + struct cvmx_sli_msi_w1s_enb3_s cn63xxp1; + struct cvmx_sli_msi_w1s_enb3_s cn66xx; + struct cvmx_sli_msi_w1s_enb3_s cn68xx; + struct cvmx_sli_msi_w1s_enb3_s cn68xxp1; +}; + +union cvmx_sli_msi_wr_map { + uint64_t u64; + struct cvmx_sli_msi_wr_map_s { + uint64_t reserved_16_63:48; + uint64_t ciu_int:8; + uint64_t msi_int:8; + } s; + struct cvmx_sli_msi_wr_map_s cn61xx; + struct cvmx_sli_msi_wr_map_s cn63xx; + struct cvmx_sli_msi_wr_map_s cn63xxp1; + struct cvmx_sli_msi_wr_map_s cn66xx; + struct cvmx_sli_msi_wr_map_s cn68xx; + struct cvmx_sli_msi_wr_map_s cn68xxp1; +}; + +union cvmx_sli_pcie_msi_rcv { + uint64_t u64; + struct cvmx_sli_pcie_msi_rcv_s { + uint64_t reserved_8_63:56; + uint64_t intr:8; + } s; + struct cvmx_sli_pcie_msi_rcv_s cn61xx; + struct cvmx_sli_pcie_msi_rcv_s cn63xx; + struct cvmx_sli_pcie_msi_rcv_s cn63xxp1; + struct cvmx_sli_pcie_msi_rcv_s cn66xx; + struct cvmx_sli_pcie_msi_rcv_s cn68xx; + struct cvmx_sli_pcie_msi_rcv_s cn68xxp1; +}; + +union cvmx_sli_pcie_msi_rcv_b1 { + uint64_t u64; + struct cvmx_sli_pcie_msi_rcv_b1_s { + uint64_t reserved_16_63:48; + uint64_t intr:8; + uint64_t reserved_0_7:8; + } s; + struct cvmx_sli_pcie_msi_rcv_b1_s cn61xx; + struct cvmx_sli_pcie_msi_rcv_b1_s cn63xx; + struct cvmx_sli_pcie_msi_rcv_b1_s cn63xxp1; + struct cvmx_sli_pcie_msi_rcv_b1_s cn66xx; + struct cvmx_sli_pcie_msi_rcv_b1_s cn68xx; + struct cvmx_sli_pcie_msi_rcv_b1_s cn68xxp1; +}; + +union cvmx_sli_pcie_msi_rcv_b2 { + uint64_t u64; + struct cvmx_sli_pcie_msi_rcv_b2_s { + uint64_t reserved_24_63:40; + uint64_t intr:8; + uint64_t reserved_0_15:16; + } s; + struct cvmx_sli_pcie_msi_rcv_b2_s cn61xx; + struct cvmx_sli_pcie_msi_rcv_b2_s cn63xx; + struct cvmx_sli_pcie_msi_rcv_b2_s cn63xxp1; + struct cvmx_sli_pcie_msi_rcv_b2_s cn66xx; + struct cvmx_sli_pcie_msi_rcv_b2_s cn68xx; + struct cvmx_sli_pcie_msi_rcv_b2_s cn68xxp1; +}; + +union cvmx_sli_pcie_msi_rcv_b3 { + uint64_t u64; + struct cvmx_sli_pcie_msi_rcv_b3_s { + uint64_t reserved_32_63:32; + uint64_t intr:8; + uint64_t reserved_0_23:24; + } s; + struct cvmx_sli_pcie_msi_rcv_b3_s cn61xx; + struct cvmx_sli_pcie_msi_rcv_b3_s cn63xx; + struct cvmx_sli_pcie_msi_rcv_b3_s cn63xxp1; + struct cvmx_sli_pcie_msi_rcv_b3_s cn66xx; + struct cvmx_sli_pcie_msi_rcv_b3_s cn68xx; + struct cvmx_sli_pcie_msi_rcv_b3_s cn68xxp1; +}; + +union cvmx_sli_pktx_cnts { + uint64_t u64; + struct cvmx_sli_pktx_cnts_s { + uint64_t reserved_54_63:10; + uint64_t timer:22; + uint64_t cnt:32; + } s; + struct cvmx_sli_pktx_cnts_s cn61xx; + struct cvmx_sli_pktx_cnts_s cn63xx; + struct cvmx_sli_pktx_cnts_s cn63xxp1; + struct cvmx_sli_pktx_cnts_s cn66xx; + struct cvmx_sli_pktx_cnts_s cn68xx; + struct cvmx_sli_pktx_cnts_s cn68xxp1; +}; + +union cvmx_sli_pktx_in_bp { + uint64_t u64; + struct cvmx_sli_pktx_in_bp_s { + uint64_t wmark:32; + uint64_t cnt:32; + } s; + struct cvmx_sli_pktx_in_bp_s cn61xx; + struct cvmx_sli_pktx_in_bp_s cn63xx; + struct cvmx_sli_pktx_in_bp_s cn63xxp1; + struct cvmx_sli_pktx_in_bp_s cn66xx; +}; + +union cvmx_sli_pktx_instr_baddr { + uint64_t u64; + struct cvmx_sli_pktx_instr_baddr_s { + uint64_t addr:61; + uint64_t reserved_0_2:3; + } s; + struct cvmx_sli_pktx_instr_baddr_s cn61xx; + struct cvmx_sli_pktx_instr_baddr_s cn63xx; + struct cvmx_sli_pktx_instr_baddr_s cn63xxp1; + struct cvmx_sli_pktx_instr_baddr_s cn66xx; + struct cvmx_sli_pktx_instr_baddr_s cn68xx; + struct cvmx_sli_pktx_instr_baddr_s cn68xxp1; +}; + +union cvmx_sli_pktx_instr_baoff_dbell { + uint64_t u64; + struct cvmx_sli_pktx_instr_baoff_dbell_s { + uint64_t aoff:32; + uint64_t dbell:32; + } s; + struct cvmx_sli_pktx_instr_baoff_dbell_s cn61xx; + struct cvmx_sli_pktx_instr_baoff_dbell_s cn63xx; + struct cvmx_sli_pktx_instr_baoff_dbell_s cn63xxp1; + struct cvmx_sli_pktx_instr_baoff_dbell_s cn66xx; + struct cvmx_sli_pktx_instr_baoff_dbell_s cn68xx; + struct cvmx_sli_pktx_instr_baoff_dbell_s cn68xxp1; +}; + +union cvmx_sli_pktx_instr_fifo_rsize { + uint64_t u64; + struct cvmx_sli_pktx_instr_fifo_rsize_s { + uint64_t max:9; + uint64_t rrp:9; + uint64_t wrp:9; + uint64_t fcnt:5; + uint64_t rsize:32; + } s; + struct cvmx_sli_pktx_instr_fifo_rsize_s cn61xx; + struct cvmx_sli_pktx_instr_fifo_rsize_s cn63xx; + struct cvmx_sli_pktx_instr_fifo_rsize_s cn63xxp1; + struct cvmx_sli_pktx_instr_fifo_rsize_s cn66xx; + struct cvmx_sli_pktx_instr_fifo_rsize_s cn68xx; + struct cvmx_sli_pktx_instr_fifo_rsize_s cn68xxp1; +}; + +union cvmx_sli_pktx_instr_header { + uint64_t u64; + struct cvmx_sli_pktx_instr_header_s { + uint64_t reserved_44_63:20; + uint64_t pbp:1; + uint64_t reserved_38_42:5; + uint64_t rparmode:2; + uint64_t reserved_35_35:1; + uint64_t rskp_len:7; + uint64_t rngrpext:2; + uint64_t rnqos:1; + uint64_t rngrp:1; + uint64_t rntt:1; + uint64_t rntag:1; + uint64_t use_ihdr:1; + uint64_t reserved_16_20:5; + uint64_t par_mode:2; + uint64_t reserved_13_13:1; + uint64_t skp_len:7; + uint64_t ngrpext:2; + uint64_t nqos:1; + uint64_t ngrp:1; + uint64_t ntt:1; + uint64_t ntag:1; + } s; + struct cvmx_sli_pktx_instr_header_cn61xx { + uint64_t reserved_44_63:20; + uint64_t pbp:1; + uint64_t reserved_38_42:5; + uint64_t rparmode:2; + uint64_t reserved_35_35:1; + uint64_t rskp_len:7; + uint64_t reserved_26_27:2; + uint64_t rnqos:1; + uint64_t rngrp:1; + uint64_t rntt:1; + uint64_t rntag:1; + uint64_t use_ihdr:1; + uint64_t reserved_16_20:5; + uint64_t par_mode:2; + uint64_t reserved_13_13:1; + uint64_t skp_len:7; + uint64_t reserved_4_5:2; + uint64_t nqos:1; + uint64_t ngrp:1; + uint64_t ntt:1; + uint64_t ntag:1; + } cn61xx; + struct cvmx_sli_pktx_instr_header_cn61xx cn63xx; + struct cvmx_sli_pktx_instr_header_cn61xx cn63xxp1; + struct cvmx_sli_pktx_instr_header_cn61xx cn66xx; + struct cvmx_sli_pktx_instr_header_s cn68xx; + struct cvmx_sli_pktx_instr_header_cn61xx cn68xxp1; +}; + +union cvmx_sli_pktx_out_size { + uint64_t u64; + struct cvmx_sli_pktx_out_size_s { + uint64_t reserved_23_63:41; + uint64_t isize:7; + uint64_t bsize:16; + } s; + struct cvmx_sli_pktx_out_size_s cn61xx; + struct cvmx_sli_pktx_out_size_s cn63xx; + struct cvmx_sli_pktx_out_size_s cn63xxp1; + struct cvmx_sli_pktx_out_size_s cn66xx; + struct cvmx_sli_pktx_out_size_s cn68xx; + struct cvmx_sli_pktx_out_size_s cn68xxp1; +}; + +union cvmx_sli_pktx_slist_baddr { + uint64_t u64; + struct cvmx_sli_pktx_slist_baddr_s { + uint64_t addr:60; + uint64_t reserved_0_3:4; + } s; + struct cvmx_sli_pktx_slist_baddr_s cn61xx; + struct cvmx_sli_pktx_slist_baddr_s cn63xx; + struct cvmx_sli_pktx_slist_baddr_s cn63xxp1; + struct cvmx_sli_pktx_slist_baddr_s cn66xx; + struct cvmx_sli_pktx_slist_baddr_s cn68xx; + struct cvmx_sli_pktx_slist_baddr_s cn68xxp1; +}; + +union cvmx_sli_pktx_slist_baoff_dbell { + uint64_t u64; + struct cvmx_sli_pktx_slist_baoff_dbell_s { + uint64_t aoff:32; + uint64_t dbell:32; + } s; + struct cvmx_sli_pktx_slist_baoff_dbell_s cn61xx; + struct cvmx_sli_pktx_slist_baoff_dbell_s cn63xx; + struct cvmx_sli_pktx_slist_baoff_dbell_s cn63xxp1; + struct cvmx_sli_pktx_slist_baoff_dbell_s cn66xx; + struct cvmx_sli_pktx_slist_baoff_dbell_s cn68xx; + struct cvmx_sli_pktx_slist_baoff_dbell_s cn68xxp1; +}; + +union cvmx_sli_pktx_slist_fifo_rsize { + uint64_t u64; + struct cvmx_sli_pktx_slist_fifo_rsize_s { + uint64_t reserved_32_63:32; + uint64_t rsize:32; + } s; + struct cvmx_sli_pktx_slist_fifo_rsize_s cn61xx; + struct cvmx_sli_pktx_slist_fifo_rsize_s cn63xx; + struct cvmx_sli_pktx_slist_fifo_rsize_s cn63xxp1; + struct cvmx_sli_pktx_slist_fifo_rsize_s cn66xx; + struct cvmx_sli_pktx_slist_fifo_rsize_s cn68xx; + struct cvmx_sli_pktx_slist_fifo_rsize_s cn68xxp1; +}; + +union cvmx_sli_pkt_cnt_int { + uint64_t u64; + struct cvmx_sli_pkt_cnt_int_s { + uint64_t reserved_32_63:32; + uint64_t port:32; + } s; + struct cvmx_sli_pkt_cnt_int_s cn61xx; + struct cvmx_sli_pkt_cnt_int_s cn63xx; + struct cvmx_sli_pkt_cnt_int_s cn63xxp1; + struct cvmx_sli_pkt_cnt_int_s cn66xx; + struct cvmx_sli_pkt_cnt_int_s cn68xx; + struct cvmx_sli_pkt_cnt_int_s cn68xxp1; +}; + +union cvmx_sli_pkt_cnt_int_enb { + uint64_t u64; + struct cvmx_sli_pkt_cnt_int_enb_s { + uint64_t reserved_32_63:32; + uint64_t port:32; + } s; + struct cvmx_sli_pkt_cnt_int_enb_s cn61xx; + struct cvmx_sli_pkt_cnt_int_enb_s cn63xx; + struct cvmx_sli_pkt_cnt_int_enb_s cn63xxp1; + struct cvmx_sli_pkt_cnt_int_enb_s cn66xx; + struct cvmx_sli_pkt_cnt_int_enb_s cn68xx; + struct cvmx_sli_pkt_cnt_int_enb_s cn68xxp1; +}; + +union cvmx_sli_pkt_ctl { + uint64_t u64; + struct cvmx_sli_pkt_ctl_s { + uint64_t reserved_5_63:59; + uint64_t ring_en:1; + uint64_t pkt_bp:4; + } s; + struct cvmx_sli_pkt_ctl_s cn61xx; + struct cvmx_sli_pkt_ctl_s cn63xx; + struct cvmx_sli_pkt_ctl_s cn63xxp1; + struct cvmx_sli_pkt_ctl_s cn66xx; + struct cvmx_sli_pkt_ctl_s cn68xx; + struct cvmx_sli_pkt_ctl_s cn68xxp1; +}; + +union cvmx_sli_pkt_data_out_es { + uint64_t u64; + struct cvmx_sli_pkt_data_out_es_s { + uint64_t es:64; + } s; + struct cvmx_sli_pkt_data_out_es_s cn61xx; + struct cvmx_sli_pkt_data_out_es_s cn63xx; + struct cvmx_sli_pkt_data_out_es_s cn63xxp1; + struct cvmx_sli_pkt_data_out_es_s cn66xx; + struct cvmx_sli_pkt_data_out_es_s cn68xx; + struct cvmx_sli_pkt_data_out_es_s cn68xxp1; +}; + +union cvmx_sli_pkt_data_out_ns { + uint64_t u64; + struct cvmx_sli_pkt_data_out_ns_s { + uint64_t reserved_32_63:32; + uint64_t nsr:32; + } s; + struct cvmx_sli_pkt_data_out_ns_s cn61xx; + struct cvmx_sli_pkt_data_out_ns_s cn63xx; + struct cvmx_sli_pkt_data_out_ns_s cn63xxp1; + struct cvmx_sli_pkt_data_out_ns_s cn66xx; + struct cvmx_sli_pkt_data_out_ns_s cn68xx; + struct cvmx_sli_pkt_data_out_ns_s cn68xxp1; +}; + +union cvmx_sli_pkt_data_out_ror { + uint64_t u64; + struct cvmx_sli_pkt_data_out_ror_s { + uint64_t reserved_32_63:32; + uint64_t ror:32; + } s; + struct cvmx_sli_pkt_data_out_ror_s cn61xx; + struct cvmx_sli_pkt_data_out_ror_s cn63xx; + struct cvmx_sli_pkt_data_out_ror_s cn63xxp1; + struct cvmx_sli_pkt_data_out_ror_s cn66xx; + struct cvmx_sli_pkt_data_out_ror_s cn68xx; + struct cvmx_sli_pkt_data_out_ror_s cn68xxp1; +}; + +union cvmx_sli_pkt_dpaddr { + uint64_t u64; + struct cvmx_sli_pkt_dpaddr_s { + uint64_t reserved_32_63:32; + uint64_t dptr:32; + } s; + struct cvmx_sli_pkt_dpaddr_s cn61xx; + struct cvmx_sli_pkt_dpaddr_s cn63xx; + struct cvmx_sli_pkt_dpaddr_s cn63xxp1; + struct cvmx_sli_pkt_dpaddr_s cn66xx; + struct cvmx_sli_pkt_dpaddr_s cn68xx; + struct cvmx_sli_pkt_dpaddr_s cn68xxp1; +}; + +union cvmx_sli_pkt_in_bp { + uint64_t u64; + struct cvmx_sli_pkt_in_bp_s { + uint64_t reserved_32_63:32; + uint64_t bp:32; + } s; + struct cvmx_sli_pkt_in_bp_s cn61xx; + struct cvmx_sli_pkt_in_bp_s cn63xx; + struct cvmx_sli_pkt_in_bp_s cn63xxp1; + struct cvmx_sli_pkt_in_bp_s cn66xx; +}; + +union cvmx_sli_pkt_in_donex_cnts { + uint64_t u64; + struct cvmx_sli_pkt_in_donex_cnts_s { + uint64_t reserved_32_63:32; + uint64_t cnt:32; + } s; + struct cvmx_sli_pkt_in_donex_cnts_s cn61xx; + struct cvmx_sli_pkt_in_donex_cnts_s cn63xx; + struct cvmx_sli_pkt_in_donex_cnts_s cn63xxp1; + struct cvmx_sli_pkt_in_donex_cnts_s cn66xx; + struct cvmx_sli_pkt_in_donex_cnts_s cn68xx; + struct cvmx_sli_pkt_in_donex_cnts_s cn68xxp1; +}; + +union cvmx_sli_pkt_in_instr_counts { + uint64_t u64; + struct cvmx_sli_pkt_in_instr_counts_s { + uint64_t wr_cnt:32; + uint64_t rd_cnt:32; + } s; + struct cvmx_sli_pkt_in_instr_counts_s cn61xx; + struct cvmx_sli_pkt_in_instr_counts_s cn63xx; + struct cvmx_sli_pkt_in_instr_counts_s cn63xxp1; + struct cvmx_sli_pkt_in_instr_counts_s cn66xx; + struct cvmx_sli_pkt_in_instr_counts_s cn68xx; + struct cvmx_sli_pkt_in_instr_counts_s cn68xxp1; +}; + +union cvmx_sli_pkt_in_pcie_port { + uint64_t u64; + struct cvmx_sli_pkt_in_pcie_port_s { + uint64_t pp:64; + } s; + struct cvmx_sli_pkt_in_pcie_port_s cn61xx; + struct cvmx_sli_pkt_in_pcie_port_s cn63xx; + struct cvmx_sli_pkt_in_pcie_port_s cn63xxp1; + struct cvmx_sli_pkt_in_pcie_port_s cn66xx; + struct cvmx_sli_pkt_in_pcie_port_s cn68xx; + struct cvmx_sli_pkt_in_pcie_port_s cn68xxp1; +}; + +union cvmx_sli_pkt_input_control { + uint64_t u64; + struct cvmx_sli_pkt_input_control_s { + uint64_t prd_erst:1; + uint64_t prd_rds:7; + uint64_t gii_erst:1; + uint64_t gii_rds:7; + uint64_t reserved_41_47:7; + uint64_t prc_idle:1; + uint64_t reserved_24_39:16; + uint64_t pin_rst:1; + uint64_t pkt_rr:1; + uint64_t pbp_dhi:13; + uint64_t d_nsr:1; + uint64_t d_esr:2; + uint64_t d_ror:1; + uint64_t use_csr:1; + uint64_t nsr:1; + uint64_t esr:2; + uint64_t ror:1; + } s; + struct cvmx_sli_pkt_input_control_s cn61xx; + struct cvmx_sli_pkt_input_control_cn63xx { + uint64_t reserved_23_63:41; + uint64_t pkt_rr:1; + uint64_t pbp_dhi:13; + uint64_t d_nsr:1; + uint64_t d_esr:2; + uint64_t d_ror:1; + uint64_t use_csr:1; + uint64_t nsr:1; + uint64_t esr:2; + uint64_t ror:1; + } cn63xx; + struct cvmx_sli_pkt_input_control_cn63xx cn63xxp1; + struct cvmx_sli_pkt_input_control_s cn66xx; + struct cvmx_sli_pkt_input_control_s cn68xx; + struct cvmx_sli_pkt_input_control_s cn68xxp1; +}; + +union cvmx_sli_pkt_instr_enb { + uint64_t u64; + struct cvmx_sli_pkt_instr_enb_s { + uint64_t reserved_32_63:32; + uint64_t enb:32; + } s; + struct cvmx_sli_pkt_instr_enb_s cn61xx; + struct cvmx_sli_pkt_instr_enb_s cn63xx; + struct cvmx_sli_pkt_instr_enb_s cn63xxp1; + struct cvmx_sli_pkt_instr_enb_s cn66xx; + struct cvmx_sli_pkt_instr_enb_s cn68xx; + struct cvmx_sli_pkt_instr_enb_s cn68xxp1; +}; + +union cvmx_sli_pkt_instr_rd_size { + uint64_t u64; + struct cvmx_sli_pkt_instr_rd_size_s { + uint64_t rdsize:64; + } s; + struct cvmx_sli_pkt_instr_rd_size_s cn61xx; + struct cvmx_sli_pkt_instr_rd_size_s cn63xx; + struct cvmx_sli_pkt_instr_rd_size_s cn63xxp1; + struct cvmx_sli_pkt_instr_rd_size_s cn66xx; + struct cvmx_sli_pkt_instr_rd_size_s cn68xx; + struct cvmx_sli_pkt_instr_rd_size_s cn68xxp1; +}; + +union cvmx_sli_pkt_instr_size { + uint64_t u64; + struct cvmx_sli_pkt_instr_size_s { + uint64_t reserved_32_63:32; + uint64_t is_64b:32; + } s; + struct cvmx_sli_pkt_instr_size_s cn61xx; + struct cvmx_sli_pkt_instr_size_s cn63xx; + struct cvmx_sli_pkt_instr_size_s cn63xxp1; + struct cvmx_sli_pkt_instr_size_s cn66xx; + struct cvmx_sli_pkt_instr_size_s cn68xx; + struct cvmx_sli_pkt_instr_size_s cn68xxp1; +}; + +union cvmx_sli_pkt_int_levels { + uint64_t u64; + struct cvmx_sli_pkt_int_levels_s { + uint64_t reserved_54_63:10; + uint64_t time:22; + uint64_t cnt:32; + } s; + struct cvmx_sli_pkt_int_levels_s cn61xx; + struct cvmx_sli_pkt_int_levels_s cn63xx; + struct cvmx_sli_pkt_int_levels_s cn63xxp1; + struct cvmx_sli_pkt_int_levels_s cn66xx; + struct cvmx_sli_pkt_int_levels_s cn68xx; + struct cvmx_sli_pkt_int_levels_s cn68xxp1; +}; + +union cvmx_sli_pkt_iptr { + uint64_t u64; + struct cvmx_sli_pkt_iptr_s { + uint64_t reserved_32_63:32; + uint64_t iptr:32; + } s; + struct cvmx_sli_pkt_iptr_s cn61xx; + struct cvmx_sli_pkt_iptr_s cn63xx; + struct cvmx_sli_pkt_iptr_s cn63xxp1; + struct cvmx_sli_pkt_iptr_s cn66xx; + struct cvmx_sli_pkt_iptr_s cn68xx; + struct cvmx_sli_pkt_iptr_s cn68xxp1; +}; + +union cvmx_sli_pkt_out_bmode { + uint64_t u64; + struct cvmx_sli_pkt_out_bmode_s { + uint64_t reserved_32_63:32; + uint64_t bmode:32; + } s; + struct cvmx_sli_pkt_out_bmode_s cn61xx; + struct cvmx_sli_pkt_out_bmode_s cn63xx; + struct cvmx_sli_pkt_out_bmode_s cn63xxp1; + struct cvmx_sli_pkt_out_bmode_s cn66xx; + struct cvmx_sli_pkt_out_bmode_s cn68xx; + struct cvmx_sli_pkt_out_bmode_s cn68xxp1; +}; + +union cvmx_sli_pkt_out_bp_en { + uint64_t u64; + struct cvmx_sli_pkt_out_bp_en_s { + uint64_t reserved_32_63:32; + uint64_t bp_en:32; + } s; + struct cvmx_sli_pkt_out_bp_en_s cn68xx; + struct cvmx_sli_pkt_out_bp_en_s cn68xxp1; +}; + +union cvmx_sli_pkt_out_enb { + uint64_t u64; + struct cvmx_sli_pkt_out_enb_s { + uint64_t reserved_32_63:32; + uint64_t enb:32; + } s; + struct cvmx_sli_pkt_out_enb_s cn61xx; + struct cvmx_sli_pkt_out_enb_s cn63xx; + struct cvmx_sli_pkt_out_enb_s cn63xxp1; + struct cvmx_sli_pkt_out_enb_s cn66xx; + struct cvmx_sli_pkt_out_enb_s cn68xx; + struct cvmx_sli_pkt_out_enb_s cn68xxp1; +}; + +union cvmx_sli_pkt_output_wmark { + uint64_t u64; + struct cvmx_sli_pkt_output_wmark_s { + uint64_t reserved_32_63:32; + uint64_t wmark:32; + } s; + struct cvmx_sli_pkt_output_wmark_s cn61xx; + struct cvmx_sli_pkt_output_wmark_s cn63xx; + struct cvmx_sli_pkt_output_wmark_s cn63xxp1; + struct cvmx_sli_pkt_output_wmark_s cn66xx; + struct cvmx_sli_pkt_output_wmark_s cn68xx; + struct cvmx_sli_pkt_output_wmark_s cn68xxp1; +}; + +union cvmx_sli_pkt_pcie_port { + uint64_t u64; + struct cvmx_sli_pkt_pcie_port_s { + uint64_t pp:64; + } s; + struct cvmx_sli_pkt_pcie_port_s cn61xx; + struct cvmx_sli_pkt_pcie_port_s cn63xx; + struct cvmx_sli_pkt_pcie_port_s cn63xxp1; + struct cvmx_sli_pkt_pcie_port_s cn66xx; + struct cvmx_sli_pkt_pcie_port_s cn68xx; + struct cvmx_sli_pkt_pcie_port_s cn68xxp1; +}; + +union cvmx_sli_pkt_port_in_rst { + uint64_t u64; + struct cvmx_sli_pkt_port_in_rst_s { + uint64_t in_rst:32; + uint64_t out_rst:32; + } s; + struct cvmx_sli_pkt_port_in_rst_s cn61xx; + struct cvmx_sli_pkt_port_in_rst_s cn63xx; + struct cvmx_sli_pkt_port_in_rst_s cn63xxp1; + struct cvmx_sli_pkt_port_in_rst_s cn66xx; + struct cvmx_sli_pkt_port_in_rst_s cn68xx; + struct cvmx_sli_pkt_port_in_rst_s cn68xxp1; +}; + +union cvmx_sli_pkt_slist_es { + uint64_t u64; + struct cvmx_sli_pkt_slist_es_s { + uint64_t es:64; + } s; + struct cvmx_sli_pkt_slist_es_s cn61xx; + struct cvmx_sli_pkt_slist_es_s cn63xx; + struct cvmx_sli_pkt_slist_es_s cn63xxp1; + struct cvmx_sli_pkt_slist_es_s cn66xx; + struct cvmx_sli_pkt_slist_es_s cn68xx; + struct cvmx_sli_pkt_slist_es_s cn68xxp1; +}; + +union cvmx_sli_pkt_slist_ns { + uint64_t u64; + struct cvmx_sli_pkt_slist_ns_s { + uint64_t reserved_32_63:32; + uint64_t nsr:32; + } s; + struct cvmx_sli_pkt_slist_ns_s cn61xx; + struct cvmx_sli_pkt_slist_ns_s cn63xx; + struct cvmx_sli_pkt_slist_ns_s cn63xxp1; + struct cvmx_sli_pkt_slist_ns_s cn66xx; + struct cvmx_sli_pkt_slist_ns_s cn68xx; + struct cvmx_sli_pkt_slist_ns_s cn68xxp1; +}; + +union cvmx_sli_pkt_slist_ror { + uint64_t u64; + struct cvmx_sli_pkt_slist_ror_s { + uint64_t reserved_32_63:32; + uint64_t ror:32; + } s; + struct cvmx_sli_pkt_slist_ror_s cn61xx; + struct cvmx_sli_pkt_slist_ror_s cn63xx; + struct cvmx_sli_pkt_slist_ror_s cn63xxp1; + struct cvmx_sli_pkt_slist_ror_s cn66xx; + struct cvmx_sli_pkt_slist_ror_s cn68xx; + struct cvmx_sli_pkt_slist_ror_s cn68xxp1; +}; + +union cvmx_sli_pkt_time_int { + uint64_t u64; + struct cvmx_sli_pkt_time_int_s { + uint64_t reserved_32_63:32; + uint64_t port:32; + } s; + struct cvmx_sli_pkt_time_int_s cn61xx; + struct cvmx_sli_pkt_time_int_s cn63xx; + struct cvmx_sli_pkt_time_int_s cn63xxp1; + struct cvmx_sli_pkt_time_int_s cn66xx; + struct cvmx_sli_pkt_time_int_s cn68xx; + struct cvmx_sli_pkt_time_int_s cn68xxp1; +}; + +union cvmx_sli_pkt_time_int_enb { + uint64_t u64; + struct cvmx_sli_pkt_time_int_enb_s { + uint64_t reserved_32_63:32; + uint64_t port:32; + } s; + struct cvmx_sli_pkt_time_int_enb_s cn61xx; + struct cvmx_sli_pkt_time_int_enb_s cn63xx; + struct cvmx_sli_pkt_time_int_enb_s cn63xxp1; + struct cvmx_sli_pkt_time_int_enb_s cn66xx; + struct cvmx_sli_pkt_time_int_enb_s cn68xx; + struct cvmx_sli_pkt_time_int_enb_s cn68xxp1; +}; + +union cvmx_sli_portx_pkind { + uint64_t u64; + struct cvmx_sli_portx_pkind_s { + uint64_t reserved_25_63:39; + uint64_t rpk_enb:1; + uint64_t reserved_22_23:2; + uint64_t pkindr:6; + uint64_t reserved_14_15:2; + uint64_t bpkind:6; + uint64_t reserved_6_7:2; + uint64_t pkind:6; + } s; + struct cvmx_sli_portx_pkind_s cn68xx; + struct cvmx_sli_portx_pkind_cn68xxp1 { + uint64_t reserved_14_63:50; + uint64_t bpkind:6; + uint64_t reserved_6_7:2; + uint64_t pkind:6; + } cn68xxp1; +}; + +union cvmx_sli_s2m_portx_ctl { + uint64_t u64; + struct cvmx_sli_s2m_portx_ctl_s { + uint64_t reserved_5_63:59; + uint64_t wind_d:1; + uint64_t bar0_d:1; + uint64_t mrrs:3; + } s; + struct cvmx_sli_s2m_portx_ctl_s cn61xx; + struct cvmx_sli_s2m_portx_ctl_s cn63xx; + struct cvmx_sli_s2m_portx_ctl_s cn63xxp1; + struct cvmx_sli_s2m_portx_ctl_s cn66xx; + struct cvmx_sli_s2m_portx_ctl_s cn68xx; + struct cvmx_sli_s2m_portx_ctl_s cn68xxp1; +}; + +union cvmx_sli_scratch_1 { + uint64_t u64; + struct cvmx_sli_scratch_1_s { + uint64_t data:64; + } s; + struct cvmx_sli_scratch_1_s cn61xx; + struct cvmx_sli_scratch_1_s cn63xx; + struct cvmx_sli_scratch_1_s cn63xxp1; + struct cvmx_sli_scratch_1_s cn66xx; + struct cvmx_sli_scratch_1_s cn68xx; + struct cvmx_sli_scratch_1_s cn68xxp1; +}; + +union cvmx_sli_scratch_2 { + uint64_t u64; + struct cvmx_sli_scratch_2_s { + uint64_t data:64; + } s; + struct cvmx_sli_scratch_2_s cn61xx; + struct cvmx_sli_scratch_2_s cn63xx; + struct cvmx_sli_scratch_2_s cn63xxp1; + struct cvmx_sli_scratch_2_s cn66xx; + struct cvmx_sli_scratch_2_s cn68xx; + struct cvmx_sli_scratch_2_s cn68xxp1; +}; + +union cvmx_sli_state1 { + uint64_t u64; + struct cvmx_sli_state1_s { + uint64_t cpl1:12; + uint64_t cpl0:12; + uint64_t arb:1; + uint64_t csr:39; + } s; + struct cvmx_sli_state1_s cn61xx; + struct cvmx_sli_state1_s cn63xx; + struct cvmx_sli_state1_s cn63xxp1; + struct cvmx_sli_state1_s cn66xx; + struct cvmx_sli_state1_s cn68xx; + struct cvmx_sli_state1_s cn68xxp1; +}; + +union cvmx_sli_state2 { + uint64_t u64; + struct cvmx_sli_state2_s { + uint64_t reserved_56_63:8; + uint64_t nnp1:8; + uint64_t reserved_47_47:1; + uint64_t rac:1; + uint64_t csm1:15; + uint64_t csm0:15; + uint64_t nnp0:8; + uint64_t nnd:8; + } s; + struct cvmx_sli_state2_s cn61xx; + struct cvmx_sli_state2_s cn63xx; + struct cvmx_sli_state2_s cn63xxp1; + struct cvmx_sli_state2_s cn66xx; + struct cvmx_sli_state2_s cn68xx; + struct cvmx_sli_state2_s cn68xxp1; +}; + +union cvmx_sli_state3 { + uint64_t u64; + struct cvmx_sli_state3_s { + uint64_t reserved_56_63:8; + uint64_t psm1:15; + uint64_t psm0:15; + uint64_t nsm1:13; + uint64_t nsm0:13; + } s; + struct cvmx_sli_state3_s cn61xx; + struct cvmx_sli_state3_s cn63xx; + struct cvmx_sli_state3_s cn63xxp1; + struct cvmx_sli_state3_s cn66xx; + struct cvmx_sli_state3_s cn68xx; + struct cvmx_sli_state3_s cn68xxp1; +}; + +union cvmx_sli_tx_pipe { + uint64_t u64; + struct cvmx_sli_tx_pipe_s { + uint64_t reserved_24_63:40; + uint64_t nump:8; + uint64_t reserved_7_15:9; + uint64_t base:7; + } s; + struct cvmx_sli_tx_pipe_s cn68xx; + struct cvmx_sli_tx_pipe_s cn68xxp1; +}; + +union cvmx_sli_win_rd_addr { + uint64_t u64; + struct cvmx_sli_win_rd_addr_s { + uint64_t reserved_51_63:13; + uint64_t ld_cmd:2; + uint64_t iobit:1; + uint64_t rd_addr:48; + } s; + struct cvmx_sli_win_rd_addr_s cn61xx; + struct cvmx_sli_win_rd_addr_s cn63xx; + struct cvmx_sli_win_rd_addr_s cn63xxp1; + struct cvmx_sli_win_rd_addr_s cn66xx; + struct cvmx_sli_win_rd_addr_s cn68xx; + struct cvmx_sli_win_rd_addr_s cn68xxp1; +}; + +union cvmx_sli_win_rd_data { + uint64_t u64; + struct cvmx_sli_win_rd_data_s { + uint64_t rd_data:64; + } s; + struct cvmx_sli_win_rd_data_s cn61xx; + struct cvmx_sli_win_rd_data_s cn63xx; + struct cvmx_sli_win_rd_data_s cn63xxp1; + struct cvmx_sli_win_rd_data_s cn66xx; + struct cvmx_sli_win_rd_data_s cn68xx; + struct cvmx_sli_win_rd_data_s cn68xxp1; +}; + +union cvmx_sli_win_wr_addr { + uint64_t u64; + struct cvmx_sli_win_wr_addr_s { + uint64_t reserved_49_63:15; + uint64_t iobit:1; + uint64_t wr_addr:45; + uint64_t reserved_0_2:3; + } s; + struct cvmx_sli_win_wr_addr_s cn61xx; + struct cvmx_sli_win_wr_addr_s cn63xx; + struct cvmx_sli_win_wr_addr_s cn63xxp1; + struct cvmx_sli_win_wr_addr_s cn66xx; + struct cvmx_sli_win_wr_addr_s cn68xx; + struct cvmx_sli_win_wr_addr_s cn68xxp1; +}; + +union cvmx_sli_win_wr_data { + uint64_t u64; + struct cvmx_sli_win_wr_data_s { + uint64_t wr_data:64; + } s; + struct cvmx_sli_win_wr_data_s cn61xx; + struct cvmx_sli_win_wr_data_s cn63xx; + struct cvmx_sli_win_wr_data_s cn63xxp1; + struct cvmx_sli_win_wr_data_s cn66xx; + struct cvmx_sli_win_wr_data_s cn68xx; + struct cvmx_sli_win_wr_data_s cn68xxp1; +}; + +union cvmx_sli_win_wr_mask { + uint64_t u64; + struct cvmx_sli_win_wr_mask_s { + uint64_t reserved_8_63:56; + uint64_t wr_mask:8; + } s; + struct cvmx_sli_win_wr_mask_s cn61xx; + struct cvmx_sli_win_wr_mask_s cn63xx; + struct cvmx_sli_win_wr_mask_s cn63xxp1; + struct cvmx_sli_win_wr_mask_s cn66xx; + struct cvmx_sli_win_wr_mask_s cn68xx; + struct cvmx_sli_win_wr_mask_s cn68xxp1; +}; + +union cvmx_sli_window_ctl { + uint64_t u64; + struct cvmx_sli_window_ctl_s { + uint64_t reserved_32_63:32; + uint64_t time:32; + } s; + struct cvmx_sli_window_ctl_s cn61xx; + struct cvmx_sli_window_ctl_s cn63xx; + struct cvmx_sli_window_ctl_s cn63xxp1; + struct cvmx_sli_window_ctl_s cn66xx; + struct cvmx_sli_window_ctl_s cn68xx; + struct cvmx_sli_window_ctl_s cn68xxp1; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-spi.h b/arch/mips/include/asm/octeon/cvmx-spi.h index e814648953a5..e814648953a5 100644 --- a/drivers/staging/octeon/cvmx-spi.h +++ b/arch/mips/include/asm/octeon/cvmx-spi.h diff --git a/drivers/staging/octeon/cvmx-spxx-defs.h b/arch/mips/include/asm/octeon/cvmx-spxx-defs.h index b16940e32c83..b16940e32c83 100644 --- a/drivers/staging/octeon/cvmx-spxx-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-spxx-defs.h diff --git a/arch/mips/include/asm/octeon/cvmx-sriox-defs.h b/arch/mips/include/asm/octeon/cvmx-sriox-defs.h new file mode 100644 index 000000000000..7be7e9ed7465 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-sriox-defs.h @@ -0,0 +1,1036 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2011 Cavium Networks + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, Version 2, as + * published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_SRIOX_DEFS_H__ +#define __CVMX_SRIOX_DEFS_H__ + +#define CVMX_SRIOX_ACC_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000148ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_ASMBLY_ID(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000200ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_ASMBLY_INFO(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000208ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_BELL_RESP_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000310ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_BIST_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000108ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_IMSG_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000508ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_IMSG_INST_HDRX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000510ull) + (((offset) & 1) + ((block_id) & 3) * 0x200000ull) * 8) +#define CVMX_SRIOX_IMSG_QOS_GRPX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000600ull) + (((offset) & 31) + ((block_id) & 3) * 0x200000ull) * 8) +#define CVMX_SRIOX_IMSG_STATUSX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000700ull) + (((offset) & 31) + ((block_id) & 3) * 0x200000ull) * 8) +#define CVMX_SRIOX_IMSG_VPORT_THR(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000500ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_IMSG_VPORT_THR2(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000528ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_INT2_ENABLE(block_id) (CVMX_ADD_IO_SEG(0x00011800C80003E0ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_INT2_REG(block_id) (CVMX_ADD_IO_SEG(0x00011800C80003E8ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_INT_ENABLE(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000110ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_INT_INFO0(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000120ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_INT_INFO1(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000128ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_INT_INFO2(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000130ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_INT_INFO3(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000138ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_INT_REG(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000118ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_IP_FEATURE(block_id) (CVMX_ADD_IO_SEG(0x00011800C80003F8ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_MAC_BUFFERS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000390ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_MAINT_OP(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000158ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_MAINT_RD_DATA(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000160ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_MCE_TX_CTL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000240ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_MEM_OP_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000168ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_OMSG_CTRLX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000488ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64) +#define CVMX_SRIOX_OMSG_DONE_COUNTSX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C80004B0ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64) +#define CVMX_SRIOX_OMSG_FMP_MRX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000498ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64) +#define CVMX_SRIOX_OMSG_NMP_MRX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C80004A0ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64) +#define CVMX_SRIOX_OMSG_PORTX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000480ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64) +#define CVMX_SRIOX_OMSG_SILO_THR(block_id) (CVMX_ADD_IO_SEG(0x00011800C80004F8ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_OMSG_SP_MRX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000490ull) + (((offset) & 1) + ((block_id) & 3) * 0x40000ull) * 64) +#define CVMX_SRIOX_PRIOX_IN_USE(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C80003C0ull) + (((offset) & 3) + ((block_id) & 3) * 0x200000ull) * 8) +#define CVMX_SRIOX_RX_BELL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000308ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_RX_BELL_SEQ(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000300ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_RX_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000380ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_S2M_TYPEX(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000180ull) + (((offset) & 15) + ((block_id) & 3) * 0x200000ull) * 8) +#define CVMX_SRIOX_SEQ(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000278ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_STATUS_REG(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000100ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_TAG_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000178ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_TLP_CREDITS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000150ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_TX_BELL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000280ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_TX_BELL_INFO(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000288ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_TX_CTRL(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000170ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_TX_EMPHASIS(block_id) (CVMX_ADD_IO_SEG(0x00011800C80003F0ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_TX_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000388ull) + ((block_id) & 3) * 0x1000000ull) +#define CVMX_SRIOX_WR_DONE_COUNTS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000340ull) + ((block_id) & 3) * 0x1000000ull) + +union cvmx_sriox_acc_ctrl { + uint64_t u64; + struct cvmx_sriox_acc_ctrl_s { + uint64_t reserved_7_63:57; + uint64_t deny_adr2:1; + uint64_t deny_adr1:1; + uint64_t deny_adr0:1; + uint64_t reserved_3_3:1; + uint64_t deny_bar2:1; + uint64_t deny_bar1:1; + uint64_t deny_bar0:1; + } s; + struct cvmx_sriox_acc_ctrl_cn63xx { + uint64_t reserved_3_63:61; + uint64_t deny_bar2:1; + uint64_t deny_bar1:1; + uint64_t deny_bar0:1; + } cn63xx; + struct cvmx_sriox_acc_ctrl_cn63xx cn63xxp1; + struct cvmx_sriox_acc_ctrl_s cn66xx; +}; + +union cvmx_sriox_asmbly_id { + uint64_t u64; + struct cvmx_sriox_asmbly_id_s { + uint64_t reserved_32_63:32; + uint64_t assy_id:16; + uint64_t assy_ven:16; + } s; + struct cvmx_sriox_asmbly_id_s cn63xx; + struct cvmx_sriox_asmbly_id_s cn63xxp1; + struct cvmx_sriox_asmbly_id_s cn66xx; +}; + +union cvmx_sriox_asmbly_info { + uint64_t u64; + struct cvmx_sriox_asmbly_info_s { + uint64_t reserved_32_63:32; + uint64_t assy_rev:16; + uint64_t reserved_0_15:16; + } s; + struct cvmx_sriox_asmbly_info_s cn63xx; + struct cvmx_sriox_asmbly_info_s cn63xxp1; + struct cvmx_sriox_asmbly_info_s cn66xx; +}; + +union cvmx_sriox_bell_resp_ctrl { + uint64_t u64; + struct cvmx_sriox_bell_resp_ctrl_s { + uint64_t reserved_6_63:58; + uint64_t rp1_sid:1; + uint64_t rp0_sid:2; + uint64_t rp1_pid:1; + uint64_t rp0_pid:2; + } s; + struct cvmx_sriox_bell_resp_ctrl_s cn63xx; + struct cvmx_sriox_bell_resp_ctrl_s cn63xxp1; + struct cvmx_sriox_bell_resp_ctrl_s cn66xx; +}; + +union cvmx_sriox_bist_status { + uint64_t u64; + struct cvmx_sriox_bist_status_s { + uint64_t reserved_45_63:19; + uint64_t lram:1; + uint64_t mram:2; + uint64_t cram:2; + uint64_t bell:2; + uint64_t otag:2; + uint64_t itag:1; + uint64_t ofree:1; + uint64_t rtn:2; + uint64_t obulk:4; + uint64_t optrs:4; + uint64_t oarb2:2; + uint64_t rxbuf2:2; + uint64_t oarb:2; + uint64_t ispf:1; + uint64_t ospf:1; + uint64_t txbuf:2; + uint64_t rxbuf:2; + uint64_t imsg:5; + uint64_t omsg:7; + } s; + struct cvmx_sriox_bist_status_cn63xx { + uint64_t reserved_44_63:20; + uint64_t mram:2; + uint64_t cram:2; + uint64_t bell:2; + uint64_t otag:2; + uint64_t itag:1; + uint64_t ofree:1; + uint64_t rtn:2; + uint64_t obulk:4; + uint64_t optrs:4; + uint64_t oarb2:2; + uint64_t rxbuf2:2; + uint64_t oarb:2; + uint64_t ispf:1; + uint64_t ospf:1; + uint64_t txbuf:2; + uint64_t rxbuf:2; + uint64_t imsg:5; + uint64_t omsg:7; + } cn63xx; + struct cvmx_sriox_bist_status_cn63xxp1 { + uint64_t reserved_44_63:20; + uint64_t mram:2; + uint64_t cram:2; + uint64_t bell:2; + uint64_t otag:2; + uint64_t itag:1; + uint64_t ofree:1; + uint64_t rtn:2; + uint64_t obulk:4; + uint64_t optrs:4; + uint64_t reserved_20_23:4; + uint64_t oarb:2; + uint64_t ispf:1; + uint64_t ospf:1; + uint64_t txbuf:2; + uint64_t rxbuf:2; + uint64_t imsg:5; + uint64_t omsg:7; + } cn63xxp1; + struct cvmx_sriox_bist_status_s cn66xx; +}; + +union cvmx_sriox_imsg_ctrl { + uint64_t u64; + struct cvmx_sriox_imsg_ctrl_s { + uint64_t reserved_32_63:32; + uint64_t to_mode:1; + uint64_t reserved_30_30:1; + uint64_t rsp_thr:6; + uint64_t reserved_22_23:2; + uint64_t rp1_sid:1; + uint64_t rp0_sid:2; + uint64_t rp1_pid:1; + uint64_t rp0_pid:2; + uint64_t reserved_15_15:1; + uint64_t prt_sel:3; + uint64_t lttr:4; + uint64_t prio:4; + uint64_t mbox:4; + } s; + struct cvmx_sriox_imsg_ctrl_s cn63xx; + struct cvmx_sriox_imsg_ctrl_s cn63xxp1; + struct cvmx_sriox_imsg_ctrl_s cn66xx; +}; + +union cvmx_sriox_imsg_inst_hdrx { + uint64_t u64; + struct cvmx_sriox_imsg_inst_hdrx_s { + uint64_t r:1; + uint64_t reserved_58_62:5; + uint64_t pm:2; + uint64_t reserved_55_55:1; + uint64_t sl:7; + uint64_t reserved_46_47:2; + uint64_t nqos:1; + uint64_t ngrp:1; + uint64_t ntt:1; + uint64_t ntag:1; + uint64_t reserved_35_41:7; + uint64_t rs:1; + uint64_t tt:2; + uint64_t tag:32; + } s; + struct cvmx_sriox_imsg_inst_hdrx_s cn63xx; + struct cvmx_sriox_imsg_inst_hdrx_s cn63xxp1; + struct cvmx_sriox_imsg_inst_hdrx_s cn66xx; +}; + +union cvmx_sriox_imsg_qos_grpx { + uint64_t u64; + struct cvmx_sriox_imsg_qos_grpx_s { + uint64_t reserved_63_63:1; + uint64_t qos7:3; + uint64_t grp7:4; + uint64_t reserved_55_55:1; + uint64_t qos6:3; + uint64_t grp6:4; + uint64_t reserved_47_47:1; + uint64_t qos5:3; + uint64_t grp5:4; + uint64_t reserved_39_39:1; + uint64_t qos4:3; + uint64_t grp4:4; + uint64_t reserved_31_31:1; + uint64_t qos3:3; + uint64_t grp3:4; + uint64_t reserved_23_23:1; + uint64_t qos2:3; + uint64_t grp2:4; + uint64_t reserved_15_15:1; + uint64_t qos1:3; + uint64_t grp1:4; + uint64_t reserved_7_7:1; + uint64_t qos0:3; + uint64_t grp0:4; + } s; + struct cvmx_sriox_imsg_qos_grpx_s cn63xx; + struct cvmx_sriox_imsg_qos_grpx_s cn63xxp1; + struct cvmx_sriox_imsg_qos_grpx_s cn66xx; +}; + +union cvmx_sriox_imsg_statusx { + uint64_t u64; + struct cvmx_sriox_imsg_statusx_s { + uint64_t val1:1; + uint64_t err1:1; + uint64_t toe1:1; + uint64_t toc1:1; + uint64_t prt1:1; + uint64_t reserved_58_58:1; + uint64_t tt1:1; + uint64_t dis1:1; + uint64_t seg1:4; + uint64_t mbox1:2; + uint64_t lttr1:2; + uint64_t sid1:16; + uint64_t val0:1; + uint64_t err0:1; + uint64_t toe0:1; + uint64_t toc0:1; + uint64_t prt0:1; + uint64_t reserved_26_26:1; + uint64_t tt0:1; + uint64_t dis0:1; + uint64_t seg0:4; + uint64_t mbox0:2; + uint64_t lttr0:2; + uint64_t sid0:16; + } s; + struct cvmx_sriox_imsg_statusx_s cn63xx; + struct cvmx_sriox_imsg_statusx_s cn63xxp1; + struct cvmx_sriox_imsg_statusx_s cn66xx; +}; + +union cvmx_sriox_imsg_vport_thr { + uint64_t u64; + struct cvmx_sriox_imsg_vport_thr_s { + uint64_t reserved_54_63:10; + uint64_t max_tot:6; + uint64_t reserved_46_47:2; + uint64_t max_s1:6; + uint64_t reserved_38_39:2; + uint64_t max_s0:6; + uint64_t sp_vport:1; + uint64_t reserved_20_30:11; + uint64_t buf_thr:4; + uint64_t reserved_14_15:2; + uint64_t max_p1:6; + uint64_t reserved_6_7:2; + uint64_t max_p0:6; + } s; + struct cvmx_sriox_imsg_vport_thr_s cn63xx; + struct cvmx_sriox_imsg_vport_thr_s cn63xxp1; + struct cvmx_sriox_imsg_vport_thr_s cn66xx; +}; + +union cvmx_sriox_imsg_vport_thr2 { + uint64_t u64; + struct cvmx_sriox_imsg_vport_thr2_s { + uint64_t reserved_46_63:18; + uint64_t max_s3:6; + uint64_t reserved_38_39:2; + uint64_t max_s2:6; + uint64_t reserved_0_31:32; + } s; + struct cvmx_sriox_imsg_vport_thr2_s cn66xx; +}; + +union cvmx_sriox_int2_enable { + uint64_t u64; + struct cvmx_sriox_int2_enable_s { + uint64_t reserved_1_63:63; + uint64_t pko_rst:1; + } s; + struct cvmx_sriox_int2_enable_s cn63xx; + struct cvmx_sriox_int2_enable_s cn66xx; +}; + +union cvmx_sriox_int2_reg { + uint64_t u64; + struct cvmx_sriox_int2_reg_s { + uint64_t reserved_32_63:32; + uint64_t int_sum:1; + uint64_t reserved_1_30:30; + uint64_t pko_rst:1; + } s; + struct cvmx_sriox_int2_reg_s cn63xx; + struct cvmx_sriox_int2_reg_s cn66xx; +}; + +union cvmx_sriox_int_enable { + uint64_t u64; + struct cvmx_sriox_int_enable_s { + uint64_t reserved_27_63:37; + uint64_t zero_pkt:1; + uint64_t ttl_tout:1; + uint64_t fail:1; + uint64_t degrade:1; + uint64_t mac_buf:1; + uint64_t f_error:1; + uint64_t rtry_err:1; + uint64_t pko_err:1; + uint64_t omsg_err:1; + uint64_t omsg1:1; + uint64_t omsg0:1; + uint64_t link_up:1; + uint64_t link_dwn:1; + uint64_t phy_erb:1; + uint64_t log_erb:1; + uint64_t soft_rx:1; + uint64_t soft_tx:1; + uint64_t mce_rx:1; + uint64_t mce_tx:1; + uint64_t wr_done:1; + uint64_t sli_err:1; + uint64_t deny_wr:1; + uint64_t bar_err:1; + uint64_t maint_op:1; + uint64_t rxbell:1; + uint64_t bell_err:1; + uint64_t txbell:1; + } s; + struct cvmx_sriox_int_enable_s cn63xx; + struct cvmx_sriox_int_enable_cn63xxp1 { + uint64_t reserved_22_63:42; + uint64_t f_error:1; + uint64_t rtry_err:1; + uint64_t pko_err:1; + uint64_t omsg_err:1; + uint64_t omsg1:1; + uint64_t omsg0:1; + uint64_t link_up:1; + uint64_t link_dwn:1; + uint64_t phy_erb:1; + uint64_t log_erb:1; + uint64_t soft_rx:1; + uint64_t soft_tx:1; + uint64_t mce_rx:1; + uint64_t mce_tx:1; + uint64_t wr_done:1; + uint64_t sli_err:1; + uint64_t deny_wr:1; + uint64_t bar_err:1; + uint64_t maint_op:1; + uint64_t rxbell:1; + uint64_t bell_err:1; + uint64_t txbell:1; + } cn63xxp1; + struct cvmx_sriox_int_enable_s cn66xx; +}; + +union cvmx_sriox_int_info0 { + uint64_t u64; + struct cvmx_sriox_int_info0_s { + uint64_t cmd:4; + uint64_t type:4; + uint64_t tag:8; + uint64_t reserved_42_47:6; + uint64_t length:10; + uint64_t status:3; + uint64_t reserved_16_28:13; + uint64_t be0:8; + uint64_t be1:8; + } s; + struct cvmx_sriox_int_info0_s cn63xx; + struct cvmx_sriox_int_info0_s cn63xxp1; + struct cvmx_sriox_int_info0_s cn66xx; +}; + +union cvmx_sriox_int_info1 { + uint64_t u64; + struct cvmx_sriox_int_info1_s { + uint64_t info1:64; + } s; + struct cvmx_sriox_int_info1_s cn63xx; + struct cvmx_sriox_int_info1_s cn63xxp1; + struct cvmx_sriox_int_info1_s cn66xx; +}; + +union cvmx_sriox_int_info2 { + uint64_t u64; + struct cvmx_sriox_int_info2_s { + uint64_t prio:2; + uint64_t tt:1; + uint64_t sis:1; + uint64_t ssize:4; + uint64_t did:16; + uint64_t xmbox:4; + uint64_t mbox:2; + uint64_t letter:2; + uint64_t rsrvd:30; + uint64_t lns:1; + uint64_t intr:1; + } s; + struct cvmx_sriox_int_info2_s cn63xx; + struct cvmx_sriox_int_info2_s cn63xxp1; + struct cvmx_sriox_int_info2_s cn66xx; +}; + +union cvmx_sriox_int_info3 { + uint64_t u64; + struct cvmx_sriox_int_info3_s { + uint64_t prio:2; + uint64_t tt:2; + uint64_t type:4; + uint64_t other:48; + uint64_t reserved_0_7:8; + } s; + struct cvmx_sriox_int_info3_s cn63xx; + struct cvmx_sriox_int_info3_s cn63xxp1; + struct cvmx_sriox_int_info3_s cn66xx; +}; + +union cvmx_sriox_int_reg { + uint64_t u64; + struct cvmx_sriox_int_reg_s { + uint64_t reserved_32_63:32; + uint64_t int2_sum:1; + uint64_t reserved_27_30:4; + uint64_t zero_pkt:1; + uint64_t ttl_tout:1; + uint64_t fail:1; + uint64_t degrad:1; + uint64_t mac_buf:1; + uint64_t f_error:1; + uint64_t rtry_err:1; + uint64_t pko_err:1; + uint64_t omsg_err:1; + uint64_t omsg1:1; + uint64_t omsg0:1; + uint64_t link_up:1; + uint64_t link_dwn:1; + uint64_t phy_erb:1; + uint64_t log_erb:1; + uint64_t soft_rx:1; + uint64_t soft_tx:1; + uint64_t mce_rx:1; + uint64_t mce_tx:1; + uint64_t wr_done:1; + uint64_t sli_err:1; + uint64_t deny_wr:1; + uint64_t bar_err:1; + uint64_t maint_op:1; + uint64_t rxbell:1; + uint64_t bell_err:1; + uint64_t txbell:1; + } s; + struct cvmx_sriox_int_reg_s cn63xx; + struct cvmx_sriox_int_reg_cn63xxp1 { + uint64_t reserved_22_63:42; + uint64_t f_error:1; + uint64_t rtry_err:1; + uint64_t pko_err:1; + uint64_t omsg_err:1; + uint64_t omsg1:1; + uint64_t omsg0:1; + uint64_t link_up:1; + uint64_t link_dwn:1; + uint64_t phy_erb:1; + uint64_t log_erb:1; + uint64_t soft_rx:1; + uint64_t soft_tx:1; + uint64_t mce_rx:1; + uint64_t mce_tx:1; + uint64_t wr_done:1; + uint64_t sli_err:1; + uint64_t deny_wr:1; + uint64_t bar_err:1; + uint64_t maint_op:1; + uint64_t rxbell:1; + uint64_t bell_err:1; + uint64_t txbell:1; + } cn63xxp1; + struct cvmx_sriox_int_reg_s cn66xx; +}; + +union cvmx_sriox_ip_feature { + uint64_t u64; + struct cvmx_sriox_ip_feature_s { + uint64_t ops:32; + uint64_t reserved_15_31:17; + uint64_t no_vmin:1; + uint64_t a66:1; + uint64_t a50:1; + uint64_t reserved_11_11:1; + uint64_t tx_flow:1; + uint64_t pt_width:2; + uint64_t tx_pol:4; + uint64_t rx_pol:4; + } s; + struct cvmx_sriox_ip_feature_cn63xx { + uint64_t ops:32; + uint64_t reserved_14_31:18; + uint64_t a66:1; + uint64_t a50:1; + uint64_t reserved_11_11:1; + uint64_t tx_flow:1; + uint64_t pt_width:2; + uint64_t tx_pol:4; + uint64_t rx_pol:4; + } cn63xx; + struct cvmx_sriox_ip_feature_cn63xx cn63xxp1; + struct cvmx_sriox_ip_feature_s cn66xx; +}; + +union cvmx_sriox_mac_buffers { + uint64_t u64; + struct cvmx_sriox_mac_buffers_s { + uint64_t reserved_56_63:8; + uint64_t tx_enb:8; + uint64_t reserved_44_47:4; + uint64_t tx_inuse:4; + uint64_t tx_stat:8; + uint64_t reserved_24_31:8; + uint64_t rx_enb:8; + uint64_t reserved_12_15:4; + uint64_t rx_inuse:4; + uint64_t rx_stat:8; + } s; + struct cvmx_sriox_mac_buffers_s cn63xx; + struct cvmx_sriox_mac_buffers_s cn66xx; +}; + +union cvmx_sriox_maint_op { + uint64_t u64; + struct cvmx_sriox_maint_op_s { + uint64_t wr_data:32; + uint64_t reserved_27_31:5; + uint64_t fail:1; + uint64_t pending:1; + uint64_t op:1; + uint64_t addr:24; + } s; + struct cvmx_sriox_maint_op_s cn63xx; + struct cvmx_sriox_maint_op_s cn63xxp1; + struct cvmx_sriox_maint_op_s cn66xx; +}; + +union cvmx_sriox_maint_rd_data { + uint64_t u64; + struct cvmx_sriox_maint_rd_data_s { + uint64_t reserved_33_63:31; + uint64_t valid:1; + uint64_t rd_data:32; + } s; + struct cvmx_sriox_maint_rd_data_s cn63xx; + struct cvmx_sriox_maint_rd_data_s cn63xxp1; + struct cvmx_sriox_maint_rd_data_s cn66xx; +}; + +union cvmx_sriox_mce_tx_ctl { + uint64_t u64; + struct cvmx_sriox_mce_tx_ctl_s { + uint64_t reserved_1_63:63; + uint64_t mce:1; + } s; + struct cvmx_sriox_mce_tx_ctl_s cn63xx; + struct cvmx_sriox_mce_tx_ctl_s cn63xxp1; + struct cvmx_sriox_mce_tx_ctl_s cn66xx; +}; + +union cvmx_sriox_mem_op_ctrl { + uint64_t u64; + struct cvmx_sriox_mem_op_ctrl_s { + uint64_t reserved_10_63:54; + uint64_t rr_ro:1; + uint64_t w_ro:1; + uint64_t reserved_6_7:2; + uint64_t rp1_sid:1; + uint64_t rp0_sid:2; + uint64_t rp1_pid:1; + uint64_t rp0_pid:2; + } s; + struct cvmx_sriox_mem_op_ctrl_s cn63xx; + struct cvmx_sriox_mem_op_ctrl_s cn63xxp1; + struct cvmx_sriox_mem_op_ctrl_s cn66xx; +}; + +union cvmx_sriox_omsg_ctrlx { + uint64_t u64; + struct cvmx_sriox_omsg_ctrlx_s { + uint64_t testmode:1; + uint64_t reserved_37_62:26; + uint64_t silo_max:5; + uint64_t rtry_thr:16; + uint64_t rtry_en:1; + uint64_t reserved_11_14:4; + uint64_t idm_tt:1; + uint64_t idm_sis:1; + uint64_t idm_did:1; + uint64_t lttr_sp:4; + uint64_t lttr_mp:4; + } s; + struct cvmx_sriox_omsg_ctrlx_s cn63xx; + struct cvmx_sriox_omsg_ctrlx_cn63xxp1 { + uint64_t testmode:1; + uint64_t reserved_32_62:31; + uint64_t rtry_thr:16; + uint64_t rtry_en:1; + uint64_t reserved_11_14:4; + uint64_t idm_tt:1; + uint64_t idm_sis:1; + uint64_t idm_did:1; + uint64_t lttr_sp:4; + uint64_t lttr_mp:4; + } cn63xxp1; + struct cvmx_sriox_omsg_ctrlx_s cn66xx; +}; + +union cvmx_sriox_omsg_done_countsx { + uint64_t u64; + struct cvmx_sriox_omsg_done_countsx_s { + uint64_t reserved_32_63:32; + uint64_t bad:16; + uint64_t good:16; + } s; + struct cvmx_sriox_omsg_done_countsx_s cn63xx; + struct cvmx_sriox_omsg_done_countsx_s cn66xx; +}; + +union cvmx_sriox_omsg_fmp_mrx { + uint64_t u64; + struct cvmx_sriox_omsg_fmp_mrx_s { + uint64_t reserved_15_63:49; + uint64_t ctlr_sp:1; + uint64_t ctlr_fmp:1; + uint64_t ctlr_nmp:1; + uint64_t id_sp:1; + uint64_t id_fmp:1; + uint64_t id_nmp:1; + uint64_t id_psd:1; + uint64_t mbox_sp:1; + uint64_t mbox_fmp:1; + uint64_t mbox_nmp:1; + uint64_t mbox_psd:1; + uint64_t all_sp:1; + uint64_t all_fmp:1; + uint64_t all_nmp:1; + uint64_t all_psd:1; + } s; + struct cvmx_sriox_omsg_fmp_mrx_s cn63xx; + struct cvmx_sriox_omsg_fmp_mrx_s cn63xxp1; + struct cvmx_sriox_omsg_fmp_mrx_s cn66xx; +}; + +union cvmx_sriox_omsg_nmp_mrx { + uint64_t u64; + struct cvmx_sriox_omsg_nmp_mrx_s { + uint64_t reserved_15_63:49; + uint64_t ctlr_sp:1; + uint64_t ctlr_fmp:1; + uint64_t ctlr_nmp:1; + uint64_t id_sp:1; + uint64_t id_fmp:1; + uint64_t id_nmp:1; + uint64_t reserved_8_8:1; + uint64_t mbox_sp:1; + uint64_t mbox_fmp:1; + uint64_t mbox_nmp:1; + uint64_t reserved_4_4:1; + uint64_t all_sp:1; + uint64_t all_fmp:1; + uint64_t all_nmp:1; + uint64_t reserved_0_0:1; + } s; + struct cvmx_sriox_omsg_nmp_mrx_s cn63xx; + struct cvmx_sriox_omsg_nmp_mrx_s cn63xxp1; + struct cvmx_sriox_omsg_nmp_mrx_s cn66xx; +}; + +union cvmx_sriox_omsg_portx { + uint64_t u64; + struct cvmx_sriox_omsg_portx_s { + uint64_t reserved_32_63:32; + uint64_t enable:1; + uint64_t reserved_3_30:28; + uint64_t port:3; + } s; + struct cvmx_sriox_omsg_portx_cn63xx { + uint64_t reserved_32_63:32; + uint64_t enable:1; + uint64_t reserved_2_30:29; + uint64_t port:2; + } cn63xx; + struct cvmx_sriox_omsg_portx_cn63xx cn63xxp1; + struct cvmx_sriox_omsg_portx_s cn66xx; +}; + +union cvmx_sriox_omsg_silo_thr { + uint64_t u64; + struct cvmx_sriox_omsg_silo_thr_s { + uint64_t reserved_5_63:59; + uint64_t tot_silo:5; + } s; + struct cvmx_sriox_omsg_silo_thr_s cn63xx; + struct cvmx_sriox_omsg_silo_thr_s cn66xx; +}; + +union cvmx_sriox_omsg_sp_mrx { + uint64_t u64; + struct cvmx_sriox_omsg_sp_mrx_s { + uint64_t reserved_16_63:48; + uint64_t xmbox_sp:1; + uint64_t ctlr_sp:1; + uint64_t ctlr_fmp:1; + uint64_t ctlr_nmp:1; + uint64_t id_sp:1; + uint64_t id_fmp:1; + uint64_t id_nmp:1; + uint64_t id_psd:1; + uint64_t mbox_sp:1; + uint64_t mbox_fmp:1; + uint64_t mbox_nmp:1; + uint64_t mbox_psd:1; + uint64_t all_sp:1; + uint64_t all_fmp:1; + uint64_t all_nmp:1; + uint64_t all_psd:1; + } s; + struct cvmx_sriox_omsg_sp_mrx_s cn63xx; + struct cvmx_sriox_omsg_sp_mrx_s cn63xxp1; + struct cvmx_sriox_omsg_sp_mrx_s cn66xx; +}; + +union cvmx_sriox_priox_in_use { + uint64_t u64; + struct cvmx_sriox_priox_in_use_s { + uint64_t reserved_32_63:32; + uint64_t end_cnt:16; + uint64_t start_cnt:16; + } s; + struct cvmx_sriox_priox_in_use_s cn63xx; + struct cvmx_sriox_priox_in_use_s cn66xx; +}; + +union cvmx_sriox_rx_bell { + uint64_t u64; + struct cvmx_sriox_rx_bell_s { + uint64_t reserved_48_63:16; + uint64_t data:16; + uint64_t src_id:16; + uint64_t count:8; + uint64_t reserved_5_7:3; + uint64_t dest_id:1; + uint64_t id16:1; + uint64_t reserved_2_2:1; + uint64_t priority:2; + } s; + struct cvmx_sriox_rx_bell_s cn63xx; + struct cvmx_sriox_rx_bell_s cn63xxp1; + struct cvmx_sriox_rx_bell_s cn66xx; +}; + +union cvmx_sriox_rx_bell_seq { + uint64_t u64; + struct cvmx_sriox_rx_bell_seq_s { + uint64_t reserved_40_63:24; + uint64_t count:8; + uint64_t seq:32; + } s; + struct cvmx_sriox_rx_bell_seq_s cn63xx; + struct cvmx_sriox_rx_bell_seq_s cn63xxp1; + struct cvmx_sriox_rx_bell_seq_s cn66xx; +}; + +union cvmx_sriox_rx_status { + uint64_t u64; + struct cvmx_sriox_rx_status_s { + uint64_t rtn_pr3:8; + uint64_t rtn_pr2:8; + uint64_t rtn_pr1:8; + uint64_t reserved_28_39:12; + uint64_t mbox:4; + uint64_t comp:8; + uint64_t reserved_13_15:3; + uint64_t n_post:5; + uint64_t post:8; + } s; + struct cvmx_sriox_rx_status_s cn63xx; + struct cvmx_sriox_rx_status_s cn63xxp1; + struct cvmx_sriox_rx_status_s cn66xx; +}; + +union cvmx_sriox_s2m_typex { + uint64_t u64; + struct cvmx_sriox_s2m_typex_s { + uint64_t reserved_19_63:45; + uint64_t wr_op:3; + uint64_t reserved_15_15:1; + uint64_t rd_op:3; + uint64_t wr_prior:2; + uint64_t rd_prior:2; + uint64_t reserved_6_7:2; + uint64_t src_id:1; + uint64_t id16:1; + uint64_t reserved_2_3:2; + uint64_t iaow_sel:2; + } s; + struct cvmx_sriox_s2m_typex_s cn63xx; + struct cvmx_sriox_s2m_typex_s cn63xxp1; + struct cvmx_sriox_s2m_typex_s cn66xx; +}; + +union cvmx_sriox_seq { + uint64_t u64; + struct cvmx_sriox_seq_s { + uint64_t reserved_32_63:32; + uint64_t seq:32; + } s; + struct cvmx_sriox_seq_s cn63xx; + struct cvmx_sriox_seq_s cn63xxp1; + struct cvmx_sriox_seq_s cn66xx; +}; + +union cvmx_sriox_status_reg { + uint64_t u64; + struct cvmx_sriox_status_reg_s { + uint64_t reserved_2_63:62; + uint64_t access:1; + uint64_t srio:1; + } s; + struct cvmx_sriox_status_reg_s cn63xx; + struct cvmx_sriox_status_reg_s cn63xxp1; + struct cvmx_sriox_status_reg_s cn66xx; +}; + +union cvmx_sriox_tag_ctrl { + uint64_t u64; + struct cvmx_sriox_tag_ctrl_s { + uint64_t reserved_17_63:47; + uint64_t o_clr:1; + uint64_t reserved_13_15:3; + uint64_t otag:5; + uint64_t reserved_5_7:3; + uint64_t itag:5; + } s; + struct cvmx_sriox_tag_ctrl_s cn63xx; + struct cvmx_sriox_tag_ctrl_s cn63xxp1; + struct cvmx_sriox_tag_ctrl_s cn66xx; +}; + +union cvmx_sriox_tlp_credits { + uint64_t u64; + struct cvmx_sriox_tlp_credits_s { + uint64_t reserved_28_63:36; + uint64_t mbox:4; + uint64_t comp:8; + uint64_t reserved_13_15:3; + uint64_t n_post:5; + uint64_t post:8; + } s; + struct cvmx_sriox_tlp_credits_s cn63xx; + struct cvmx_sriox_tlp_credits_s cn63xxp1; + struct cvmx_sriox_tlp_credits_s cn66xx; +}; + +union cvmx_sriox_tx_bell { + uint64_t u64; + struct cvmx_sriox_tx_bell_s { + uint64_t reserved_48_63:16; + uint64_t data:16; + uint64_t dest_id:16; + uint64_t reserved_9_15:7; + uint64_t pending:1; + uint64_t reserved_5_7:3; + uint64_t src_id:1; + uint64_t id16:1; + uint64_t reserved_2_2:1; + uint64_t priority:2; + } s; + struct cvmx_sriox_tx_bell_s cn63xx; + struct cvmx_sriox_tx_bell_s cn63xxp1; + struct cvmx_sriox_tx_bell_s cn66xx; +}; + +union cvmx_sriox_tx_bell_info { + uint64_t u64; + struct cvmx_sriox_tx_bell_info_s { + uint64_t reserved_48_63:16; + uint64_t data:16; + uint64_t dest_id:16; + uint64_t reserved_8_15:8; + uint64_t timeout:1; + uint64_t error:1; + uint64_t retry:1; + uint64_t src_id:1; + uint64_t id16:1; + uint64_t reserved_2_2:1; + uint64_t priority:2; + } s; + struct cvmx_sriox_tx_bell_info_s cn63xx; + struct cvmx_sriox_tx_bell_info_s cn63xxp1; + struct cvmx_sriox_tx_bell_info_s cn66xx; +}; + +union cvmx_sriox_tx_ctrl { + uint64_t u64; + struct cvmx_sriox_tx_ctrl_s { + uint64_t reserved_53_63:11; + uint64_t tag_th2:5; + uint64_t reserved_45_47:3; + uint64_t tag_th1:5; + uint64_t reserved_37_39:3; + uint64_t tag_th0:5; + uint64_t reserved_20_31:12; + uint64_t tx_th2:4; + uint64_t reserved_12_15:4; + uint64_t tx_th1:4; + uint64_t reserved_4_7:4; + uint64_t tx_th0:4; + } s; + struct cvmx_sriox_tx_ctrl_s cn63xx; + struct cvmx_sriox_tx_ctrl_s cn63xxp1; + struct cvmx_sriox_tx_ctrl_s cn66xx; +}; + +union cvmx_sriox_tx_emphasis { + uint64_t u64; + struct cvmx_sriox_tx_emphasis_s { + uint64_t reserved_4_63:60; + uint64_t emph:4; + } s; + struct cvmx_sriox_tx_emphasis_s cn63xx; + struct cvmx_sriox_tx_emphasis_s cn66xx; +}; + +union cvmx_sriox_tx_status { + uint64_t u64; + struct cvmx_sriox_tx_status_s { + uint64_t reserved_32_63:32; + uint64_t s2m_pr3:8; + uint64_t s2m_pr2:8; + uint64_t s2m_pr1:8; + uint64_t s2m_pr0:8; + } s; + struct cvmx_sriox_tx_status_s cn63xx; + struct cvmx_sriox_tx_status_s cn63xxp1; + struct cvmx_sriox_tx_status_s cn66xx; +}; + +union cvmx_sriox_wr_done_counts { + uint64_t u64; + struct cvmx_sriox_wr_done_counts_s { + uint64_t reserved_32_63:32; + uint64_t bad:16; + uint64_t good:16; + } s; + struct cvmx_sriox_wr_done_counts_s cn63xx; + struct cvmx_sriox_wr_done_counts_s cn66xx; +}; + +#endif diff --git a/drivers/staging/octeon/cvmx-srxx-defs.h b/arch/mips/include/asm/octeon/cvmx-srxx-defs.h index d82b366c279f..d82b366c279f 100644 --- a/drivers/staging/octeon/cvmx-srxx-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-srxx-defs.h diff --git a/drivers/staging/octeon/cvmx-stxx-defs.h b/arch/mips/include/asm/octeon/cvmx-stxx-defs.h index 4f209b62cae1..4f209b62cae1 100644 --- a/drivers/staging/octeon/cvmx-stxx-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-stxx-defs.h diff --git a/drivers/staging/octeon/cvmx-wqe.h b/arch/mips/include/asm/octeon/cvmx-wqe.h index 653610953d28..653610953d28 100644 --- a/drivers/staging/octeon/cvmx-wqe.h +++ b/arch/mips/include/asm/octeon/cvmx-wqe.h diff --git a/arch/mips/include/asm/octeon/cvmx.h b/arch/mips/include/asm/octeon/cvmx.h index 7e1286706d46..740be97a3251 100644 --- a/arch/mips/include/asm/octeon/cvmx.h +++ b/arch/mips/include/asm/octeon/cvmx.h @@ -31,6 +31,27 @@ #include <linux/kernel.h> #include <linux/string.h> +enum cvmx_mips_space { + CVMX_MIPS_SPACE_XKSEG = 3LL, + CVMX_MIPS_SPACE_XKPHYS = 2LL, + CVMX_MIPS_SPACE_XSSEG = 1LL, + CVMX_MIPS_SPACE_XUSEG = 0LL +}; + +/* These macros for use when using 32 bit pointers. */ +#define CVMX_MIPS32_SPACE_KSEG0 1l +#define CVMX_ADD_SEG32(segment, add) \ + (((int32_t)segment << 31) | (int32_t)(add)) + +#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS + +/* These macros simplify the process of creating common IO addresses */ +#define CVMX_ADD_SEG(segment, add) \ + ((((uint64_t)segment) << 62) | (add)) +#ifndef CVMX_ADD_IO_SEG +#define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add)) +#endif + #include "cvmx-asm.h" #include "cvmx-packet.h" #include "cvmx-sysinfo.h" @@ -129,27 +150,6 @@ static inline uint64_t cvmx_build_bits(uint64_t high_bit, return (value & cvmx_build_mask(high_bit - low_bit + 1)) << low_bit; } -enum cvmx_mips_space { - CVMX_MIPS_SPACE_XKSEG = 3LL, - CVMX_MIPS_SPACE_XKPHYS = 2LL, - CVMX_MIPS_SPACE_XSSEG = 1LL, - CVMX_MIPS_SPACE_XUSEG = 0LL -}; - -/* These macros for use when using 32 bit pointers. */ -#define CVMX_MIPS32_SPACE_KSEG0 1l -#define CVMX_ADD_SEG32(segment, add) \ - (((int32_t)segment << 31) | (int32_t)(add)) - -#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS - -/* These macros simplify the process of creating common IO addresses */ -#define CVMX_ADD_SEG(segment, add) \ - ((((uint64_t)segment) << 62) | (add)) -#ifndef CVMX_ADD_IO_SEG -#define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add)) -#endif - /** * Convert a memory pointer (void*) into a hardware compatible * memory address (uint64_t). Octeon hardware widgets don't diff --git a/arch/mips/include/asm/octeon/octeon-feature.h b/arch/mips/include/asm/octeon/octeon-feature.h index cba6fbed9f43..8008da2f8779 100644 --- a/arch/mips/include/asm/octeon/octeon-feature.h +++ b/arch/mips/include/asm/octeon/octeon-feature.h @@ -31,8 +31,14 @@ #ifndef __OCTEON_FEATURE_H__ #define __OCTEON_FEATURE_H__ +#include <asm/octeon/cvmx-mio-defs.h> +#include <asm/octeon/cvmx-rnm-defs.h> enum octeon_feature { + /* CN68XX uses port kinds for packet interface */ + OCTEON_FEATURE_PKND, + /* CN68XX has different fields in word0 - word2 */ + OCTEON_FEATURE_CN68XX_WQE, /* * Octeon models in the CN5XXX family and higher support * atomic add instructions to memory (saa/saad). @@ -42,8 +48,13 @@ enum octeon_feature { OCTEON_FEATURE_ZIP, /* Does this Octeon support crypto acceleration using COP2? */ OCTEON_FEATURE_CRYPTO, + OCTEON_FEATURE_DORM_CRYPTO, /* Does this Octeon support PCI express? */ OCTEON_FEATURE_PCIE, + /* Does this Octeon support SRIOs */ + OCTEON_FEATURE_SRIO, + /* Does this Octeon support Interlaken */ + OCTEON_FEATURE_ILK, /* Some Octeon models support internal memory for storing * cryptographic keys */ OCTEON_FEATURE_KEY_MEMORY, @@ -64,6 +75,15 @@ enum octeon_feature { /* Octeon MDIO block supports clause 45 transactions for 10 * Gig support */ OCTEON_FEATURE_MDIO_CLAUSE_45, + /* + * CN52XX and CN56XX used a block named NPEI for PCIe + * access. Newer chips replaced this with SLI+DPI. + */ + OCTEON_FEATURE_NPEI, + OCTEON_FEATURE_HFA, + OCTEON_FEATURE_DFM, + OCTEON_FEATURE_CIU2, + OCTEON_MAX_FEATURE }; static inline int cvmx_fuse_read(int fuse); @@ -96,30 +116,78 @@ static inline int octeon_has_feature(enum octeon_feature feature) return !cvmx_fuse_read(121); case OCTEON_FEATURE_CRYPTO: - return !cvmx_fuse_read(90); + if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { + union cvmx_mio_fus_dat2 fus_2; + fus_2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); + if (fus_2.s.nocrypto || fus_2.s.nomul) { + return 0; + } else if (!fus_2.s.dorm_crypto) { + return 1; + } else { + union cvmx_rnm_ctl_status st; + st.u64 = cvmx_read_csr(CVMX_RNM_CTL_STATUS); + return st.s.eer_val; + } + } else { + return !cvmx_fuse_read(90); + } + + case OCTEON_FEATURE_DORM_CRYPTO: + if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { + union cvmx_mio_fus_dat2 fus_2; + fus_2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); + return !fus_2.s.nocrypto && !fus_2.s.nomul && fus_2.s.dorm_crypto; + } else { + return 0; + } case OCTEON_FEATURE_PCIE: - case OCTEON_FEATURE_MGMT_PORT: - case OCTEON_FEATURE_RAID: return OCTEON_IS_MODEL(OCTEON_CN56XX) - || OCTEON_IS_MODEL(OCTEON_CN52XX); + || OCTEON_IS_MODEL(OCTEON_CN52XX) + || OCTEON_IS_MODEL(OCTEON_CN6XXX); + + case OCTEON_FEATURE_SRIO: + return OCTEON_IS_MODEL(OCTEON_CN63XX) + || OCTEON_IS_MODEL(OCTEON_CN66XX); + + case OCTEON_FEATURE_ILK: + return (OCTEON_IS_MODEL(OCTEON_CN68XX)); case OCTEON_FEATURE_KEY_MEMORY: + return OCTEON_IS_MODEL(OCTEON_CN38XX) + || OCTEON_IS_MODEL(OCTEON_CN58XX) + || OCTEON_IS_MODEL(OCTEON_CN56XX) + || OCTEON_IS_MODEL(OCTEON_CN6XXX); + case OCTEON_FEATURE_LED_CONTROLLER: return OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX); + case OCTEON_FEATURE_TRA: return !(OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)); + case OCTEON_FEATURE_MGMT_PORT: + return OCTEON_IS_MODEL(OCTEON_CN56XX) + || OCTEON_IS_MODEL(OCTEON_CN52XX) + || OCTEON_IS_MODEL(OCTEON_CN6XXX); + + case OCTEON_FEATURE_RAID: + return OCTEON_IS_MODEL(OCTEON_CN56XX) + || OCTEON_IS_MODEL(OCTEON_CN52XX) + || OCTEON_IS_MODEL(OCTEON_CN6XXX); + case OCTEON_FEATURE_USB: return !(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)); + case OCTEON_FEATURE_NO_WPTR: return (OCTEON_IS_MODEL(OCTEON_CN56XX) - || OCTEON_IS_MODEL(OCTEON_CN52XX)) - && !OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) - && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X); + || OCTEON_IS_MODEL(OCTEON_CN52XX) + || OCTEON_IS_MODEL(OCTEON_CN6XXX)) + && !OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) + && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X); + case OCTEON_FEATURE_DFA: if (!OCTEON_IS_MODEL(OCTEON_CN38XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX) @@ -127,14 +195,42 @@ static inline int octeon_has_feature(enum octeon_feature feature) return 0; else if (OCTEON_IS_MODEL(OCTEON_CN3020)) return 0; - else if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS1)) - return 1; else return !cvmx_fuse_read(120); + + case OCTEON_FEATURE_HFA: + if (!OCTEON_IS_MODEL(OCTEON_CN6XXX)) + return 0; + else + return !cvmx_fuse_read(90); + + case OCTEON_FEATURE_DFM: + if (!(OCTEON_IS_MODEL(OCTEON_CN63XX) + || OCTEON_IS_MODEL(OCTEON_CN66XX))) + return 0; + else + return !cvmx_fuse_read(90); + case OCTEON_FEATURE_MDIO_CLAUSE_45: return !(OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)); + + case OCTEON_FEATURE_NPEI: + return OCTEON_IS_MODEL(OCTEON_CN56XX) + || OCTEON_IS_MODEL(OCTEON_CN52XX); + + case OCTEON_FEATURE_PKND: + return OCTEON_IS_MODEL(OCTEON_CN68XX); + + case OCTEON_FEATURE_CN68XX_WQE: + return OCTEON_IS_MODEL(OCTEON_CN68XX); + + case OCTEON_FEATURE_CIU2: + return OCTEON_IS_MODEL(OCTEON_CN68XX); + + default: + break; } return 0; } diff --git a/arch/mips/include/asm/octeon/octeon-model.h b/arch/mips/include/asm/octeon/octeon-model.h index 700f88e31cad..4e338a4d9424 100644 --- a/arch/mips/include/asm/octeon/octeon-model.h +++ b/arch/mips/include/asm/octeon/octeon-model.h @@ -4,7 +4,7 @@ * Contact: support@caviumnetworks.com * This file is part of the OCTEON SDK * - * Copyright (c) 2003-2008 Cavium Networks + * Copyright (c) 2003-2010 Cavium Networks * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 2, as @@ -24,14 +24,6 @@ * This file may also be available under a different license from Cavium. * Contact Cavium Networks for more information ***********************license end**************************************/ - -/* - * - * File defining different Octeon model IDs and macros to - * compare them. - * - */ - #ifndef __OCTEON_MODEL_H__ #define __OCTEON_MODEL_H__ @@ -52,6 +44,8 @@ * for internal use only, and may change without notice. */ +#define OCTEON_FAMILY_MASK 0x00ffff00 + /* Flag bits in top byte */ /* Ignores revision in model checks */ #define OM_IGNORE_REVISION 0x01000000 @@ -63,21 +57,48 @@ #define OM_IGNORE_MINOR_REVISION 0x08000000 #define OM_FLAG_MASK 0xff000000 -#define OM_MATCH_5XXX_FAMILY_MODELS 0x20000000 /* Match all cn5XXX Octeon models. */ -#define OM_MATCH_6XXX_FAMILY_MODELS 0x40000000 /* Match all cn6XXX Octeon models. */ +/* Match all cn5XXX Octeon models. */ +#define OM_MATCH_5XXX_FAMILY_MODELS 0x20000000 +/* Match all cn6XXX Octeon models. */ +#define OM_MATCH_6XXX_FAMILY_MODELS 0x40000000 /* * CN6XXX models with new revision encoding */ +#define OCTEON_CN68XX_PASS1_0 0x000d9100 +#define OCTEON_CN68XX_PASS1_1 0x000d9101 +#define OCTEON_CN68XX_PASS1_2 0x000d9102 +#define OCTEON_CN68XX_PASS2_0 0x000d9108 + +#define OCTEON_CN68XX (OCTEON_CN68XX_PASS2_0 | OM_IGNORE_REVISION) +#define OCTEON_CN68XX_PASS1_X (OCTEON_CN68XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN68XX_PASS2_X (OCTEON_CN68XX_PASS2_0 | OM_IGNORE_MINOR_REVISION) + +#define OCTEON_CN68XX_PASS1 OCTEON_CN68XX_PASS1_X +#define OCTEON_CN68XX_PASS2 OCTEON_CN68XX_PASS2_X + +#define OCTEON_CN66XX_PASS1_0 0x000d9200 +#define OCTEON_CN66XX_PASS1_2 0x000d9202 + +#define OCTEON_CN66XX (OCTEON_CN66XX_PASS1_0 | OM_IGNORE_REVISION) +#define OCTEON_CN66XX_PASS1_X (OCTEON_CN66XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) + #define OCTEON_CN63XX_PASS1_0 0x000d9000 #define OCTEON_CN63XX_PASS1_1 0x000d9001 #define OCTEON_CN63XX_PASS1_2 0x000d9002 #define OCTEON_CN63XX_PASS2_0 0x000d9008 +#define OCTEON_CN63XX_PASS2_1 0x000d9009 +#define OCTEON_CN63XX_PASS2_2 0x000d900a #define OCTEON_CN63XX (OCTEON_CN63XX_PASS2_0 | OM_IGNORE_REVISION) #define OCTEON_CN63XX_PASS1_X (OCTEON_CN63XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) #define OCTEON_CN63XX_PASS2_X (OCTEON_CN63XX_PASS2_0 | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN61XX_PASS1_0 0x000d9300 + +#define OCTEON_CN61XX (OCTEON_CN61XX_PASS1_0 | OM_IGNORE_REVISION) +#define OCTEON_CN61XX_PASS1_X (OCTEON_CN61XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) + /* * CN5XXX models with new revision encoding */ @@ -90,10 +111,8 @@ #define OCTEON_CN58XX_PASS2_3 0x000d030b #define OCTEON_CN58XX (OCTEON_CN58XX_PASS1_0 | OM_IGNORE_REVISION) -#define OCTEON_CN58XX_PASS1_X (OCTEON_CN58XX_PASS1_0 \ - | OM_IGNORE_MINOR_REVISION) -#define OCTEON_CN58XX_PASS2_X (OCTEON_CN58XX_PASS2_0 \ - | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN58XX_PASS1_X (OCTEON_CN58XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN58XX_PASS2_X (OCTEON_CN58XX_PASS2_0 | OM_IGNORE_MINOR_REVISION) #define OCTEON_CN58XX_PASS1 OCTEON_CN58XX_PASS1_X #define OCTEON_CN58XX_PASS2 OCTEON_CN58XX_PASS2_X @@ -103,10 +122,8 @@ #define OCTEON_CN56XX_PASS2_1 0x000d0409 #define OCTEON_CN56XX (OCTEON_CN56XX_PASS2_0 | OM_IGNORE_REVISION) -#define OCTEON_CN56XX_PASS1_X (OCTEON_CN56XX_PASS1_0 \ - | OM_IGNORE_MINOR_REVISION) -#define OCTEON_CN56XX_PASS2_X (OCTEON_CN56XX_PASS2_0 \ - | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN56XX_PASS1_X (OCTEON_CN56XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN56XX_PASS2_X (OCTEON_CN56XX_PASS2_0 | OM_IGNORE_MINOR_REVISION) #define OCTEON_CN56XX_PASS1 OCTEON_CN56XX_PASS1_X #define OCTEON_CN56XX_PASS2 OCTEON_CN56XX_PASS2_X @@ -125,8 +142,7 @@ #define OCTEON_CN50XX_PASS1_0 0x000d0600 #define OCTEON_CN50XX (OCTEON_CN50XX_PASS1_0 | OM_IGNORE_REVISION) -#define OCTEON_CN50XX_PASS1_X (OCTEON_CN50XX_PASS1_0 \ - | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN50XX_PASS1_X (OCTEON_CN50XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) #define OCTEON_CN50XX_PASS1 OCTEON_CN50XX_PASS1_X /* @@ -138,10 +154,8 @@ #define OCTEON_CN52XX_PASS2_0 0x000d0708 #define OCTEON_CN52XX (OCTEON_CN52XX_PASS2_0 | OM_IGNORE_REVISION) -#define OCTEON_CN52XX_PASS1_X (OCTEON_CN52XX_PASS1_0 \ - | OM_IGNORE_MINOR_REVISION) -#define OCTEON_CN52XX_PASS2_X (OCTEON_CN52XX_PASS2_0 \ - | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN52XX_PASS1_X (OCTEON_CN52XX_PASS1_0 | OM_IGNORE_MINOR_REVISION) +#define OCTEON_CN52XX_PASS2_X (OCTEON_CN52XX_PASS2_0 | OM_IGNORE_MINOR_REVISION) #define OCTEON_CN52XX_PASS1 OCTEON_CN52XX_PASS1_X #define OCTEON_CN52XX_PASS2 OCTEON_CN52XX_PASS2_X @@ -174,28 +188,23 @@ #define OCTEON_CN3005_PASS1 (0x000d0210 | OM_CHECK_SUBMODEL) #define OCTEON_CN3005_PASS1_0 (0x000d0210 | OM_CHECK_SUBMODEL) #define OCTEON_CN3005_PASS1_1 (0x000d0212 | OM_CHECK_SUBMODEL) -#define OCTEON_CN3005 (OCTEON_CN3005_PASS1 | OM_IGNORE_REVISION \ - | OM_CHECK_SUBMODEL) +#define OCTEON_CN3005 (OCTEON_CN3005_PASS1 | OM_IGNORE_REVISION | OM_CHECK_SUBMODEL) #define OCTEON_CN3010_PASS1 (0x000d0200 | OM_CHECK_SUBMODEL) #define OCTEON_CN3010_PASS1_0 (0x000d0200 | OM_CHECK_SUBMODEL) #define OCTEON_CN3010_PASS1_1 (0x000d0202 | OM_CHECK_SUBMODEL) -#define OCTEON_CN3010 (OCTEON_CN3010_PASS1 | OM_IGNORE_REVISION \ - | OM_CHECK_SUBMODEL) +#define OCTEON_CN3010 (OCTEON_CN3010_PASS1 | OM_IGNORE_REVISION | OM_CHECK_SUBMODEL) #define OCTEON_CN3020_PASS1 (0x000d0110 | OM_CHECK_SUBMODEL) #define OCTEON_CN3020_PASS1_0 (0x000d0110 | OM_CHECK_SUBMODEL) #define OCTEON_CN3020_PASS1_1 (0x000d0112 | OM_CHECK_SUBMODEL) -#define OCTEON_CN3020 (OCTEON_CN3020_PASS1 | OM_IGNORE_REVISION \ - | OM_CHECK_SUBMODEL) - - - -/* This matches the complete family of CN3xxx CPUs, and not subsequent models */ -#define OCTEON_CN3XXX (OCTEON_CN58XX_PASS1_0 \ - | OM_MATCH_PREVIOUS_MODELS \ - | OM_IGNORE_REVISION) +#define OCTEON_CN3020 (OCTEON_CN3020_PASS1 | OM_IGNORE_REVISION | OM_CHECK_SUBMODEL) +/* + * This matches the complete family of CN3xxx CPUs, and not subsequent + * models + */ +#define OCTEON_CN3XXX (OCTEON_CN58XX_PASS1_0 | OM_MATCH_PREVIOUS_MODELS | OM_IGNORE_REVISION) #define OCTEON_CN5XXX (OCTEON_CN58XX_PASS1_0 | OM_MATCH_5XXX_FAMILY_MODELS) #define OCTEON_CN6XXX (OCTEON_CN63XX_PASS1_0 | OM_MATCH_6XXX_FAMILY_MODELS) @@ -221,90 +230,55 @@ #define OCTEON_38XX_FAMILY_MASK 0x00ffff00 #define OCTEON_38XX_FAMILY_REV_MASK 0x00ffff0f #define OCTEON_38XX_MODEL_MASK 0x00ffff10 -#define OCTEON_38XX_MODEL_REV_MASK (OCTEON_38XX_FAMILY_REV_MASK \ - | OCTEON_38XX_MODEL_MASK) +#define OCTEON_38XX_MODEL_REV_MASK (OCTEON_38XX_FAMILY_REV_MASK | OCTEON_38XX_MODEL_MASK) /* CN5XXX and later use different layout of bits in the revision ID field */ #define OCTEON_58XX_FAMILY_MASK OCTEON_38XX_FAMILY_MASK #define OCTEON_58XX_FAMILY_REV_MASK 0x00ffff3f #define OCTEON_58XX_MODEL_MASK 0x00ffffc0 -#define OCTEON_58XX_MODEL_REV_MASK (OCTEON_58XX_FAMILY_REV_MASK \ - | OCTEON_58XX_MODEL_MASK) -#define OCTEON_58XX_MODEL_MINOR_REV_MASK (OCTEON_58XX_MODEL_REV_MASK \ - & 0x00fffff8) +#define OCTEON_58XX_MODEL_REV_MASK (OCTEON_58XX_FAMILY_REV_MASK | OCTEON_58XX_MODEL_MASK) +#define OCTEON_58XX_MODEL_MINOR_REV_MASK (OCTEON_58XX_MODEL_REV_MASK & 0x00fffff8) #define OCTEON_5XXX_MODEL_MASK 0x00ff0fc0 -#define __OCTEON_MATCH_MASK__(x, y, z) (((x) & (z)) == ((y) & (z))) - -/* NOTE: This is for internal (to this file) use only. */ -static inline int __OCTEON_IS_MODEL_COMPILE__(uint32_t arg_model, - uint32_t chip_model) -{ - uint32_t rev_and_sub = OM_IGNORE_REVISION | OM_CHECK_SUBMODEL; - - if ((arg_model & OCTEON_38XX_FAMILY_MASK) < OCTEON_CN58XX_PASS1_0) { - if (((arg_model & OM_FLAG_MASK) == rev_and_sub) && - __OCTEON_MATCH_MASK__(chip_model, arg_model, - OCTEON_38XX_MODEL_MASK)) - return 1; - if (((arg_model & OM_FLAG_MASK) == 0) && - __OCTEON_MATCH_MASK__(chip_model, arg_model, - OCTEON_38XX_FAMILY_REV_MASK)) - return 1; - if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_REVISION) && - __OCTEON_MATCH_MASK__(chip_model, arg_model, - OCTEON_38XX_FAMILY_MASK)) - return 1; - if (((arg_model & OM_FLAG_MASK) == OM_CHECK_SUBMODEL) && - __OCTEON_MATCH_MASK__((chip_model), (arg_model), - OCTEON_38XX_MODEL_REV_MASK)) - return 1; - if ((arg_model & OM_MATCH_PREVIOUS_MODELS) && - ((chip_model & OCTEON_38XX_MODEL_MASK) < - (arg_model & OCTEON_38XX_MODEL_MASK))) - return 1; - } else { - if (((arg_model & OM_FLAG_MASK) == rev_and_sub) && - __OCTEON_MATCH_MASK__((chip_model), (arg_model), - OCTEON_58XX_MODEL_MASK)) - return 1; - if (((arg_model & OM_FLAG_MASK) == 0) && - __OCTEON_MATCH_MASK__((chip_model), (arg_model), - OCTEON_58XX_FAMILY_REV_MASK)) - return 1; - if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_MINOR_REVISION) && - __OCTEON_MATCH_MASK__((chip_model), (arg_model), - OCTEON_58XX_MODEL_MINOR_REV_MASK)) - return 1; - if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_REVISION) && - __OCTEON_MATCH_MASK__((chip_model), (arg_model), - OCTEON_58XX_FAMILY_MASK)) - return 1; - if (((arg_model & OM_FLAG_MASK) == OM_CHECK_SUBMODEL) && - __OCTEON_MATCH_MASK__((chip_model), (arg_model), - OCTEON_58XX_MODEL_REV_MASK)) - return 1; - - if (((arg_model & OM_MATCH_5XXX_FAMILY_MODELS) == OM_MATCH_5XXX_FAMILY_MODELS) && - ((chip_model) >= OCTEON_CN58XX_PASS1_0) && ((chip_model) < OCTEON_CN63XX_PASS1_0)) - return 1; - - if (((arg_model & OM_MATCH_6XXX_FAMILY_MODELS) == OM_MATCH_6XXX_FAMILY_MODELS) && - ((chip_model) >= OCTEON_CN63XX_PASS1_0)) - return 1; - - if ((arg_model & OM_MATCH_PREVIOUS_MODELS) && - ((chip_model & OCTEON_58XX_MODEL_MASK) < - (arg_model & OCTEON_58XX_MODEL_MASK))) - return 1; - } - return 0; -} - /* forward declarations */ static inline uint32_t cvmx_get_proc_id(void) __attribute__ ((pure)); static inline uint64_t cvmx_read_csr(uint64_t csr_addr); +#define __OCTEON_MATCH_MASK__(x, y, z) (((x) & (z)) == ((y) & (z))) + +/* NOTE: This for internal use only! */ +#define __OCTEON_IS_MODEL_COMPILE__(arg_model, chip_model) \ +((((arg_model & OCTEON_38XX_FAMILY_MASK) < OCTEON_CN58XX_PASS1_0) && ( \ + ((((arg_model) & (OM_FLAG_MASK)) == (OM_IGNORE_REVISION | OM_CHECK_SUBMODEL)) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_38XX_MODEL_MASK)) || \ + ((((arg_model) & (OM_FLAG_MASK)) == 0) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_38XX_FAMILY_REV_MASK)) || \ + ((((arg_model) & (OM_FLAG_MASK)) == OM_IGNORE_REVISION) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_38XX_FAMILY_MASK)) || \ + ((((arg_model) & (OM_FLAG_MASK)) == OM_CHECK_SUBMODEL) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_38XX_MODEL_REV_MASK)) || \ + ((((arg_model) & (OM_MATCH_PREVIOUS_MODELS)) == OM_MATCH_PREVIOUS_MODELS) \ + && (((chip_model) & OCTEON_38XX_MODEL_MASK) < ((arg_model) & OCTEON_38XX_MODEL_MASK))) \ + )) || \ + (((arg_model & OCTEON_38XX_FAMILY_MASK) >= OCTEON_CN58XX_PASS1_0) && ( \ + ((((arg_model) & (OM_FLAG_MASK)) == (OM_IGNORE_REVISION | OM_CHECK_SUBMODEL)) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_MODEL_MASK)) || \ + ((((arg_model) & (OM_FLAG_MASK)) == 0) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_FAMILY_REV_MASK)) || \ + ((((arg_model) & (OM_FLAG_MASK)) == OM_IGNORE_MINOR_REVISION) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_MODEL_MINOR_REV_MASK)) || \ + ((((arg_model) & (OM_FLAG_MASK)) == OM_IGNORE_REVISION) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_FAMILY_MASK)) || \ + ((((arg_model) & (OM_FLAG_MASK)) == OM_CHECK_SUBMODEL) \ + && __OCTEON_MATCH_MASK__((chip_model), (arg_model), OCTEON_58XX_MODEL_REV_MASK)) || \ + ((((arg_model) & (OM_MATCH_5XXX_FAMILY_MODELS)) == OM_MATCH_5XXX_FAMILY_MODELS) \ + && ((chip_model) >= OCTEON_CN58XX_PASS1_0) && ((chip_model) < OCTEON_CN63XX_PASS1_0)) || \ + ((((arg_model) & (OM_MATCH_6XXX_FAMILY_MODELS)) == OM_MATCH_6XXX_FAMILY_MODELS) \ + && ((chip_model) >= OCTEON_CN63XX_PASS1_0)) || \ + ((((arg_model) & (OM_MATCH_PREVIOUS_MODELS)) == OM_MATCH_PREVIOUS_MODELS) \ + && (((chip_model) & OCTEON_58XX_MODEL_MASK) < ((arg_model) & OCTEON_58XX_MODEL_MASK))) \ + ))) + /* NOTE: This for internal use only!!!!! */ static inline int __octeon_is_model_runtime__(uint32_t model) { @@ -312,22 +286,25 @@ static inline int __octeon_is_model_runtime__(uint32_t model) /* * Check for special case of mismarked 3005 samples. We only - * need to check if the sub model isn't being ignored. + * need to check if the sub model isn't being ignored */ if ((model & OM_CHECK_SUBMODEL) == OM_CHECK_SUBMODEL) { - if (cpuid == OCTEON_CN3010_PASS1 \ - && (cvmx_read_csr(0x80011800800007B8ull) & (1ull << 34))) + if (cpuid == OCTEON_CN3010_PASS1 && (cvmx_read_csr(0x80011800800007B8ull) & (1ull << 34))) cpuid |= 0x10; } return __OCTEON_IS_MODEL_COMPILE__(model, cpuid); } /* - * The OCTEON_IS_MODEL macro should be used for all Octeon model - * checking done in a program. This should be kept runtime if at all - * possible. Any compile time (#if OCTEON_IS_MODEL) usage must be - * condtionalized with OCTEON_IS_COMMON_BINARY() if runtime checking - * support is required. + * The OCTEON_IS_MODEL macro should be used for all Octeon model checking done + * in a program. + * This should be kept runtime if at all possible and must be conditionalized + * with OCTEON_IS_COMMON_BINARY() if runtime checking support is required. + * + * Use of the macro in preprocessor directives ( #if OCTEON_IS_MODEL(...) ) + * is NOT SUPPORTED, and should be replaced with CVMX_COMPILED_FOR() + * I.e.: + * #if OCTEON_IS_MODEL(OCTEON_CN56XX) -> #if CVMX_COMPILED_FOR(OCTEON_CN56XX) */ #define OCTEON_IS_MODEL(x) __octeon_is_model_runtime__(x) #define OCTEON_IS_COMMON_BINARY() 1 diff --git a/arch/mips/include/asm/octeon/pci-octeon.h b/arch/mips/include/asm/octeon/pci-octeon.h index fba2ba200f58..c66734bd3382 100644 --- a/arch/mips/include/asm/octeon/pci-octeon.h +++ b/arch/mips/include/asm/octeon/pci-octeon.h @@ -56,7 +56,8 @@ enum octeon_dma_bar_type { OCTEON_DMA_BAR_TYPE_INVALID, OCTEON_DMA_BAR_TYPE_SMALL, OCTEON_DMA_BAR_TYPE_BIG, - OCTEON_DMA_BAR_TYPE_PCIE + OCTEON_DMA_BAR_TYPE_PCIE, + OCTEON_DMA_BAR_TYPE_PCIE2 }; /* diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index e59cd1ac09c2..d41790928c64 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -38,6 +38,14 @@ #define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT) #define HPAGE_MASK (~(HPAGE_SIZE - 1)) #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) +#else /* !CONFIG_HUGETLB_PAGE */ +# ifndef BUILD_BUG +# define BUILD_BUG() do { extern void __build_bug(void); __build_bug(); } while (0) +# endif +#define HPAGE_SHIFT ({BUILD_BUG(); 0; }) +#define HPAGE_SIZE ({BUILD_BUG(); 0; }) +#define HPAGE_MASK ({BUILD_BUG(); 0; }) +#define HUGETLB_PAGE_ORDER ({BUILD_BUG(); 0; }) #endif /* CONFIG_HUGETLB_PAGE */ #ifndef __ASSEMBLY__ diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h index 8a153d2fa62a..5d56bb230345 100644 --- a/arch/mips/include/asm/pgtable-32.h +++ b/arch/mips/include/asm/pgtable-32.h @@ -19,23 +19,7 @@ #include <asm-generic/pgtable-nopmd.h> /* - * - add_wired_entry() add a fixed TLB entry, and move wired register - */ -extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask); - -/* - * - add_temporary_entry() add a temporary TLB entry. We use TLB entries - * starting at the top and working down. This is for populating the - * TLB before trap_init() puts the TLB miss handler in place. It - * should be used only for entries matching the actual page tables, - * to prevent inconsistencies. - */ -extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask); - - -/* Basically we have the same two-level (which is the logical three level + * Basically we have the same two-level (which is the logical three level * Linux page table layout folded) page tables as the i386. Some day * when we have proper page coloring support we can have a 1% quicker * tlb refill handling mechanism, but for now it is a bit slower but diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index 7b99c670e478..4b7f5252d2fd 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -137,7 +137,19 @@ extern int ptrace_set_watch_regs(struct task_struct *child, */ #define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER) -#define regs_return_value(_regs) ((_regs)->regs[2]) +static inline int is_syscall_success(struct pt_regs *regs) +{ + return !regs->regs[7]; +} + +static inline long regs_return_value(struct pt_regs *regs) +{ + if (is_syscall_success(regs)) + return regs->regs[2]; + else + return -regs->regs[2]; +} + #define instruction_pointer(regs) ((regs)->cp0_epc) #define profile_pc(regs) instruction_pointer(regs) diff --git a/arch/mips/include/asm/tlbmisc.h b/arch/mips/include/asm/tlbmisc.h new file mode 100644 index 000000000000..3a452282cba0 --- /dev/null +++ b/arch/mips/include/asm/tlbmisc.h @@ -0,0 +1,10 @@ +#ifndef __ASM_TLBMISC_H +#define __ASM_TLBMISC_H + +/* + * - add_wired_entry() add a fixed TLB entry, and move wired register + */ +extern void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask); + +#endif /* __ASM_TLBMISC_H */ diff --git a/arch/mips/include/asm/traps.h b/arch/mips/include/asm/traps.h index 90ff2f497c50..ff74aec3561a 100644 --- a/arch/mips/include/asm/traps.h +++ b/arch/mips/include/asm/traps.h @@ -24,5 +24,18 @@ extern int (*board_be_handler)(struct pt_regs *regs, int is_fixup); extern void (*board_nmi_handler_setup)(void); extern void (*board_ejtag_handler_setup)(void); extern void (*board_bind_eic_interrupt)(int irq, int regset); +extern void (*board_ebase_setup)(void); + +extern int register_nmi_notifier(struct notifier_block *nb); + +#define nmi_notifier(fn, pri) \ +({ \ + static struct notifier_block fn##_nb = { \ + .notifier_call = fn, \ + .priority = pri \ + }; \ + \ + register_nmi_notifier(&fn##_nb); \ +}) #endif /* _ASM_TRAPS_H */ diff --git a/arch/mips/include/asm/types.h b/arch/mips/include/asm/types.h index 43bf70ebd3a2..1228b25b290a 100644 --- a/arch/mips/include/asm/types.h +++ b/arch/mips/include/asm/types.h @@ -15,10 +15,14 @@ * We don't use int-l64.h for the kernel anymore but still use it for * userspace to avoid code changes. */ -#if (_MIPS_SZLONG == 64) && !defined(__KERNEL__) -# include <asm-generic/int-l64.h> -#else +#ifdef __KERNEL__ # include <asm-generic/int-ll64.h> +#else +# if _MIPS_SZLONG == 64 +# include <asm-generic/int-l64.h> +# else +# include <asm-generic/int-ll64.h> +# endif #endif /* diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index ca9bd2069142..f21868b28b24 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -20,6 +20,7 @@ #include <asm/io.h> #include <asm/jazz.h> #include <asm/pgtable.h> +#include <asm/tlbmisc.h> static DEFINE_RAW_SPINLOCK(r4030_lock); @@ -133,7 +134,7 @@ static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) static struct irqaction r4030_timer_irqaction = { .handler = r4030_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .name = "R4030 timer", }; diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c index 0d0f054a02f4..820e926dacbc 100644 --- a/arch/mips/jazz/setup.c +++ b/arch/mips/jazz/setup.c @@ -21,6 +21,7 @@ #include <asm/jazzdma.h> #include <asm/reboot.h> #include <asm/pgtable.h> +#include <asm/tlbmisc.h> extern asmlinkage void jazz_handle_int(void); diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index c3b04be3fb2b..639e3ce6c264 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -488,7 +488,7 @@ static int __init qi_lb60_board_setup(void) board_gpio_setup(); if (qi_lb60_init_platform_devices()) - panic("Failed to initialize platform devices\n"); + panic("Failed to initialize platform devices"); return 0; } diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 1a966183e353..0c6877ea9004 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -55,9 +55,11 @@ obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o obj-$(CONFIG_CPU_XLR) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_XLP) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP_UP) += smp-up.o +obj-$(CONFIG_CPU_BMIPS) += smp-bmips.o bmips_vec.o obj-$(CONFIG_MIPS_MT) += mips-mt.o obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S new file mode 100644 index 000000000000..e908e81330b1 --- /dev/null +++ b/arch/mips/kernel/bmips_vec.S @@ -0,0 +1,255 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011 by Kevin Cernekee (cernekee@gmail.com) + * + * Reset/NMI/re-entry vectors for BMIPS processors + */ + +#include <linux/init.h> + +#include <asm/asm.h> +#include <asm/asmmacro.h> +#include <asm/cacheops.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/stackframe.h> +#include <asm/addrspace.h> +#include <asm/hazards.h> +#include <asm/bmips.h> + + .macro BARRIER + .set mips32 + _ssnop + _ssnop + _ssnop + .set mips0 + .endm + + __CPUINIT + +/*********************************************************************** + * Alternate CPU1 startup vector for BMIPS4350 + * + * On some systems the bootloader has already started CPU1 and configured + * it to resume execution at 0x8000_0200 (!BEV IV vector) when it is + * triggered by the SW1 interrupt. If that is the case we try to move + * it to a more convenient place: BMIPS_WARM_RESTART_VEC @ 0x8000_0380. + ***********************************************************************/ + +LEAF(bmips_smp_movevec) + la k0, 1f + li k1, CKSEG1 + or k0, k1 + jr k0 + +1: + /* clear IV, pending IPIs */ + mtc0 zero, CP0_CAUSE + + /* re-enable IRQs to wait for SW1 */ + li k0, ST0_IE | ST0_BEV | STATUSF_IP1 + mtc0 k0, CP0_STATUS + + /* set up CPU1 CBR; move BASE to 0xa000_0000 */ + li k0, 0xff400000 + mtc0 k0, $22, 6 + li k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_1 + or k0, k1 + li k1, 0xa0080000 + sw k1, 0(k0) + + /* wait here for SW1 interrupt from bmips_boot_secondary() */ + wait + + la k0, bmips_reset_nmi_vec + li k1, CKSEG1 + or k0, k1 + jr k0 +END(bmips_smp_movevec) + +/*********************************************************************** + * Reset/NMI vector + * For BMIPS processors that can relocate their exception vectors, this + * entire function gets copied to 0x8000_0000. + ***********************************************************************/ + +NESTED(bmips_reset_nmi_vec, PT_SIZE, sp) + .set push + .set noat + .align 4 + +#ifdef CONFIG_SMP + /* if the NMI bit is clear, assume this is a CPU1 reset instead */ + li k1, (1 << 19) + mfc0 k0, CP0_STATUS + and k0, k1 + beqz k0, bmips_smp_entry + +#if defined(CONFIG_CPU_BMIPS5000) + /* if we're not on core 0, this must be the SMP boot signal */ + li k1, (3 << 25) + mfc0 k0, $22 + and k0, k1 + bnez k0, bmips_smp_entry +#endif +#endif /* CONFIG_SMP */ + + /* nope, it's just a regular NMI */ + SAVE_ALL + move a0, sp + + /* clear EXL, ERL, BEV so that TLB refills still work */ + mfc0 k0, CP0_STATUS + li k1, ST0_ERL | ST0_EXL | ST0_BEV | ST0_IE + or k0, k1 + xor k0, k1 + mtc0 k0, CP0_STATUS + BARRIER + + /* jump to the NMI handler function */ + la k0, nmi_handler + jr k0 + + RESTORE_ALL + .set mips3 + eret + +/*********************************************************************** + * CPU1 reset vector (used for the initial boot only) + * This is still part of bmips_reset_nmi_vec(). + ***********************************************************************/ + +#ifdef CONFIG_SMP + +bmips_smp_entry: + + /* set up CP0 STATUS; enable FPU */ + li k0, 0x30000000 + mtc0 k0, CP0_STATUS + BARRIER + + /* set local CP0 CONFIG to make kseg0 cacheable, write-back */ + mfc0 k0, CP0_CONFIG + ori k0, 0x07 + xori k0, 0x04 + mtc0 k0, CP0_CONFIG + +#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) + /* initialize CPU1's local I-cache */ + li k0, 0x80000000 + li k1, 0x80010000 + mtc0 zero, $28 + mtc0 zero, $28, 1 + BARRIER + +1: cache Index_Store_Tag_I, 0(k0) + addiu k0, 16 + bne k0, k1, 1b +#elif defined(CONFIG_CPU_BMIPS5000) + /* set exception vector base */ + la k0, ebase + lw k0, 0(k0) + mtc0 k0, $15, 1 + BARRIER +#endif + + /* jump back to kseg0 in case we need to remap the kseg1 area */ + la k0, 1f + jr k0 +1: + la k0, bmips_enable_xks01 + jalr k0 + + /* use temporary stack to set up upper memory TLB */ + li sp, BMIPS_WARM_RESTART_VEC + la k0, plat_wired_tlb_setup + jalr k0 + + /* switch to permanent stack and continue booting */ + + .global bmips_secondary_reentry +bmips_secondary_reentry: + la k0, bmips_smp_boot_sp + lw sp, 0(k0) + la k0, bmips_smp_boot_gp + lw gp, 0(k0) + la k0, start_secondary + jr k0 + +#endif /* CONFIG_SMP */ + + .align 4 + .global bmips_reset_nmi_vec_end +bmips_reset_nmi_vec_end: + +END(bmips_reset_nmi_vec) + + .set pop + .previous + +/*********************************************************************** + * CPU1 warm restart vector (used for second and subsequent boots). + * Also used for S2 standby recovery (PM). + * This entire function gets copied to (BMIPS_WARM_RESTART_VEC) + ***********************************************************************/ + +LEAF(bmips_smp_int_vec) + + .align 4 + mfc0 k0, CP0_STATUS + ori k0, 0x01 + xori k0, 0x01 + mtc0 k0, CP0_STATUS + eret + + .align 4 + .global bmips_smp_int_vec_end +bmips_smp_int_vec_end: + +END(bmips_smp_int_vec) + +/*********************************************************************** + * XKS01 support + * Certain CPUs support extending kseg0 to 1024MB. + ***********************************************************************/ + + __CPUINIT + +LEAF(bmips_enable_xks01) + +#if defined(CONFIG_XKS01) + +#if defined(CONFIG_CPU_BMIPS4380) + mfc0 t0, $22, 3 + li t1, 0x1ff0 + li t2, (1 << 12) | (1 << 9) + or t0, t1 + xor t0, t1 + or t0, t2 + mtc0 t0, $22, 3 + BARRIER +#elif defined(CONFIG_CPU_BMIPS5000) + mfc0 t0, $22, 5 + li t1, 0x01ff + li t2, (1 << 8) | (1 << 5) + or t0, t1 + xor t0, t1 + or t0, t2 + mtc0 t0, $22, 5 + BARRIER +#else + +#error Missing XKS01 setup + +#endif + +#endif /* defined(CONFIG_XKS01) */ + + jr ra + +END(bmips_enable_xks01) + + .previous diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 32103cc2a257..4d735d0e58f5 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/sched.h> #include <linux/signal.h> +#include <linux/module.h> #include <asm/branch.h> #include <asm/cpu.h> #include <asm/cpu-features.h> @@ -17,28 +18,22 @@ #include <asm/ptrace.h> #include <asm/uaccess.h> -/* - * Compute the return address and do emulate branch simulation, if required. +/** + * __compute_return_epc_for_insn - Computes the return address and do emulate + * branch simulation, if required. + * + * @regs: Pointer to pt_regs + * @insn: branch instruction to decode + * @returns: -EFAULT on error and forces SIGBUS, and on success + * returns 0 or BRANCH_LIKELY_TAKEN as appropriate after + * evaluating the branch. */ -int __compute_return_epc(struct pt_regs *regs) +int __compute_return_epc_for_insn(struct pt_regs *regs, + union mips_instruction insn) { - unsigned int __user *addr; unsigned int bit, fcr31, dspcontrol; - long epc; - union mips_instruction insn; - - epc = regs->cp0_epc; - if (epc & 3) - goto unaligned; - - /* - * Read the instruction - */ - addr = (unsigned int __user *) epc; - if (__get_user(insn.word, addr)) { - force_sig(SIGSEGV, current); - return -EFAULT; - } + long epc = regs->cp0_epc; + int ret = 0; switch (insn.i_format.opcode) { /* @@ -64,18 +59,22 @@ int __compute_return_epc(struct pt_regs *regs) switch (insn.i_format.rt) { case bltz_op: case bltzl_op: - if ((long)regs->regs[insn.i_format.rs] < 0) + if ((long)regs->regs[insn.i_format.rs] < 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == bltzl_op) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; case bgez_op: case bgezl_op: - if ((long)regs->regs[insn.i_format.rs] >= 0) + if ((long)regs->regs[insn.i_format.rs] >= 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == bgezl_op) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; @@ -83,9 +82,11 @@ int __compute_return_epc(struct pt_regs *regs) case bltzal_op: case bltzall_op: regs->regs[31] = epc + 8; - if ((long)regs->regs[insn.i_format.rs] < 0) + if ((long)regs->regs[insn.i_format.rs] < 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == bltzall_op) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; @@ -93,12 +94,15 @@ int __compute_return_epc(struct pt_regs *regs) case bgezal_op: case bgezall_op: regs->regs[31] = epc + 8; - if ((long)regs->regs[insn.i_format.rs] >= 0) + if ((long)regs->regs[insn.i_format.rs] >= 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == bgezall_op) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; + case bposge32_op: if (!cpu_has_dsp) goto sigill; @@ -133,9 +137,11 @@ int __compute_return_epc(struct pt_regs *regs) case beq_op: case beql_op: if (regs->regs[insn.i_format.rs] == - regs->regs[insn.i_format.rt]) + regs->regs[insn.i_format.rt]) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == beql_op) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; @@ -143,9 +149,11 @@ int __compute_return_epc(struct pt_regs *regs) case bne_op: case bnel_op: if (regs->regs[insn.i_format.rs] != - regs->regs[insn.i_format.rt]) + regs->regs[insn.i_format.rt]) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == bnel_op) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; @@ -153,9 +161,11 @@ int __compute_return_epc(struct pt_regs *regs) case blez_op: /* not really i_format */ case blezl_op: /* rt field assumed to be zero */ - if ((long)regs->regs[insn.i_format.rs] <= 0) + if ((long)regs->regs[insn.i_format.rs] <= 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == bnel_op) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; @@ -163,9 +173,11 @@ int __compute_return_epc(struct pt_regs *regs) case bgtz_op: case bgtzl_op: /* rt field assumed to be zero */ - if ((long)regs->regs[insn.i_format.rs] > 0) + if ((long)regs->regs[insn.i_format.rs] > 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == bnel_op) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; @@ -187,18 +199,22 @@ int __compute_return_epc(struct pt_regs *regs) switch (insn.i_format.rt & 3) { case 0: /* bc1f */ case 2: /* bc1fl */ - if (~fcr31 & (1 << bit)) + if (~fcr31 & (1 << bit)) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == 2) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; case 1: /* bc1t */ case 3: /* bc1tl */ - if (fcr31 & (1 << bit)) + if (fcr31 & (1 << bit)) { epc = epc + 4 + (insn.i_format.simmediate << 2); - else + if (insn.i_format.rt == 3) + ret = BRANCH_LIKELY_TAKEN; + } else epc += 8; regs->cp0_epc = epc; break; @@ -239,15 +255,39 @@ int __compute_return_epc(struct pt_regs *regs) #endif } - return 0; + return ret; -unaligned: - printk("%s: unaligned epc - sending SIGBUS.\n", current->comm); +sigill: + printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); force_sig(SIGBUS, current); return -EFAULT; +} +EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn); -sigill: - printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); +int __compute_return_epc(struct pt_regs *regs) +{ + unsigned int __user *addr; + long epc; + union mips_instruction insn; + + epc = regs->cp0_epc; + if (epc & 3) + goto unaligned; + + /* + * Read the instruction + */ + addr = (unsigned int __user *) epc; + if (__get_user(insn.word, addr)) { + force_sig(SIGSEGV, current); + return -EFAULT; + } + + return __compute_return_epc_for_insn(regs, insn); + +unaligned: + printk("%s: unaligned epc - sending SIGBUS.\n", current->comm); force_sig(SIGBUS, current); return -EFAULT; + } diff --git a/arch/mips/kernel/cevt-bcm1480.c b/arch/mips/kernel/cevt-bcm1480.c index 36c3898b76db..69bbfae183bc 100644 --- a/arch/mips/kernel/cevt-bcm1480.c +++ b/arch/mips/kernel/cevt-bcm1480.c @@ -145,7 +145,7 @@ void __cpuinit sb1480_clockevent_init(void) bcm1480_unmask_irq(cpu, irq); action->handler = sibyte_counter_handler; - action->flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER; + action->flags = IRQF_PERCPU | IRQF_TIMER; action->name = name; action->dev_id = cd; diff --git a/arch/mips/kernel/cevt-ds1287.c b/arch/mips/kernel/cevt-ds1287.c index 939157e397b9..ed648cb5a69f 100644 --- a/arch/mips/kernel/cevt-ds1287.c +++ b/arch/mips/kernel/cevt-ds1287.c @@ -108,7 +108,7 @@ static irqreturn_t ds1287_interrupt(int irq, void *dev_id) static struct irqaction ds1287_irqaction = { .handler = ds1287_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, + .flags = IRQF_PERCPU | IRQF_TIMER, .name = "ds1287", }; diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c index 339f3639b90e..831b47585b7c 100644 --- a/arch/mips/kernel/cevt-gt641xx.c +++ b/arch/mips/kernel/cevt-gt641xx.c @@ -114,7 +114,7 @@ static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id) static struct irqaction gt641xx_timer0_irqaction = { .handler = gt641xx_timer0_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, + .flags = IRQF_PERCPU | IRQF_TIMER, .name = "gt641xx_timer0", }; diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index e2d8e199be32..51095dd9599d 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -84,7 +84,7 @@ out: struct irqaction c0_compare_irqaction = { .handler = c0_compare_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, + .flags = IRQF_PERCPU | IRQF_TIMER, .name = "timer", }; diff --git a/arch/mips/kernel/cevt-sb1250.c b/arch/mips/kernel/cevt-sb1250.c index 590c54f28a81..e73439fd6850 100644 --- a/arch/mips/kernel/cevt-sb1250.c +++ b/arch/mips/kernel/cevt-sb1250.c @@ -144,7 +144,7 @@ void __cpuinit sb1250_clockevent_init(void) sb1250_unmask_irq(cpu, irq); action->handler = sibyte_counter_handler; - action->flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER; + action->flags = IRQF_PERCPU | IRQF_TIMER; action->name = name; action->dev_id = cd; diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c index f0ab92a1b057..e5c30b1d0860 100644 --- a/arch/mips/kernel/cevt-txx9.c +++ b/arch/mips/kernel/cevt-txx9.c @@ -146,7 +146,7 @@ static irqreturn_t txx9tmr_interrupt(int irq, void *dev_id) static struct irqaction txx9tmr_irq = { .handler = txx9tmr_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, + .flags = IRQF_PERCPU | IRQF_TIMER, .name = "txx9tmr", .dev_id = &txx9_clock_event_device, }; diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index c7d3cf1ce46e..0bab464b8e33 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -191,6 +191,8 @@ void __init check_wait(void) case CPU_CAVIUM_OCTEON_PLUS: case CPU_CAVIUM_OCTEON2: case CPU_JZRISC: + case CPU_XLR: + case CPU_XLP: cpu_wait = r4k_wait; break; @@ -1014,6 +1016,13 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) { decode_configs(c); + if ((c->processor_id & 0xff00) == PRID_IMP_NETLOGIC_AU13XX) { + c->cputype = CPU_ALCHEMY; + __cpu_name[cpu] = "Au1300"; + /* following stuff is not for Alchemy */ + return; + } + c->options = (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_COUNTER | @@ -1023,6 +1032,12 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) MIPS_CPU_LLSC); switch (c->processor_id & 0xff00) { + case PRID_IMP_NETLOGIC_XLP8XX: + case PRID_IMP_NETLOGIC_XLP3XX: + c->cputype = CPU_XLP; + __cpu_name[cpu] = "Netlogic XLP"; + break; + case PRID_IMP_NETLOGIC_XLR732: case PRID_IMP_NETLOGIC_XLR716: case PRID_IMP_NETLOGIC_XLR532: @@ -1053,14 +1068,21 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) break; default: - printk(KERN_INFO "Unknown Netlogic chip id [%02x]!\n", + pr_info("Unknown Netlogic chip id [%02x]!\n", c->processor_id); c->cputype = CPU_XLR; break; } - c->isa_level = MIPS_CPU_ISA_M64R1; - c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1; + if (c->cputype == CPU_XLP) { + c->isa_level = MIPS_CPU_ISA_M64R2; + c->options |= (MIPS_CPU_FPU | MIPS_CPU_ULRI | MIPS_CPU_MCHECK); + /* This will be updated again after all threads are woken up */ + c->tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; + } else { + c->isa_level = MIPS_CPU_ISA_M64R1; + c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1; + } } #ifdef CONFIG_64BIT diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c index 7047bff35ea5..c5bc344fc745 100644 --- a/arch/mips/kernel/i8253.c +++ b/arch/mips/kernel/i8253.c @@ -19,7 +19,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) static struct irqaction irq0 = { .handler = timer_interrupt, - .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, + .flags = IRQF_NOBALANCING | IRQF_TIMER, .name = "timer" }; diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c index ee28683fc2ac..158467da9bc1 100644 --- a/arch/mips/kernel/kprobes.c +++ b/arch/mips/kernel/kprobes.c @@ -25,10 +25,12 @@ #include <linux/kprobes.h> #include <linux/preempt.h> +#include <linux/uaccess.h> #include <linux/kdebug.h> #include <linux/slab.h> #include <asm/ptrace.h> +#include <asm/branch.h> #include <asm/break.h> #include <asm/inst.h> @@ -112,17 +114,49 @@ insn_ok: return 0; } +/* + * insn_has_ll_or_sc function checks whether instruction is ll or sc + * one; putting breakpoint on top of atomic ll/sc pair is bad idea; + * so we need to prevent it and refuse kprobes insertion for such + * instructions; cannot do much about breakpoint in the middle of + * ll/sc pair; it is upto user to avoid those places + */ +static int __kprobes insn_has_ll_or_sc(union mips_instruction insn) +{ + int ret = 0; + + switch (insn.i_format.opcode) { + case ll_op: + case lld_op: + case sc_op: + case scd_op: + ret = 1; + break; + default: + break; + } + return ret; +} + int __kprobes arch_prepare_kprobe(struct kprobe *p) { union mips_instruction insn; union mips_instruction prev_insn; int ret = 0; - prev_insn = p->addr[-1]; insn = p->addr[0]; - if (insn_has_delayslot(insn) || insn_has_delayslot(prev_insn)) { - pr_notice("Kprobes for branch and jump instructions are not supported\n"); + if (insn_has_ll_or_sc(insn)) { + pr_notice("Kprobes for ll and sc instructions are not" + "supported\n"); + ret = -EINVAL; + goto out; + } + + if ((probe_kernel_read(&prev_insn, p->addr - 1, + sizeof(mips_instruction)) == 0) && + insn_has_delayslot(prev_insn)) { + pr_notice("Kprobes for branch delayslot are not supported\n"); ret = -EINVAL; goto out; } @@ -138,9 +172,20 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) * In the kprobe->ainsn.insn[] array we store the original * instruction at index zero and a break trap instruction at * index one. + * + * On MIPS arch if the instruction at probed address is a + * branch instruction, we need to execute the instruction at + * Branch Delayslot (BD) at the time of probe hit. As MIPS also + * doesn't have single stepping support, the BD instruction can + * not be executed in-line and it would be executed on SSOL slot + * using a normal breakpoint instruction in the next slot. + * So, read the instruction and save it for later execution. */ + if (insn_has_delayslot(insn)) + memcpy(&p->ainsn.insn[0], p->addr + 1, sizeof(kprobe_opcode_t)); + else + memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); - memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); p->ainsn.insn[1] = breakpoint2_insn; p->opcode = *p->addr; @@ -191,16 +236,96 @@ static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, kcb->kprobe_saved_epc = regs->cp0_epc; } -static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +/** + * evaluate_branch_instrucion - + * + * Evaluate the branch instruction at probed address during probe hit. The + * result of evaluation would be the updated epc. The insturction in delayslot + * would actually be single stepped using a normal breakpoint) on SSOL slot. + * + * The result is also saved in the kprobe control block for later use, + * in case we need to execute the delayslot instruction. The latter will be + * false for NOP instruction in dealyslot and the branch-likely instructions + * when the branch is taken. And for those cases we set a flag as + * SKIP_DELAYSLOT in the kprobe control block + */ +static int evaluate_branch_instruction(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { + union mips_instruction insn = p->opcode; + long epc; + int ret = 0; + + epc = regs->cp0_epc; + if (epc & 3) + goto unaligned; + + if (p->ainsn.insn->word == 0) + kcb->flags |= SKIP_DELAYSLOT; + else + kcb->flags &= ~SKIP_DELAYSLOT; + + ret = __compute_return_epc_for_insn(regs, insn); + if (ret < 0) + return ret; + + if (ret == BRANCH_LIKELY_TAKEN) + kcb->flags |= SKIP_DELAYSLOT; + + kcb->target_epc = regs->cp0_epc; + + return 0; + +unaligned: + pr_notice("%s: unaligned epc - sending SIGBUS.\n", current->comm); + force_sig(SIGBUS, current); + return -EFAULT; + +} + +static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) +{ + int ret = 0; + regs->cp0_status &= ~ST0_IE; /* single step inline if the instruction is a break */ if (p->opcode.word == breakpoint_insn.word || p->opcode.word == breakpoint2_insn.word) regs->cp0_epc = (unsigned long)p->addr; - else - regs->cp0_epc = (unsigned long)&p->ainsn.insn[0]; + else if (insn_has_delayslot(p->opcode)) { + ret = evaluate_branch_instruction(p, regs, kcb); + if (ret < 0) { + pr_notice("Kprobes: Error in evaluating branch\n"); + return; + } + } + regs->cp0_epc = (unsigned long)&p->ainsn.insn[0]; +} + +/* + * Called after single-stepping. p->addr is the address of the + * instruction whose first byte has been replaced by the "break 0" + * instruction. To avoid the SMP problems that can occur when we + * temporarily put back the original opcode to single-step, we + * single-stepped a copy of the instruction. The address of this + * copy is p->ainsn.insn. + * + * This function prepares to return from the post-single-step + * breakpoint trap. In case of branch instructions, the target + * epc to be restored. + */ +static void __kprobes resume_execution(struct kprobe *p, + struct pt_regs *regs, + struct kprobe_ctlblk *kcb) +{ + if (insn_has_delayslot(p->opcode)) + regs->cp0_epc = kcb->target_epc; + else { + unsigned long orig_epc = kcb->kprobe_saved_epc; + regs->cp0_epc = orig_epc + 4; + } } static int __kprobes kprobe_handler(struct pt_regs *regs) @@ -239,8 +364,13 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) save_previous_kprobe(kcb); set_current_kprobe(p, regs, kcb); kprobes_inc_nmissed_count(p); - prepare_singlestep(p, regs); + prepare_singlestep(p, regs, kcb); kcb->kprobe_status = KPROBE_REENTER; + if (kcb->flags & SKIP_DELAYSLOT) { + resume_execution(p, regs, kcb); + restore_previous_kprobe(kcb); + preempt_enable_no_resched(); + } return 1; } else { if (addr->word != breakpoint_insn.word) { @@ -284,8 +414,16 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) } ss_probe: - prepare_singlestep(p, regs); - kcb->kprobe_status = KPROBE_HIT_SS; + prepare_singlestep(p, regs, kcb); + if (kcb->flags & SKIP_DELAYSLOT) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + if (p->post_handler) + p->post_handler(p, regs, 0); + resume_execution(p, regs, kcb); + preempt_enable_no_resched(); + } else + kcb->kprobe_status = KPROBE_HIT_SS; + return 1; no_kprobe: @@ -294,25 +432,6 @@ no_kprobe: } -/* - * Called after single-stepping. p->addr is the address of the - * instruction whose first byte has been replaced by the "break 0" - * instruction. To avoid the SMP problems that can occur when we - * temporarily put back the original opcode to single-step, we - * single-stepped a copy of the instruction. The address of this - * copy is p->ainsn.insn. - * - * This function prepares to return from the post-single-step - * breakpoint trap. - */ -static void __kprobes resume_execution(struct kprobe *p, - struct pt_regs *regs, - struct kprobe_ctlblk *kcb) -{ - unsigned long orig_epc = kcb->kprobe_saved_epc; - regs->cp0_epc = orig_epc + 4; -} - static inline int post_kprobe_handler(struct pt_regs *regs) { struct kprobe *cur = kprobe_running(); diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index 315fc0b250f8..e3b897acfbc0 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -621,11 +621,6 @@ static int mipspmu_event_init(struct perf_event *event) return -ENODEV; if (!atomic_inc_not_zero(&active_events)) { - if (atomic_read(&active_events) > MIPS_MAX_HWEVENTS) { - atomic_dec(&active_events); - return -EINVAL; - } - mutex_lock(&pmu_reserve_mutex); if (atomic_read(&active_events) == 0) err = mipspmu_get_irq(); @@ -638,11 +633,7 @@ static int mipspmu_event_init(struct perf_event *event) if (err) return err; - err = __hw_perf_event_init(event); - if (err) - hw_perf_event_destroy(event); - - return err; + return __hw_perf_event_init(event); } static struct pmu pmu = { @@ -712,18 +703,6 @@ static const struct mips_perf_event *mipspmu_map_cache_event(u64 config) } -static int validate_event(struct cpu_hw_events *cpuc, - struct perf_event *event) -{ - struct hw_perf_event fake_hwc = event->hw; - - /* Allow mixed event group. So return 1 to pass validation. */ - if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF) - return 1; - - return mipsxx_pmu_alloc_counter(cpuc, &fake_hwc) >= 0; -} - static int validate_group(struct perf_event *event) { struct perf_event *sibling, *leader = event->group_leader; @@ -731,15 +710,15 @@ static int validate_group(struct perf_event *event) memset(&fake_cpuc, 0, sizeof(fake_cpuc)); - if (!validate_event(&fake_cpuc, leader)) + if (mipsxx_pmu_alloc_counter(&fake_cpuc, &leader->hw) < 0) return -EINVAL; list_for_each_entry(sibling, &leader->sibling_list, group_entry) { - if (!validate_event(&fake_cpuc, sibling)) + if (mipsxx_pmu_alloc_counter(&fake_cpuc, &sibling->hw) < 0) return -EINVAL; } - if (!validate_event(&fake_cpuc, event)) + if (mipsxx_pmu_alloc_counter(&fake_cpuc, &event->hw) < 0) return -EINVAL; return 0; @@ -1279,13 +1258,14 @@ static int __hw_perf_event_init(struct perf_event *event) } err = 0; - if (event->group_leader != event) { + if (event->group_leader != event) err = validate_group(event); - if (err) - return -EINVAL; - } event->destroy = hw_perf_event_destroy; + + if (err) + event->destroy(event); + return err; } @@ -1380,20 +1360,10 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev) } /* 24K */ -#define IS_UNSUPPORTED_24K_EVENT(r, b) \ - ((b) == 12 || (r) == 151 || (r) == 152 || (b) == 26 || \ - (b) == 27 || (r) == 28 || (r) == 158 || (b) == 31 || \ - (b) == 32 || (b) == 34 || (b) == 36 || (r) == 168 || \ - (r) == 172 || (b) == 47 || ((b) >= 56 && (b) <= 63) || \ - ((b) >= 68 && (b) <= 127)) #define IS_BOTH_COUNTERS_24K_EVENT(b) \ ((b) == 0 || (b) == 1 || (b) == 11) /* 34K */ -#define IS_UNSUPPORTED_34K_EVENT(r, b) \ - ((b) == 12 || (r) == 27 || (r) == 158 || (b) == 36 || \ - (b) == 38 || (r) == 175 || ((b) >= 56 && (b) <= 63) || \ - ((b) >= 68 && (b) <= 127)) #define IS_BOTH_COUNTERS_34K_EVENT(b) \ ((b) == 0 || (b) == 1 || (b) == 11) #ifdef CONFIG_MIPS_MT_SMP @@ -1406,20 +1376,10 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev) #endif /* 74K */ -#define IS_UNSUPPORTED_74K_EVENT(r, b) \ - ((r) == 5 || ((r) >= 135 && (r) <= 137) || \ - ((b) >= 10 && (b) <= 12) || (b) == 22 || (b) == 27 || \ - (b) == 33 || (b) == 34 || ((b) >= 47 && (b) <= 49) || \ - (r) == 178 || (b) == 55 || (b) == 57 || (b) == 60 || \ - (b) == 61 || (r) == 62 || (r) == 191 || \ - ((b) >= 64 && (b) <= 127)) #define IS_BOTH_COUNTERS_74K_EVENT(b) \ ((b) == 0 || (b) == 1) /* 1004K */ -#define IS_UNSUPPORTED_1004K_EVENT(r, b) \ - ((b) == 12 || (r) == 27 || (r) == 158 || (b) == 38 || \ - (r) == 175 || (b) == 63 || ((b) >= 68 && (b) <= 127)) #define IS_BOTH_COUNTERS_1004K_EVENT(b) \ ((b) == 0 || (b) == 1 || (b) == 11) #ifdef CONFIG_MIPS_MT_SMP @@ -1445,11 +1405,10 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) unsigned int raw_id = config & 0xff; unsigned int base_id = raw_id & 0x7f; + raw_event.event_id = base_id; + switch (current_cpu_type()) { case CPU_24K: - if (IS_UNSUPPORTED_24K_EVENT(raw_id, base_id)) - return ERR_PTR(-EOPNOTSUPP); - raw_event.event_id = base_id; if (IS_BOTH_COUNTERS_24K_EVENT(base_id)) raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; else @@ -1464,9 +1423,6 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) #endif break; case CPU_34K: - if (IS_UNSUPPORTED_34K_EVENT(raw_id, base_id)) - return ERR_PTR(-EOPNOTSUPP); - raw_event.event_id = base_id; if (IS_BOTH_COUNTERS_34K_EVENT(base_id)) raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; else @@ -1482,9 +1438,6 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) #endif break; case CPU_74K: - if (IS_UNSUPPORTED_74K_EVENT(raw_id, base_id)) - return ERR_PTR(-EOPNOTSUPP); - raw_event.event_id = base_id; if (IS_BOTH_COUNTERS_74K_EVENT(base_id)) raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; else @@ -1495,9 +1448,6 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) #endif break; case CPU_1004K: - if (IS_UNSUPPORTED_1004K_EVENT(raw_id, base_id)) - return ERR_PTR(-EOPNOTSUPP); - raw_event.event_id = base_id; if (IS_BOTH_COUNTERS_1004K_EVENT(base_id)) raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; else diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 4e6ea1ffad46..7786b608d932 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -560,10 +560,9 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs) } out: - if (unlikely(current->audit_context)) - audit_syscall_entry(audit_arch(), regs->regs[2], - regs->regs[4], regs->regs[5], - regs->regs[6], regs->regs[7]); + audit_syscall_entry(audit_arch(), regs->regs[2], + regs->regs[4], regs->regs[5], + regs->regs[6], regs->regs[7]); } /* @@ -572,9 +571,7 @@ out: */ asmlinkage void syscall_trace_leave(struct pt_regs *regs) { - if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]), - -regs->regs[2]); + audit_syscall_exit(regs); if (!(current->ptrace & PT_PTRACED)) return; diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 933166f44a6d..a9d801dec6b0 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -473,7 +473,6 @@ static const struct file_operations rtlx_fops = { static struct irqaction rtlx_irq = { .handler = rtlx_interrupt, - .flags = IRQF_DISABLED, .name = "RTLX", }; diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index b1cb8f87d7b4..058e964e7303 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -122,6 +122,9 @@ static void __init print_memory_map(void) case BOOT_MEM_RAM: printk(KERN_CONT "(usable)\n"); break; + case BOOT_MEM_INIT_RAM: + printk(KERN_CONT "(usable after init)\n"); + break; case BOOT_MEM_ROM_DATA: printk(KERN_CONT "(ROM data)\n"); break; @@ -362,15 +365,24 @@ static void __init bootmem_init(void) for (i = 0; i < boot_mem_map.nr_map; i++) { unsigned long start, end, size; + start = PFN_UP(boot_mem_map.map[i].addr); + end = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + /* * Reserve usable memory. */ - if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + break; + case BOOT_MEM_INIT_RAM: + memory_present(0, start, end); continue; + default: + /* Not usable memory */ + continue; + } - start = PFN_UP(boot_mem_map.map[i].addr); - end = PFN_DOWN(boot_mem_map.map[i].addr - + boot_mem_map.map[i].size); /* * We are rounding up the start address of usable memory * and at the end of the usable range downwards. @@ -456,11 +468,33 @@ early_param("mem", early_parse_mem); static void __init arch_mem_init(char **cmdline_p) { + phys_t init_mem, init_end, init_size; + extern void plat_mem_setup(void); /* call board setup routine */ plat_mem_setup(); + init_mem = PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT; + init_end = PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT; + init_size = init_end - init_mem; + if (init_size) { + /* Make sure it is in the boot_mem_map */ + int i, found; + found = 0; + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (init_mem >= boot_mem_map.map[i].addr && + init_mem < (boot_mem_map.map[i].addr + + boot_mem_map.map[i].size)) { + found = 1; + break; + } + } + if (!found) + add_memory_region(init_mem, init_size, + BOOT_MEM_INIT_RAM); + } + pr_info("Determined physical RAM map:\n"); print_memory_map(); @@ -524,6 +558,7 @@ static void __init resource_init(void) res = alloc_bootmem(sizeof(struct resource)); switch (boot_mem_map.map[i].type) { case BOOT_MEM_RAM: + case BOOT_MEM_INIT_RAM: case BOOT_MEM_ROM_DATA: res->name = "System RAM"; break; diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c new file mode 100644 index 000000000000..58fe71afd879 --- /dev/null +++ b/arch/mips/kernel/smp-bmips.c @@ -0,0 +1,458 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2011 by Kevin Cernekee (cernekee@gmail.com) + * + * SMP support for BMIPS + */ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/delay.h> +#include <linux/smp.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <linux/cpu.h> +#include <linux/cpumask.h> +#include <linux/reboot.h> +#include <linux/io.h> +#include <linux/compiler.h> +#include <linux/linkage.h> +#include <linux/bug.h> +#include <linux/kernel.h> + +#include <asm/time.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/bootinfo.h> +#include <asm/pmon.h> +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> +#include <asm/mipsregs.h> +#include <asm/bmips.h> +#include <asm/traps.h> +#include <asm/barrier.h> + +static int __maybe_unused max_cpus = 1; + +/* these may be configured by the platform code */ +int bmips_smp_enabled = 1; +int bmips_cpu_offset; +cpumask_t bmips_booted_mask; + +#ifdef CONFIG_SMP + +/* initial $sp, $gp - used by arch/mips/kernel/bmips_vec.S */ +unsigned long bmips_smp_boot_sp; +unsigned long bmips_smp_boot_gp; + +static void bmips_send_ipi_single(int cpu, unsigned int action); +static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id); + +/* SW interrupts 0,1 are used for interprocessor signaling */ +#define IPI0_IRQ (MIPS_CPU_IRQ_BASE + 0) +#define IPI1_IRQ (MIPS_CPU_IRQ_BASE + 1) + +#define CPUNUM(cpu, shift) (((cpu) + bmips_cpu_offset) << (shift)) +#define ACTION_CLR_IPI(cpu, ipi) (0x2000 | CPUNUM(cpu, 9) | ((ipi) << 8)) +#define ACTION_SET_IPI(cpu, ipi) (0x3000 | CPUNUM(cpu, 9) | ((ipi) << 8)) +#define ACTION_BOOT_THREAD(cpu) (0x08 | CPUNUM(cpu, 0)) + +static void __init bmips_smp_setup(void) +{ + int i; + +#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) + /* arbitration priority */ + clear_c0_brcm_cmt_ctrl(0x30); + + /* NBK and weak order flags */ + set_c0_brcm_config_0(0x30000); + + /* + * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread + * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output + * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output + */ + change_c0_brcm_cmt_intr(0xf8018000, + (0x02 << 27) | (0x03 << 15)); + + /* single core, 2 threads (2 pipelines) */ + max_cpus = 2; +#elif defined(CONFIG_CPU_BMIPS5000) + /* enable raceless SW interrupts */ + set_c0_brcm_config(0x03 << 22); + + /* route HW interrupt 0 to CPU0, HW interrupt 1 to CPU1 */ + change_c0_brcm_mode(0x1f << 27, 0x02 << 27); + + /* N cores, 2 threads per core */ + max_cpus = (((read_c0_brcm_config() >> 6) & 0x03) + 1) << 1; + + /* clear any pending SW interrupts */ + for (i = 0; i < max_cpus; i++) { + write_c0_brcm_action(ACTION_CLR_IPI(i, 0)); + write_c0_brcm_action(ACTION_CLR_IPI(i, 1)); + } +#endif + + if (!bmips_smp_enabled) + max_cpus = 1; + + /* this can be overridden by the BSP */ + if (!board_ebase_setup) + board_ebase_setup = &bmips_ebase_setup; + + for (i = 0; i < max_cpus; i++) { + __cpu_number_map[i] = 1; + __cpu_logical_map[i] = 1; + set_cpu_possible(i, 1); + set_cpu_present(i, 1); + } +} + +/* + * IPI IRQ setup - runs on CPU0 + */ +static void bmips_prepare_cpus(unsigned int max_cpus) +{ + if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, + "smp_ipi0", NULL)) + panic("Can't request IPI0 interrupt\n"); + if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, + "smp_ipi1", NULL)) + panic("Can't request IPI1 interrupt\n"); +} + +/* + * Tell the hardware to boot CPUx - runs on CPU0 + */ +static void bmips_boot_secondary(int cpu, struct task_struct *idle) +{ + bmips_smp_boot_sp = __KSTK_TOS(idle); + bmips_smp_boot_gp = (unsigned long)task_thread_info(idle); + mb(); + + /* + * Initial boot sequence for secondary CPU: + * bmips_reset_nmi_vec @ a000_0000 -> + * bmips_smp_entry -> + * plat_wired_tlb_setup (cached function call; optional) -> + * start_secondary (cached jump) + * + * Warm restart sequence: + * play_dead WAIT loop -> + * bmips_smp_int_vec @ BMIPS_WARM_RESTART_VEC -> + * eret to play_dead -> + * bmips_secondary_reentry -> + * start_secondary + */ + + pr_info("SMP: Booting CPU%d...\n", cpu); + + if (cpumask_test_cpu(cpu, &bmips_booted_mask)) + bmips_send_ipi_single(cpu, 0); + else { +#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) + set_c0_brcm_cmt_ctrl(0x01); +#elif defined(CONFIG_CPU_BMIPS5000) + if (cpu & 0x01) + write_c0_brcm_action(ACTION_BOOT_THREAD(cpu)); + else { + /* + * core N thread 0 was already booted; just + * pulse the NMI line + */ + bmips_write_zscm_reg(0x210, 0xc0000000); + udelay(10); + bmips_write_zscm_reg(0x210, 0x00); + } +#endif + cpumask_set_cpu(cpu, &bmips_booted_mask); + } +} + +/* + * Early setup - runs on secondary CPU after cache probe + */ +static void bmips_init_secondary(void) +{ + /* move NMI vector to kseg0, in case XKS01 is enabled */ + +#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) + void __iomem *cbr = BMIPS_GET_CBR(); + unsigned long old_vec; + + old_vec = __raw_readl(cbr + BMIPS_RELO_VECTOR_CONTROL_1); + __raw_writel(old_vec & ~0x20000000, cbr + BMIPS_RELO_VECTOR_CONTROL_1); + + clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); +#elif defined(CONFIG_CPU_BMIPS5000) + write_c0_brcm_bootvec(read_c0_brcm_bootvec() & + (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000)); + + write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0)); +#endif + + /* make sure there won't be a timer interrupt for a little while */ + write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); + + irq_enable_hazard(); + set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE); + irq_enable_hazard(); +} + +/* + * Late setup - runs on secondary CPU before entering the idle loop + */ +static void bmips_smp_finish(void) +{ + pr_info("SMP: CPU%d is running\n", smp_processor_id()); +} + +/* + * Runs on CPU0 after all CPUs have been booted + */ +static void bmips_cpus_done(void) +{ +} + +#if defined(CONFIG_CPU_BMIPS5000) + +/* + * BMIPS5000 raceless IPIs + * + * Each CPU has two inbound SW IRQs which are independent of all other CPUs. + * IPI0 is used for SMP_RESCHEDULE_YOURSELF + * IPI1 is used for SMP_CALL_FUNCTION + */ + +static void bmips_send_ipi_single(int cpu, unsigned int action) +{ + write_c0_brcm_action(ACTION_SET_IPI(cpu, action == SMP_CALL_FUNCTION)); +} + +static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id) +{ + int action = irq - IPI0_IRQ; + + write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), action)); + + if (action == 0) + scheduler_ipi(); + else + smp_call_function_interrupt(); + + return IRQ_HANDLED; +} + +#else + +/* + * BMIPS43xx racey IPIs + * + * We use one inbound SW IRQ for each CPU. + * + * A spinlock must be held in order to keep CPUx from accidentally clearing + * an incoming IPI when it writes CP0 CAUSE to raise an IPI on CPUy. The + * same spinlock is used to protect the action masks. + */ + +static DEFINE_SPINLOCK(ipi_lock); +static DEFINE_PER_CPU(int, ipi_action_mask); + +static void bmips_send_ipi_single(int cpu, unsigned int action) +{ + unsigned long flags; + + spin_lock_irqsave(&ipi_lock, flags); + set_c0_cause(cpu ? C_SW1 : C_SW0); + per_cpu(ipi_action_mask, cpu) |= action; + irq_enable_hazard(); + spin_unlock_irqrestore(&ipi_lock, flags); +} + +static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id) +{ + unsigned long flags; + int action, cpu = irq - IPI0_IRQ; + + spin_lock_irqsave(&ipi_lock, flags); + action = __get_cpu_var(ipi_action_mask); + per_cpu(ipi_action_mask, cpu) = 0; + clear_c0_cause(cpu ? C_SW1 : C_SW0); + spin_unlock_irqrestore(&ipi_lock, flags); + + if (action & SMP_RESCHEDULE_YOURSELF) + scheduler_ipi(); + if (action & SMP_CALL_FUNCTION) + smp_call_function_interrupt(); + + return IRQ_HANDLED; +} + +#endif /* BMIPS type */ + +static void bmips_send_ipi_mask(const struct cpumask *mask, + unsigned int action) +{ + unsigned int i; + + for_each_cpu(i, mask) + bmips_send_ipi_single(i, action); +} + +#ifdef CONFIG_HOTPLUG_CPU + +static int bmips_cpu_disable(void) +{ + unsigned int cpu = smp_processor_id(); + + if (cpu == 0) + return -EBUSY; + + pr_info("SMP: CPU%d is offline\n", cpu); + + cpu_clear(cpu, cpu_online_map); + cpu_clear(cpu, cpu_callin_map); + + local_flush_tlb_all(); + local_flush_icache_range(0, ~0); + + return 0; +} + +static void bmips_cpu_die(unsigned int cpu) +{ +} + +void __ref play_dead(void) +{ + idle_task_exit(); + + /* flush data cache */ + _dma_cache_wback_inv(0, ~0); + + /* + * Wakeup is on SW0 or SW1; disable everything else + * Use BEV !IV (BMIPS_WARM_RESTART_VEC) to avoid the regular Linux + * IRQ handlers; this clears ST0_IE and returns immediately. + */ + clear_c0_cause(CAUSEF_IV | C_SW0 | C_SW1); + change_c0_status(IE_IRQ5 | IE_IRQ1 | IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV, + IE_SW0 | IE_SW1 | ST0_IE | ST0_BEV); + irq_disable_hazard(); + + /* + * wait for SW interrupt from bmips_boot_secondary(), then jump + * back to start_secondary() + */ + __asm__ __volatile__( + " wait\n" + " j bmips_secondary_reentry\n" + : : : "memory"); +} + +#endif /* CONFIG_HOTPLUG_CPU */ + +struct plat_smp_ops bmips_smp_ops = { + .smp_setup = bmips_smp_setup, + .prepare_cpus = bmips_prepare_cpus, + .boot_secondary = bmips_boot_secondary, + .smp_finish = bmips_smp_finish, + .init_secondary = bmips_init_secondary, + .cpus_done = bmips_cpus_done, + .send_ipi_single = bmips_send_ipi_single, + .send_ipi_mask = bmips_send_ipi_mask, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = bmips_cpu_disable, + .cpu_die = bmips_cpu_die, +#endif +}; + +#endif /* CONFIG_SMP */ + +/*********************************************************************** + * BMIPS vector relocation + * This is primarily used for SMP boot, but it is applicable to some + * UP BMIPS systems as well. + ***********************************************************************/ + +static void __cpuinit bmips_wr_vec(unsigned long dst, char *start, char *end) +{ + memcpy((void *)dst, start, end - start); + dma_cache_wback((unsigned long)start, end - start); + local_flush_icache_range(dst, dst + (end - start)); + instruction_hazard(); +} + +static inline void __cpuinit bmips_nmi_handler_setup(void) +{ + bmips_wr_vec(BMIPS_NMI_RESET_VEC, &bmips_reset_nmi_vec, + &bmips_reset_nmi_vec_end); + bmips_wr_vec(BMIPS_WARM_RESTART_VEC, &bmips_smp_int_vec, + &bmips_smp_int_vec_end); +} + +void __cpuinit bmips_ebase_setup(void) +{ + unsigned long new_ebase = ebase; + void __iomem __maybe_unused *cbr; + + BUG_ON(ebase != CKSEG0); + +#if defined(CONFIG_CPU_BMIPS4350) + /* + * BMIPS4350 cannot relocate the normal vectors, but it + * can relocate the BEV=1 vectors. So CPU1 starts up at + * the relocated BEV=1, IV=0 general exception vector @ + * 0xa000_0380. + * + * set_uncached_handler() is used here because: + * - CPU1 will run this from uncached space + * - None of the cacheflush functions are set up yet + */ + set_uncached_handler(BMIPS_WARM_RESTART_VEC - CKSEG0, + &bmips_smp_int_vec, 0x80); + __sync(); + return; +#elif defined(CONFIG_CPU_BMIPS4380) + /* + * 0x8000_0000: reset/NMI (initially in kseg1) + * 0x8000_0400: normal vectors + */ + new_ebase = 0x80000400; + cbr = BMIPS_GET_CBR(); + __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0); + __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1); +#elif defined(CONFIG_CPU_BMIPS5000) + /* + * 0x8000_0000: reset/NMI (initially in kseg1) + * 0x8000_1000: normal vectors + */ + new_ebase = 0x80001000; + write_c0_brcm_bootvec(0xa0088008); + write_c0_ebase(new_ebase); + if (max_cpus > 2) + bmips_write_zscm_reg(0xa0, 0xa008a008); +#else + return; +#endif + board_nmi_handler_setup = &bmips_nmi_handler_setup; + ebase = new_ebase; +} + +asmlinkage void __weak plat_wired_tlb_setup(void) +{ + /* + * Called when starting/restarting a secondary CPU. + * Kernel stacks and other important data might only be accessible + * once the wired entries are present. + */ +} diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index f0895e70e283..0a42ff3ff6a1 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -559,7 +559,7 @@ void smtc_prepare_cpus(int cpus) pipi = kmalloc(nipi *sizeof(struct smtc_ipi), GFP_KERNEL); if (pipi == NULL) - panic("kmalloc of IPI message buffers failed\n"); + panic("kmalloc of IPI message buffers failed"); else printk("IPI buffer pool of %d buffers\n", nipi); for (i = 0; i < nipi; i++) { @@ -813,7 +813,7 @@ void smtc_send_ipi(int cpu, int type, unsigned int action) if (pipi == NULL) { bust_spinlocks(1); mips_mt_regdump(dvpe()); - panic("IPI Msg. Buffers Depleted\n"); + panic("IPI Msg. Buffers Depleted"); } pipi->type = type; pipi->arg = (void *)action; @@ -1130,7 +1130,7 @@ static void ipi_irq_dispatch(void) static struct irqaction irq_ipi = { .handler = ipi_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU, + .flags = IRQF_PERCPU, .name = "SMTC_IPI" }; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index bbddb86c1fa1..cc4a3f120f54 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -91,6 +91,7 @@ int (*board_be_handler)(struct pt_regs *regs, int is_fixup); void (*board_nmi_handler_setup)(void); void (*board_ejtag_handler_setup)(void); void (*board_bind_eic_interrupt)(int irq, int regset); +void (*board_ebase_setup)(void); static void show_raw_backtrace(unsigned long reg29) @@ -400,7 +401,7 @@ void __noreturn die(const char *str, struct pt_regs *regs) panic("Fatal exception in interrupt"); if (panic_on_oops) { - printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + printk(KERN_EMERG "Fatal exception: panic in 5 seconds"); ssleep(5); panic("Fatal exception"); } @@ -1150,7 +1151,7 @@ asmlinkage void do_mt(struct pt_regs *regs) asmlinkage void do_dsp(struct pt_regs *regs) { if (cpu_has_dsp) - panic("Unexpected DSP exception\n"); + panic("Unexpected DSP exception"); force_sig(SIGILL, current); } @@ -1339,9 +1340,18 @@ void ejtag_exception_handler(struct pt_regs *regs) /* * NMI exception handler. + * No lock; only written during early bootup by CPU 0. */ +static RAW_NOTIFIER_HEAD(nmi_chain); + +int register_nmi_notifier(struct notifier_block *nb) +{ + return raw_notifier_chain_register(&nmi_chain, nb); +} + void __noreturn nmi_exception_handler(struct pt_regs *regs) { + raw_notifier_call_chain(&nmi_chain, 0, regs); bust_spinlocks(1); printk("NMI taken!!!!\n"); die("NMI", regs); @@ -1682,6 +1692,8 @@ void __init trap_init(void) ebase += (read_c0_ebase() & 0x3ffff000); } + if (board_ebase_setup) + board_ebase_setup(); per_cpu_trap_init(); /* diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c index 77ed70fc2fe5..412814fdd3ee 100644 --- a/arch/mips/lantiq/clk.c +++ b/arch/mips/lantiq/clk.c @@ -134,11 +134,11 @@ void __init plat_time_init(void) struct clk *clk; if (insert_resource(&iomem_resource, <q_cgu_resource) < 0) - panic("Failed to insert cgu memory\n"); + panic("Failed to insert cgu memory"); if (request_mem_region(ltq_cgu_resource.start, resource_size(<q_cgu_resource), "cgu") < 0) - panic("Failed to request cgu memory\n"); + panic("Failed to request cgu memory"); ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, resource_size(<q_cgu_resource)); diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index f9737bb3c5ab..d673731c538a 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -240,7 +240,6 @@ out: static struct irqaction cascade = { .handler = no_action, - .flags = IRQF_DISABLED, .name = "cascade", }; @@ -249,28 +248,28 @@ void __init arch_init_irq(void) int i; if (insert_resource(&iomem_resource, <q_icu_resource) < 0) - panic("Failed to insert icu memory\n"); + panic("Failed to insert icu memory"); if (request_mem_region(ltq_icu_resource.start, resource_size(<q_icu_resource), "icu") < 0) - panic("Failed to request icu memory\n"); + panic("Failed to request icu memory"); ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start, resource_size(<q_icu_resource)); if (!ltq_icu_membase) - panic("Failed to remap icu memory\n"); + panic("Failed to remap icu memory"); if (insert_resource(&iomem_resource, <q_eiu_resource) < 0) - panic("Failed to insert eiu memory\n"); + panic("Failed to insert eiu memory"); if (request_mem_region(ltq_eiu_resource.start, resource_size(<q_eiu_resource), "eiu") < 0) - panic("Failed to request eiu memory\n"); + panic("Failed to request eiu memory"); ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, resource_size(<q_eiu_resource)); if (!ltq_eiu_membase) - panic("Failed to remap eiu memory\n"); + panic("Failed to remap eiu memory"); /* make sure all irqs are turned off by default */ for (i = 0; i < 5; i++) diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c index cbb6ae5747b9..b210e936c7c3 100644 --- a/arch/mips/lantiq/xway/dma.c +++ b/arch/mips/lantiq/xway/dma.c @@ -222,17 +222,17 @@ ltq_dma_init(void) /* insert and request the memory region */ if (insert_resource(&iomem_resource, <q_dma_resource) < 0) - panic("Failed to insert dma memory\n"); + panic("Failed to insert dma memory"); if (request_mem_region(ltq_dma_resource.start, resource_size(<q_dma_resource), "dma") < 0) - panic("Failed to request dma memory\n"); + panic("Failed to request dma memory"); /* remap dma register range */ ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start, resource_size(<q_dma_resource)); if (!ltq_dma_membase) - panic("Failed to remap dma memory\n"); + panic("Failed to remap dma memory"); /* power up and reset the dma engine */ ltq_pmu_enable(PMU_DMA); diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c index 033b3184c7a7..862e3e830680 100644 --- a/arch/mips/lantiq/xway/ebu.c +++ b/arch/mips/lantiq/xway/ebu.c @@ -32,17 +32,17 @@ static int __init lantiq_ebu_init(void) { /* insert and request the memory region */ if (insert_resource(&iomem_resource, <q_ebu_resource) < 0) - panic("Failed to insert ebu memory\n"); + panic("Failed to insert ebu memory"); if (request_mem_region(ltq_ebu_resource.start, resource_size(<q_ebu_resource), "ebu") < 0) - panic("Failed to request ebu memory\n"); + panic("Failed to request ebu memory"); /* remap ebu register range */ ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start, resource_size(<q_ebu_resource)); if (!ltq_ebu_membase) - panic("Failed to remap ebu memory\n"); + panic("Failed to remap ebu memory"); /* make sure to unprotect the memory region where flash is located */ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c index 39f0d2641cbf..fe85361e032e 100644 --- a/arch/mips/lantiq/xway/pmu.c +++ b/arch/mips/lantiq/xway/pmu.c @@ -40,7 +40,7 @@ void ltq_pmu_enable(unsigned int module) do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module)); if (!err) - panic("activating PMU module failed!\n"); + panic("activating PMU module failed!"); } EXPORT_SYMBOL(ltq_pmu_enable); @@ -53,16 +53,16 @@ EXPORT_SYMBOL(ltq_pmu_disable); int __init ltq_pmu_init(void) { if (insert_resource(&iomem_resource, <q_pmu_resource) < 0) - panic("Failed to insert pmu memory\n"); + panic("Failed to insert pmu memory"); if (request_mem_region(ltq_pmu_resource.start, resource_size(<q_pmu_resource), "pmu") < 0) - panic("Failed to request pmu memory\n"); + panic("Failed to request pmu memory"); ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start, resource_size(<q_pmu_resource)); if (!ltq_pmu_membase) - panic("Failed to remap pmu memory\n"); + panic("Failed to remap pmu memory"); return 0; } diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c index 3d41f0bb5bf7..8b66bd87f0c1 100644 --- a/arch/mips/lantiq/xway/reset.c +++ b/arch/mips/lantiq/xway/reset.c @@ -69,17 +69,17 @@ static int __init mips_reboot_setup(void) { /* insert and request the memory region */ if (insert_resource(&iomem_resource, <q_rcu_resource) < 0) - panic("Failed to insert rcu memory\n"); + panic("Failed to insert rcu memory"); if (request_mem_region(ltq_rcu_resource.start, resource_size(<q_rcu_resource), "rcu") < 0) - panic("Failed to request rcu memory\n"); + panic("Failed to request rcu memory"); /* remap rcu register range */ ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start, resource_size(<q_rcu_resource)); if (!ltq_rcu_membase) - panic("Failed to remap rcu memory\n"); + panic("Failed to remap rcu memory"); _machine_restart = ltq_machine_restart; _machine_halt = ltq_machine_halt; diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index b2cad4fd5fc4..2a7c74fc15fc 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_TX49XX) += dump_tlb.o obj-$(CONFIG_CPU_VR41XX) += dump_tlb.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += dump_tlb.o obj-$(CONFIG_CPU_XLR) += dump_tlb.o +obj-$(CONFIG_CPU_XLP) += dump_tlb.o # libgcc-style stuff needed in the kernel obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c index 0cb1b9760e34..5d1f48fa1a52 100644 --- a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c +++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c @@ -111,7 +111,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) static struct irqaction irq5 = { .handler = timer_interrupt, - .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, + .flags = IRQF_NOBALANCING | IRQF_TIMER, .name = "timer" }; diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index dbf2f93a5091..a03bf00a1a9c 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -245,7 +245,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, */ emulpc = xcp->cp0_epc + 4; /* Snapshot emulation target */ - if (__compute_return_epc(xcp)) { + if (__compute_return_epc(xcp) < 0) { #ifdef CP1DBG printk("failed to emulate branch at %p\n", (void *) (xcp->cp0_epc)); diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 4d8c1623eee2..4aa20280613e 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -3,8 +3,8 @@ # obj-y += cache.o dma-default.o extable.o fault.o \ - init.o mmap.o tlbex.o tlbex-fault.o uasm.o \ - page.o + gup.o init.o mmap.o page.o tlbex.o \ + tlbex-fault.o uasm.o obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_64BIT) += pgtable-64.o @@ -31,6 +31,7 @@ obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o tlb-r4k.o obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o tlb-r4k.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-octeon.o cex-oct.o tlb-r4k.o obj-$(CONFIG_CPU_XLR) += c-r4k.o tlb-r4k.o cex-gen.o +obj-$(CONFIG_CPU_XLP) += c-r4k.o tlb-r4k.o cex-gen.o obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c index daa81f7284ac..cf7895db0739 100644 --- a/arch/mips/mm/c-octeon.c +++ b/arch/mips/mm/c-octeon.c @@ -223,7 +223,7 @@ static void __cpuinit probe_octeon(void) break; default: - panic("Unsupported Cavium Networks CPU type\n"); + panic("Unsupported Cavium Networks CPU type"); break; } diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index a79fe9aa7721..4f9eb0b23036 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1235,6 +1235,9 @@ static void __cpuinit setup_scache(void) loongson2_sc_init(); return; #endif + case CPU_XLP: + /* don't need to worry about L2, fully coherent */ + return; default: if (c->isa_level == MIPS_CPU_ISA_M32R1 || diff --git a/arch/mips/mm/gup.c b/arch/mips/mm/gup.c new file mode 100644 index 000000000000..33aadbcf170b --- /dev/null +++ b/arch/mips/mm/gup.c @@ -0,0 +1,315 @@ +/* + * Lockless get_user_pages_fast for MIPS + * + * Copyright (C) 2008 Nick Piggin + * Copyright (C) 2008 Novell Inc. + * Copyright (C) 2011 Ralf Baechle + */ +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/vmstat.h> +#include <linux/highmem.h> +#include <linux/swap.h> +#include <linux/hugetlb.h> + +#include <asm/pgtable.h> + +static inline pte_t gup_get_pte(pte_t *ptep) +{ +#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) + pte_t pte; + +retry: + pte.pte_low = ptep->pte_low; + smp_rmb(); + pte.pte_high = ptep->pte_high; + smp_rmb(); + if (unlikely(pte.pte_low != ptep->pte_low)) + goto retry; + + return pte; +#else + return ACCESS_ONCE(*ptep); +#endif +} + +static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, + int write, struct page **pages, int *nr) +{ + pte_t *ptep = pte_offset_map(&pmd, addr); + do { + pte_t pte = gup_get_pte(ptep); + struct page *page; + + if (!pte_present(pte) || + pte_special(pte) || (write && !pte_write(pte))) { + pte_unmap(ptep); + return 0; + } + VM_BUG_ON(!pfn_valid(pte_pfn(pte))); + page = pte_page(pte); + get_page(page); + SetPageReferenced(page); + pages[*nr] = page; + (*nr)++; + + } while (ptep++, addr += PAGE_SIZE, addr != end); + + pte_unmap(ptep - 1); + return 1; +} + +static inline void get_head_page_multiple(struct page *page, int nr) +{ + VM_BUG_ON(page != compound_head(page)); + VM_BUG_ON(page_count(page) == 0); + atomic_add(nr, &page->_count); + SetPageReferenced(page); +} + +static int gup_huge_pmd(pmd_t pmd, unsigned long addr, unsigned long end, + int write, struct page **pages, int *nr) +{ + pte_t pte = *(pte_t *)&pmd; + struct page *head, *page; + int refs; + + if (write && !pte_write(pte)) + return 0; + /* hugepages are never "special" */ + VM_BUG_ON(pte_special(pte)); + VM_BUG_ON(!pfn_valid(pte_pfn(pte))); + + refs = 0; + head = pte_page(pte); + page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT); + do { + VM_BUG_ON(compound_head(page) != head); + pages[*nr] = page; + if (PageTail(page)) + get_huge_page_tail(page); + (*nr)++; + page++; + refs++; + } while (addr += PAGE_SIZE, addr != end); + + get_head_page_multiple(head, refs); + return 1; +} + +static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, + int write, struct page **pages, int *nr) +{ + unsigned long next; + pmd_t *pmdp; + + pmdp = pmd_offset(&pud, addr); + do { + pmd_t pmd = *pmdp; + + next = pmd_addr_end(addr, end); + /* + * The pmd_trans_splitting() check below explains why + * pmdp_splitting_flush has to flush the tlb, to stop + * this gup-fast code from running while we set the + * splitting bit in the pmd. Returning zero will take + * the slow path that will call wait_split_huge_page() + * if the pmd is still in splitting state. gup-fast + * can't because it has irq disabled and + * wait_split_huge_page() would never return as the + * tlb flush IPI wouldn't run. + */ + if (pmd_none(pmd) || pmd_trans_splitting(pmd)) + return 0; + if (unlikely(pmd_huge(pmd))) { + if (!gup_huge_pmd(pmd, addr, next, write, pages,nr)) + return 0; + } else { + if (!gup_pte_range(pmd, addr, next, write, pages,nr)) + return 0; + } + } while (pmdp++, addr = next, addr != end); + + return 1; +} + +static int gup_huge_pud(pud_t pud, unsigned long addr, unsigned long end, + int write, struct page **pages, int *nr) +{ + pte_t pte = *(pte_t *)&pud; + struct page *head, *page; + int refs; + + if (write && !pte_write(pte)) + return 0; + /* hugepages are never "special" */ + VM_BUG_ON(pte_special(pte)); + VM_BUG_ON(!pfn_valid(pte_pfn(pte))); + + refs = 0; + head = pte_page(pte); + page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT); + do { + VM_BUG_ON(compound_head(page) != head); + pages[*nr] = page; + (*nr)++; + page++; + refs++; + } while (addr += PAGE_SIZE, addr != end); + + get_head_page_multiple(head, refs); + return 1; +} + +static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end, + int write, struct page **pages, int *nr) +{ + unsigned long next; + pud_t *pudp; + + pudp = pud_offset(&pgd, addr); + do { + pud_t pud = *pudp; + + next = pud_addr_end(addr, end); + if (pud_none(pud)) + return 0; + if (unlikely(pud_huge(pud))) { + if (!gup_huge_pud(pud, addr, next, write, pages,nr)) + return 0; + } else { + if (!gup_pmd_range(pud, addr, next, write, pages,nr)) + return 0; + } + } while (pudp++, addr = next, addr != end); + + return 1; +} + +/* + * Like get_user_pages_fast() except its IRQ-safe in that it won't fall + * back to the regular GUP. + */ +int __get_user_pages_fast(unsigned long start, int nr_pages, int write, + struct page **pages) +{ + struct mm_struct *mm = current->mm; + unsigned long addr, len, end; + unsigned long next; + unsigned long flags; + pgd_t *pgdp; + int nr = 0; + + start &= PAGE_MASK; + addr = start; + len = (unsigned long) nr_pages << PAGE_SHIFT; + end = start + len; + if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, + (void __user *)start, len))) + return 0; + + /* + * XXX: batch / limit 'nr', to avoid large irq off latency + * needs some instrumenting to determine the common sizes used by + * important workloads (eg. DB2), and whether limiting the batch + * size will decrease performance. + * + * It seems like we're in the clear for the moment. Direct-IO is + * the main guy that batches up lots of get_user_pages, and even + * they are limited to 64-at-a-time which is not so many. + */ + /* + * This doesn't prevent pagetable teardown, but does prevent + * the pagetables and pages from being freed. + * + * So long as we atomically load page table pointers versus teardown, + * we can follow the address down to the page and take a ref on it. + */ + local_irq_save(flags); + pgdp = pgd_offset(mm, addr); + do { + pgd_t pgd = *pgdp; + + next = pgd_addr_end(addr, end); + if (pgd_none(pgd)) + break; + if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) + break; + } while (pgdp++, addr = next, addr != end); + local_irq_restore(flags); + + return nr; +} + +/** + * get_user_pages_fast() - pin user pages in memory + * @start: starting user address + * @nr_pages: number of pages from start to pin + * @write: whether pages will be written to + * @pages: array that receives pointers to the pages pinned. + * Should be at least nr_pages long. + * + * Attempt to pin user pages in memory without taking mm->mmap_sem. + * If not successful, it will fall back to taking the lock and + * calling get_user_pages(). + * + * Returns number of pages pinned. This may be fewer than the number + * requested. If nr_pages is 0 or negative, returns 0. If no pages + * were pinned, returns -errno. + */ +int get_user_pages_fast(unsigned long start, int nr_pages, int write, + struct page **pages) +{ + struct mm_struct *mm = current->mm; + unsigned long addr, len, end; + unsigned long next; + pgd_t *pgdp; + int ret, nr = 0; + + start &= PAGE_MASK; + addr = start; + len = (unsigned long) nr_pages << PAGE_SHIFT; + + end = start + len; + if (end < start) + goto slow_irqon; + + /* XXX: batch / limit 'nr' */ + local_irq_disable(); + pgdp = pgd_offset(mm, addr); + do { + pgd_t pgd = *pgdp; + + next = pgd_addr_end(addr, end); + if (pgd_none(pgd)) + goto slow; + if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) + goto slow; + } while (pgdp++, addr = next, addr != end); + local_irq_enable(); + + VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT); + return nr; +slow: + local_irq_enable(); + +slow_irqon: + /* Try to get the remaining pages with get_user_pages */ + start += nr << PAGE_SHIFT; + pages += nr; + + down_read(&mm->mmap_sem); + ret = get_user_pages(current, mm, start, + (end - start) >> PAGE_SHIFT, + write, 0, pages, NULL); + up_read(&mm->mmap_sem); + + /* Have to be a bit careful with return values */ + if (nr > 0) { + if (ret < 0) + ret = nr; + else + ret += nr; + } + return ret; +} diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index b7ebc4fa89bc..3b3ffd439cd7 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -304,9 +304,14 @@ int page_is_ram(unsigned long pagenr) for (i = 0; i < boot_mem_map.nr_map; i++) { unsigned long addr, end; - if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + case BOOT_MEM_INIT_RAM: + break; + default: /* not usable memory */ continue; + } addr = PFN_UP(boot_mem_map.map[i].addr); end = PFN_DOWN(boot_mem_map.map[i].addr + @@ -379,7 +384,7 @@ void __init mem_init(void) reservedpages = ram = 0; for (tmp = 0; tmp < max_low_pfn; tmp++) - if (page_is_ram(tmp)) { + if (page_is_ram(tmp) && pfn_valid(tmp)) { ram++; if (PageReserved(pfn_to_page(tmp))) reservedpages++; diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c index 87bb85d8d537..ed1fa460f84e 100644 --- a/arch/mips/mm/tlb-r3k.c +++ b/arch/mips/mm/tlb-r3k.c @@ -20,6 +20,7 @@ #include <asm/pgtable.h> #include <asm/mmu_context.h> #include <asm/system.h> +#include <asm/tlbmisc.h> #include <asm/isadep.h> #include <asm/io.h> #include <asm/bootinfo.h> diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 0d394e0e8837..2dc625346c40 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -19,6 +19,7 @@ #include <asm/mmu_context.h> #include <asm/pgtable.h> #include <asm/system.h> +#include <asm/tlbmisc.h> extern void build_tlb_refill_handler(void); @@ -120,22 +121,30 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, if (cpu_context(cpu, mm) != 0) { unsigned long size, flags; + int huge = is_vm_hugetlb_page(vma); ENTER_CRITICAL(flags); - size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - size = (size + 1) >> 1; + if (huge) { + start = round_down(start, HPAGE_SIZE); + end = round_up(end, HPAGE_SIZE); + size = (end - start) >> HPAGE_SHIFT; + } else { + start = round_down(start, PAGE_SIZE << 1); + end = round_up(end, PAGE_SIZE << 1); + size = (end - start) >> (PAGE_SHIFT + 1); + } if (size <= current_cpu_data.tlbsize/2) { int oldpid = read_c0_entryhi(); int newpid = cpu_asid(cpu, mm); - start &= (PAGE_MASK << 1); - end += ((PAGE_SIZE << 1) - 1); - end &= (PAGE_MASK << 1); while (start < end) { int idx; write_c0_entryhi(start | newpid); - start += (PAGE_SIZE << 1); + if (huge) + start += HPAGE_SIZE; + else + start += (PAGE_SIZE << 1); mtc0_tlbw_hazard(); tlb_probe(); tlb_probe_hazard(); @@ -368,51 +377,6 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, EXIT_CRITICAL(flags); } -/* - * Used for loading TLB entries before trap_init() has started, when we - * don't actually want to add a wired entry which remains throughout the - * lifetime of the system - */ - -static int temp_tlb_entry __cpuinitdata; - -__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - int ret = 0; - unsigned long flags; - unsigned long wired; - unsigned long old_pagemask; - unsigned long old_ctx; - - ENTER_CRITICAL(flags); - /* Save old context and create impossible VPN2 value */ - old_ctx = read_c0_entryhi(); - old_pagemask = read_c0_pagemask(); - wired = read_c0_wired(); - if (--temp_tlb_entry < wired) { - printk(KERN_WARNING - "No TLB space left for add_temporary_entry\n"); - ret = -ENOSPC; - goto out; - } - - write_c0_index(temp_tlb_entry); - write_c0_pagemask(pagemask); - write_c0_entryhi(entryhi); - write_c0_entrylo0(entrylo0); - write_c0_entrylo1(entrylo1); - mtc0_tlbw_hazard(); - tlb_write_indexed(); - tlbw_use_hazard(); - - write_c0_entryhi(old_ctx); - write_c0_pagemask(old_pagemask); -out: - EXIT_CRITICAL(flags); - return ret; -} - static int __cpuinitdata ntlb; static int __init set_ntlb(char *str) { @@ -450,8 +414,6 @@ void __cpuinit tlb_init(void) write_c0_pagegrain(pg); } - temp_tlb_entry = current_cpu_data.tlbsize - 1; - /* From this point on the ARC firmware is dead. */ local_flush_tlb_all(); diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index d53ff91b277c..a588b5cef8d2 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -322,13 +322,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) static struct irqaction irq_resched = { .handler = ipi_resched_interrupt, - .flags = IRQF_DISABLED|IRQF_PERCPU, + .flags = IRQF_PERCPU, .name = "IPI_resched" }; static struct irqaction irq_call = { .handler = ipi_call_interrupt, - .flags = IRQF_DISABLED|IRQF_PERCPU, + .flags = IRQF_PERCPU, .name = "IPI_call" }; #endif /* CONFIG_MIPS_MT_SMP */ diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig index a5ca743613f2..75bec44b5856 100644 --- a/arch/mips/netlogic/Kconfig +++ b/arch/mips/netlogic/Kconfig @@ -1,5 +1,2 @@ config NLM_COMMON bool - -config NLM_XLR - bool diff --git a/arch/mips/netlogic/Makefile b/arch/mips/netlogic/Makefile new file mode 100644 index 000000000000..36d169b2ca6d --- /dev/null +++ b/arch/mips/netlogic/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_NLM_COMMON) += common/ +obj-$(CONFIG_CPU_XLR) += xlr/ +obj-$(CONFIG_CPU_XLP) += xlp/ diff --git a/arch/mips/netlogic/Platform b/arch/mips/netlogic/Platform index b648b487fd66..cdfc9abbbb7b 100644 --- a/arch/mips/netlogic/Platform +++ b/arch/mips/netlogic/Platform @@ -1,16 +1,17 @@ # # NETLOGIC includes # -cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/mach-netlogic -cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/netlogic +cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/mach-netlogic +cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/netlogic # # use mips64 if xlr is not available # -cflags-$(CONFIG_NLM_XLR) += $(call cc-option,-march=xlr,-march=mips64) +cflags-$(CONFIG_CPU_XLR) += $(call cc-option,-march=xlr,-march=mips64) +cflags-$(CONFIG_CPU_XLP) += $(call cc-option,-march=xlp,-march=mips64r2) # -# NETLOGIC XLR/XLS SoC, Simulator and boards +# NETLOGIC processor support # -core-$(CONFIG_NLM_XLR) += arch/mips/netlogic/xlr/ -load-$(CONFIG_NLM_XLR_BOARD) += 0xffffffff84000000 +platform-$(CONFIG_NLM_COMMON) += netlogic/ +load-$(CONFIG_NLM_COMMON) += 0xffffffff80100000 diff --git a/arch/mips/netlogic/common/Makefile b/arch/mips/netlogic/common/Makefile new file mode 100644 index 000000000000..291372a086f5 --- /dev/null +++ b/arch/mips/netlogic/common/Makefile @@ -0,0 +1,3 @@ +obj-y += irq.o time.o +obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_EARLY_PRINTK) += earlycons.o diff --git a/arch/mips/netlogic/common/earlycons.c b/arch/mips/netlogic/common/earlycons.c new file mode 100644 index 000000000000..f193f7b3bd81 --- /dev/null +++ b/arch/mips/netlogic/common/earlycons.c @@ -0,0 +1,60 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/types.h> +#include <linux/serial_reg.h> + +#include <asm/mipsregs.h> +#include <asm/netlogic/haldefs.h> + +#if defined(CONFIG_CPU_XLP) +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/uart.h> +#elif defined(CONFIG_CPU_XLR) +#include <asm/netlogic/xlr/iomap.h> +#endif + +void prom_putchar(char c) +{ + uint64_t uartbase; + +#if defined(CONFIG_CPU_XLP) + uartbase = nlm_get_uart_regbase(0, 0); +#elif defined(CONFIG_CPU_XLR) + uartbase = nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); +#endif + while (nlm_read_reg(uartbase, UART_LSR) == 0) + ; + nlm_write_reg(uartbase, UART_TX, c); +} diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c new file mode 100644 index 000000000000..49a4f6cf71e5 --- /dev/null +++ b/arch/mips/netlogic/common/irq.c @@ -0,0 +1,238 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/linkage.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/irq.h> + +#include <asm/errno.h> +#include <asm/signal.h> +#include <asm/system.h> +#include <asm/ptrace.h> +#include <asm/mipsregs.h> +#include <asm/thread_info.h> + +#include <asm/netlogic/mips-extns.h> +#include <asm/netlogic/interrupt.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> + +#if defined(CONFIG_CPU_XLP) +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#elif defined(CONFIG_CPU_XLR) +#include <asm/netlogic/xlr/iomap.h> +#include <asm/netlogic/xlr/pic.h> +#else +#error "Unknown CPU" +#endif +/* + * These are the routines that handle all the low level interrupt stuff. + * Actions handled here are: initialization of the interrupt map, requesting of + * interrupt lines by handlers, dispatching if interrupts to handlers, probing + * for interrupt lines + */ + +/* Globals */ +static uint64_t nlm_irq_mask; +static DEFINE_SPINLOCK(nlm_pic_lock); + +static void xlp_pic_enable(struct irq_data *d) +{ + unsigned long flags; + int irt; + + irt = nlm_irq_to_irt(d->irq); + if (irt == -1) + return; + spin_lock_irqsave(&nlm_pic_lock, flags); + nlm_pic_enable_irt(nlm_pic_base, irt); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +static void xlp_pic_disable(struct irq_data *d) +{ + unsigned long flags; + int irt; + + irt = nlm_irq_to_irt(d->irq); + if (irt == -1) + return; + spin_lock_irqsave(&nlm_pic_lock, flags); + nlm_pic_disable_irt(nlm_pic_base, irt); + spin_unlock_irqrestore(&nlm_pic_lock, flags); +} + +static void xlp_pic_mask_ack(struct irq_data *d) +{ + uint64_t mask = 1ull << d->irq; + + write_c0_eirr(mask); /* ack by writing EIRR */ +} + +static void xlp_pic_unmask(struct irq_data *d) +{ + void *hd = irq_data_get_irq_handler_data(d); + int irt; + + irt = nlm_irq_to_irt(d->irq); + if (irt == -1) + return; + + if (hd) { + void (*extra_ack)(void *) = hd; + extra_ack(d); + } + /* Ack is a single write, no need to lock */ + nlm_pic_ack(nlm_pic_base, irt); +} + +static struct irq_chip xlp_pic = { + .name = "XLP-PIC", + .irq_enable = xlp_pic_enable, + .irq_disable = xlp_pic_disable, + .irq_mask_ack = xlp_pic_mask_ack, + .irq_unmask = xlp_pic_unmask, +}; + +static void cpuintr_disable(struct irq_data *d) +{ + uint64_t eimr; + uint64_t mask = 1ull << d->irq; + + eimr = read_c0_eimr(); + write_c0_eimr(eimr & ~mask); +} + +static void cpuintr_enable(struct irq_data *d) +{ + uint64_t eimr; + uint64_t mask = 1ull << d->irq; + + eimr = read_c0_eimr(); + write_c0_eimr(eimr | mask); +} + +static void cpuintr_ack(struct irq_data *d) +{ + uint64_t mask = 1ull << d->irq; + + write_c0_eirr(mask); +} + +static void cpuintr_nop(struct irq_data *d) +{ + WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq); +} + +/* + * Chip definition for CPU originated interrupts(timer, msg) and + * IPIs + */ +struct irq_chip nlm_cpu_intr = { + .name = "XLP-CPU-INTR", + .irq_enable = cpuintr_enable, + .irq_disable = cpuintr_disable, + .irq_mask = cpuintr_nop, + .irq_ack = cpuintr_nop, + .irq_eoi = cpuintr_ack, +}; + +void __init init_nlm_common_irqs(void) +{ + int i, irq, irt; + + for (i = 0; i < PIC_IRT_FIRST_IRQ; i++) + irq_set_chip_and_handler(i, &nlm_cpu_intr, handle_percpu_irq); + + for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ ; i++) + irq_set_chip_and_handler(i, &xlp_pic, handle_level_irq); + +#ifdef CONFIG_SMP + irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr, + nlm_smp_function_ipi_handler); + irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, + nlm_smp_resched_ipi_handler); + nlm_irq_mask |= + ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); +#endif + + for (irq = PIC_IRT_FIRST_IRQ; irq <= PIC_IRT_LAST_IRQ; irq++) { + irt = nlm_irq_to_irt(irq); + if (irt == -1) + continue; + nlm_irq_mask |= (1ULL << irq); + nlm_pic_init_irt(nlm_pic_base, irt, irq, 0); + } + + nlm_irq_mask |= (1ULL << IRQ_TIMER); +} + +void __init arch_init_irq(void) +{ + /* Initialize the irq descriptors */ + init_nlm_common_irqs(); + + write_c0_eimr(nlm_irq_mask); +} + +void __cpuinit nlm_smp_irq_init(void) +{ + /* set interrupt mask for non-zero cpus */ + write_c0_eimr(nlm_irq_mask); +} + +asmlinkage void plat_irq_dispatch(void) +{ + uint64_t eirr; + int i; + + eirr = read_c0_eirr() & read_c0_eimr(); + if (eirr & (1 << IRQ_TIMER)) { + do_IRQ(IRQ_TIMER); + return; + } + + i = __ilog2_u64(eirr); + if (i == -1) + return; + + do_IRQ(i); +} diff --git a/arch/mips/netlogic/xlr/smp.c b/arch/mips/netlogic/common/smp.c index 080284ded508..db17f49886c2 100644 --- a/arch/mips/netlogic/xlr/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -42,31 +42,29 @@ #include <asm/netlogic/interrupt.h> #include <asm/netlogic/mips-extns.h> - +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> + +#if defined(CONFIG_CPU_XLP) +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#elif defined(CONFIG_CPU_XLR) #include <asm/netlogic/xlr/iomap.h> #include <asm/netlogic/xlr/pic.h> #include <asm/netlogic/xlr/xlr.h> +#else +#error "Unknown CPU" +#endif -void core_send_ipi(int logical_cpu, unsigned int action) +void nlm_send_ipi_single(int logical_cpu, unsigned int action) { int cpu = cpu_logical_map(logical_cpu); - u32 tid = cpu & 0x3; - u32 pid = (cpu >> 2) & 0x07; - u32 ipi = (tid << 16) | (pid << 20); if (action & SMP_CALL_FUNCTION) - ipi |= IRQ_IPI_SMP_FUNCTION; - else if (action & SMP_RESCHEDULE_YOURSELF) - ipi |= IRQ_IPI_SMP_RESCHEDULE; - else - return; - - pic_send_ipi(ipi); -} - -void nlm_send_ipi_single(int cpu, unsigned int action) -{ - core_send_ipi(cpu, action); + nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_FUNCTION, 0); + if (action & SMP_RESCHEDULE_YOURSELF) + nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_RESCHEDULE, 0); } void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) @@ -74,29 +72,35 @@ void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) int cpu; for_each_cpu(cpu, mask) { - core_send_ipi(cpu, action); + nlm_send_ipi_single(cpu, action); } } /* IRQ_IPI_SMP_FUNCTION Handler */ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) { + write_c0_eirr(1ull << irq); smp_call_function_interrupt(); } /* IRQ_IPI_SMP_RESCHEDULE handler */ void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) { + write_c0_eirr(1ull << irq); scheduler_ipi(); } /* * Called before going into mips code, early cpu init */ -void nlm_early_init_secondary(void) +void nlm_early_init_secondary(int cpu) { + change_c0_config(CONF_CM_CMASK, 0x3); write_c0_ebase((uint32_t)nlm_common_ebase); - /* TLB partition here later */ +#ifdef CONFIG_CPU_XLP + if (hard_smp_processor_id() % 4 == 0) + xlp_mmu_init(); +#endif } /* @@ -104,9 +108,16 @@ void nlm_early_init_secondary(void) */ static void __cpuinit nlm_init_secondary(void) { + current_cpu_data.core = hard_smp_processor_id() / 4; nlm_smp_irq_init(); } +void nlm_prepare_cpus(unsigned int max_cpus) +{ + /* declare we are SMT capable */ + smp_num_siblings = nlm_threads_per_core; +} + void nlm_smp_finish(void) { #ifdef notyet @@ -123,10 +134,10 @@ void nlm_cpus_done(void) * Boot all other cpus in the system, initialize them, and bring them into * the boot function */ -int nlm_cpu_unblock[NR_CPUS]; int nlm_cpu_ready[NR_CPUS]; unsigned long nlm_next_gp; unsigned long nlm_next_sp; + cpumask_t phys_cpu_present_map; void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) @@ -140,7 +151,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) /* barrier */ __sync(); - nlm_cpu_unblock[cpu] = 1; + nlm_pic_send_ipi(nlm_pic_base, cpu, 1, 1); } void __init nlm_smp_setup(void) @@ -159,8 +170,8 @@ void __init nlm_smp_setup(void) num_cpus = 1; for (i = 0; i < NR_CPUS; i++) { /* - * BSP is not set in nlm_cpu_ready array, it is only for - * ASPs (goto see smpboot.S) + * nlm_cpu_ready array is not set for the boot_cpu, + * it is only set for ASPs (see smpboot.S) */ if (nlm_cpu_ready[i]) { cpu_set(i, phys_cpu_present_map); @@ -176,10 +187,75 @@ void __init nlm_smp_setup(void) (unsigned long)cpu_possible_map.bits[0]); pr_info("Detected %i Slave CPU(s)\n", num_cpus); + nlm_set_nmi_handler(nlm_boot_secondary_cpus); } -void nlm_prepare_cpus(unsigned int max_cpus) +static int nlm_parse_cpumask(u32 cpu_mask) +{ + uint32_t core0_thr_mask, core_thr_mask; + int threadmode, i; + + core0_thr_mask = cpu_mask & 0xf; + switch (core0_thr_mask) { + case 1: + nlm_threads_per_core = 1; + threadmode = 0; + break; + case 3: + nlm_threads_per_core = 2; + threadmode = 2; + break; + case 0xf: + nlm_threads_per_core = 4; + threadmode = 3; + break; + default: + goto unsupp; + } + + /* Verify other cores CPU masks */ + nlm_coremask = 1; + nlm_cpumask = core0_thr_mask; + for (i = 1; i < 8; i++) { + core_thr_mask = (cpu_mask >> (i * 4)) & 0xf; + if (core_thr_mask) { + if (core_thr_mask != core0_thr_mask) + goto unsupp; + nlm_coremask |= 1 << i; + nlm_cpumask |= core0_thr_mask << (4 * i); + } + } + return threadmode; + +unsupp: + panic("Unsupported CPU mask %x\n", cpu_mask); + return 0; +} + +int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask) { + unsigned long reset_vec; + char *reset_data; + int threadmode; + + /* Update reset entry point with CPU init code */ + reset_vec = CKSEG1ADDR(RESET_VEC_PHYS); + memcpy((void *)reset_vec, (void *)nlm_reset_entry, + (nlm_reset_entry_end - nlm_reset_entry)); + + /* verify the mask and setup core config variables */ + threadmode = nlm_parse_cpumask(wakeup_mask); + + /* Setup CPU init parameters */ + reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS); + *(int *)(reset_data + BOOT_THREAD_MODE) = threadmode; + +#ifdef CONFIG_CPU_XLP + xlp_wakeup_secondary_cpus(); +#else + xlr_wakeup_secondary_cpus(); +#endif + return 0; } struct plat_smp_ops nlm_smp_ops = { @@ -192,29 +268,3 @@ struct plat_smp_ops nlm_smp_ops = { .smp_setup = nlm_smp_setup, .prepare_cpus = nlm_prepare_cpus, }; - -unsigned long secondary_entry_point; - -int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask) -{ - unsigned int tid, pid, ipi, i, boot_cpu; - void *reset_vec; - - secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus; - reset_vec = (void *)CKSEG1ADDR(0x1fc00000); - memcpy(reset_vec, nlm_boot_smp_nmi, 0x80); - boot_cpu = hard_smp_processor_id(); - - for (i = 0; i < NR_CPUS; i++) { - if (i == boot_cpu) - continue; - if (wakeup_mask & (1u << i)) { - tid = i & 0x3; - pid = (i >> 2) & 0x7; - ipi = (tid << 16) | (pid << 20) | (1 << 8); - pic_send_ipi(ipi); - } - } - - return 0; -} diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S new file mode 100644 index 000000000000..c138b1a6dec3 --- /dev/null +++ b/arch/mips/netlogic/common/smpboot.S @@ -0,0 +1,272 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/init.h> + +#include <asm/asm.h> +#include <asm/asm-offsets.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/stackframe.h> +#include <asm/asmmacro.h> +#include <asm/addrspace.h> + +#include <asm/netlogic/common.h> + +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/sys.h> +#include <asm/netlogic/xlp-hal/cpucontrol.h> + +#define CP0_EBASE $15 +#define SYS_CPU_COHERENT_BASE(node) CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ + XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \ + SYS_CPU_NONCOHERENT_MODE * 4 + +.macro __config_lsu + li t0, LSU_DEFEATURE + mfcr t1, t0 + + lui t2, 0x4080 /* Enable Unaligned Access, L2HPE */ + or t1, t1, t2 + li t2, ~0xe /* S1RCM */ + and t1, t1, t2 + mtcr t1, t0 + + li t0, SCHED_DEFEATURE + lui t1, 0x0100 /* Experimental: Disable BRU accepting ALU ops */ + mtcr t1, t0 +.endm + +/* + * The cores can come start when they are woken up. This is also the NMI + * entry, so check that first. + * + * The data corresponding to reset is stored at RESET_DATA_PHYS location, + * this will have the thread mask (used when core is woken up) and the + * current NMI handler in case we reached here for an NMI. + * + * When a core or thread is newly woken up, it loops in a 'wait'. When + * the CPU really needs waking up, we send an NMI to it, with the NMI + * handler set to prom_boot_secondary_cpus + */ + + .set noreorder + .set noat + .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ + +FEXPORT(nlm_reset_entry) + dmtc0 k0, $22, 6 + dmtc0 k1, $22, 7 + mfc0 k0, CP0_STATUS + li k1, 0x80000 + and k1, k0, k1 + beqz k1, 1f /* go to real reset entry */ + nop + li k1, CKSEG1ADDR(RESET_DATA_PHYS) /* NMI */ + ld k0, BOOT_NMI_HANDLER(k1) + jr k0 + nop + +1: /* Entry point on core wakeup */ + mfc0 t0, CP0_EBASE, 1 + mfc0 t1, CP0_EBASE, 1 + srl t1, 5 + andi t1, 0x3 /* t1 <- node */ + li t2, 0x40000 + mul t3, t2, t1 /* t3 = node * 0x40000 */ + srl t0, t0, 2 + and t0, t0, 0x7 /* t0 <- core */ + li t1, 0x1 + sll t0, t1, t0 + nor t0, t0, zero /* t0 <- ~(1 << core) */ + li t2, SYS_CPU_COHERENT_BASE(0) + add t2, t2, t3 /* t2 <- SYS offset for node */ + lw t1, 0(t2) + and t1, t1, t0 + sw t1, 0(t2) + + /* read back to ensure complete */ + lw t1, 0(t2) + sync + + /* Configure LSU on Non-0 Cores. */ + __config_lsu + +/* + * Wake up sibling threads from the initial thread in + * a core. + */ +EXPORT(nlm_boot_siblings) + li t0, CKSEG1ADDR(RESET_DATA_PHYS) + lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ + li t0, ((CPU_BLOCKID_MAP << 8) | MAP_THREADMODE) + mfcr t2, t0 + or t2, t2, t1 + mtcr t2, t0 + + /* + * The new hardware thread starts at the next instruction + * For all the cases other than core 0 thread 0, we will + * jump to the secondary wait function. + */ + mfc0 v0, CP0_EBASE, 1 + andi v0, 0x7f /* v0 <- node/core */ + +#if 1 + /* A0 errata - Write MMU_SETUP after changing thread mode register. */ + andi v1, v0, 0x3 /* v1 <- thread id */ + bnez v1, 2f + nop + + li t0, MMU_SETUP + li t1, 0 + mtcr t1, t0 + ehb +#endif + +2: beqz v0, 4f + nop + + /* setup status reg */ + mfc0 t1, CP0_STATUS + li t0, ST0_BEV + or t1, t0 + xor t1, t0 +#ifdef CONFIG_64BIT + ori t1, ST0_KX +#endif + mtc0 t1, CP0_STATUS + /* mark CPU ready */ + PTR_LA t1, nlm_cpu_ready + sll v1, v0, 2 + PTR_ADDU t1, v1 + li t2, 1 + sw t2, 0(t1) + /* Wait until NMI hits */ +3: wait + j 3b + nop + + /* + * For the boot CPU, we have to restore registers and + * return + */ +4: dmfc0 t0, $4, 2 /* restore SP from UserLocal */ + li t1, 0xfadebeef + dmtc0 t1, $4, 2 /* restore SP from UserLocal */ + PTR_SUBU sp, t0, PT_SIZE + RESTORE_ALL + jr ra + nop +EXPORT(nlm_reset_entry_end) + +FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ + __config_lsu + dmtc0 sp, $4, 2 /* SP saved in UserLocal */ + SAVE_ALL + sync + /* find the location to which nlm_boot_siblings was relocated */ + li t0, CKSEG1ADDR(RESET_VEC_PHYS) + dla t1, nlm_reset_entry + dla t2, nlm_boot_siblings + dsubu t2, t1 + daddu t2, t0 + /* call it */ + jr t2 + nop + /* not reached */ + + __CPUINIT +NESTED(nlm_boot_secondary_cpus, 16, sp) + PTR_LA t1, nlm_next_sp + PTR_L sp, 0(t1) + PTR_LA t1, nlm_next_gp + PTR_L gp, 0(t1) + + /* a0 has the processor id */ + PTR_LA t0, nlm_early_init_secondary + jalr t0 + nop + + PTR_LA t0, smp_bootstrap + jr t0 + nop +END(nlm_boot_secondary_cpus) + __FINIT + +/* + * In case of RMIboot bootloader which is used on XLR boards, the CPUs + * be already woken up and waiting in bootloader code. + * This will get them out of the bootloader code and into linux. Needed + * because the bootloader area will be taken and initialized by linux. + */ + __CPUINIT +NESTED(nlm_rmiboot_preboot, 16, sp) + mfc0 t0, $15, 1 # read ebase + andi t0, 0x1f # t0 has the processor_id() + andi t2, t0, 0x3 # thread no + sll t0, 2 # offset in cpu array + + PTR_LA t1, nlm_cpu_ready # mark CPU ready + PTR_ADDU t1, t0 + li t3, 1 + sw t3, 0(t1) + + bnez t2, 1f # skip thread programming + nop # for non zero hw threads + + /* + * MMU setup only for first thread in core + */ + li t0, 0x400 + mfcr t1, t0 + li t2, 6 # XLR thread mode mask + nor t3, t2, zero + and t2, t1, t2 # t2 - current thread mode + li v0, CKSEG1ADDR(RESET_DATA_PHYS) + lw v1, BOOT_THREAD_MODE(v0) # v1 - new thread mode + sll v1, 1 + beq v1, t2, 1f # same as request value + nop # nothing to do */ + + and t2, t1, t3 # mask out old thread mode + or t1, t2, v1 # put in new value + mtcr t1, t0 # update core control + +1: wait + j 1b + nop +END(nlm_rmiboot_preboot) + __FINIT diff --git a/arch/mips/netlogic/xlr/time.c b/arch/mips/netlogic/common/time.c index 0d81b262593c..bd3e498157ff 100644 --- a/arch/mips/netlogic/xlr/time.c +++ b/arch/mips/netlogic/common/time.c @@ -36,7 +36,7 @@ #include <asm/time.h> #include <asm/netlogic/interrupt.h> -#include <asm/netlogic/psb-bootinfo.h> +#include <asm/netlogic/common.h> unsigned int __cpuinit get_c0_compare_int(void) { @@ -45,7 +45,7 @@ unsigned int __cpuinit get_c0_compare_int(void) void __init plat_time_init(void) { - mips_hpt_frequency = nlm_prom_info.cpu_frequency; + mips_hpt_frequency = nlm_get_cpu_frequency(); pr_info("MIPS counter frequency [%ld]\n", - (unsigned long)mips_hpt_frequency); + (unsigned long)mips_hpt_frequency); } diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile new file mode 100644 index 000000000000..b93ed83474ec --- /dev/null +++ b/arch/mips/netlogic/xlp/Makefile @@ -0,0 +1,2 @@ +obj-y += setup.o platform.o nlm_hal.o +obj-$(CONFIG_SMP) += wakeup.o diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c new file mode 100644 index 000000000000..9428e7125fed --- /dev/null +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -0,0 +1,111 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/delay.h> + +#include <asm/mipsregs.h> +#include <asm/time.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#include <asm/netlogic/xlp-hal/sys.h> + +/* These addresses are computed by the nlm_hal_init() */ +uint64_t nlm_io_base; +uint64_t nlm_sys_base; +uint64_t nlm_pic_base; + +/* Main initialization */ +void nlm_hal_init(void) +{ + nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE); + nlm_sys_base = nlm_get_sys_regbase(0); /* node 0 */ + nlm_pic_base = nlm_get_pic_regbase(0); /* node 0 */ +} + +int nlm_irq_to_irt(int irq) +{ + if (!PIC_IRQ_IS_IRT(irq)) + return -1; + + switch (irq) { + case PIC_UART_0_IRQ: + return PIC_IRT_UART_0_INDEX; + case PIC_UART_1_IRQ: + return PIC_IRT_UART_1_INDEX; + default: + return -1; + } +} + +int nlm_irt_to_irq(int irt) +{ + switch (irt) { + case PIC_IRT_UART_0_INDEX: + return PIC_UART_0_IRQ; + case PIC_IRT_UART_1_INDEX: + return PIC_UART_1_IRQ; + default: + return -1; + } +} + +unsigned int nlm_get_core_frequency(int core) +{ + unsigned int pll_divf, pll_divr, dfs_div, ext_div; + unsigned int rstval, dfsval, denom; + uint64_t num; + + rstval = nlm_read_sys_reg(nlm_sys_base, SYS_POWER_ON_RESET_CFG); + dfsval = nlm_read_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIV_VALUE); + pll_divf = ((rstval >> 10) & 0x7f) + 1; + pll_divr = ((rstval >> 8) & 0x3) + 1; + ext_div = ((rstval >> 30) & 0x3) + 1; + dfs_div = ((dfsval >> (core * 4)) & 0xf) + 1; + + num = 800000000ULL * pll_divf; + denom = 3 * pll_divr * ext_div * dfs_div; + do_div(num, denom); + return (unsigned int)num; +} + +unsigned int nlm_get_cpu_frequency(void) +{ + return nlm_get_core_frequency(0); +} diff --git a/arch/mips/netlogic/xlp/platform.c b/arch/mips/netlogic/xlp/platform.c new file mode 100644 index 000000000000..1f5e4cba891d --- /dev/null +++ b/arch/mips/netlogic/xlp/platform.c @@ -0,0 +1,108 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_8250.h> +#include <linux/pci.h> +#include <linux/serial_reg.h> +#include <linux/spinlock.h> + +#include <asm/time.h> +#include <asm/addrspace.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#include <asm/netlogic/xlp-hal/uart.h> + +static unsigned int nlm_xlp_uart_in(struct uart_port *p, int offset) +{ + return nlm_read_reg(p->iobase, offset); +} + +static void nlm_xlp_uart_out(struct uart_port *p, int offset, int value) +{ + nlm_write_reg(p->iobase, offset, value); +} + +#define PORT(_irq) \ + { \ + .irq = _irq, \ + .regshift = 2, \ + .iotype = UPIO_MEM32, \ + .flags = (UPF_SKIP_TEST|UPF_FIXED_TYPE|\ + UPF_BOOT_AUTOCONF), \ + .uartclk = XLP_IO_CLK, \ + .type = PORT_16550A, \ + .serial_in = nlm_xlp_uart_in, \ + .serial_out = nlm_xlp_uart_out, \ + } + +static struct plat_serial8250_port xlp_uart_data[] = { + PORT(PIC_UART_0_IRQ), + PORT(PIC_UART_1_IRQ), + {}, +}; + +static struct platform_device uart_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = xlp_uart_data, + }, +}; + +static int __init nlm_platform_uart_init(void) +{ + unsigned long mmio; + + mmio = (unsigned long)nlm_get_uart_regbase(0, 0); + xlp_uart_data[0].iobase = mmio; + xlp_uart_data[0].membase = (void __iomem *)mmio; + xlp_uart_data[0].mapbase = mmio; + + mmio = (unsigned long)nlm_get_uart_regbase(0, 1); + xlp_uart_data[1].iobase = mmio; + xlp_uart_data[1].membase = (void __iomem *)mmio; + xlp_uart_data[1].mapbase = mmio; + + return platform_device_register(&uart_device); +} + +arch_initcall(nlm_platform_uart_init); diff --git a/arch/mips/netlogic/xlp/setup.c b/arch/mips/netlogic/xlp/setup.c new file mode 100644 index 000000000000..acb677a1227c --- /dev/null +++ b/arch/mips/netlogic/xlp/setup.c @@ -0,0 +1,105 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/kernel.h> +#include <linux/serial_8250.h> +#include <linux/pm.h> + +#include <asm/reboot.h> +#include <asm/time.h> +#include <asm/bootinfo.h> + +#include <linux/of_fdt.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> + +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/sys.h> + +unsigned long nlm_common_ebase = 0x0; + +/* default to uniprocessor */ +uint32_t nlm_coremask = 1, nlm_cpumask = 1; +int nlm_threads_per_core = 1; + +static void nlm_linux_exit(void) +{ + nlm_write_sys_reg(nlm_sys_base, SYS_CHIP_RESET, 1); + for ( ; ; ) + cpu_wait(); +} + +void __init plat_mem_setup(void) +{ + panic_timeout = 5; + _machine_restart = (void (*)(char *))nlm_linux_exit; + _machine_halt = nlm_linux_exit; + pm_power_off = nlm_linux_exit; +} + +const char *get_system_type(void) +{ + return "Netlogic XLP Series"; +} + +void __init prom_free_prom_memory(void) +{ + /* Nothing yet */ +} + +void xlp_mmu_init(void) +{ + write_c0_config6(read_c0_config6() | 0x24); + current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1; + write_c0_config7(PM_DEFAULT_MASK >> + (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2))); +} + +void __init prom_init(void) +{ + void *fdtp; + + fdtp = (void *)(long)fw_arg0; + xlp_mmu_init(); + nlm_hal_init(); + early_init_devtree(fdtp); + + nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1)); +#ifdef CONFIG_SMP + nlm_wakeup_secondary_cpus(0xffffffff); + register_smp_ops(&nlm_smp_ops); +#endif +} diff --git a/arch/mips/netlogic/xlp/wakeup.c b/arch/mips/netlogic/xlp/wakeup.c new file mode 100644 index 000000000000..44d923ff3846 --- /dev/null +++ b/arch/mips/netlogic/xlp/wakeup.c @@ -0,0 +1,102 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/threads.h> + +#include <asm/asm.h> +#include <asm/asm-offsets.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/string.h> + +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> +#include <asm/netlogic/mips-extns.h> + +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/pic.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/sys.h> + +static void xlp_enable_secondary_cores(void) +{ + uint32_t core, value, coremask, syscoremask; + int count; + + /* read cores in reset from SYS block */ + syscoremask = nlm_read_sys_reg(nlm_sys_base, SYS_CPU_RESET); + + /* update user specified */ + nlm_coremask = nlm_coremask & (syscoremask | 1); + + for (core = 1; core < 8; core++) { + coremask = 1 << core; + if ((nlm_coremask & coremask) == 0) + continue; + + /* Enable CPU clock */ + value = nlm_read_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIS_CTRL); + value &= ~coremask; + nlm_write_sys_reg(nlm_sys_base, SYS_CORE_DFS_DIS_CTRL, value); + + /* Remove CPU Reset */ + value = nlm_read_sys_reg(nlm_sys_base, SYS_CPU_RESET); + value &= ~coremask; + nlm_write_sys_reg(nlm_sys_base, SYS_CPU_RESET, value); + + /* Poll for CPU to mark itself coherent */ + count = 100000; + do { + value = nlm_read_sys_reg(nlm_sys_base, + SYS_CPU_NONCOHERENT_MODE); + } while ((value & coremask) != 0 && count-- > 0); + + if (count == 0) + pr_err("Failed to enable core %d\n", core); + } +} + +void xlp_wakeup_secondary_cpus(void) +{ + /* + * In case of u-boot, the secondaries are in reset + * first wakeup core 0 threads + */ + xlp_boot_core0_siblings(); + + /* now get other cores out of reset */ + xlp_enable_secondary_cores(); +} diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile index 2dca585dd2f7..f01e4d7a0600 100644 --- a/arch/mips/netlogic/xlr/Makefile +++ b/arch/mips/netlogic/xlr/Makefile @@ -1,5 +1,2 @@ -obj-y += setup.o platform.o irq.o setup.o time.o -obj-$(CONFIG_SMP) += smp.o smpboot.o -obj-$(CONFIG_EARLY_PRINTK) += xlr_console.o - -ccflags-y += -Werror +obj-y += setup.o platform.o +obj-$(CONFIG_SMP) += wakeup.o diff --git a/arch/mips/netlogic/xlr/irq.c b/arch/mips/netlogic/xlr/irq.c deleted file mode 100644 index 521bb7377eb0..000000000000 --- a/arch/mips/netlogic/xlr/irq.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights - * reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the NetLogic - * license below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/linkage.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mm.h> - -#include <asm/mipsregs.h> - -#include <asm/netlogic/xlr/iomap.h> -#include <asm/netlogic/xlr/pic.h> -#include <asm/netlogic/xlr/xlr.h> - -#include <asm/netlogic/interrupt.h> -#include <asm/netlogic/mips-extns.h> - -static u64 nlm_irq_mask; -static DEFINE_SPINLOCK(nlm_pic_lock); - -static void xlr_pic_enable(struct irq_data *d) -{ - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - unsigned long flags; - nlm_reg_t reg; - int irq = d->irq; - - WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); - - spin_lock_irqsave(&nlm_pic_lock, flags); - reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); - netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, - reg | (1 << 6) | (1 << 30) | (1 << 31)); - spin_unlock_irqrestore(&nlm_pic_lock, flags); -} - -static void xlr_pic_mask(struct irq_data *d) -{ - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - unsigned long flags; - nlm_reg_t reg; - int irq = d->irq; - - WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); - - spin_lock_irqsave(&nlm_pic_lock, flags); - reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); - netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, - reg | (1 << 6) | (1 << 30) | (0 << 31)); - spin_unlock_irqrestore(&nlm_pic_lock, flags); -} - -#ifdef CONFIG_PCI -/* Extra ACK needed for XLR on chip PCI controller */ -static void xlr_pci_ack(struct irq_data *d) -{ - nlm_reg_t *pci_mmio = netlogic_io_mmio(NETLOGIC_IO_PCIX_OFFSET); - - netlogic_read_reg(pci_mmio, (0x140 >> 2)); -} - -/* Extra ACK needed for XLS on chip PCIe controller */ -static void xls_pcie_ack(struct irq_data *d) -{ - nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET); - - switch (d->irq) { - case PIC_PCIE_LINK0_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff); - break; - case PIC_PCIE_LINK1_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff); - break; - case PIC_PCIE_LINK2_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff); - break; - case PIC_PCIE_LINK3_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff); - break; - } -} - -/* For XLS B silicon, the 3,4 PCI interrupts are different */ -static void xls_pcie_ack_b(struct irq_data *d) -{ - nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET); - - switch (d->irq) { - case PIC_PCIE_LINK0_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff); - break; - case PIC_PCIE_LINK1_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff); - break; - case PIC_PCIE_XLSB0_LINK2_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff); - break; - case PIC_PCIE_XLSB0_LINK3_IRQ: - netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff); - break; - } -} -#endif - -static void xlr_pic_ack(struct irq_data *d) -{ - unsigned long flags; - nlm_reg_t *mmio; - int irq = d->irq; - void *hd = irq_data_get_irq_handler_data(d); - - WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq); - - if (hd) { - void (*extra_ack)(void *) = hd; - extra_ack(d); - } - mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - spin_lock_irqsave(&nlm_pic_lock, flags); - netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE))); - spin_unlock_irqrestore(&nlm_pic_lock, flags); -} - -/* - * This chip definition handles interrupts routed thru the XLR - * hardware PIC, currently IRQs 8-39 are mapped to hardware intr - * 0-31 wired the XLR PIC - */ -static struct irq_chip xlr_pic = { - .name = "XLR-PIC", - .irq_enable = xlr_pic_enable, - .irq_mask = xlr_pic_mask, - .irq_ack = xlr_pic_ack, -}; - -static void rsvd_irq_handler(struct irq_data *d) -{ - WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq); -} - -/* - * Chip definition for CPU originated interrupts(timer, msg) and - * IPIs - */ -struct irq_chip nlm_cpu_intr = { - .name = "XLR-CPU-INTR", - .irq_enable = rsvd_irq_handler, - .irq_mask = rsvd_irq_handler, - .irq_ack = rsvd_irq_handler, -}; - -void __init init_xlr_irqs(void) -{ - nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET); - uint32_t thread_mask = 1; - int level, i; - - pr_info("Interrupt thread mask [%x]\n", thread_mask); - for (i = 0; i < PIC_NUM_IRTS; i++) { - level = PIC_IRQ_IS_EDGE_TRIGGERED(i); - - /* Bind all PIC irqs to boot cpu */ - netlogic_write_reg(mmio, PIC_IRT_0_BASE + i, thread_mask); - - /* - * Use local scheduling and high polarity for all IRTs - * Invalidate all IRTs, by default - */ - netlogic_write_reg(mmio, PIC_IRT_1_BASE + i, - (level << 30) | (1 << 6) | (PIC_IRQ_BASE + i)); - } - - /* Make all IRQs as level triggered by default */ - for (i = 0; i < NR_IRQS; i++) { - if (PIC_IRQ_IS_IRT(i)) - irq_set_chip_and_handler(i, &xlr_pic, handle_level_irq); - else - irq_set_chip_and_handler(i, &nlm_cpu_intr, - handle_percpu_irq); - } -#ifdef CONFIG_SMP - irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr, - nlm_smp_function_ipi_handler); - irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr, - nlm_smp_resched_ipi_handler); - nlm_irq_mask |= - ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE)); -#endif - -#ifdef CONFIG_PCI - /* - * For PCI interrupts, we need to ack the PIC controller too, overload - * irq handler data to do this - */ - if (nlm_chip_is_xls()) { - if (nlm_chip_is_xls_b()) { - irq_set_handler_data(PIC_PCIE_LINK0_IRQ, - xls_pcie_ack_b); - irq_set_handler_data(PIC_PCIE_LINK1_IRQ, - xls_pcie_ack_b); - irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ, - xls_pcie_ack_b); - irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, - xls_pcie_ack_b); - } else { - irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack); - irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack); - irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack); - irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack); - } - } else { - /* XLR PCI controller ACK */ - irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack); - } -#endif - /* unmask all PIC related interrupts. If no handler is installed by the - * drivers, it'll just ack the interrupt and return - */ - for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) - nlm_irq_mask |= (1ULL << i); - - nlm_irq_mask |= (1ULL << IRQ_TIMER); -} - -void __init arch_init_irq(void) -{ - /* Initialize the irq descriptors */ - init_xlr_irqs(); - write_c0_eimr(nlm_irq_mask); -} - -void __cpuinit nlm_smp_irq_init(void) -{ - /* set interrupt mask for non-zero cpus */ - write_c0_eimr(nlm_irq_mask); -} - -asmlinkage void plat_irq_dispatch(void) -{ - uint64_t eirr; - int i; - - eirr = read_c0_eirr() & read_c0_eimr(); - if (!eirr) - return; - - /* no need of EIRR here, writing compare clears interrupt */ - if (eirr & (1 << IRQ_TIMER)) { - do_IRQ(IRQ_TIMER); - return; - } - - /* use dcltz: optimize below code */ - for (i = 63; i != -1; i--) { - if (eirr & (1ULL << i)) - break; - } - if (i == -1) { - pr_err("no interrupt !!\n"); - return; - } - - /* Ack eirr */ - write_c0_eirr(1ULL << i); - - do_IRQ(i); -} diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index 609ec2534642..eab64b45dffd 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -15,18 +15,19 @@ #include <linux/serial_8250.h> #include <linux/serial_reg.h> +#include <asm/netlogic/haldefs.h> #include <asm/netlogic/xlr/iomap.h> #include <asm/netlogic/xlr/pic.h> #include <asm/netlogic/xlr/xlr.h> unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) { - nlm_reg_t *mmio; + uint64_t uartbase; unsigned int value; - /* XLR uart does not need any mapping of regs */ - mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift)); - value = netlogic_read_reg(mmio, 0); + /* sign extend to 64 bits, if needed */ + uartbase = (uint64_t)(long)p->membase; + value = nlm_read_reg(uartbase, offset); /* See XLR/XLS errata */ if (offset == UART_MSR) @@ -39,10 +40,10 @@ unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset) void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) { - nlm_reg_t *mmio; + uint64_t uartbase; - /* XLR uart does not need any mapping of regs */ - mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift)); + /* sign extend to 64 bits, if needed */ + uartbase = (uint64_t)(long)p->membase; /* See XLR/XLS errata */ if (offset == UART_MSR) @@ -50,7 +51,7 @@ void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) else if (offset == UART_MCR) value ^= 0x3; - netlogic_write_reg(mmio, 0, value); + nlm_write_reg(uartbase, offset, value); } #define PORT(_irq) \ @@ -82,15 +83,15 @@ static struct platform_device uart_device = { static int __init nlm_uart_init(void) { - nlm_reg_t *mmio; + unsigned long uartbase; - mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); - xlr_uart_data[0].membase = (void __iomem *)mmio; - xlr_uart_data[0].mapbase = CPHYSADDR((unsigned long)mmio); + uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); + xlr_uart_data[0].membase = (void __iomem *)uartbase; + xlr_uart_data[0].mapbase = CPHYSADDR(uartbase); - mmio = netlogic_io_mmio(NETLOGIC_IO_UART_1_OFFSET); - xlr_uart_data[1].membase = (void __iomem *)mmio; - xlr_uart_data[1].mapbase = CPHYSADDR((unsigned long)mmio); + uartbase = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_1_OFFSET); + xlr_uart_data[1].membase = (void __iomem *)uartbase; + xlr_uart_data[1].mapbase = CPHYSADDR(uartbase); return platform_device_register(&uart_device); } diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index cee25ddd0887..c9d066dedc4e 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -39,26 +39,33 @@ #include <asm/reboot.h> #include <asm/time.h> #include <asm/bootinfo.h> -#include <asm/smp-ops.h> #include <asm/netlogic/interrupt.h> #include <asm/netlogic/psb-bootinfo.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> #include <asm/netlogic/xlr/xlr.h> #include <asm/netlogic/xlr/iomap.h> #include <asm/netlogic/xlr/pic.h> #include <asm/netlogic/xlr/gpio.h> -unsigned long netlogic_io_base = (unsigned long)(DEFAULT_NETLOGIC_IO_BASE); -unsigned long nlm_common_ebase = 0x0; +uint64_t nlm_io_base = DEFAULT_NETLOGIC_IO_BASE; +uint64_t nlm_pic_base; struct psb_info nlm_prom_info; +unsigned long nlm_common_ebase = 0x0; + +/* default to uniprocessor */ +uint32_t nlm_coremask = 1, nlm_cpumask = 1; +int nlm_threads_per_core = 1; + static void __init nlm_early_serial_setup(void) { struct uart_port s; - nlm_reg_t *uart_base; + unsigned long uart_base; - uart_base = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET); + uart_base = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET); memset(&s, 0, sizeof(s)); s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; s.iotype = UPIO_MEM32; @@ -67,18 +74,18 @@ static void __init nlm_early_serial_setup(void) s.uartclk = PIC_CLKS_PER_SEC; s.serial_in = nlm_xlr_uart_in; s.serial_out = nlm_xlr_uart_out; - s.mapbase = (unsigned long)uart_base; + s.mapbase = uart_base; s.membase = (unsigned char __iomem *)uart_base; early_serial_setup(&s); } static void nlm_linux_exit(void) { - nlm_reg_t *mmio; + uint64_t gpiobase; - mmio = netlogic_io_mmio(NETLOGIC_IO_GPIO_OFFSET); + gpiobase = nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET); /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */ - netlogic_write_reg(mmio, NETLOGIC_GPIO_SWRESET_REG, 1); + nlm_write_reg(gpiobase, NETLOGIC_GPIO_SWRESET_REG, 1); for ( ; ; ) cpu_wait(); } @@ -96,6 +103,11 @@ const char *get_system_type(void) return "Netlogic XLR/XLS Series"; } +unsigned int nlm_get_cpu_frequency(void) +{ + return (unsigned int)nlm_prom_info.cpu_frequency; +} + void __init prom_free_prom_memory(void) { /* Nothing yet */ @@ -175,6 +187,7 @@ void __init prom_init(void) prom_infop = (struct psb_info *)(long)(int)fw_arg3; nlm_prom_info = *prom_infop; + nlm_pic_base = nlm_mmio_base(NETLOGIC_IO_PIC_OFFSET); nlm_early_serial_setup(); build_arcs_cmdline(argv); diff --git a/arch/mips/netlogic/xlr/smpboot.S b/arch/mips/netlogic/xlr/wakeup.c index 8cb7889ce0cc..db5d987d4881 100644 --- a/arch/mips/netlogic/xlr/smpboot.S +++ b/arch/mips/netlogic/xlr/wakeup.c @@ -33,68 +33,36 @@ */ #include <linux/init.h> +#include <linux/threads.h> #include <asm/asm.h> #include <asm/asm-offsets.h> -#include <asm/regdef.h> #include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/string.h> -/* - * Early code for secondary CPUs. This will get them out of the bootloader - * code and into linux. Needed because the bootloader area will be taken - * and initialized by linux. - */ - __CPUINIT -NESTED(prom_pre_boot_secondary_cpus, 16, sp) - .set mips64 - mfc0 t0, $15, 1 # read ebase - andi t0, 0x1f # t0 has the processor_id() - sll t0, 2 # offset in cpu array - - PTR_LA t1, nlm_cpu_ready # mark CPU ready - PTR_ADDU t1, t0 - li t2, 1 - sw t2, 0(t1) - - PTR_LA t1, nlm_cpu_unblock - PTR_ADDU t1, t0 -1: lw t2, 0(t1) # wait till unblocked - beqz t2, 1b - nop +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> +#include <asm/netlogic/mips-extns.h> - PTR_LA t1, nlm_next_sp - PTR_L sp, 0(t1) - PTR_LA t1, nlm_next_gp - PTR_L gp, 0(t1) +#include <asm/netlogic/xlr/iomap.h> +#include <asm/netlogic/xlr/pic.h> - PTR_LA t0, nlm_early_init_secondary - jalr t0 - nop - - PTR_LA t0, smp_bootstrap - jr t0 - nop -END(prom_pre_boot_secondary_cpus) - __FINIT - -/* - * NMI code, used for CPU wakeup, copied to reset entry - */ -NESTED(nlm_boot_smp_nmi, 0, sp) - .set push - .set noat - .set mips64 - .set noreorder +int __cpuinit xlr_wakeup_secondary_cpus(void) +{ + unsigned int i, boot_cpu; - /* Clear the NMI and BEV bits */ - MFC0 k0, CP0_STATUS - li k1, 0xffb7ffff - and k0, k0, k1 - MTC0 k0, CP0_STATUS + /* + * In case of RMI boot, hit with NMI to get the cores + * from bootloader to linux code. + */ + boot_cpu = hard_smp_processor_id(); + nlm_set_nmi_handler(nlm_rmiboot_preboot); + for (i = 0; i < NR_CPUS; i++) { + if (i == boot_cpu || (nlm_cpumask & (1u << i)) == 0) + continue; + nlm_pic_send_ipi(nlm_pic_base, i, 1, 1); /* send NMI */ + } - PTR_LA k1, secondary_entry_point - PTR_L k0, 0(k1) - jr k0 - nop - .set pop -END(nlm_boot_smp_nmi) + return 0; +} diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index bb82cbdbc62a..c3ac4b086eb2 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ ops-bcm63xx.o obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o +obj-$(CONFIG_SOC_AR724X) += pci-ath724x.o # # These are still pretty much in the old state, watch, go blind. @@ -55,7 +56,7 @@ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o -obj-$(CONFIG_NLM_XLR) += pci-xlr.o +obj-$(CONFIG_CPU_XLR) += pci-xlr.o ifdef CONFIG_PCI_MSI obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index 5d530f89d872..d37be36dc659 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -162,7 +162,7 @@ msi_irq_allocated: msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32; break; default: - panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type\n"); + panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type"); } msg.data = irq - OCTEON_IRQ_MSI_BIT0; diff --git a/arch/mips/pci/ops-pmcmsp.c b/arch/mips/pci/ops-pmcmsp.c index 8fbfbf2b931c..389bf669d56e 100644 --- a/arch/mips/pci/ops-pmcmsp.c +++ b/arch/mips/pci/ops-pmcmsp.c @@ -405,7 +405,7 @@ int msp_pcibios_config_access(unsigned char access_type, if (pciirqflag == 0) { ret = request_irq(MSP_INT_PCI,/* Hardcoded internal MSP7120 wiring */ bpci_interrupt, - IRQF_SHARED | IRQF_DISABLED, + IRQF_SHARED, "PMC MSP PCI Host", preg); if (ret != 0) diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c index 6a3bdb5ffa80..02d64f77e967 100644 --- a/arch/mips/pci/ops-tx3927.c +++ b/arch/mips/pci/ops-tx3927.c @@ -225,7 +225,7 @@ void __init tx3927_setup_pcierr_irq(void) { if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI, tx3927_pcierr_interrupt, - IRQF_DISABLED, "PCI error", + 0, "PCI error", (void *)TX3927_PCIC_REG)) printk(KERN_WARNING "Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c index b5ce041cdafb..ec125bed721c 100644 --- a/arch/mips/pci/pci-alchemy.c +++ b/arch/mips/pci/pci-alchemy.c @@ -13,9 +13,11 @@ #include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/syscore_ops.h> #include <linux/vmalloc.h> #include <asm/mach-au1x00/au1000.h> +#include <asm/tlbmisc.h> #ifdef CONFIG_DEBUG_PCI #define DBG(x...) printk(KERN_DEBUG x) @@ -41,6 +43,12 @@ struct alchemy_pci_context { int (*board_pci_idsel)(unsigned int devsel, int assert); }; +/* for syscore_ops. There's only one PCI controller on Alchemy chips, so this + * should suffice for now. + */ +static struct alchemy_pci_context *__alchemy_pci_ctx; + + /* IO/MEM resources for PCI. Keep the memres in sync with __fixup_bigphys_addr * in arch/mips/alchemy/common/setup.c */ @@ -99,18 +107,6 @@ static int config_access(unsigned char access_type, struct pci_bus *bus, return -1; } - /* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired - * on resume, clearing our wired entry. Unfortunately the ->resume() - * callback is called way way way too late (and ->suspend() too early) - * to have them destroy and recreate it. Instead just test if c0_wired - * is now lower than the index we retrieved before suspending and then - * recreate the entry if necessary. Of course this is totally bonkers - * and breaks as soon as someone else adds another wired entry somewhere - * else. Anyone have any ideas how to handle this better? - */ - if (unlikely(read_c0_wired() < ctx->wired_entry)) - alchemy_pci_wired_entry(ctx); - local_irq_save(flags); r = __raw_readl(ctx->regs + PCI_REG_STATCMD) & 0x0000ffff; r |= PCI_STATCMD_STATUS(0x2000); @@ -304,6 +300,62 @@ static int alchemy_pci_def_idsel(unsigned int devsel, int assert) return 1; /* success */ } +/* save PCI controller register contents. */ +static int alchemy_pci_suspend(void) +{ + struct alchemy_pci_context *ctx = __alchemy_pci_ctx; + if (!ctx) + return 0; + + ctx->pm[0] = __raw_readl(ctx->regs + PCI_REG_CMEM); + ctx->pm[1] = __raw_readl(ctx->regs + PCI_REG_CONFIG) & 0x0009ffff; + ctx->pm[2] = __raw_readl(ctx->regs + PCI_REG_B2BMASK_CCH); + ctx->pm[3] = __raw_readl(ctx->regs + PCI_REG_B2BBASE0_VID); + ctx->pm[4] = __raw_readl(ctx->regs + PCI_REG_B2BBASE1_SID); + ctx->pm[5] = __raw_readl(ctx->regs + PCI_REG_MWMASK_DEV); + ctx->pm[6] = __raw_readl(ctx->regs + PCI_REG_MWBASE_REV_CCL); + ctx->pm[7] = __raw_readl(ctx->regs + PCI_REG_ID); + ctx->pm[8] = __raw_readl(ctx->regs + PCI_REG_CLASSREV); + ctx->pm[9] = __raw_readl(ctx->regs + PCI_REG_PARAM); + ctx->pm[10] = __raw_readl(ctx->regs + PCI_REG_MBAR); + ctx->pm[11] = __raw_readl(ctx->regs + PCI_REG_TIMEOUT); + + return 0; +} + +static void alchemy_pci_resume(void) +{ + struct alchemy_pci_context *ctx = __alchemy_pci_ctx; + if (!ctx) + return; + + __raw_writel(ctx->pm[0], ctx->regs + PCI_REG_CMEM); + __raw_writel(ctx->pm[2], ctx->regs + PCI_REG_B2BMASK_CCH); + __raw_writel(ctx->pm[3], ctx->regs + PCI_REG_B2BBASE0_VID); + __raw_writel(ctx->pm[4], ctx->regs + PCI_REG_B2BBASE1_SID); + __raw_writel(ctx->pm[5], ctx->regs + PCI_REG_MWMASK_DEV); + __raw_writel(ctx->pm[6], ctx->regs + PCI_REG_MWBASE_REV_CCL); + __raw_writel(ctx->pm[7], ctx->regs + PCI_REG_ID); + __raw_writel(ctx->pm[8], ctx->regs + PCI_REG_CLASSREV); + __raw_writel(ctx->pm[9], ctx->regs + PCI_REG_PARAM); + __raw_writel(ctx->pm[10], ctx->regs + PCI_REG_MBAR); + __raw_writel(ctx->pm[11], ctx->regs + PCI_REG_TIMEOUT); + wmb(); + __raw_writel(ctx->pm[1], ctx->regs + PCI_REG_CONFIG); + wmb(); + + /* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired + * on resume, making it necessary to recreate it as soon as possible. + */ + ctx->wired_entry = 8191; /* impossibly high value */ + alchemy_pci_wired_entry(ctx); /* install it */ +} + +static struct syscore_ops alchemy_pci_pmops = { + .suspend = alchemy_pci_suspend, + .resume = alchemy_pci_resume, +}; + static int __devinit alchemy_pci_probe(struct platform_device *pdev) { struct alchemy_pci_platdata *pd = pdev->dev.platform_data; @@ -396,7 +448,8 @@ static int __devinit alchemy_pci_probe(struct platform_device *pdev) ret = -ENOMEM; goto out4; } - ctx->wired_entry = 8192; /* impossibly high value */ + ctx->wired_entry = 8191; /* impossibly high value */ + alchemy_pci_wired_entry(ctx); /* install it */ set_io_port_base((unsigned long)ctx->alchemy_pci_ctrl.io_map_base); @@ -408,7 +461,9 @@ static int __devinit alchemy_pci_probe(struct platform_device *pdev) __raw_writel(val, ctx->regs + PCI_REG_CONFIG); wmb(); + __alchemy_pci_ctx = ctx; platform_set_drvdata(pdev, ctx); + register_syscore_ops(&alchemy_pci_pmops); register_pci_controller(&ctx->alchemy_pci_ctrl); return 0; @@ -425,68 +480,11 @@ out: return ret; } - -#ifdef CONFIG_PM -/* save PCI controller register contents. */ -static int alchemy_pci_suspend(struct device *dev) -{ - struct alchemy_pci_context *ctx = dev_get_drvdata(dev); - - ctx->pm[0] = __raw_readl(ctx->regs + PCI_REG_CMEM); - ctx->pm[1] = __raw_readl(ctx->regs + PCI_REG_CONFIG) & 0x0009ffff; - ctx->pm[2] = __raw_readl(ctx->regs + PCI_REG_B2BMASK_CCH); - ctx->pm[3] = __raw_readl(ctx->regs + PCI_REG_B2BBASE0_VID); - ctx->pm[4] = __raw_readl(ctx->regs + PCI_REG_B2BBASE1_SID); - ctx->pm[5] = __raw_readl(ctx->regs + PCI_REG_MWMASK_DEV); - ctx->pm[6] = __raw_readl(ctx->regs + PCI_REG_MWBASE_REV_CCL); - ctx->pm[7] = __raw_readl(ctx->regs + PCI_REG_ID); - ctx->pm[8] = __raw_readl(ctx->regs + PCI_REG_CLASSREV); - ctx->pm[9] = __raw_readl(ctx->regs + PCI_REG_PARAM); - ctx->pm[10] = __raw_readl(ctx->regs + PCI_REG_MBAR); - ctx->pm[11] = __raw_readl(ctx->regs + PCI_REG_TIMEOUT); - - return 0; -} - -static int alchemy_pci_resume(struct device *dev) -{ - struct alchemy_pci_context *ctx = dev_get_drvdata(dev); - - __raw_writel(ctx->pm[0], ctx->regs + PCI_REG_CMEM); - __raw_writel(ctx->pm[2], ctx->regs + PCI_REG_B2BMASK_CCH); - __raw_writel(ctx->pm[3], ctx->regs + PCI_REG_B2BBASE0_VID); - __raw_writel(ctx->pm[4], ctx->regs + PCI_REG_B2BBASE1_SID); - __raw_writel(ctx->pm[5], ctx->regs + PCI_REG_MWMASK_DEV); - __raw_writel(ctx->pm[6], ctx->regs + PCI_REG_MWBASE_REV_CCL); - __raw_writel(ctx->pm[7], ctx->regs + PCI_REG_ID); - __raw_writel(ctx->pm[8], ctx->regs + PCI_REG_CLASSREV); - __raw_writel(ctx->pm[9], ctx->regs + PCI_REG_PARAM); - __raw_writel(ctx->pm[10], ctx->regs + PCI_REG_MBAR); - __raw_writel(ctx->pm[11], ctx->regs + PCI_REG_TIMEOUT); - wmb(); - __raw_writel(ctx->pm[1], ctx->regs + PCI_REG_CONFIG); - wmb(); - - return 0; -} - -static const struct dev_pm_ops alchemy_pci_pmops = { - .suspend = alchemy_pci_suspend, - .resume = alchemy_pci_resume, -}; - -#define ALCHEMY_PCICTL_PM (&alchemy_pci_pmops) - -#else -#define ALCHEMY_PCICTL_PM NULL -#endif - static struct platform_driver alchemy_pcictl_driver = { .probe = alchemy_pci_probe, .driver = { .name = "alchemy-pci", .owner = THIS_MODULE, - .pm = ALCHEMY_PCICTL_PM, }, }; diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c new file mode 100644 index 000000000000..a4dd24a4130b --- /dev/null +++ b/arch/mips/pci/pci-ath724x.c @@ -0,0 +1,174 @@ +/* + * Atheros 724x PCI support + * + * Copyright (C) 2011 RenĂ© Bolldorf <xsecute@googlemail.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 <linux/pci.h> +#include <asm/mach-ath79/pci-ath724x.h> + +#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) +#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) + +#define ATH724X_PCI_DEV_BASE 0x14000000 +#define ATH724X_PCI_MEM_BASE 0x10000000 +#define ATH724X_PCI_MEM_SIZE 0x08000000 + +static DEFINE_SPINLOCK(ath724x_pci_lock); +static struct ath724x_pci_data *pci_data; +static int pci_data_size; + +static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, uint32_t *value) +{ + unsigned long flags, addr, tval, mask; + + if (devfn) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + spin_lock_irqsave(&ath724x_pci_lock, flags); + + switch (size) { + case 1: + addr = where & ~3; + mask = 0xff000000 >> ((where % 4) * 8); + tval = reg_read(ATH724X_PCI_DEV_BASE + addr); + tval = tval & ~mask; + *value = (tval >> ((4 - (where % 4))*8)); + break; + case 2: + addr = where & ~3; + mask = 0xffff0000 >> ((where % 4)*8); + tval = reg_read(ATH724X_PCI_DEV_BASE + addr); + tval = tval & ~mask; + *value = (tval >> ((4 - (where % 4))*8)); + break; + case 4: + *value = reg_read(ATH724X_PCI_DEV_BASE + where); + break; + default: + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, uint32_t value) +{ + unsigned long flags, tval, addr, mask; + + if (devfn) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + spin_lock_irqsave(&ath724x_pci_lock, flags); + + switch (size) { + case 1: + addr = (ATH724X_PCI_DEV_BASE + where) & ~3; + mask = 0xff000000 >> ((where % 4)*8); + tval = reg_read(addr); + tval = tval & ~mask; + tval |= (value << ((4 - (where % 4))*8)) & mask; + reg_write(addr, tval); + break; + case 2: + addr = (ATH724X_PCI_DEV_BASE + where) & ~3; + mask = 0xffff0000 >> ((where % 4)*8); + tval = reg_read(addr); + tval = tval & ~mask; + tval |= (value << ((4 - (where % 4))*8)) & mask; + reg_write(addr, tval); + break; + case 4: + reg_write((ATH724X_PCI_DEV_BASE + where), value); + break; + default: + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ath724x_pci_ops = { + .read = ath724x_pci_read, + .write = ath724x_pci_write, +}; + +static struct resource ath724x_io_resource = { + .name = "PCI IO space", + .start = 0, + .end = 0, + .flags = IORESOURCE_IO, +}; + +static struct resource ath724x_mem_resource = { + .name = "PCI memory space", + .start = ATH724X_PCI_MEM_BASE, + .end = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct pci_controller ath724x_pci_controller = { + .pci_ops = &ath724x_pci_ops, + .io_resource = &ath724x_io_resource, + .mem_resource = &ath724x_mem_resource, +}; + +void ath724x_pci_add_data(struct ath724x_pci_data *data, int size) +{ + pci_data = data; + pci_data_size = size; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) +{ + unsigned int devfn = dev->devfn; + int irq = -1; + + if (devfn > pci_data_size - 1) + return irq; + + irq = pci_data[devfn].irq; + + return irq; +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + unsigned int devfn = dev->devfn; + + if (devfn > pci_data_size - 1) + return PCIBIOS_DEVICE_NOT_FOUND; + + dev->dev.platform_data = pci_data[devfn].pdata; + + return PCIBIOS_SUCCESSFUL; +} + +static int __init ath724x_pcibios_init(void) +{ + register_pci_controller(&ath724x_pci_controller); + + return PCIBIOS_SUCCESSFUL; +} + +arch_initcall(ath724x_pcibios_init); diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index 82e0fde1dba0..39eb7c417e2f 100644 --- a/arch/mips/pci/pci-bcm63xx.c +++ b/arch/mips/pci/pci-bcm63xx.c @@ -99,7 +99,7 @@ static int __init bcm63xx_pci_init(void) unsigned int mem_size; u32 val; - if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358()) + if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358() && !BCMCPU_IS_6368()) return -ENODEV; if (!bcm63xx_pci_enabled) @@ -159,7 +159,7 @@ static int __init bcm63xx_pci_init(void) /* setup PCI to local bus access, used by PCI device to target * local RAM while bus mastering */ bcm63xx_int_cfg_writel(0, PCI_BASE_ADDRESS_3); - if (BCMCPU_IS_6358()) + if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) val = MPI_SP0_REMAP_ENABLE_MASK; else val = 0; diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c index ed1c54284b8f..52a1ba70b3b6 100644 --- a/arch/mips/pci/pci-octeon.c +++ b/arch/mips/pci/pci-octeon.c @@ -99,7 +99,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) */ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4); /* Set latency timers for all devices */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); /* Enable reporting System errors and parity errors on all devices */ /* Enable parity checking and error reporting */ @@ -109,7 +109,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) if (dev->subordinate) { /* Set latency timers on sub bridges */ - pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48); + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 64); /* More bridge error detection */ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config); config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR; @@ -121,14 +121,10 @@ int pcibios_plat_dev_init(struct pci_dev *dev) if (pos) { /* Update Device Control */ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config); - /* Correctable Error Reporting */ - config |= PCI_EXP_DEVCTL_CERE; - /* Non-Fatal Error Reporting */ - config |= PCI_EXP_DEVCTL_NFERE; - /* Fatal Error Reporting */ - config |= PCI_EXP_DEVCTL_FERE; - /* Unsupported Request */ - config |= PCI_EXP_DEVCTL_URRE; + config |= PCI_EXP_DEVCTL_CERE; /* Correctable Error Reporting */ + config |= PCI_EXP_DEVCTL_NFERE; /* Non-Fatal Error Reporting */ + config |= PCI_EXP_DEVCTL_FERE; /* Fatal Error Reporting */ + config |= PCI_EXP_DEVCTL_URRE; /* Unsupported Request */ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config); } diff --git a/arch/mips/pci/pci-tx4927.c b/arch/mips/pci/pci-tx4927.c index a5807406a7f1..a032ae0a533d 100644 --- a/arch/mips/pci/pci-tx4927.c +++ b/arch/mips/pci/pci-tx4927.c @@ -85,7 +85,7 @@ void __init tx4927_setup_pcierr_irq(void) { if (request_irq(TXX9_IRQ_BASE + TX4927_IR_PCIERR, tx4927_pcierr_interrupt, - IRQF_DISABLED, "PCI error", + 0, "PCI error", (void *)TX4927_PCIC_REG)) printk(KERN_WARNING "Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-tx4938.c b/arch/mips/pci/pci-tx4938.c index 20e45f30b2ef..141bba562488 100644 --- a/arch/mips/pci/pci-tx4938.c +++ b/arch/mips/pci/pci-tx4938.c @@ -136,7 +136,7 @@ void __init tx4938_setup_pcierr_irq(void) { if (request_irq(TXX9_IRQ_BASE + TX4938_IR_PCIERR, tx4927_pcierr_interrupt, - IRQF_DISABLED, "PCI error", + 0, "PCI error", (void *)TX4927_PCIC_REG)) printk(KERN_WARNING "Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-tx4939.c b/arch/mips/pci/pci-tx4939.c index 9ef840693baf..c10fbf2a19dc 100644 --- a/arch/mips/pci/pci-tx4939.c +++ b/arch/mips/pci/pci-tx4939.c @@ -101,7 +101,7 @@ void __init tx4939_setup_pcierr_irq(void) { if (request_irq(TXX9_IRQ_BASE + TX4939_IR_PCIERR, tx4927_pcierr_interrupt, - IRQF_DISABLED, "PCI error", + 0, "PCI error", (void *)TX4939_PCIC_REG)) pr_warning("Failed to request irq for PCIERR\n"); } diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c index 38fece16c435..3d701a962ef4 100644 --- a/arch/mips/pci/pci-xlr.c +++ b/arch/mips/pci/pci-xlr.c @@ -36,12 +36,18 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/msi.h> #include <linux/mm.h> +#include <linux/irq.h> +#include <linux/irqdesc.h> #include <linux/console.h> #include <asm/io.h> #include <asm/netlogic/interrupt.h> +#include <asm/netlogic/haldefs.h> + +#include <asm/netlogic/xlr/msidef.h> #include <asm/netlogic/xlr/iomap.h> #include <asm/netlogic/xlr/pic.h> #include <asm/netlogic/xlr/xlr.h> @@ -150,7 +156,7 @@ struct pci_controller nlm_pci_controller = { .io_offset = 0x00000000UL, }; -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +static int get_irq_vector(const struct pci_dev *dev) { if (!nlm_chip_is_xls()) return PIC_PCIX_IRQ; /* for XLR just one IRQ*/ @@ -182,6 +188,101 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) return 0; } +#ifdef CONFIG_PCI_MSI +void destroy_irq(unsigned int irq) +{ + /* nothing to do yet */ +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + destroy_irq(irq); +} + +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) +{ + struct msi_msg msg; + int irq, ret; + + irq = get_irq_vector(dev); + if (irq <= 0) + return 1; + + msg.address_hi = MSI_ADDR_BASE_HI; + msg.address_lo = MSI_ADDR_BASE_LO | + MSI_ADDR_DEST_MODE_PHYSICAL | + MSI_ADDR_REDIRECTION_CPU; + + msg.data = MSI_DATA_TRIGGER_EDGE | + MSI_DATA_LEVEL_ASSERT | + MSI_DATA_DELIVERY_FIXED; + + ret = irq_set_msi_desc(irq, desc); + if (ret < 0) { + destroy_irq(irq); + return ret; + } + + write_msi_msg(irq, &msg); + return 0; +} +#endif + +/* Extra ACK needed for XLR on chip PCI controller */ +static void xlr_pci_ack(struct irq_data *d) +{ + uint64_t pcibase = nlm_mmio_base(NETLOGIC_IO_PCIX_OFFSET); + + nlm_read_reg(pcibase, (0x140 >> 2)); +} + +/* Extra ACK needed for XLS on chip PCIe controller */ +static void xls_pcie_ack(struct irq_data *d) +{ + uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); + + switch (d->irq) { + case PIC_PCIE_LINK0_IRQ: + nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK1_IRQ: + nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK2_IRQ: + nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK3_IRQ: + nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); + break; + } +} + +/* For XLS B silicon, the 3,4 PCI interrupts are different */ +static void xls_pcie_ack_b(struct irq_data *d) +{ + uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); + + switch (d->irq) { + case PIC_PCIE_LINK0_IRQ: + nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); + break; + case PIC_PCIE_LINK1_IRQ: + nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); + break; + case PIC_PCIE_XLSB0_LINK2_IRQ: + nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); + break; + case PIC_PCIE_XLSB0_LINK3_IRQ: + nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); + break; + } +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return get_irq_vector(dev); +} + /* Do platform specific device initialization at pci_enable_device() time */ int pcibios_plat_dev_init(struct pci_dev *dev) { @@ -204,6 +305,31 @@ static int __init pcibios_init(void) pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n"); register_pci_controller(&nlm_pci_controller); + /* + * For PCI interrupts, we need to ack the PCI controller too, overload + * irq handler data to do this + */ + if (nlm_chip_is_xls()) { + if (nlm_chip_is_xls_b()) { + irq_set_handler_data(PIC_PCIE_LINK0_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_LINK1_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ, + xls_pcie_ack_b); + irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, + xls_pcie_ack_b); + } else { + irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack); + irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack); + } + } else { + /* XLR PCI controller ACK */ + irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack); + } + return 0; } diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index fa8e378413b1..aec2b111d35b 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -4,8 +4,11 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * - * Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2003, 04, 11 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2011 Wind River Systems, + * written by Ralf Baechle (ralf@linux-mips.org) */ +#include <linux/bug.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/bootmem.h> @@ -14,6 +17,8 @@ #include <linux/types.h> #include <linux/pci.h> +#include <asm/cpu-info.h> + /* * Indicate whether we respect the PCI setup left by the firmware. * @@ -157,10 +162,32 @@ out: "Skipping PCI bus scan due to resource conflict\n"); } +static void __init pcibios_set_cache_line_size(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned int lsize; + + /* + * Set PCI cacheline size to that of the highest level in the + * cache hierarchy. + */ + lsize = c->dcache.linesz; + lsize = c->scache.linesz ? : lsize; + lsize = c->tcache.linesz ? : lsize; + + BUG_ON(!lsize); + + pci_dfl_cache_line_size = lsize >> 2; + + pr_debug("PCI: pci_cache_line_size set to %d bytes\n", lsize); +} + static int __init pcibios_init(void) { struct pci_controller *hose; + pcibios_set_cache_line_size(); + /* Scan all of the recorded PCI controllers. */ for (hose = hose_head; hose; hose = hose->next) pcibios_scanbus(hose); diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c index 0583c463e5f1..fdb4d558c0cc 100644 --- a/arch/mips/pci/pcie-octeon.c +++ b/arch/mips/pci/pcie-octeon.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2007, 2008 Cavium Networks + * Copyright (C) 2007, 2008, 2009, 2010, 2011 Cavium Networks */ #include <linux/kernel.h> #include <linux/init.h> @@ -11,15 +11,32 @@ #include <linux/interrupt.h> #include <linux/time.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/octeon/octeon.h> #include <asm/octeon/cvmx-npei-defs.h> #include <asm/octeon/cvmx-pciercx-defs.h> #include <asm/octeon/cvmx-pescx-defs.h> #include <asm/octeon/cvmx-pexp-defs.h> +#include <asm/octeon/cvmx-pemx-defs.h> +#include <asm/octeon/cvmx-dpi-defs.h> +#include <asm/octeon/cvmx-sli-defs.h> +#include <asm/octeon/cvmx-sriox-defs.h> #include <asm/octeon/cvmx-helper-errata.h> #include <asm/octeon/pci-octeon.h> +#define MRRS_CN5XXX 0 /* 128 byte Max Read Request Size */ +#define MPS_CN5XXX 0 /* 128 byte Max Packet Size (Limit of most PCs) */ +#define MRRS_CN6XXX 3 /* 1024 byte Max Read Request Size */ +#define MPS_CN6XXX 0 /* 128 byte Max Packet Size (Limit of most PCs) */ + +/* Module parameter to disable PCI probing */ +static int pcie_disable; +module_param(pcie_disable, int, S_IRUGO); + +static int enable_pcie_14459_war; +static int enable_pcie_bus_num_war[2]; + union cvmx_pcie_address { uint64_t u64; struct { @@ -75,6 +92,8 @@ union cvmx_pcie_address { } mem; }; +static int cvmx_pcie_rc_initialize(int pcie_port); + #include <dma-coherence.h> /** @@ -154,12 +173,21 @@ static inline uint64_t cvmx_pcie_get_mem_size(int pcie_port) */ static uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset) { - union cvmx_pescx_cfg_rd pescx_cfg_rd; - pescx_cfg_rd.u64 = 0; - pescx_cfg_rd.s.addr = cfg_offset; - cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64); - pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port)); - return pescx_cfg_rd.s.data; + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + union cvmx_pescx_cfg_rd pescx_cfg_rd; + pescx_cfg_rd.u64 = 0; + pescx_cfg_rd.s.addr = cfg_offset; + cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64); + pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port)); + return pescx_cfg_rd.s.data; + } else { + union cvmx_pemx_cfg_rd pemx_cfg_rd; + pemx_cfg_rd.u64 = 0; + pemx_cfg_rd.s.addr = cfg_offset; + cvmx_write_csr(CVMX_PEMX_CFG_RD(pcie_port), pemx_cfg_rd.u64); + pemx_cfg_rd.u64 = cvmx_read_csr(CVMX_PEMX_CFG_RD(pcie_port)); + return pemx_cfg_rd.s.data; + } } /** @@ -173,11 +201,19 @@ static uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset) static void cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset, uint32_t val) { - union cvmx_pescx_cfg_wr pescx_cfg_wr; - pescx_cfg_wr.u64 = 0; - pescx_cfg_wr.s.addr = cfg_offset; - pescx_cfg_wr.s.data = val; - cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64); + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + union cvmx_pescx_cfg_wr pescx_cfg_wr; + pescx_cfg_wr.u64 = 0; + pescx_cfg_wr.s.addr = cfg_offset; + pescx_cfg_wr.s.data = val; + cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64); + } else { + union cvmx_pemx_cfg_wr pemx_cfg_wr; + pemx_cfg_wr.u64 = 0; + pemx_cfg_wr.s.addr = cfg_offset; + pemx_cfg_wr.s.data = val; + cvmx_write_csr(CVMX_PEMX_CFG_WR(pcie_port), pemx_cfg_wr.u64); + } } /** @@ -348,7 +384,6 @@ static void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) { union cvmx_pciercx_cfg030 pciercx_cfg030; - union cvmx_npei_ctl_status2 npei_ctl_status2; union cvmx_pciercx_cfg070 pciercx_cfg070; union cvmx_pciercx_cfg001 pciercx_cfg001; union cvmx_pciercx_cfg032 pciercx_cfg032; @@ -365,21 +400,21 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) /* Max Read Request Size (PCIE*_CFG030[MRRS]) */ /* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */ /* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */ - pciercx_cfg030.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); - /* - * Max payload size = 128 bytes for best Octeon DMA - * performance. - */ - pciercx_cfg030.s.mps = 0; + + pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); + if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { + pciercx_cfg030.s.mps = MPS_CN5XXX; + pciercx_cfg030.s.mrrs = MRRS_CN5XXX; + } else { + pciercx_cfg030.s.mps = MPS_CN6XXX; + pciercx_cfg030.s.mrrs = MRRS_CN6XXX; + } /* - * Max read request size = 128 bytes for best Octeon DMA - * performance. + * Enable relaxed order processing. This will allow devices to + * affect read response ordering. */ - pciercx_cfg030.s.mrrs = 0; - /* Enable relaxed ordering. */ pciercx_cfg030.s.ro_en = 1; - /* Enable no snoop. */ + /* Enable no snoop processing. Not used by Octeon */ pciercx_cfg030.s.ns_en = 1; /* Correctable error reporting enable. */ pciercx_cfg030.s.ce_en = 1; @@ -389,50 +424,67 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) pciercx_cfg030.s.fe_en = 1; /* Unsupported request reporting enable. */ pciercx_cfg030.s.ur_en = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), - pciercx_cfg030.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32); - /* - * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match - * PCIE*_CFG030[MPS] - * - * Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not - * exceed PCIE*_CFG030[MRRS]. - */ - npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); - /* Max payload size = 128 bytes for best Octeon DMA performance */ - npei_ctl_status2.s.mps = 0; - /* Max read request size = 128 bytes for best Octeon DMA performance */ - npei_ctl_status2.s.mrrs = 0; - if (pcie_port) - npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */ - else - npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */ - cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); + + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + union cvmx_npei_ctl_status2 npei_ctl_status2; + /* + * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match + * PCIE*_CFG030[MPS]. Max Read Request Size + * (NPEI_CTL_STATUS2[MRRS]) must not exceed + * PCIE*_CFG030[MRRS] + */ + npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); + /* Max payload size = 128 bytes for best Octeon DMA performance */ + npei_ctl_status2.s.mps = MPS_CN5XXX; + /* Max read request size = 128 bytes for best Octeon DMA performance */ + npei_ctl_status2.s.mrrs = MRRS_CN5XXX; + if (pcie_port) + npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */ + else + npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */ + + cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); + } else { + /* + * Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match + * PCIE*_CFG030[MPS]. Max Read Request Size + * (DPI_SLI_PRTX_CFG[MRRS]) must not exceed + * PCIE*_CFG030[MRRS]. + */ + union cvmx_dpi_sli_prtx_cfg prt_cfg; + union cvmx_sli_s2m_portx_ctl sli_s2m_portx_ctl; + prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port)); + prt_cfg.s.mps = MPS_CN6XXX; + prt_cfg.s.mrrs = MRRS_CN6XXX; + /* Max outstanding load request. */ + prt_cfg.s.molr = 32; + cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64); + + sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port)); + sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX; + cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64); + } /* ECRC Generation (PCIE*_CFG070[GE,CE]) */ - pciercx_cfg070.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); + pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); pciercx_cfg070.s.ge = 1; /* ECRC generation enable. */ pciercx_cfg070.s.ce = 1; /* ECRC check enable. */ - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), - pciercx_cfg070.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32); /* - * Access Enables (PCIE*_CFG001[MSAE,ME]) ME and MSAE should - * always be set. - * - * Interrupt Disable (PCIE*_CFG001[I_DIS]) System Error - * Message Enable (PCIE*_CFG001[SEE]) + * Access Enables (PCIE*_CFG001[MSAE,ME]) + * ME and MSAE should always be set. + * Interrupt Disable (PCIE*_CFG001[I_DIS]) + * System Error Message Enable (PCIE*_CFG001[SEE]) */ - pciercx_cfg001.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); + pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); pciercx_cfg001.s.msae = 1; /* Memory space enable. */ pciercx_cfg001.s.me = 1; /* Bus master enable. */ pciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */ pciercx_cfg001.s.see = 1; /* SERR# enable */ - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), - pciercx_cfg001.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32); /* Advanced Error Recovery Message Enables */ /* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */ @@ -440,14 +492,11 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) /* Use CVMX_PCIERCX_CFG067 hardware default */ cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0); - /* Active State Power Management (PCIE*_CFG032[ASLPC]) */ - pciercx_cfg032.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); - pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), - pciercx_cfg032.u32); - /* Entrance Latencies (PCIE*_CFG451[L0EL,L1EL]) */ + /* Active State Power Management (PCIE*_CFG032[ASLPC]) */ + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); + pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32); /* * Link Width Mode (PCIERCn_CFG452[LME]) - Set during @@ -462,8 +511,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) pciercx_cfg006.s.pbnum = 1; pciercx_cfg006.s.sbnum = 1; pciercx_cfg006.s.subbnum = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), - pciercx_cfg006.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32); + /* * Memory-mapped I/O BAR (PCIERCn_CFG008) @@ -473,8 +522,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) pciercx_cfg008.u32 = 0; pciercx_cfg008.s.mb_addr = 0x100; pciercx_cfg008.s.ml_addr = 0; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), - pciercx_cfg008.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32); + /* * Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) @@ -482,72 +531,51 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) * PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < * PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] */ - pciercx_cfg009.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); - pciercx_cfg010.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); - pciercx_cfg011.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); + pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); + pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); + pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); pciercx_cfg009.s.lmem_base = 0x100; pciercx_cfg009.s.lmem_limit = 0; pciercx_cfg010.s.umem_base = 0x100; pciercx_cfg011.s.umem_limit = 0; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), - pciercx_cfg009.u32); - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), - pciercx_cfg010.u32); - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), - pciercx_cfg011.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32); /* * System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) * PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) - */ - pciercx_cfg035.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); - /* System error on correctable error enable. */ - pciercx_cfg035.s.secee = 1; - /* System error on fatal error enable. */ - pciercx_cfg035.s.sefee = 1; - /* System error on non-fatal error enable. */ - pciercx_cfg035.s.senfee = 1; - /* PME interrupt enable. */ - pciercx_cfg035.s.pmeie = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), - pciercx_cfg035.u32); + */ + pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); + pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */ + pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */ + pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */ + pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */ + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32); /* * Advanced Error Recovery Interrupt Enables * (PCIERCn_CFG075[CERE,NFERE,FERE]) */ - pciercx_cfg075.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); - /* Correctable error reporting enable. */ - pciercx_cfg075.s.cere = 1; - /* Non-fatal error reporting enable. */ - pciercx_cfg075.s.nfere = 1; - /* Fatal error reporting enable. */ - pciercx_cfg075.s.fere = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), - pciercx_cfg075.u32); + pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); + pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */ + pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */ + pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */ + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32); - /* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], + /* + * HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], * PCIERCn_CFG034[DLLS_EN,CCINT_EN]) */ - pciercx_cfg034.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); - /* Hot-plug interrupt enable. */ - pciercx_cfg034.s.hpint_en = 1; - /* Data Link Layer state changed enable */ - pciercx_cfg034.s.dlls_en = 1; - /* Command completed interrupt enable. */ - pciercx_cfg034.s.ccint_en = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), - pciercx_cfg034.u32); + pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); + pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */ + pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */ + pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */ + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32); } /** - * Initialize a host mode PCIe link. This function takes a PCIe + * Initialize a host mode PCIe gen 1 link. This function takes a PCIe * port from reset to a link up state. Software can then begin * configuring the rest of the link. * @@ -555,7 +583,7 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port) * * Returns Zero on success */ -static int __cvmx_pcie_rc_initialize_link(int pcie_port) +static int __cvmx_pcie_rc_initialize_link_gen1(int pcie_port) { uint64_t start_cycle; union cvmx_pescx_ctl_status pescx_ctl_status; @@ -564,18 +592,15 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) union cvmx_pciercx_cfg448 pciercx_cfg448; /* Set the lane width */ - pciercx_cfg452.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); + pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); - if (pescx_ctl_status.s.qlm_cfg == 0) { + if (pescx_ctl_status.s.qlm_cfg == 0) /* We're in 8 lane (56XX) or 4 lane (54XX) mode */ pciercx_cfg452.s.lme = 0xf; - } else { + else /* We're in 4 lane (56XX) or 2 lane (52XX) mode */ pciercx_cfg452.s.lme = 0x7; - } - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), - pciercx_cfg452.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32); /* * CN52XX pass 1.x has an errata where length mismatches on UR @@ -584,19 +609,15 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) */ if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { union cvmx_pciercx_cfg455 pciercx_cfg455; - pciercx_cfg455.u32 = - cvmx_pcie_cfgx_read(pcie_port, - CVMX_PCIERCX_CFG455(pcie_port)); + pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port)); pciercx_cfg455.s.m_cpl_len_err = 1; - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), - pciercx_cfg455.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32); } /* Lane swap needs to be manually enabled for CN52XX */ if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) { pescx_ctl_status.s.lane_swp = 1; - cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), - pescx_ctl_status.u64); + cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64); } /* Bring up the link */ @@ -612,24 +633,18 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) __cvmx_helper_errata_qlm_disable_2nd_order_cdr(0); /* Wait for the link to come up */ - cvmx_dprintf("PCIe: Waiting for port %d link\n", pcie_port); start_cycle = cvmx_get_cycle(); do { - if (cvmx_get_cycle() - start_cycle > - 2 * cvmx_sysinfo_get()->cpu_clock_hz) { - cvmx_dprintf("PCIe: Port %d link timeout\n", - pcie_port); + if (cvmx_get_cycle() - start_cycle > 2 * octeon_get_clock_rate()) { + cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port); return -1; } cvmx_wait(10000); - pciercx_cfg032.u32 = - cvmx_pcie_cfgx_read(pcie_port, - CVMX_PCIERCX_CFG032(pcie_port)); + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); } while (pciercx_cfg032.s.dlla == 0); - /* Display the link status */ - cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, - pciercx_cfg032.s.nlw); + /* Clear all pending errors */ + cvmx_write_csr(CVMX_PEXP_NPEI_INT_SUM, cvmx_read_csr(CVMX_PEXP_NPEI_INT_SUM)); /* * Update the Replay Time Limit. Empirically, some PCIe @@ -639,8 +654,7 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) * our actual 256 byte MPS. The numbers below are directly * from the PCIe spec table 3-4. */ - pciercx_cfg448.u32 = - cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); + pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); switch (pciercx_cfg032.s.nlw) { case 1: /* 1 lane */ pciercx_cfg448.s.rtl = 1677; @@ -655,21 +669,28 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port) pciercx_cfg448.s.rtl = 258; break; } - cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), - pciercx_cfg448.u32); + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); return 0; } +static void __cvmx_increment_ba(union cvmx_sli_mem_access_subidx *pmas) +{ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + pmas->cn68xx.ba++; + else + pmas->cn63xx.ba++; +} + /** - * Initialize a PCIe port for use in host(RC) mode. It doesn't + * Initialize a PCIe gen 1 port for use in host(RC) mode. It doesn't * enumerate the bus. * * @pcie_port: PCIe port to initialize * * Returns Zero on success */ -static int cvmx_pcie_rc_initialize(int pcie_port) +static int __cvmx_pcie_rc_initialize_gen1(int pcie_port) { int i; int base; @@ -682,16 +703,17 @@ static int cvmx_pcie_rc_initialize(int pcie_port) union cvmx_npei_mem_access_subidx mem_access_subid; union cvmx_npei_dbg_data npei_dbg_data; union cvmx_pescx_ctl_status2 pescx_ctl_status2; + union cvmx_pciercx_cfg032 pciercx_cfg032; union cvmx_npei_bar1_indexx bar1_index; +retry: /* * Make sure we aren't trying to setup a target mode interface * in host mode. */ npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); if ((pcie_port == 0) && !npei_ctl_status.s.host_mode) { - cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called " - "on port0, but port0 is not in host mode\n"); + cvmx_dprintf("PCIe: Port %d in endpoint mode\n", pcie_port); return -1; } @@ -702,9 +724,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port) if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); if ((pcie_port == 1) && npei_dbg_data.cn52xx.qlm0_link_width) { - cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() " - "called on port1, but port1 is " - "disabled\n"); + cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n"); return -1; } } @@ -733,7 +753,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port) * the board. As a workaround for this bug, we bring * both PCIe ports out of reset at the same time * instead of on separate calls. So for port 0, we - * bring both out of reset and do nothing on port 1. + * bring both out of reset and do nothing on port 1 */ if (pcie_port == 0) { ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); @@ -746,13 +766,10 @@ static int cvmx_pcie_rc_initialize(int pcie_port) if (ciu_soft_prst.s.soft_prst == 0) { /* Reset the ports */ ciu_soft_prst.s.soft_prst = 1; - cvmx_write_csr(CVMX_CIU_SOFT_PRST, - ciu_soft_prst.u64); - ciu_soft_prst.u64 = - cvmx_read_csr(CVMX_CIU_SOFT_PRST1); + cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); ciu_soft_prst.s.soft_prst = 1; - cvmx_write_csr(CVMX_CIU_SOFT_PRST1, - ciu_soft_prst.u64); + cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); /* Wait until pcie resets the ports. */ udelay(2000); } @@ -782,11 +799,9 @@ static int cvmx_pcie_rc_initialize(int pcie_port) /* Reset the port */ ciu_soft_prst.s.soft_prst = 1; if (pcie_port) - cvmx_write_csr(CVMX_CIU_SOFT_PRST1, - ciu_soft_prst.u64); + cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); else - cvmx_write_csr(CVMX_CIU_SOFT_PRST, - ciu_soft_prst.u64); + cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); /* Wait until pcie resets the ports. */ udelay(2000); } @@ -808,25 +823,21 @@ static int cvmx_pcie_rc_initialize(int pcie_port) */ cvmx_wait(400000); - /* PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of CN56XX and - CN52XX, so we only probe it on newer chips */ - if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) - && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { + /* + * PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of + * CN56XX and CN52XX, so we only probe it on newer chips + */ + if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { /* Clear PCLK_RUN so we can check if the clock is running */ - pescx_ctl_status2.u64 = - cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); + pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); pescx_ctl_status2.s.pclk_run = 1; - cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), - pescx_ctl_status2.u64); - /* - * Now that we cleared PCLK_RUN, wait for it to be set - * again telling us the clock is running. + cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64); + /* Now that we cleared PCLK_RUN, wait for it to be set + * again telling us the clock is running */ if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port), - union cvmx_pescx_ctl_status2, - pclk_run, ==, 1, 10000)) { - cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", - pcie_port); + union cvmx_pescx_ctl_status2, pclk_run, ==, 1, 10000)) { + cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port); return -1; } } @@ -836,30 +847,26 @@ static int cvmx_pcie_rc_initialize(int pcie_port) * the board probably hasn't wired the clocks up and the * interface should be skipped. */ - pescx_ctl_status2.u64 = - cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); + pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); if (pescx_ctl_status2.s.pcierst) { - cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", - pcie_port); + cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); return -1; } /* - * Check BIST2 status. If any bits are set skip this interface. This - * is an attempt to catch PCIE-813 on pass 1 parts. + * Check BIST2 status. If any bits are set skip this + * interface. This is an attempt to catch PCIE-813 on pass 1 + * parts. */ - pescx_bist_status2.u64 = - cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port)); + pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port)); if (pescx_bist_status2.u64) { - cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this " - "port isn't hooked up, skipping.\n", + cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n", pcie_port); return -1; } /* Check BIST status */ - pescx_bist_status.u64 = - cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port)); + pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port)); if (pescx_bist_status.u64) cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pescx_bist_status.u64)); @@ -868,50 +875,37 @@ static int cvmx_pcie_rc_initialize(int pcie_port) __cvmx_pcie_rc_initialize_config_space(pcie_port); /* Bring the link up */ - if (__cvmx_pcie_rc_initialize_link(pcie_port)) { - cvmx_dprintf - ("PCIe: ERROR: cvmx_pcie_rc_initialize_link() failed\n"); + if (__cvmx_pcie_rc_initialize_link_gen1(pcie_port)) { + cvmx_dprintf("PCIe: Failed to initialize port %d, probably the slot is empty\n", + pcie_port); return -1; } /* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */ npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL); - /* Allow 16 words to combine */ - npei_mem_access_ctl.s.max_word = 0; - /* Wait up to 127 cycles for more data */ - npei_mem_access_ctl.s.timer = 127; + npei_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */ + npei_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */ cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64); /* Setup Mem access SubDIDs */ mem_access_subid.u64 = 0; - /* Port the request is sent to. */ - mem_access_subid.s.port = pcie_port; - /* Due to an errata on pass 1 chips, no merging is allowed. */ - mem_access_subid.s.nmerge = 1; - /* Endian-swap for Reads. */ - mem_access_subid.s.esr = 1; - /* Endian-swap for Writes. */ - mem_access_subid.s.esw = 1; - /* No Snoop for Reads. */ - mem_access_subid.s.nsr = 1; - /* No Snoop for Writes. */ - mem_access_subid.s.nsw = 1; - /* Disable Relaxed Ordering for Reads. */ - mem_access_subid.s.ror = 0; - /* Disable Relaxed Ordering for Writes. */ - mem_access_subid.s.row = 0; - /* PCIe Address Bits <63:34>. */ - mem_access_subid.s.ba = 0; + mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ + mem_access_subid.s.nmerge = 1; /* Due to an errata on pass 1 chips, no merging is allowed. */ + mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */ + mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */ + mem_access_subid.s.nsr = 0; /* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */ + mem_access_subid.s.nsw = 0; /* Enable Snoop for Writes. */ + mem_access_subid.s.ror = 0; /* Disable Relaxed Ordering for Reads. */ + mem_access_subid.s.row = 0; /* Disable Relaxed Ordering for Writes. */ + mem_access_subid.s.ba = 0; /* PCIe Adddress Bits <63:34>. */ /* * Setup mem access 12-15 for port 0, 16-19 for port 1, * supplying 36 bits of address space. */ for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) { - cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), - mem_access_subid.u64); - /* Set each SUBID to extend the addressable range */ - mem_access_subid.s.ba += 1; + cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); + mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */ } /* @@ -927,7 +921,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port) /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0); - /* BAR1 follows BAR2 with a gap. */ + /* BAR1 follows BAR2 with a gap so it has the same address as for gen2. */ cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE); bar1_index.u32 = 0; @@ -992,14 +986,474 @@ static int cvmx_pcie_rc_initialize(int pcie_port) npei_ctl_port.s.waitl_com = 0; cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64); } + + /* + * Both pass 1 and pass 2 of CN52XX and CN56XX have an errata + * that causes TLP ordering to not be preserved after multiple + * PCIe port resets. This code detects this fault and corrects + * it by aligning the TLP counters properly. Another link + * reset is then performed. See PCIE-13340 + */ + if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) || + OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) || + OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { + union cvmx_npei_dbg_data dbg_data; + int old_in_fif_p_count; + int in_fif_p_count; + int out_p_count; + int in_p_offset = (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) ? 4 : 1; + int i; + + /* + * Choose a write address of 1MB. It should be + * harmless as all bars haven't been setup. + */ + uint64_t write_address = (cvmx_pcie_get_mem_base_address(pcie_port) + 0x100000) | (1ull<<63); + + /* + * Make sure at least in_p_offset have been executed before we try and + * read in_fif_p_count + */ + i = in_p_offset; + while (i--) { + cvmx_write64_uint32(write_address, 0); + cvmx_wait(10000); + } + + /* + * Read the IN_FIF_P_COUNT from the debug + * select. IN_FIF_P_COUNT can be unstable sometimes so + * read it twice with a write between the reads. This + * way we can tell the value is good as it will + * increment by one due to the write + */ + cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd7fc : 0xcffc); + cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); + do { + dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); + old_in_fif_p_count = dbg_data.s.data & 0xff; + cvmx_write64_uint32(write_address, 0); + cvmx_wait(10000); + dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); + in_fif_p_count = dbg_data.s.data & 0xff; + } while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff)); + + /* Update in_fif_p_count for it's offset with respect to out_p_count */ + in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff; + + /* Read the OUT_P_COUNT from the debug select */ + cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f); + cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); + dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); + out_p_count = (dbg_data.s.data>>1) & 0xff; + + /* Check that the two counters are aligned */ + if (out_p_count != in_fif_p_count) { + cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port); + while (in_fif_p_count != 0) { + cvmx_write64_uint32(write_address, 0); + cvmx_wait(10000); + in_fif_p_count = (in_fif_p_count + 1) & 0xff; + } + /* + * The EBH5200 board swapped the PCIe reset + * lines on the board. This means we must + * bring both links down and up, which will + * cause the PCIe0 to need alignment + * again. Lots of messages will be displayed, + * but everything should work + */ + if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) && + (pcie_port == 1)) + cvmx_pcie_rc_initialize(0); + /* Rety bringing this port up */ + goto retry; + } + } + + /* Display the link status */ + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); + cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw); + return 0; } +/** + * Initialize a host mode PCIe gen 2 link. This function takes a PCIe + * port from reset to a link up state. Software can then begin + * configuring the rest of the link. + * + * @pcie_port: PCIe port to initialize + * + * Return Zero on success. + */ +static int __cvmx_pcie_rc_initialize_link_gen2(int pcie_port) +{ + uint64_t start_cycle; + union cvmx_pemx_ctl_status pem_ctl_status; + union cvmx_pciercx_cfg032 pciercx_cfg032; + union cvmx_pciercx_cfg448 pciercx_cfg448; -/* Above was cvmx-pcie.c, below original pcie.c */ + /* Bring up the link */ + pem_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port)); + pem_ctl_status.s.lnk_enb = 1; + cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64); + + /* Wait for the link to come up */ + start_cycle = cvmx_get_cycle(); + do { + if (cvmx_get_cycle() - start_cycle > octeon_get_clock_rate()) + return -1; + cvmx_wait(10000); + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); + } while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1)); + + /* + * Update the Replay Time Limit. Empirically, some PCIe + * devices take a little longer to respond than expected under + * load. As a workaround for this we configure the Replay Time + * Limit to the value expected for a 512 byte MPS instead of + * our actual 256 byte MPS. The numbers below are directly + * from the PCIe spec table 3-4 + */ + pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); + switch (pciercx_cfg032.s.nlw) { + case 1: /* 1 lane */ + pciercx_cfg448.s.rtl = 1677; + break; + case 2: /* 2 lanes */ + pciercx_cfg448.s.rtl = 867; + break; + case 4: /* 4 lanes */ + pciercx_cfg448.s.rtl = 462; + break; + case 8: /* 8 lanes */ + pciercx_cfg448.s.rtl = 258; + break; + } + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); + + return 0; +} /** + * Initialize a PCIe gen 2 port for use in host(RC) mode. It doesn't enumerate + * the bus. + * + * @pcie_port: PCIe port to initialize + * + * Returns Zero on success. + */ +static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) +{ + int i; + union cvmx_ciu_soft_prst ciu_soft_prst; + union cvmx_mio_rst_ctlx mio_rst_ctl; + union cvmx_pemx_bar_ctl pemx_bar_ctl; + union cvmx_pemx_ctl_status pemx_ctl_status; + union cvmx_pemx_bist_status pemx_bist_status; + union cvmx_pemx_bist_status2 pemx_bist_status2; + union cvmx_pciercx_cfg032 pciercx_cfg032; + union cvmx_pciercx_cfg515 pciercx_cfg515; + union cvmx_sli_ctl_portx sli_ctl_portx; + union cvmx_sli_mem_access_ctl sli_mem_access_ctl; + union cvmx_sli_mem_access_subidx mem_access_subid; + union cvmx_sriox_status_reg sriox_status_reg; + union cvmx_pemx_bar1_indexx bar1_index; + + if (octeon_has_feature(OCTEON_FEATURE_SRIO)) { + /* Make sure this interface isn't SRIO */ + if (OCTEON_IS_MODEL(OCTEON_CN66XX)) { + /* + * The CN66XX requires reading the + * MIO_QLMX_CFG register to figure out the + * port type. + */ + union cvmx_mio_qlmx_cfg qlmx_cfg; + qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(pcie_port)); + + if (qlmx_cfg.s.qlm_spd == 15) { + pr_notice("PCIe: Port %d is disabled, skipping.\n", pcie_port); + return -1; + } + + switch (qlmx_cfg.s.qlm_spd) { + case 0x1: /* SRIO 1x4 short */ + case 0x3: /* SRIO 1x4 long */ + case 0x4: /* SRIO 2x2 short */ + case 0x6: /* SRIO 2x2 long */ + pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); + return -1; + case 0x9: /* SGMII */ + pr_notice("PCIe: Port %d is SGMII, skipping.\n", pcie_port); + return -1; + case 0xb: /* XAUI */ + pr_notice("PCIe: Port %d is XAUI, skipping.\n", pcie_port); + return -1; + case 0x0: /* PCIE gen2 */ + case 0x8: /* PCIE gen2 (alias) */ + case 0x2: /* PCIE gen1 */ + case 0xa: /* PCIE gen1 (alias) */ + break; + default: + pr_notice("PCIe: Port %d is unknown, skipping.\n", pcie_port); + return -1; + } + } else { + sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(pcie_port)); + if (sriox_status_reg.s.srio) { + pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); + return -1; + } + } + } + +#if 0 + /* This code is so that the PCIe analyzer is able to see 63XX traffic */ + pr_notice("PCIE : init for pcie analyzer.\n"); + cvmx_helper_qlm_jtag_init(); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); + cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); + cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); + cvmx_helper_qlm_jtag_update(pcie_port); +#endif + + /* Make sure we aren't trying to setup a target mode interface in host mode */ + mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port)); + if (!mio_rst_ctl.s.host_mode) { + pr_notice("PCIe: Port %d in endpoint mode.\n", pcie_port); + return -1; + } + + /* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) { + if (pcie_port) { + union cvmx_ciu_qlm1 ciu_qlm; + ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1); + ciu_qlm.s.txbypass = 1; + ciu_qlm.s.txdeemph = 5; + ciu_qlm.s.txmargin = 0x17; + cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64); + } else { + union cvmx_ciu_qlm0 ciu_qlm; + ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0); + ciu_qlm.s.txbypass = 1; + ciu_qlm.s.txdeemph = 5; + ciu_qlm.s.txmargin = 0x17; + cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64); + } + } + /* Bring the PCIe out of reset */ + if (pcie_port) + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); + else + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); + /* + * After a chip reset the PCIe will also be in reset. If it + * isn't, most likely someone is trying to init it again + * without a proper PCIe reset + */ + if (ciu_soft_prst.s.soft_prst == 0) { + /* Reset the port */ + ciu_soft_prst.s.soft_prst = 1; + if (pcie_port) + cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); + else + cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); + /* Wait until pcie resets the ports. */ + udelay(2000); + } + if (pcie_port) { + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); + ciu_soft_prst.s.soft_prst = 0; + cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); + } else { + ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); + ciu_soft_prst.s.soft_prst = 0; + cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); + } + + /* Wait for PCIe reset to complete */ + udelay(1000); + + /* + * Check and make sure PCIe came out of reset. If it doesn't + * the board probably hasn't wired the clocks up and the + * interface should be skipped. + */ + if (CVMX_WAIT_FOR_FIELD64(CVMX_MIO_RST_CTLX(pcie_port), union cvmx_mio_rst_ctlx, rst_done, ==, 1, 10000)) { + pr_notice("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); + return -1; + } + + /* Check BIST status */ + pemx_bist_status.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS(pcie_port)); + if (pemx_bist_status.u64) + pr_notice("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64)); + pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port)); + /* Errata PCIE-14766 may cause the lower 6 bits to be randomly set on CN63XXp1 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) + pemx_bist_status2.u64 &= ~0x3full; + if (pemx_bist_status2.u64) + pr_notice("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64)); + + /* Initialize the config space CSRs */ + __cvmx_pcie_rc_initialize_config_space(pcie_port); + + /* Enable gen2 speed selection */ + pciercx_cfg515.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG515(pcie_port)); + pciercx_cfg515.s.dsc = 1; + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32); + + /* Bring the link up */ + if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { + /* + * Some gen1 devices don't handle the gen 2 training + * correctly. Disable gen2 and try again with only + * gen1 + */ + union cvmx_pciercx_cfg031 pciercx_cfg031; + pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port)); + pciercx_cfg031.s.mls = 1; + cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32); + if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { + pr_notice("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port); + return -1; + } + } + + /* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */ + sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL); + sli_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */ + sli_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */ + cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64); + + /* Setup Mem access SubDIDs */ + mem_access_subid.u64 = 0; + mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ + mem_access_subid.s.nmerge = 0; /* Allow merging as it works on CN6XXX. */ + mem_access_subid.s.esr = 1; /* Endian-swap for Reads. */ + mem_access_subid.s.esw = 1; /* Endian-swap for Writes. */ + mem_access_subid.s.wtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ + mem_access_subid.s.rtype = 0; /* "No snoop" and "Relaxed ordering" are not set */ + /* PCIe Adddress Bits <63:34>. */ + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + mem_access_subid.cn68xx.ba = 0; + else + mem_access_subid.cn63xx.ba = 0; + + /* + * Setup mem access 12-15 for port 0, 16-19 for port 1, + * supplying 36 bits of address space. + */ + for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) { + cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); + /* Set each SUBID to extend the addressable range */ + __cvmx_increment_ba(&mem_access_subid); + } + + /* + * Disable the peer to peer forwarding register. This must be + * setup by the OS after it enumerates the bus and assigns + * addresses to the PCIe busses. + */ + for (i = 0; i < 4; i++) { + cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1); + cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1); + } + + /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ + cvmx_write_csr(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0); + + /* + * Set Octeon's BAR2 to decode 0-2^41. Bar0 and Bar1 take + * precedence where they overlap. It also overlaps with the + * device addresses, so make sure the peer to peer forwarding + * is set right. + */ + cvmx_write_csr(CVMX_PEMX_P2N_BAR2_START(pcie_port), 0); + + /* + * Setup BAR2 attributes + * Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) + * - PTLP_RO,CTLP_RO should normally be set (except for debug). + * - WAIT_COM=0 will likely work for all applications. + * Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) + */ + pemx_bar_ctl.u64 = cvmx_read_csr(CVMX_PEMX_BAR_CTL(pcie_port)); + pemx_bar_ctl.s.bar1_siz = 3; /* 256MB BAR1*/ + pemx_bar_ctl.s.bar2_enb = 1; + pemx_bar_ctl.s.bar2_esx = 1; + pemx_bar_ctl.s.bar2_cax = 0; + cvmx_write_csr(CVMX_PEMX_BAR_CTL(pcie_port), pemx_bar_ctl.u64); + sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port)); + sli_ctl_portx.s.ptlp_ro = 1; + sli_ctl_portx.s.ctlp_ro = 1; + sli_ctl_portx.s.wait_com = 0; + sli_ctl_portx.s.waitl_com = 0; + cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port), sli_ctl_portx.u64); + + /* BAR1 follows BAR2 */ + cvmx_write_csr(CVMX_PEMX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE); + + bar1_index.u64 = 0; + bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22); + bar1_index.s.ca = 1; /* Not Cached */ + bar1_index.s.end_swp = 1; /* Endian Swap mode */ + bar1_index.s.addr_v = 1; /* Valid entry */ + + for (i = 0; i < 16; i++) { + cvmx_write_csr(CVMX_PEMX_BAR1_INDEXX(i, pcie_port), bar1_index.u64); + /* 256MB / 16 >> 22 == 4 */ + bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22); + } + + /* + * Allow config retries for 250ms. Count is based off the 5Ghz + * SERDES clock. + */ + pemx_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port)); + pemx_ctl_status.s.cfg_rtry = 250 * 5000000 / 0x10000; + cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pemx_ctl_status.u64); + + /* Display the link status */ + pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); + pr_notice("PCIe: Port %d link active, %d lanes, speed gen%d\n", pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls); + + return 0; +} + +/** + * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus. + * + * @pcie_port: PCIe port to initialize + * + * Returns Zero on success + */ +static int cvmx_pcie_rc_initialize(int pcie_port) +{ + int result; + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) + result = __cvmx_pcie_rc_initialize_gen1(pcie_port); + else + result = __cvmx_pcie_rc_initialize_gen2(pcie_port); + return result; +} + +/* Above was cvmx-pcie.c, below original pcie.c */ + +/** * Map a PCI device to the appropriate interrupt line * * @dev: The Linux PCI device structure for the device to map @@ -1027,11 +1481,12 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev, */ while (dev->bus && dev->bus->parent) dev = to_pci_dev(dev->bus->bridge); - /* If the root bus is number 0 and the PEX 8114 is the + /* + * If the root bus is number 0 and the PEX 8114 is the * root, assume we are behind the miswired bus. We * need to correct the swizzle level by two. Yuck. */ - if ((dev->bus->number == 0) && + if ((dev->bus->number == 1) && (dev->vendor == 0x10b5) && (dev->device == 0x8114)) { /* * The pin field is one based, not zero. We @@ -1048,39 +1503,73 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev, return pin - 1 + OCTEON_IRQ_PCI_INT0; } -/** +static void set_cfg_read_retry(u32 retry_cnt) +{ + union cvmx_pemx_ctl_status pemx_ctl; + pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1)); + pemx_ctl.s.cfg_rtry = retry_cnt; + cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64); +} + + +static u32 disable_cfg_read_retry(void) +{ + u32 retry_cnt; + + union cvmx_pemx_ctl_status pemx_ctl; + pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1)); + retry_cnt = pemx_ctl.s.cfg_rtry; + pemx_ctl.s.cfg_rtry = 0; + cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64); + return retry_cnt; +} + +static int is_cfg_retry(void) +{ + union cvmx_pemx_int_sum pemx_int_sum; + pemx_int_sum.u64 = cvmx_read_csr(CVMX_PEMX_INT_SUM(1)); + if (pemx_int_sum.s.crs_dr) + return 1; + return 0; +} + +/* * Read a value from configuration space * - * @bus: - * @devfn: - * @reg: - * @size: - * @val: - * Returns */ -static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus, - unsigned int devfn, int reg, int size, - u32 *val) +static int octeon_pcie_read_config(unsigned int pcie_port, struct pci_bus *bus, + unsigned int devfn, int reg, int size, + u32 *val) { union octeon_cvmemctl cvmmemctl; union octeon_cvmemctl cvmmemctl_save; int bus_number = bus->number; + int cfg_retry = 0; + int retry_cnt = 0; + int max_retry_cnt = 10; + u32 cfg_retry_cnt = 0; + cvmmemctl_save.u64 = 0; + BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war)); /* * For the top level bus make sure our hardware bus number - * matches the software one. + * matches the software one */ if (bus->parent == NULL) { - union cvmx_pciercx_cfg006 pciercx_cfg006; - pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, - CVMX_PCIERCX_CFG006(pcie_port)); - if (pciercx_cfg006.s.pbnum != bus_number) { - pciercx_cfg006.s.pbnum = bus_number; - pciercx_cfg006.s.sbnum = bus_number; - pciercx_cfg006.s.subbnum = bus_number; - cvmx_pcie_cfgx_write(pcie_port, - CVMX_PCIERCX_CFG006(pcie_port), - pciercx_cfg006.u32); + if (enable_pcie_bus_num_war[pcie_port]) + bus_number = 0; + else { + union cvmx_pciercx_cfg006 pciercx_cfg006; + pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, + CVMX_PCIERCX_CFG006(pcie_port)); + if (pciercx_cfg006.s.pbnum != bus_number) { + pciercx_cfg006.s.pbnum = bus_number; + pciercx_cfg006.s.sbnum = bus_number; + pciercx_cfg006.s.subbnum = bus_number; + cvmx_pcie_cfgx_write(pcie_port, + CVMX_PCIERCX_CFG006(pcie_port), + pciercx_cfg006.u32); + } } } @@ -1116,29 +1605,52 @@ static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus, */ #if 1 /* Use this option if you aren't using either slot */ - if (bus_number == 1) + if (bus_number == 2) return PCIBIOS_FUNC_NOT_SUPPORTED; #elif 0 /* * Use this option if you are using the first slot but * not the second. */ - if ((bus_number == 1) && (devfn >> 3 != 2)) + if ((bus_number == 2) && (devfn >> 3 != 2)) return PCIBIOS_FUNC_NOT_SUPPORTED; #elif 0 /* * Use this option if you are using the second slot * but not the first. */ - if ((bus_number == 1) && (devfn >> 3 != 3)) + if ((bus_number == 2) && (devfn >> 3 != 3)) return PCIBIOS_FUNC_NOT_SUPPORTED; #elif 0 /* Use this opion if you are using both slots */ - if ((bus_number == 1) && + if ((bus_number == 2) && !((devfn == (2 << 3)) || (devfn == (3 << 3)))) return PCIBIOS_FUNC_NOT_SUPPORTED; #endif + /* The following #if gives a more complicated example. This is + the required checks for running a Nitrox CN16XX-NHBX in the + slot of the EBH5600. This card has a PLX PCIe bridge with + four Nitrox PLX parts behind it */ +#if 0 + /* PLX bridge with 4 ports */ + if ((bus_number == 4) && + !((devfn >> 3 >= 1) && (devfn >> 3 <= 4))) + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* Nitrox behind PLX 1 */ + if ((bus_number == 5) && (devfn >> 3 != 0)) + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* Nitrox behind PLX 2 */ + if ((bus_number == 6) && (devfn >> 3 != 0)) + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* Nitrox behind PLX 3 */ + if ((bus_number == 7) && (devfn >> 3 != 0)) + return PCIBIOS_FUNC_NOT_SUPPORTED; + /* Nitrox behind PLX 4 */ + if ((bus_number == 8) && (devfn >> 3 != 0)) + return PCIBIOS_FUNC_NOT_SUPPORTED; +#endif + /* * Shorten the DID timeout so bus errors for PCIe * config reads from non existent devices happen @@ -1152,26 +1664,48 @@ static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus, __write_64bit_c0_register($11, 7, cvmmemctl.u64); } - switch (size) { - case 4: - *val = cvmx_pcie_config_read32(pcie_port, bus_number, - devfn >> 3, devfn & 0x7, reg); + if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war)) + cfg_retry_cnt = disable_cfg_read_retry(); + + pr_debug("pcie_cfg_rd port=%d b=%d devfn=0x%03x reg=0x%03x" + " size=%d ", pcie_port, bus_number, devfn, reg, size); + do { + switch (size) { + case 4: + *val = cvmx_pcie_config_read32(pcie_port, bus_number, + devfn >> 3, devfn & 0x7, reg); break; - case 2: - *val = cvmx_pcie_config_read16(pcie_port, bus_number, - devfn >> 3, devfn & 0x7, reg); + case 2: + *val = cvmx_pcie_config_read16(pcie_port, bus_number, + devfn >> 3, devfn & 0x7, reg); break; - case 1: - *val = cvmx_pcie_config_read8(pcie_port, bus_number, devfn >> 3, - devfn & 0x7, reg); + case 1: + *val = cvmx_pcie_config_read8(pcie_port, bus_number, + devfn >> 3, devfn & 0x7, reg); break; - default: - return PCIBIOS_FUNC_NOT_SUPPORTED; - } + default: + if (OCTEON_IS_MODEL(OCTEON_CN63XX)) + set_cfg_read_retry(cfg_retry_cnt); + return PCIBIOS_FUNC_NOT_SUPPORTED; + } + if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && + (enable_pcie_14459_war)) { + cfg_retry = is_cfg_retry(); + retry_cnt++; + if (retry_cnt > max_retry_cnt) { + pr_err(" pcie cfg_read retries failed. retry_cnt=%d\n", + retry_cnt); + cfg_retry = 0; + } + } + } while (cfg_retry); + if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war)) + set_cfg_read_retry(cfg_retry_cnt); + pr_debug("val=%08x : tries=%02d\n", *val, retry_cnt); if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1)) - __write_64bit_c0_register($11, 7, cvmmemctl_save.u64); + write_c0_cvmmemctl(cvmmemctl_save.u64); return PCIBIOS_SUCCESSFUL; } @@ -1187,42 +1721,56 @@ static int octeon_pcie1_read_config(struct pci_bus *bus, unsigned int devfn, return octeon_pcie_read_config(1, bus, devfn, reg, size, val); } +static int octeon_dummy_read_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 *val) +{ + return PCIBIOS_FUNC_NOT_SUPPORTED; +} - -/** +/* * Write a value to PCI configuration space - * - * @bus: - * @devfn: - * @reg: - * @size: - * @val: - * Returns */ -static inline int octeon_pcie_write_config(int pcie_port, struct pci_bus *bus, - unsigned int devfn, int reg, - int size, u32 val) +static int octeon_pcie_write_config(unsigned int pcie_port, struct pci_bus *bus, + unsigned int devfn, int reg, + int size, u32 val) { int bus_number = bus->number; + BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war)); + + if ((bus->parent == NULL) && (enable_pcie_bus_num_war[pcie_port])) + bus_number = 0; + + pr_debug("pcie_cfg_wr port=%d b=%d devfn=0x%03x" + " reg=0x%03x size=%d val=%08x\n", pcie_port, bus_number, devfn, + reg, size, val); + + switch (size) { case 4: cvmx_pcie_config_write32(pcie_port, bus_number, devfn >> 3, devfn & 0x7, reg, val); - return PCIBIOS_SUCCESSFUL; + break; case 2: cvmx_pcie_config_write16(pcie_port, bus_number, devfn >> 3, devfn & 0x7, reg, val); - return PCIBIOS_SUCCESSFUL; + break; case 1: cvmx_pcie_config_write8(pcie_port, bus_number, devfn >> 3, devfn & 0x7, reg, val); - return PCIBIOS_SUCCESSFUL; + break; + default: + return PCIBIOS_FUNC_NOT_SUPPORTED; } #if PCI_CONFIG_SPACE_DELAY + /* + * Delay on writes so that devices have time to come up. Some + * bridges need this to allow time for the secondary busses to + * work + */ udelay(PCI_CONFIG_SPACE_DELAY); #endif - return PCIBIOS_FUNC_NOT_SUPPORTED; + return PCIBIOS_SUCCESSFUL; } static int octeon_pcie0_write_config(struct pci_bus *bus, unsigned int devfn, @@ -1237,6 +1785,12 @@ static int octeon_pcie1_write_config(struct pci_bus *bus, unsigned int devfn, return octeon_pcie_write_config(1, bus, devfn, reg, size, val); } +static int octeon_dummy_write_config(struct pci_bus *bus, unsigned int devfn, + int reg, int size, u32 val) +{ + return PCIBIOS_FUNC_NOT_SUPPORTED; +} + static struct pci_ops octeon_pcie0_ops = { octeon_pcie0_read_config, octeon_pcie0_write_config, @@ -1279,6 +1833,35 @@ static struct pci_controller octeon_pcie1_controller = { .io_resource = &octeon_pcie1_io_resource, }; +static struct pci_ops octeon_dummy_ops = { + octeon_dummy_read_config, + octeon_dummy_write_config, +}; + +static struct resource octeon_dummy_mem_resource = { + .name = "Virtual PCIe MEM", + .flags = IORESOURCE_MEM, +}; + +static struct resource octeon_dummy_io_resource = { + .name = "Virtual PCIe IO", + .flags = IORESOURCE_IO, +}; + +static struct pci_controller octeon_dummy_controller = { + .pci_ops = &octeon_dummy_ops, + .mem_resource = &octeon_dummy_mem_resource, + .io_resource = &octeon_dummy_io_resource, +}; + +static int device_needs_bus_num_war(uint32_t deviceid) +{ +#define IDT_VENDOR_ID 0x111d + + if ((deviceid & 0xffff) == IDT_VENDOR_ID) + return 1; + return 0; +} /** * Initialize the Octeon PCIe controllers @@ -1287,19 +1870,27 @@ static struct pci_controller octeon_pcie1_controller = { */ static int __init octeon_pcie_setup(void) { - union cvmx_npei_ctl_status npei_ctl_status; int result; + int host_mode; + int srio_war15205 = 0, port; + union cvmx_sli_ctl_portx sli_ctl_portx; + union cvmx_sriox_status_reg sriox_status_reg; /* These chips don't have PCIe */ if (!octeon_has_feature(OCTEON_FEATURE_PCIE)) return 0; + /* No PCIe simulation */ + if (octeon_is_simulation()) + return 0; + + /* Disable PCI if instructed on the command line */ + if (pcie_disable) + return 0; + /* Point pcibios_map_irq() to the PCIe version of it */ octeon_pcibios_map_irq = octeon_pcie_pcibios_map_irq; - /* Use the PCIe based DMA mappings */ - octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE; - /* * PCIe I/O range. It is based on port 0 but includes up until * port 1's end. @@ -1310,11 +1901,43 @@ static int __init octeon_pcie_setup(void) cvmx_pcie_get_io_base_address(1) - cvmx_pcie_get_io_base_address(0) + cvmx_pcie_get_io_size(1) - 1; - npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); - if (npei_ctl_status.s.host_mode) { + /* + * Create a dummy PCIe controller to swallow up bus 0. IDT bridges + * don't work if the primary bus number is zero. Here we add a fake + * PCIe controller that the kernel will give bus 0. This allows + * us to not change the normal kernel bus enumeration + */ + octeon_dummy_controller.io_map_base = -1; + octeon_dummy_controller.mem_resource->start = (1ull<<48); + octeon_dummy_controller.mem_resource->end = (1ull<<48); + register_pci_controller(&octeon_dummy_controller); + + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + union cvmx_npei_ctl_status npei_ctl_status; + npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); + host_mode = npei_ctl_status.s.host_mode; + octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE; + } else { + union cvmx_mio_rst_ctlx mio_rst_ctl; + mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(0)); + host_mode = mio_rst_ctl.s.host_mode; + octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE2; + } + + if (host_mode) { pr_notice("PCIe: Initializing port 0\n"); + /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(0)); + if (sriox_status_reg.s.srio) { + srio_war15205 += 1; /* Port is SRIO */ + port = 0; + } + } result = cvmx_pcie_rc_initialize(0); if (result == 0) { + uint32_t device0; /* Memory offsets are physical addresses */ octeon_pcie0_controller.mem_offset = cvmx_pcie_get_mem_base_address(0); @@ -1343,60 +1966,134 @@ static int __init octeon_pcie_setup(void) octeon_pcie0_controller.io_resource->start = 4 << 10; octeon_pcie0_controller.io_resource->end = cvmx_pcie_get_io_size(0) - 1; + msleep(100); /* Some devices need extra time */ register_pci_controller(&octeon_pcie0_controller); + device0 = cvmx_pcie_config_read32(0, 0, 0, 0, 0); + enable_pcie_bus_num_war[0] = + device_needs_bus_num_war(device0); } } else { pr_notice("PCIe: Port 0 in endpoint mode, skipping.\n"); + /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + srio_war15205 += 1; + port = 0; + } } - /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */ - if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { - union cvmx_npei_dbg_data npei_dbg_data; - npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); - if (npei_dbg_data.cn52xx.qlm0_link_width) - return 0; + if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { + host_mode = 1; + /* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */ + if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { + union cvmx_npei_dbg_data dbg_data; + dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); + if (dbg_data.cn52xx.qlm0_link_width) + host_mode = 0; + } + } else { + union cvmx_mio_rst_ctlx mio_rst_ctl; + mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(1)); + host_mode = mio_rst_ctl.s.host_mode; } - pr_notice("PCIe: Initializing port 1\n"); - result = cvmx_pcie_rc_initialize(1); - if (result == 0) { - /* Memory offsets are physical addresses */ - octeon_pcie1_controller.mem_offset = - cvmx_pcie_get_mem_base_address(1); - /* IO offsets are Mips virtual addresses */ - octeon_pcie1_controller.io_map_base = - CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(1)); - octeon_pcie1_controller.io_offset = - cvmx_pcie_get_io_base_address(1) - - cvmx_pcie_get_io_base_address(0); - /* - * To keep things similar to PCI, we start device - * addresses at the same place as PCI uisng big bar - * support. This normally translates to 4GB-256MB, - * which is the same as most x86 PCs. - */ - octeon_pcie1_controller.mem_resource->start = - cvmx_pcie_get_mem_base_address(1) + (4ul << 30) - - (OCTEON_PCI_BAR1_HOLE_SIZE << 20); - octeon_pcie1_controller.mem_resource->end = - cvmx_pcie_get_mem_base_address(1) + - cvmx_pcie_get_mem_size(1) - 1; - /* - * Ports must be above 16KB for the ISA bus filtering - * in the PCI-X to PCI bridge. - */ - octeon_pcie1_controller.io_resource->start = - cvmx_pcie_get_io_base_address(1) - - cvmx_pcie_get_io_base_address(0); - octeon_pcie1_controller.io_resource->end = - octeon_pcie1_controller.io_resource->start + - cvmx_pcie_get_io_size(1) - 1; - register_pci_controller(&octeon_pcie1_controller); + if (host_mode) { + pr_notice("PCIe: Initializing port 1\n"); + /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(1)); + if (sriox_status_reg.s.srio) { + srio_war15205 += 1; /* Port is SRIO */ + port = 1; + } + } + result = cvmx_pcie_rc_initialize(1); + if (result == 0) { + uint32_t device0; + /* Memory offsets are physical addresses */ + octeon_pcie1_controller.mem_offset = + cvmx_pcie_get_mem_base_address(1); + /* + * To calculate the address for accessing the 2nd PCIe device, + * either 'io_map_base' (pci_iomap()), or 'mips_io_port_base' + * (ioport_map()) value is added to + * pci_resource_start(dev,bar)). The 'mips_io_port_base' is set + * only once based on first PCIe. Also changing 'io_map_base' + * based on first slot's value so that both the routines will + * work properly. + */ + octeon_pcie1_controller.io_map_base = + CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(0)); + /* IO offsets are Mips virtual addresses */ + octeon_pcie1_controller.io_offset = + cvmx_pcie_get_io_base_address(1) - + cvmx_pcie_get_io_base_address(0); + /* + * To keep things similar to PCI, we start device + * addresses at the same place as PCI uisng big bar + * support. This normally translates to 4GB-256MB, + * which is the same as most x86 PCs. + */ + octeon_pcie1_controller.mem_resource->start = + cvmx_pcie_get_mem_base_address(1) + (4ul << 30) - + (OCTEON_PCI_BAR1_HOLE_SIZE << 20); + octeon_pcie1_controller.mem_resource->end = + cvmx_pcie_get_mem_base_address(1) + + cvmx_pcie_get_mem_size(1) - 1; + /* + * Ports must be above 16KB for the ISA bus filtering + * in the PCI-X to PCI bridge. + */ + octeon_pcie1_controller.io_resource->start = + cvmx_pcie_get_io_base_address(1) - + cvmx_pcie_get_io_base_address(0); + octeon_pcie1_controller.io_resource->end = + octeon_pcie1_controller.io_resource->start + + cvmx_pcie_get_io_size(1) - 1; + msleep(100); /* Some devices need extra time */ + register_pci_controller(&octeon_pcie1_controller); + device0 = cvmx_pcie_config_read32(1, 0, 0, 0, 0); + enable_pcie_bus_num_war[1] = + device_needs_bus_num_war(device0); + } + } else { + pr_notice("PCIe: Port 1 not in root complex mode, skipping.\n"); + /* CN63XX pass 1_x/2.0 errata PCIe-15205 */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + srio_war15205 += 1; + port = 1; + } + } + + /* + * CN63XX pass 1_x/2.0 errata PCIe-15205 requires setting all + * of SRIO MACs SLI_CTL_PORT*[INT*_MAP] to similar value and + * all of PCIe Macs SLI_CTL_PORT*[INT*_MAP] to different value + * from the previous set values + */ + if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || + OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { + if (srio_war15205 == 1) { + sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(port)); + sli_ctl_portx.s.inta_map = 1; + sli_ctl_portx.s.intb_map = 1; + sli_ctl_portx.s.intc_map = 1; + sli_ctl_portx.s.intd_map = 1; + cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(port), sli_ctl_portx.u64); + + sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(!port)); + sli_ctl_portx.s.inta_map = 0; + sli_ctl_portx.s.intb_map = 0; + sli_ctl_portx.s.intc_map = 0; + sli_ctl_portx.s.intd_map = 0; + cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(!port), sli_ctl_portx.u64); + } } octeon_pci_dma_init(); return 0; } - arch_initcall(octeon_pcie_setup); diff --git a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c index c841f083a7f5..bb57ed9ea2bd 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c @@ -149,7 +149,7 @@ static int msp_hwbutton_register(struct hwbutton_interrupt *hirq) CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq); *CIC_EXT_CFG_REG = cic_ext; - return request_irq(hirq->irq, hwbutton_handler, IRQF_DISABLED, + return request_irq(hirq->irq, hwbutton_handler, 0, hirq->name, hirq); } diff --git a/arch/mips/pmc-sierra/msp71xx/msp_setup.c b/arch/mips/pmc-sierra/msp71xx/msp_setup.c index 655308a4e1cd..7a834b2f8a5f 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_setup.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_setup.c @@ -209,7 +209,7 @@ void __init prom_init(void) default: /* we don't recognize the machine */ mips_machtype = MACH_UNKNOWN; - panic("***Bogosity factor five***, exiting\n"); + panic("***Bogosity factor five***, exiting"); break; } diff --git a/arch/mips/pmc-sierra/msp71xx/msp_smp.c b/arch/mips/pmc-sierra/msp71xx/msp_smp.c index bec17901ff03..10170580a2de 100644 --- a/arch/mips/pmc-sierra/msp71xx/msp_smp.c +++ b/arch/mips/pmc-sierra/msp71xx/msp_smp.c @@ -51,13 +51,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) static struct irqaction irq_resched = { .handler = ipi_resched_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU, + .flags = IRQF_PERCPU, .name = "IPI_resched" }; static struct irqaction irq_call = { .handler = ipi_call_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU, + .flags = IRQF_PERCPU, .name = "IPI_call" }; diff --git a/arch/mips/pnx8550/common/int.c b/arch/mips/pnx8550/common/int.c index 1ebe22bdadc8..ec684b8c3f79 100644 --- a/arch/mips/pnx8550/common/int.c +++ b/arch/mips/pnx8550/common/int.c @@ -167,13 +167,13 @@ static struct irq_chip level_irq_type = { static struct irqaction gic_action = { .handler = no_action, - .flags = IRQF_DISABLED | IRQF_NO_THREAD, + .flags = IRQF_NO_THREAD, .name = "GIC", }; static struct irqaction timer_action = { .handler = no_action, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .name = "Timer", }; diff --git a/arch/mips/pnx8550/common/time.c b/arch/mips/pnx8550/common/time.c index 8836c6203df0..831d6b369e9c 100644 --- a/arch/mips/pnx8550/common/time.c +++ b/arch/mips/pnx8550/common/time.c @@ -59,7 +59,7 @@ static irqreturn_t pnx8xxx_timer_interrupt(int irq, void *dev_id) static struct irqaction pnx8xxx_timer_irq = { .handler = pnx8xxx_timer_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, + .flags = IRQF_PERCPU | IRQF_TIMER, .name = "pnx8xxx_timer", }; @@ -72,7 +72,7 @@ static irqreturn_t monotonic_interrupt(int irq, void *dev_id) static struct irqaction monotonic_irqaction = { .handler = monotonic_interrupt, - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .name = "Monotonic timer", }; diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile index cc538493cae1..411cda9ee030 100644 --- a/arch/mips/sgi-ip22/Makefile +++ b/arch/mips/sgi-ip22/Makefile @@ -4,7 +4,7 @@ # obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \ - ip22-platform.o ip22-reset.o ip22-setup.o + ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o obj-$(CONFIG_SGI_IP22) += ip22-berr.o obj-$(CONFIG_SGI_IP28) += ip28-berr.o diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c new file mode 100644 index 000000000000..f5ebc092aed5 --- /dev/null +++ b/arch/mips/sgi-ip22/ip22-gio.c @@ -0,0 +1,428 @@ +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> + +#include <asm/addrspace.h> +#include <asm/paccess.h> +#include <asm/gio_device.h> +#include <asm/sgi/gio.h> +#include <asm/sgi/hpc3.h> +#include <asm/sgi/mc.h> +#include <asm/sgi/ip22.h> + +static struct bus_type gio_bus_type; + +static struct { + const char *name; + __u8 id; +} gio_name_table[] = { + { .name = "SGI Impact", .id = 0x10 }, + { .name = "Phobos G160", .id = 0x35 }, + /* fake IDs */ + { .name = "SGI Newport", .id = 0x7e }, + { .name = "SGI GR2/GR3", .id = 0x7f }, +}; + +static struct device gio_bus = { + .init_name = "gio", +}; + +/** + * gio_match_device - Tell if an of_device structure has a matching + * gio_match structure + * @ids: array of of device match structures to search in + * @dev: the of device structure to match against + * + * Used by a driver to check whether an of_device present in the + * system is in its list of supported devices. + */ +const struct gio_device_id *gio_match_device(const struct gio_device_id *match, + const struct gio_device *dev) +{ + const struct gio_device_id *ids; + + for (ids = match; ids->id != 0xff; ids++) + if (ids->id == dev->id.id) + return ids; + + return NULL; +} +EXPORT_SYMBOL_GPL(gio_match_device); + +struct gio_device *gio_dev_get(struct gio_device *dev) +{ + struct device *tmp; + + if (!dev) + return NULL; + tmp = get_device(&dev->dev); + if (tmp) + return to_gio_device(tmp); + else + return NULL; +} +EXPORT_SYMBOL_GPL(gio_dev_get); + +void gio_dev_put(struct gio_device *dev) +{ + if (dev) + put_device(&dev->dev); +} +EXPORT_SYMBOL_GPL(gio_dev_put); + +/** + * gio_release_dev - free an gio device structure when all users of it are finished. + * @dev: device that's been disconnected + * + * Will be called only by the device core when all users of this gio device are + * done. + */ +void gio_release_dev(struct device *dev) +{ + struct gio_device *giodev; + + giodev = to_gio_device(dev); + kfree(giodev); +} +EXPORT_SYMBOL_GPL(gio_release_dev); + +int gio_device_register(struct gio_device *giodev) +{ + giodev->dev.bus = &gio_bus_type; + giodev->dev.parent = &gio_bus; + return device_register(&giodev->dev); +} +EXPORT_SYMBOL_GPL(gio_device_register); + +void gio_device_unregister(struct gio_device *giodev) +{ + device_unregister(&giodev->dev); +} +EXPORT_SYMBOL_GPL(gio_device_unregister); + +static int gio_bus_match(struct device *dev, struct device_driver *drv) +{ + struct gio_device *gio_dev = to_gio_device(dev); + struct gio_driver *gio_drv = to_gio_driver(drv); + + return gio_match_device(gio_drv->id_table, gio_dev) != NULL; +} + +static int gio_device_probe(struct device *dev) +{ + int error = -ENODEV; + struct gio_driver *drv; + struct gio_device *gio_dev; + const struct gio_device_id *match; + + drv = to_gio_driver(dev->driver); + gio_dev = to_gio_device(dev); + + if (!drv->probe) + return error; + + gio_dev_get(gio_dev); + + match = gio_match_device(drv->id_table, gio_dev); + if (match) + error = drv->probe(gio_dev, match); + if (error) + gio_dev_put(gio_dev); + + return error; +} + +static int gio_device_remove(struct device *dev) +{ + struct gio_device *gio_dev = to_gio_device(dev); + struct gio_driver *drv = to_gio_driver(dev->driver); + + if (dev->driver && drv->remove) + drv->remove(gio_dev); + return 0; +} + +static int gio_device_suspend(struct device *dev, pm_message_t state) +{ + struct gio_device *gio_dev = to_gio_device(dev); + struct gio_driver *drv = to_gio_driver(dev->driver); + int error = 0; + + if (dev->driver && drv->suspend) + error = drv->suspend(gio_dev, state); + return error; +} + +static int gio_device_resume(struct device *dev) +{ + struct gio_device *gio_dev = to_gio_device(dev); + struct gio_driver *drv = to_gio_driver(dev->driver); + int error = 0; + + if (dev->driver && drv->resume) + error = drv->resume(gio_dev); + return error; +} + +static void gio_device_shutdown(struct device *dev) +{ + struct gio_device *gio_dev = to_gio_device(dev); + struct gio_driver *drv = to_gio_driver(dev->driver); + + if (dev->driver && drv->shutdown) + drv->shutdown(gio_dev); +} + +static ssize_t modalias_show(struct device *dev, struct device_attribute *a, + char *buf) +{ + struct gio_device *gio_dev = to_gio_device(dev); + int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id); + + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; +} + +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gio_device *giodev; + + giodev = to_gio_device(dev); + return sprintf(buf, "%s", giodev->name); +} + +static ssize_t id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gio_device *giodev; + + giodev = to_gio_device(dev); + return sprintf(buf, "%x", giodev->id.id); +} + +static struct device_attribute gio_dev_attrs[] = { + __ATTR_RO(modalias), + __ATTR_RO(name), + __ATTR_RO(id), + __ATTR_NULL, +}; + +static int gio_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct gio_device *gio_dev = to_gio_device(dev); + + add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id); + return 0; +} + +int gio_register_driver(struct gio_driver *drv) +{ + /* initialize common driver fields */ + if (!drv->driver.name) + drv->driver.name = drv->name; + if (!drv->driver.owner) + drv->driver.owner = drv->owner; + drv->driver.bus = &gio_bus_type; + + /* register with core */ + return driver_register(&drv->driver); +} +EXPORT_SYMBOL_GPL(gio_register_driver); + +void gio_unregister_driver(struct gio_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL_GPL(gio_unregister_driver); + +void gio_set_master(struct gio_device *dev) +{ + u32 tmp = sgimc->giopar; + + switch (dev->slotno) { + case 0: + tmp |= SGIMC_GIOPAR_MASTERGFX; + break; + case 1: + tmp |= SGIMC_GIOPAR_MASTEREXP0; + break; + case 2: + tmp |= SGIMC_GIOPAR_MASTEREXP1; + break; + } + sgimc->giopar = tmp; +} +EXPORT_SYMBOL_GPL(gio_set_master); + +void ip22_gio_set_64bit(int slotno) +{ + u32 tmp = sgimc->giopar; + + switch (slotno) { + case 0: + tmp |= SGIMC_GIOPAR_GFX64; + break; + case 1: + tmp |= SGIMC_GIOPAR_EXP064; + break; + case 2: + tmp |= SGIMC_GIOPAR_EXP164; + break; + } + sgimc->giopar = tmp; +} + +static int ip22_gio_id(unsigned long addr, u32 *res) +{ + u8 tmp8; + u8 tmp16; + u32 tmp32; + u8 *ptr8; + u16 *ptr16; + u32 *ptr32; + + ptr32 = (void *)CKSEG1ADDR(addr); + if (!get_dbe(tmp32, ptr32)) { + /* + * We got no DBE, but this doesn't mean anything. + * If GIO is pipelined (which can't be disabled + * for GFX slot) we don't get a DBE, but we see + * the transfer size as data. So we do an 8bit + * and a 16bit access and check whether the common + * data matches + */ + ptr8 = (void *)CKSEG1ADDR(addr + 3); + get_dbe(tmp8, ptr8); + ptr16 = (void *)CKSEG1ADDR(addr + 2); + get_dbe(tmp16, ptr16); + if (tmp8 == (tmp16 & 0xff) && + tmp8 == (tmp32 & 0xff) && + tmp16 == (tmp32 & 0xffff)) { + *res = tmp32; + return 1; + } + } + return 0; /* nothing here */ +} + +#define HQ2_MYSTERY_OFFS 0x6A07C +#define NEWPORT_USTATUS_OFFS 0xF133C + +static int ip22_is_gr2(unsigned long addr) +{ + u32 tmp; + u32 *ptr; + + /* HQ2 only allows 32bit accesses */ + ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS); + if (!get_dbe(tmp, ptr)) { + if (tmp == 0xdeadbeef) + return 1; + } + return 0; +} + + +static void ip22_check_gio(int slotno, unsigned long addr) +{ + const char *name = "Unknown"; + struct gio_device *gio_dev; + u32 tmp; + __u8 id; + int i; + + /* first look for GR2/GR3 by checking mystery register */ + if (ip22_is_gr2(addr)) + tmp = 0x7f; + else { + if (!ip22_gio_id(addr, &tmp)) { + /* + * no GIO signature at start address of slot, but + * Newport doesn't have one, so let's check usea + * status register + */ + if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp)) + tmp = 0x7e; + else + tmp = 0; + } + } + if (tmp) { + id = GIO_ID(tmp); + if (tmp & GIO_32BIT_ID) { + if (tmp & GIO_64BIT_IFACE) + ip22_gio_set_64bit(slotno); + } + for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) { + if (id == gio_name_table[i].id) { + name = gio_name_table[i].name; + break; + } + } + printk(KERN_INFO "GIO: slot %d : %s (id %x)\n", + slotno, name, id); + gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL); + gio_dev->name = name; + gio_dev->slotno = slotno; + gio_dev->id.id = id; + gio_dev->resource.start = addr; + gio_dev->resource.end = addr + 0x3fffff; + gio_dev->resource.flags = IORESOURCE_MEM; + dev_set_name(&gio_dev->dev, "%d", slotno); + gio_device_register(gio_dev); + } else + printk(KERN_INFO "GIO: slot %d : Empty\n", slotno); +} + +static struct bus_type gio_bus_type = { + .name = "gio", + .dev_attrs = gio_dev_attrs, + .match = gio_bus_match, + .probe = gio_device_probe, + .remove = gio_device_remove, + .suspend = gio_device_suspend, + .resume = gio_device_resume, + .shutdown = gio_device_shutdown, + .uevent = gio_device_uevent, +}; + +static struct resource gio_bus_resource = { + .start = GIO_SLOT_GFX_BASE, + .end = GIO_SLOT_GFX_BASE + 0x9fffff, + .name = "GIO Bus", + .flags = IORESOURCE_MEM, +}; + +int __init ip22_gio_init(void) +{ + unsigned int pbdma __maybe_unused; + int ret; + + ret = device_register(&gio_bus); + if (ret) + return ret; + + ret = bus_register(&gio_bus_type); + if (!ret) { + request_resource(&iomem_resource, &gio_bus_resource); + printk(KERN_INFO "GIO: Probing bus...\n"); + + if (ip22_is_fullhouse() || + !get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1])) { + /* Indigo2 and ChallengeS */ + ip22_check_gio(0, GIO_SLOT_GFX_BASE); + ip22_check_gio(1, GIO_SLOT_EXP0_BASE); + } else { + /* Indy */ + ip22_check_gio(0, GIO_SLOT_GFX_BASE); + ip22_check_gio(1, GIO_SLOT_EXP0_BASE); + ip22_check_gio(2, GIO_SLOT_EXP1_BASE); + } + } else + device_unregister(&gio_bus); + + return ret; +} + +subsys_initcall(ip22_gio_init); diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index f72c336ea27b..3f2b7633f946 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -155,32 +155,32 @@ static void __irq_entry indy_buserror_irq(void) static struct irqaction local0_cascade = { .handler = no_action, - .flags = IRQF_DISABLED | IRQF_NO_THREAD, + .flags = IRQF_NO_THREAD, .name = "local0 cascade", }; static struct irqaction local1_cascade = { .handler = no_action, - .flags = IRQF_DISABLED | IRQF_NO_THREAD, + .flags = IRQF_NO_THREAD, .name = "local1 cascade", }; static struct irqaction buserr = { .handler = no_action, - .flags = IRQF_DISABLED | IRQF_NO_THREAD, + .flags = IRQF_NO_THREAD, .name = "Bus Error", }; static struct irqaction map0_cascade = { .handler = no_action, - .flags = IRQF_DISABLED | IRQF_NO_THREAD, + .flags = IRQF_NO_THREAD, .name = "mapable0 cascade", }; #ifdef USE_LIO3_IRQ static struct irqaction map1_cascade = { .handler = no_action, - .flags = IRQF_DISABLED | IRQF_NO_THREAD, + .flags = IRQF_NO_THREAD, .name = "mapable1 cascade", }; #define SGI_INTERRUPTS SGINT_END diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c index d22262ee6853..75ada8a9713b 100644 --- a/arch/mips/sgi-ip22/ip22-mc.c +++ b/arch/mips/sgi-ip22/ip22-mc.c @@ -139,11 +139,11 @@ void __init sgimc_init(void) * zero. */ /* don't touch parity settings for IP28 */ -#ifndef CONFIG_SGI_IP28 tmp = sgimc->cpuctrl0; - tmp |= (SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM | - SGIMC_CCTRL0_R4KNOCHKPARR); +#ifndef CONFIG_SGI_IP28 + tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM; #endif + tmp |= SGIMC_CCTRL0_R4KNOCHKPARR; sgimc->cpuctrl0 = tmp; /* Step 3: Setup the MC write buffer depth, this is controlled @@ -178,7 +178,8 @@ void __init sgimc_init(void) */ /* First the basic invariants across all GIO64 implementations. */ - tmp = SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */ + tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */ + tmp |= SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */ tmp |= SGIMC_GIOPAR_ONEBUS; /* Only one physical GIO bus exists */ if (ip22_is_fullhouse()) { @@ -193,7 +194,6 @@ void __init sgimc_init(void) tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp[01] pipelined */ tmp |= SGIMC_GIOPAR_PLINEEXP1; tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */ - tmp |= SGIMC_GIOPAR_GFX64; /* GFX at 64 bits */ } } else { /* Guiness specific settings. */ diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c index 5e6621349471..c7bdfe43df5b 100644 --- a/arch/mips/sgi-ip22/ip22-setup.c +++ b/arch/mips/sgi-ip22/ip22-setup.c @@ -26,9 +26,6 @@ #include <asm/sgi/hpc3.h> #include <asm/sgi/ip22.h> -unsigned long sgi_gfxaddr; -EXPORT_SYMBOL_GPL(sgi_gfxaddr); - extern void ip22_be_init(void) __init; void __init plat_mem_setup(void) @@ -78,22 +75,4 @@ void __init plat_mem_setup(void) prom_flags |= PROM_FLAG_USE_AS_CONSOLE; add_preferred_console("arc", 0, NULL); } - -#if defined(CONFIG_VT) && defined(CONFIG_SGI_NEWPORT_CONSOLE) - { - ULONG *gfxinfo; - ULONG * (*__vec)(void) = (void *) (long) - *((_PULONG *)(long)((PROMBLOCK)->pvector + 0x20)); - - gfxinfo = __vec(); - sgi_gfxaddr = ((gfxinfo[1] >= 0xa0000000 - && gfxinfo[1] <= 0xc0000000) - ? gfxinfo[1] - 0xa0000000 : 0); - - /* newport addresses? */ - if (sgi_gfxaddr == 0x1f0f0000 || sgi_gfxaddr == 0x1f4f0000) { - conswitchp = &newport_con; - } - } -#endif } diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index f90dce315e04..23642238c689 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -73,7 +73,7 @@ static inline int alloc_level(int cpu, int irq) level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE); if (level >= LEVELS_PER_SLICE) - panic("Cpu %d flooded with devices\n", cpu); + panic("Cpu %d flooded with devices", cpu); __set_bit(level, hub->irq_alloc_mask); si->level_to_irq[level] = irq; @@ -96,7 +96,7 @@ static inline int find_level(cpuid_t *cpunum, int irq) } } - panic("Could not identify cpu/level for irq %d\n", irq); + panic("Could not identify cpu/level for irq %d", irq); } /* @@ -116,7 +116,7 @@ static int ms1bit(unsigned long x) } /* - * This code is unnecessarily complex, because we do IRQF_DISABLED + * This code is unnecessarily complex, because we do * intr enabling. Basically, once we grab the set of intrs we need * to service, we must mask _all_ these interrupts; firstly, to make * sure the same intr does not intr again, causing recursion that diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index ef74f3267f91..13cfeab50528 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -91,7 +91,7 @@ static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id) struct irqaction hub_rt_irqaction = { .handler = hub_rt_counter_handler, - .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, + .flags = IRQF_PERCPU | IRQF_TIMER, .name = "hub-rt", }; diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index c65ea76d56c7..a092860d5196 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -113,13 +113,11 @@ extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); static struct irqaction memerr_irq = { .handler = crime_memerr_intr, - .flags = IRQF_DISABLED, .name = "CRIME memory error", }; static struct irqaction cpuerr_irq = { .handler = crime_cpuerr_intr, - .flags = IRQF_DISABLED, .name = "CRIME CPU error", }; diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c index e8e72bb3a9af..5a4ec75382e2 100644 --- a/arch/mips/sni/irq.c +++ b/arch/mips/sni/irq.c @@ -42,7 +42,7 @@ static irqreturn_t sni_isa_irq_handler(int dummy, void *p) struct irqaction sni_isa_irq = { .handler = sni_isa_irq_handler, .name = "ISA", - .flags = IRQF_SHARED | IRQF_DISABLED + .flags = IRQF_SHARED }; /* diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index ec0be14996a4..494c9e7847aa 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c @@ -68,7 +68,7 @@ static irqreturn_t a20r_interrupt(int irq, void *dev_id) static struct irqaction a20r_irqaction = { .handler = a20r_interrupt, - .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, + .flags = IRQF_PERCPU | IRQF_TIMER, .name = "a20r-timer", }; diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 85a87de17eb4..682efb0c108d 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c @@ -262,7 +262,7 @@ txx9_i8259_irq_setup(int irq) int err; init_i8259_irqs(); - err = request_irq(irq, &i8259_interrupt, IRQF_DISABLED|IRQF_SHARED, + err = request_irq(irq, &i8259_interrupt, IRQF_SHARED, "cascade(i8259)", (void *)(long)irq); if (!err) printk(KERN_INFO "PCI-ISA bridge PIC (irq %d)\n", irq); diff --git a/arch/mn10300/include/asm/param.h b/arch/mn10300/include/asm/param.h index 789b1df41fcb..02a0ca6f13ce 100644 --- a/arch/mn10300/include/asm/param.h +++ b/arch/mn10300/include/asm/param.h @@ -11,24 +11,8 @@ #ifndef _ASM_PARAM_H #define _ASM_PARAM_H -#ifdef __KERNEL__ -#define HZ CONFIG_HZ /* Internal kernel timer frequency */ -#define USER_HZ 100 /* .. some user interfaces are in - * "ticks" */ -#define CLOCKS_PER_SEC (USER_HZ) /* like times() */ -#endif +#include <asm-generic/param.h> -#ifndef HZ -#define HZ 100 -#endif - -#define EXEC_PAGESIZE 4096 - -#ifndef NOGROUP -#define NOGROUP (-1) -#endif - -#define MAXHOSTNAMELEN 64 /* max length of hostname */ #define COMMAND_LINE_SIZE 256 #endif /* _ASM_PARAM_H */ diff --git a/arch/openrisc/boot/Makefile b/arch/openrisc/boot/Makefile index 98ca185097a5..09958358601a 100644 --- a/arch/openrisc/boot/Makefile +++ b/arch/openrisc/boot/Makefile @@ -11,5 +11,5 @@ clean-files := *.dtb.S #DTC_FLAGS ?= -p 1024 -$(obj)/%.dtb: $(src)/dts/%.dts - $(call cmd,dtc) +$(obj)/%.dtb: $(src)/dts/%.dts FORCE + $(call if_changed_dep,dtc) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 15986e70799c..8844a17ce8ed 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -345,8 +345,8 @@ $(obj)/treeImage.%: vmlinux $(obj)/%.dtb $(wrapperbits) $(call if_changed,wrap,treeboot-$*,,$(obj)/$*.dtb) # Rule to build device tree blobs -$(obj)/%.dtb: $(src)/dts/%.dts - $(call cmd,dtc) +$(obj)/%.dtb: $(src)/dts/%.dts FORCE + $(call if_changed_dep,dtc) # If there isn't a platform selected then just strip the vmlinux. ifeq (,$(image-y)) diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 48223f9b8728..78a205162fd7 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -86,7 +86,18 @@ struct pt_regs { #define instruction_pointer(regs) ((regs)->nip) #define user_stack_pointer(regs) ((regs)->gpr[1]) #define kernel_stack_pointer(regs) ((regs)->gpr[1]) -#define regs_return_value(regs) ((regs)->gpr[3]) +static inline int is_syscall_success(struct pt_regs *regs) +{ + return !(regs->ccr & 0x10000000); +} + +static inline long regs_return_value(struct pt_regs *regs) +{ + if (is_syscall_success(regs)) + return regs->gpr[3]; + else + return -regs->gpr[3]; +} #ifdef CONFIG_SMP extern unsigned long profile_pc(struct pt_regs *regs); diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 7c66ce13da89..0a48bf5db6c8 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -50,12 +50,6 @@ static int __init powersave_off(char *arg) } __setup("powersave=off", powersave_off); -#if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_TRACEPOINTS) -static const bool idle_uses_rcu = 1; -#else -static const bool idle_uses_rcu; -#endif - /* * The body of the idle task. */ @@ -67,8 +61,7 @@ void cpu_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); while (1) { tick_nohz_idle_enter(); - if (!idle_uses_rcu) - rcu_idle_enter(); + rcu_idle_enter(); while (!need_resched() && !cpu_should_die()) { ppc64_runlatch_off(); @@ -106,8 +99,7 @@ void cpu_idle(void) HMT_medium(); ppc64_runlatch_on(); - if (!idle_uses_rcu) - rcu_idle_exit(); + rcu_idle_exit(); tick_nohz_idle_exit(); preempt_enable_no_resched(); if (cpu_should_die()) diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 5de73dbd15c7..5b43325402bc 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1724,22 +1724,20 @@ long do_syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->gpr[0]); - if (unlikely(current->audit_context)) { #ifdef CONFIG_PPC64 - if (!is_32bit_task()) - audit_syscall_entry(AUDIT_ARCH_PPC64, - regs->gpr[0], - regs->gpr[3], regs->gpr[4], - regs->gpr[5], regs->gpr[6]); - else + if (!is_32bit_task()) + audit_syscall_entry(AUDIT_ARCH_PPC64, + regs->gpr[0], + regs->gpr[3], regs->gpr[4], + regs->gpr[5], regs->gpr[6]); + else #endif - audit_syscall_entry(AUDIT_ARCH_PPC, - regs->gpr[0], - regs->gpr[3] & 0xffffffff, - regs->gpr[4] & 0xffffffff, - regs->gpr[5] & 0xffffffff, - regs->gpr[6] & 0xffffffff); - } + audit_syscall_entry(AUDIT_ARCH_PPC, + regs->gpr[0], + regs->gpr[3] & 0xffffffff, + regs->gpr[4] & 0xffffffff, + regs->gpr[5] & 0xffffffff, + regs->gpr[6] & 0xffffffff); return ret ?: regs->gpr[0]; } @@ -1748,9 +1746,7 @@ void do_syscall_trace_leave(struct pt_regs *regs) { int step; - if (unlikely(current->audit_context)) - audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, - regs->result); + audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs->result); diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S index fd05fdee576a..3ce73d0052b1 100644 --- a/arch/powerpc/platforms/pseries/hvCall.S +++ b/arch/powerpc/platforms/pseries/hvCall.S @@ -36,6 +36,7 @@ BEGIN_FTR_SECTION; \ b 1f; \ END_FTR_SECTION(0, 1); \ ld r12,hcall_tracepoint_refcount@toc(r2); \ + std r12,32(r1); \ cmpdi r12,0; \ beq+ 1f; \ mflr r0; \ @@ -74,7 +75,7 @@ END_FTR_SECTION(0, 1); \ BEGIN_FTR_SECTION; \ b 1f; \ END_FTR_SECTION(0, 1); \ - ld r12,hcall_tracepoint_refcount@toc(r2); \ + ld r12,32(r1); \ cmpdi r12,0; \ beq+ 1f; \ mflr r0; \ diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 948e0e3b3547..7bc73af6c7b9 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -546,6 +546,13 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args) unsigned long flags; unsigned int *depth; + /* + * We cannot call tracepoints inside RCU idle regions which + * means we must not trace H_CEDE. + */ + if (opcode == H_CEDE) + return; + local_irq_save(flags); depth = &__get_cpu_var(hcall_trace_depth); @@ -556,8 +563,6 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args) (*depth)++; preempt_disable(); trace_hcall_entry(opcode, args); - if (opcode == H_CEDE) - rcu_idle_enter(); (*depth)--; out: @@ -570,6 +575,9 @@ void __trace_hcall_exit(long opcode, unsigned long retval, unsigned long flags; unsigned int *depth; + if (opcode == H_CEDE) + return; + local_irq_save(flags); depth = &__get_cpu_var(hcall_trace_depth); @@ -578,8 +586,6 @@ void __trace_hcall_exit(long opcode, unsigned long retval, goto out; (*depth)++; - if (opcode == H_CEDE) - rcu_idle_exit(); trace_hcall_exit(opcode, retval, retbuf); preempt_enable(); (*depth)--; diff --git a/arch/s390/include/asm/chpid.h b/arch/s390/include/asm/chpid.h index fc71d8a6709b..8e88e2221771 100644 --- a/arch/s390/include/asm/chpid.h +++ b/arch/s390/include/asm/chpid.h @@ -6,7 +6,7 @@ */ #ifndef _ASM_S390_CHPID_H -#define _ASM_S390_CHPID_H _ASM_S390_CHPID_H +#define _ASM_S390_CHPID_H #include <linux/string.h> #include <linux/types.h> diff --git a/arch/s390/include/asm/itcw.h b/arch/s390/include/asm/itcw.h index a9bc5c36b32a..fb1bedd3dc0d 100644 --- a/arch/s390/include/asm/itcw.h +++ b/arch/s390/include/asm/itcw.h @@ -6,7 +6,7 @@ */ #ifndef _ASM_S390_ITCW_H -#define _ASM_S390_ITCW_H _ASM_S390_ITCW_H +#define _ASM_S390_ITCW_H #include <linux/types.h> #include <asm/fcx.h> diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h index cf4e47b0948c..3f30dac804ea 100644 --- a/arch/s390/include/asm/kexec.h +++ b/arch/s390/include/asm/kexec.h @@ -42,6 +42,24 @@ /* The native architecture */ #define KEXEC_ARCH KEXEC_ARCH_S390 +/* + * Size for s390x ELF notes per CPU + * + * Seven notes plus zero note at the end: prstatus, fpregset, timer, + * tod_cmp, tod_reg, control regs, and prefix + */ +#define KEXEC_NOTE_BYTES \ + (ALIGN(sizeof(struct elf_note), 4) * 8 + \ + ALIGN(sizeof("CORE"), 4) * 7 + \ + ALIGN(sizeof(struct elf_prstatus), 4) + \ + ALIGN(sizeof(elf_fpregset_t), 4) + \ + ALIGN(sizeof(u64), 4) + \ + ALIGN(sizeof(u64), 4) + \ + ALIGN(sizeof(u32), 4) + \ + ALIGN(sizeof(u64) * 16, 4) + \ + ALIGN(sizeof(u32), 4) \ + ) + /* Provide a dummy definition to avoid build failures. */ static inline void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) { } diff --git a/arch/s390/include/asm/mman.h b/arch/s390/include/asm/mman.h index 4e9c8ae0a637..d49760e63506 100644 --- a/arch/s390/include/asm/mman.h +++ b/arch/s390/include/asm/mman.h @@ -11,9 +11,11 @@ #include <asm-generic/mman.h> -#if defined(__KERNEL__) && !defined(__ASSEMBLY__) && defined(CONFIG_64BIT) +#if defined(__KERNEL__) +#if !defined(__ASSEMBLY__) && defined(CONFIG_64BIT) int s390_mmap_check(unsigned long addr, unsigned long len); #define arch_mmap_check(addr,len,flags) s390_mmap_check(addr,len) #endif +#endif #endif /* __S390_MMAN_H__ */ diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 56da355678f4..aeb77f017985 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -541,9 +541,13 @@ struct user_regs_struct #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) #define user_stack_pointer(regs)((regs)->gprs[15]) -#define regs_return_value(regs)((regs)->gprs[2]) #define profile_pc(regs) instruction_pointer(regs) +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->gprs[2]; +} + int regs_query_register_offset(const char *name); const char *regs_query_register_name(unsigned int offset); unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset); diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 573bc29551ef..9d82ed4bcb27 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -740,20 +740,17 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->gprs[2]); - if (unlikely(current->audit_context)) - audit_syscall_entry(is_compat_task() ? - AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, - regs->gprs[2], regs->orig_gpr2, - regs->gprs[3], regs->gprs[4], - regs->gprs[5]); + audit_syscall_entry(is_compat_task() ? + AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, + regs->gprs[2], regs->orig_gpr2, + regs->gprs[3], regs->gprs[4], + regs->gprs[5]); return ret ?: regs->gprs[2]; } asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) { - if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), - regs->gprs[2]); + audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs->gprs[2]); diff --git a/arch/score/kernel/entry.S b/arch/score/kernel/entry.S index 577abba3fac6..83bb96079c43 100644 --- a/arch/score/kernel/entry.S +++ b/arch/score/kernel/entry.S @@ -408,7 +408,7 @@ ENTRY(handle_sys) sw r9, [r0, PT_EPC] cmpi.c r27, __NR_syscalls # check syscall number - bgtu illegal_syscall + bgeu illegal_syscall slli r8, r27, 2 # get syscall routine la r11, sys_call_table diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 74d49c01783b..6418e95c2b6b 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -207,7 +207,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = RGB18, .clock_divider = 1, .lcd_cfg = ap325rxa_lcdc_modes, diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 9a19fb07276c..033ef2ba621f 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -324,7 +324,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .ch[0] = { .interface_type = RGB18, .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .lcd_size_cfg = { /* 7.0 inch */ .width = 152, .height = 91, diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 5c3c71366848..2a18b06abdaf 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -143,7 +143,7 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { .clock_source = LCDC_CLK_BUS, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = SYS18, .clock_divider = 6, .flags = LCDC_FLAGS_DWPOL, diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index f8f9377d5684..68c3d6f42896 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -241,7 +241,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { .clock_source = LCDC_CLK_BUS, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = RGB16, .clock_divider = 2, .lcd_cfg = migor_lcd_modes, @@ -255,7 +255,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { .clock_source = LCDC_CLK_PERIPHERAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = SYS16A, .clock_divider = 10, .lcd_cfg = migor_lcd_modes, diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 2585733e9bce..036fe1adaef1 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -179,7 +179,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .clock_divider = 1, .lcd_size_cfg = { /* 7.0 inch */ .width = 152, diff --git a/arch/sh/include/asm/ptrace_32.h b/arch/sh/include/asm/ptrace_32.h index 6c2239cca1a2..2d3e906aa722 100644 --- a/arch/sh/include/asm/ptrace_32.h +++ b/arch/sh/include/asm/ptrace_32.h @@ -76,7 +76,10 @@ struct pt_dspregs { #ifdef __KERNEL__ #define MAX_REG_OFFSET offsetof(struct pt_regs, tra) -#define regs_return_value(_regs) ((_regs)->regs[0]) +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->regs[0]; +} #endif /* __KERNEL__ */ diff --git a/arch/sh/include/asm/ptrace_64.h b/arch/sh/include/asm/ptrace_64.h index bf9be7764d69..eb3fcceaf64b 100644 --- a/arch/sh/include/asm/ptrace_64.h +++ b/arch/sh/include/asm/ptrace_64.h @@ -13,7 +13,10 @@ struct pt_regs { #ifdef __KERNEL__ #define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7]) -#define regs_return_value(_regs) ((_regs)->regs[3]) +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->regs[3]; +} #endif /* __KERNEL__ */ diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 92b3c276339a..a3e651563763 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -518,10 +518,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->regs[0]); - if (unlikely(current->audit_context)) - audit_syscall_entry(audit_arch(), regs->regs[3], - regs->regs[4], regs->regs[5], - regs->regs[6], regs->regs[7]); + audit_syscall_entry(audit_arch(), regs->regs[3], + regs->regs[4], regs->regs[5], + regs->regs[6], regs->regs[7]); return ret ?: regs->regs[0]; } @@ -530,9 +529,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) { int step; - if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]), - regs->regs[0]); + audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs->regs[0]); diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index c8f97649f354..3d0080b5c976 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -536,10 +536,9 @@ asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->regs[9]); - if (unlikely(current->audit_context)) - audit_syscall_entry(audit_arch(), regs->regs[1], - regs->regs[2], regs->regs[3], - regs->regs[4], regs->regs[5]); + audit_syscall_entry(audit_arch(), regs->regs[1], + regs->regs[2], regs->regs[3], + regs->regs[4], regs->regs[5]); return ret ?: regs->regs[9]; } @@ -548,9 +547,7 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) { int step; - if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(regs->regs[9]), - regs->regs[9]); + audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs->regs[9]); diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index a0e1bcf843a1..c00c3b5c2806 100644 --- a/arch/sparc/include/asm/ptrace.h +++ b/arch/sparc/include/asm/ptrace.h @@ -207,7 +207,15 @@ do { current_thread_info()->syscall_noerror = 1; \ #define instruction_pointer(regs) ((regs)->tpc) #define instruction_pointer_set(regs, val) ((regs)->tpc = (val)) #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) -#define regs_return_value(regs) ((regs)->u_regs[UREG_I0]) +static inline int is_syscall_success(struct pt_regs *regs) +{ + return !(regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)); +} + +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->u_regs[UREG_I0]; +} #ifdef CONFIG_SMP extern unsigned long profile_pc(struct pt_regs *); #else diff --git a/arch/sparc/include/asm/siginfo.h b/arch/sparc/include/asm/siginfo.h index 988e5d8ed11a..215900fce21b 100644 --- a/arch/sparc/include/asm/siginfo.h +++ b/arch/sparc/include/asm/siginfo.h @@ -16,8 +16,6 @@ #ifdef __KERNEL__ -#include <linux/compat.h> - #ifdef CONFIG_COMPAT struct compat_siginfo; diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 96ee50a80661..9388844cd88c 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c @@ -1071,32 +1071,22 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->u_regs[UREG_G1]); - if (unlikely(current->audit_context) && !ret) - audit_syscall_entry((test_thread_flag(TIF_32BIT) ? - AUDIT_ARCH_SPARC : - AUDIT_ARCH_SPARC64), - regs->u_regs[UREG_G1], - regs->u_regs[UREG_I0], - regs->u_regs[UREG_I1], - regs->u_regs[UREG_I2], - regs->u_regs[UREG_I3]); + audit_syscall_entry((test_thread_flag(TIF_32BIT) ? + AUDIT_ARCH_SPARC : + AUDIT_ARCH_SPARC64), + regs->u_regs[UREG_G1], + regs->u_regs[UREG_I0], + regs->u_regs[UREG_I1], + regs->u_regs[UREG_I2], + regs->u_regs[UREG_I3]); return ret; } asmlinkage void syscall_trace_leave(struct pt_regs *regs) { -#ifdef CONFIG_AUDITSYSCALL - if (unlikely(current->audit_context)) { - unsigned long tstate = regs->tstate; - int result = AUDITSC_SUCCESS; + audit_syscall_exit(regs); - if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) - result = AUDITSC_FAILURE; - - audit_syscall_exit(result, regs->u_regs[UREG_I0]); - } -#endif if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs->u_regs[UREG_G1]); diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h index 1e1e616783eb..1e5e49aad548 100644 --- a/arch/tile/include/asm/signal.h +++ b/arch/tile/include/asm/signal.h @@ -23,7 +23,8 @@ #include <asm-generic/signal.h> -#if defined(__KERNEL__) && !defined(__ASSEMBLY__) +#if defined(__KERNEL__) +#if !defined(__ASSEMBLY__) struct pt_regs; int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); int setup_sigcontext(struct sigcontext __user *, struct pt_regs *); @@ -33,5 +34,6 @@ 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/um/Makefile b/arch/um/Makefile index 7730af6ec13f..28688e6d96d7 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -64,7 +64,8 @@ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\ #This will adjust *FLAGS accordingly to the platform. include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS) -KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/include +KBUILD_CPPFLAGS += -I$(srctree)/$(HOST_DIR)/include \ + -I$(HOST_DIR)/include/generated # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common @@ -96,6 +97,10 @@ endef KBUILD_KCONFIG := $(HOST_DIR)/um/Kconfig +archheaders: + $(Q)$(MAKE) -C '$(srctree)' KBUILD_SRC= \ + ARCH=$(SUBARCH) O='$(objtree)' archheaders + archprepare: include/generated/user_constants.h LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static @@ -135,7 +140,7 @@ archclean: # Generated files -$(HOST_DIR)/um/user-offsets.s: FORCE +$(HOST_DIR)/um/user-offsets.s: __headers FORCE $(Q)$(MAKE) $(build)=$(HOST_DIR)/um $@ define filechk_gen-asm-offsets diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index c9da32b0c707..06b190390505 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -167,17 +167,15 @@ void syscall_trace(struct uml_pt_regs *regs, int entryexit) int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit; int tracesysgood; - if (unlikely(current->audit_context)) { - if (!entryexit) - audit_syscall_entry(HOST_AUDIT_ARCH, - UPT_SYSCALL_NR(regs), - UPT_SYSCALL_ARG1(regs), - UPT_SYSCALL_ARG2(regs), - UPT_SYSCALL_ARG3(regs), - UPT_SYSCALL_ARG4(regs)); - else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), - UPT_SYSCALL_RET(regs)); - } + if (!entryexit) + audit_syscall_entry(HOST_AUDIT_ARCH, + UPT_SYSCALL_NR(regs), + UPT_SYSCALL_ARG1(regs), + UPT_SYSCALL_ARG2(regs), + UPT_SYSCALL_ARG3(regs), + UPT_SYSCALL_ARG4(regs)); + else + audit_syscall_exit(regs); /* Fake a debug trap */ if (is_singlestep) diff --git a/arch/x86/.gitignore b/arch/x86/.gitignore index 028079065af6..7cab8c08e6d1 100644 --- a/arch/x86/.gitignore +++ b/arch/x86/.gitignore @@ -1,3 +1,4 @@ boot/compressed/vmlinux tools/test_get_len +tools/insn_sanity diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6c14ecd851d0..864cc6e6ac8e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -125,16 +125,6 @@ config HAVE_LATENCYTOP_SUPPORT config MMU def_bool y -config ZONE_DMA - bool "DMA memory allocation support" if EXPERT - default y - help - DMA memory allocation support allows devices with less than 32-bit - addressing to allocate within the first 16MB of address space. - Disable if no such devices will be used. - - If unsure, say Y. - config SBUS bool @@ -255,6 +245,16 @@ source "kernel/Kconfig.freezer" menu "Processor type and features" +config ZONE_DMA + bool "DMA memory allocation support" if EXPERT + default y + help + DMA memory allocation support allows devices with less than 32-bit + addressing to allocate within the first 16MB of address space. + Disable if no such devices will be used. + + If unsure, say Y. + source "kernel/time/Kconfig" config SMP diff --git a/arch/x86/Makefile b/arch/x86/Makefile index b02e509072a7..209ba1294592 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -118,6 +118,12 @@ KBUILD_CFLAGS += $(mflags-y) KBUILD_AFLAGS += $(mflags-y) ### +# Syscall table generation + +archheaders: + $(Q)$(MAKE) $(build)=arch/x86/syscalls all + +### # Kernel objects head-y := arch/x86/kernel/head_$(BITS).o diff --git a/arch/x86/ia32/Makefile b/arch/x86/ia32/Makefile index 52d0ccfcf6ea..455646e0e532 100644 --- a/arch/x86/ia32/Makefile +++ b/arch/x86/ia32/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_signal.o +obj-$(CONFIG_IA32_EMULATION) += nosyscall.o syscall_ia32.o sysv-$(CONFIG_SYSVIPC) := ipc32.o obj-$(CONFIG_IA32_EMULATION) += $(sysv-y) diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 3e274564f6bf..e3e734005e19 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -14,6 +14,7 @@ #include <asm/segment.h> #include <asm/irqflags.h> #include <linux/linkage.h> +#include <linux/err.h> /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ #include <linux/elf-em.h> @@ -27,8 +28,6 @@ .section .entry.text, "ax" -#define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8) - .macro IA32_ARG_FIXUP noebp=0 movl %edi,%r8d .if \noebp @@ -191,7 +190,7 @@ sysexit_from_sys_call: movl %ebx,%edx /* 3rd arg: 1st syscall arg */ movl %eax,%esi /* 2nd arg: syscall number */ movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */ - call audit_syscall_entry + call __audit_syscall_entry movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */ cmpq $(IA32_NR_syscalls-1),%rax ja ia32_badsys @@ -208,12 +207,13 @@ sysexit_from_sys_call: TRACE_IRQS_ON sti movl %eax,%esi /* second arg, syscall return value */ - cmpl $0,%eax /* is it < 0? */ - setl %al /* 1 if so, 0 if not */ + cmpl $-MAX_ERRNO,%eax /* is it an error ? */ + jbe 1f + movslq %eax, %rsi /* if error sign extend to 64 bits */ +1: setbe %al /* 1 if error, 0 if not */ movzbl %al,%edi /* zero-extend that into %edi */ - inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ - call audit_syscall_exit - movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall return value */ + call __audit_syscall_exit + movq RAX-ARGOFFSET(%rsp),%rax /* reload syscall return value */ movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi cli TRACE_IRQS_OFF @@ -447,9 +447,6 @@ ia32_badsys: movq $-ENOSYS,%rax jmp ia32_sysret -quiet_ni_syscall: - movq $-ENOSYS,%rax - ret CFI_ENDPROC .macro PTREGSCALL label, func, arg @@ -494,357 +491,3 @@ ia32_ptregs_common: jmp ia32_sysret /* misbalances the return cache */ CFI_ENDPROC END(ia32_ptregs_common) - - .section .rodata,"a" - .align 8 -ia32_sys_call_table: - .quad sys_restart_syscall - .quad sys_exit - .quad stub32_fork - .quad sys_read - .quad sys_write - .quad compat_sys_open /* 5 */ - .quad sys_close - .quad sys32_waitpid - .quad sys_creat - .quad sys_link - .quad sys_unlink /* 10 */ - .quad stub32_execve - .quad sys_chdir - .quad compat_sys_time - .quad sys_mknod - .quad sys_chmod /* 15 */ - .quad sys_lchown16 - .quad quiet_ni_syscall /* old break syscall holder */ - .quad sys_stat - .quad sys32_lseek - .quad sys_getpid /* 20 */ - .quad compat_sys_mount /* mount */ - .quad sys_oldumount /* old_umount */ - .quad sys_setuid16 - .quad sys_getuid16 - .quad compat_sys_stime /* stime */ /* 25 */ - .quad compat_sys_ptrace /* ptrace */ - .quad sys_alarm - .quad sys_fstat /* (old)fstat */ - .quad sys_pause - .quad compat_sys_utime /* 30 */ - .quad quiet_ni_syscall /* old stty syscall holder */ - .quad quiet_ni_syscall /* old gtty syscall holder */ - .quad sys_access - .quad sys_nice - .quad quiet_ni_syscall /* 35 */ /* old ftime syscall holder */ - .quad sys_sync - .quad sys32_kill - .quad sys_rename - .quad sys_mkdir - .quad sys_rmdir /* 40 */ - .quad sys_dup - .quad sys_pipe - .quad compat_sys_times - .quad quiet_ni_syscall /* old prof syscall holder */ - .quad sys_brk /* 45 */ - .quad sys_setgid16 - .quad sys_getgid16 - .quad sys_signal - .quad sys_geteuid16 - .quad sys_getegid16 /* 50 */ - .quad sys_acct - .quad sys_umount /* new_umount */ - .quad quiet_ni_syscall /* old lock syscall holder */ - .quad compat_sys_ioctl - .quad compat_sys_fcntl64 /* 55 */ - .quad quiet_ni_syscall /* old mpx syscall holder */ - .quad sys_setpgid - .quad quiet_ni_syscall /* old ulimit syscall holder */ - .quad sys_olduname - .quad sys_umask /* 60 */ - .quad sys_chroot - .quad compat_sys_ustat - .quad sys_dup2 - .quad sys_getppid - .quad sys_getpgrp /* 65 */ - .quad sys_setsid - .quad sys32_sigaction - .quad sys_sgetmask - .quad sys_ssetmask - .quad sys_setreuid16 /* 70 */ - .quad sys_setregid16 - .quad sys32_sigsuspend - .quad compat_sys_sigpending - .quad sys_sethostname - .quad compat_sys_setrlimit /* 75 */ - .quad compat_sys_old_getrlimit /* old_getrlimit */ - .quad compat_sys_getrusage - .quad compat_sys_gettimeofday - .quad compat_sys_settimeofday - .quad sys_getgroups16 /* 80 */ - .quad sys_setgroups16 - .quad compat_sys_old_select - .quad sys_symlink - .quad sys_lstat - .quad sys_readlink /* 85 */ - .quad sys_uselib - .quad sys_swapon - .quad sys_reboot - .quad compat_sys_old_readdir - .quad sys32_mmap /* 90 */ - .quad sys_munmap - .quad sys_truncate - .quad sys_ftruncate - .quad sys_fchmod - .quad sys_fchown16 /* 95 */ - .quad sys_getpriority - .quad sys_setpriority - .quad quiet_ni_syscall /* old profil syscall holder */ - .quad compat_sys_statfs - .quad compat_sys_fstatfs /* 100 */ - .quad sys_ioperm - .quad compat_sys_socketcall - .quad sys_syslog - .quad compat_sys_setitimer - .quad compat_sys_getitimer /* 105 */ - .quad compat_sys_newstat - .quad compat_sys_newlstat - .quad compat_sys_newfstat - .quad sys_uname - .quad stub32_iopl /* 110 */ - .quad sys_vhangup - .quad quiet_ni_syscall /* old "idle" system call */ - .quad sys32_vm86_warning /* vm86old */ - .quad compat_sys_wait4 - .quad sys_swapoff /* 115 */ - .quad compat_sys_sysinfo - .quad sys32_ipc - .quad sys_fsync - .quad stub32_sigreturn - .quad stub32_clone /* 120 */ - .quad sys_setdomainname - .quad sys_newuname - .quad sys_modify_ldt - .quad compat_sys_adjtimex - .quad sys32_mprotect /* 125 */ - .quad compat_sys_sigprocmask - .quad quiet_ni_syscall /* create_module */ - .quad sys_init_module - .quad sys_delete_module - .quad quiet_ni_syscall /* 130 get_kernel_syms */ - .quad sys32_quotactl - .quad sys_getpgid - .quad sys_fchdir - .quad quiet_ni_syscall /* bdflush */ - .quad sys_sysfs /* 135 */ - .quad sys_personality - .quad quiet_ni_syscall /* for afs_syscall */ - .quad sys_setfsuid16 - .quad sys_setfsgid16 - .quad sys_llseek /* 140 */ - .quad compat_sys_getdents - .quad compat_sys_select - .quad sys_flock - .quad sys_msync - .quad compat_sys_readv /* 145 */ - .quad compat_sys_writev - .quad sys_getsid - .quad sys_fdatasync - .quad compat_sys_sysctl /* sysctl */ - .quad sys_mlock /* 150 */ - .quad sys_munlock - .quad sys_mlockall - .quad sys_munlockall - .quad sys_sched_setparam - .quad sys_sched_getparam /* 155 */ - .quad sys_sched_setscheduler - .quad sys_sched_getscheduler - .quad sys_sched_yield - .quad sys_sched_get_priority_max - .quad sys_sched_get_priority_min /* 160 */ - .quad sys32_sched_rr_get_interval - .quad compat_sys_nanosleep - .quad sys_mremap - .quad sys_setresuid16 - .quad sys_getresuid16 /* 165 */ - .quad sys32_vm86_warning /* vm86 */ - .quad quiet_ni_syscall /* query_module */ - .quad sys_poll - .quad quiet_ni_syscall /* old nfsservctl */ - .quad sys_setresgid16 /* 170 */ - .quad sys_getresgid16 - .quad sys_prctl - .quad stub32_rt_sigreturn - .quad sys32_rt_sigaction - .quad sys32_rt_sigprocmask /* 175 */ - .quad sys32_rt_sigpending - .quad compat_sys_rt_sigtimedwait - .quad sys32_rt_sigqueueinfo - .quad sys_rt_sigsuspend - .quad sys32_pread /* 180 */ - .quad sys32_pwrite - .quad sys_chown16 - .quad sys_getcwd - .quad sys_capget - .quad sys_capset - .quad stub32_sigaltstack - .quad sys32_sendfile - .quad quiet_ni_syscall /* streams1 */ - .quad quiet_ni_syscall /* streams2 */ - .quad stub32_vfork /* 190 */ - .quad compat_sys_getrlimit - .quad sys_mmap_pgoff - .quad sys32_truncate64 - .quad sys32_ftruncate64 - .quad sys32_stat64 /* 195 */ - .quad sys32_lstat64 - .quad sys32_fstat64 - .quad sys_lchown - .quad sys_getuid - .quad sys_getgid /* 200 */ - .quad sys_geteuid - .quad sys_getegid - .quad sys_setreuid - .quad sys_setregid - .quad sys_getgroups /* 205 */ - .quad sys_setgroups - .quad sys_fchown - .quad sys_setresuid - .quad sys_getresuid - .quad sys_setresgid /* 210 */ - .quad sys_getresgid - .quad sys_chown - .quad sys_setuid - .quad sys_setgid - .quad sys_setfsuid /* 215 */ - .quad sys_setfsgid - .quad sys_pivot_root - .quad sys_mincore - .quad sys_madvise - .quad compat_sys_getdents64 /* 220 getdents64 */ - .quad compat_sys_fcntl64 - .quad quiet_ni_syscall /* tux */ - .quad quiet_ni_syscall /* security */ - .quad sys_gettid - .quad sys32_readahead /* 225 */ - .quad sys_setxattr - .quad sys_lsetxattr - .quad sys_fsetxattr - .quad sys_getxattr - .quad sys_lgetxattr /* 230 */ - .quad sys_fgetxattr - .quad sys_listxattr - .quad sys_llistxattr - .quad sys_flistxattr - .quad sys_removexattr /* 235 */ - .quad sys_lremovexattr - .quad sys_fremovexattr - .quad sys_tkill - .quad sys_sendfile64 - .quad compat_sys_futex /* 240 */ - .quad compat_sys_sched_setaffinity - .quad compat_sys_sched_getaffinity - .quad sys_set_thread_area - .quad sys_get_thread_area - .quad compat_sys_io_setup /* 245 */ - .quad sys_io_destroy - .quad compat_sys_io_getevents - .quad compat_sys_io_submit - .quad sys_io_cancel - .quad sys32_fadvise64 /* 250 */ - .quad quiet_ni_syscall /* free_huge_pages */ - .quad sys_exit_group - .quad sys32_lookup_dcookie - .quad sys_epoll_create - .quad sys_epoll_ctl /* 255 */ - .quad sys_epoll_wait - .quad sys_remap_file_pages - .quad sys_set_tid_address - .quad compat_sys_timer_create - .quad compat_sys_timer_settime /* 260 */ - .quad compat_sys_timer_gettime - .quad sys_timer_getoverrun - .quad sys_timer_delete - .quad compat_sys_clock_settime - .quad compat_sys_clock_gettime /* 265 */ - .quad compat_sys_clock_getres - .quad compat_sys_clock_nanosleep - .quad compat_sys_statfs64 - .quad compat_sys_fstatfs64 - .quad sys_tgkill /* 270 */ - .quad compat_sys_utimes - .quad sys32_fadvise64_64 - .quad quiet_ni_syscall /* sys_vserver */ - .quad sys_mbind - .quad compat_sys_get_mempolicy /* 275 */ - .quad sys_set_mempolicy - .quad compat_sys_mq_open - .quad sys_mq_unlink - .quad compat_sys_mq_timedsend - .quad compat_sys_mq_timedreceive /* 280 */ - .quad compat_sys_mq_notify - .quad compat_sys_mq_getsetattr - .quad compat_sys_kexec_load /* reserved for kexec */ - .quad compat_sys_waitid - .quad quiet_ni_syscall /* 285: sys_altroot */ - .quad sys_add_key - .quad sys_request_key - .quad sys_keyctl - .quad sys_ioprio_set - .quad sys_ioprio_get /* 290 */ - .quad sys_inotify_init - .quad sys_inotify_add_watch - .quad sys_inotify_rm_watch - .quad sys_migrate_pages - .quad compat_sys_openat /* 295 */ - .quad sys_mkdirat - .quad sys_mknodat - .quad sys_fchownat - .quad compat_sys_futimesat - .quad sys32_fstatat /* 300 */ - .quad sys_unlinkat - .quad sys_renameat - .quad sys_linkat - .quad sys_symlinkat - .quad sys_readlinkat /* 305 */ - .quad sys_fchmodat - .quad sys_faccessat - .quad compat_sys_pselect6 - .quad compat_sys_ppoll - .quad sys_unshare /* 310 */ - .quad compat_sys_set_robust_list - .quad compat_sys_get_robust_list - .quad sys_splice - .quad sys32_sync_file_range - .quad sys_tee /* 315 */ - .quad compat_sys_vmsplice - .quad compat_sys_move_pages - .quad sys_getcpu - .quad sys_epoll_pwait - .quad compat_sys_utimensat /* 320 */ - .quad compat_sys_signalfd - .quad sys_timerfd_create - .quad sys_eventfd - .quad sys32_fallocate - .quad compat_sys_timerfd_settime /* 325 */ - .quad compat_sys_timerfd_gettime - .quad compat_sys_signalfd4 - .quad sys_eventfd2 - .quad sys_epoll_create1 - .quad sys_dup3 /* 330 */ - .quad sys_pipe2 - .quad sys_inotify_init1 - .quad compat_sys_preadv - .quad compat_sys_pwritev - .quad compat_sys_rt_tgsigqueueinfo /* 335 */ - .quad sys_perf_event_open - .quad compat_sys_recvmmsg - .quad sys_fanotify_init - .quad sys32_fanotify_mark - .quad sys_prlimit64 /* 340 */ - .quad sys_name_to_handle_at - .quad compat_sys_open_by_handle_at - .quad compat_sys_clock_adjtime - .quad sys_syncfs - .quad compat_sys_sendmmsg /* 345 */ - .quad sys_setns - .quad compat_sys_process_vm_readv - .quad compat_sys_process_vm_writev -ia32_syscall_end: diff --git a/arch/x86/ia32/nosyscall.c b/arch/x86/ia32/nosyscall.c new file mode 100644 index 000000000000..51ecd5b4e787 --- /dev/null +++ b/arch/x86/ia32/nosyscall.c @@ -0,0 +1,7 @@ +#include <linux/kernel.h> +#include <linux/errno.h> + +long compat_ni_syscall(void) +{ + return -ENOSYS; +} diff --git a/arch/x86/ia32/syscall_ia32.c b/arch/x86/ia32/syscall_ia32.c new file mode 100644 index 000000000000..4754ba0f5d9f --- /dev/null +++ b/arch/x86/ia32/syscall_ia32.c @@ -0,0 +1,25 @@ +/* System call table for ia32 emulation. */ + +#include <linux/linkage.h> +#include <linux/sys.h> +#include <linux/cache.h> +#include <asm/asm-offsets.h> + +#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void compat(void) ; +#include <asm/syscalls_32.h> +#undef __SYSCALL_I386 + +#define __SYSCALL_I386(nr, sym, compat) [nr] = compat, + +typedef void (*sys_call_ptr_t)(void); + +extern void compat_ni_syscall(void); + +const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = { + /* + * Smells like a compiler bug -- it doesn't work + * when the & below is removed. + */ + [0 ... __NR_ia32_syscall_max] = &compat_ni_syscall, +#include <asm/syscalls_32.h> +}; diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild index 6fa90a845e4c..b57e6a43a37a 100644 --- a/arch/x86/include/asm/Kbuild +++ b/arch/x86/include/asm/Kbuild @@ -19,7 +19,8 @@ header-y += processor-flags.h header-y += ptrace-abi.h header-y += sigcontext32.h header-y += ucontext.h -header-y += unistd_32.h -header-y += unistd_64.h header-y += vm86.h header-y += vsyscall.h + +genhdr-y += unistd_32.h +genhdr-y += unistd_64.h diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h index 24098aafce0d..fa13f0ec2874 100644 --- a/arch/x86/include/asm/atomic64_32.h +++ b/arch/x86/include/asm/atomic64_32.h @@ -82,7 +82,7 @@ static inline void atomic64_set(atomic64_t *v, long long i) * * Atomically reads the value of @v and returns it. */ -static inline long long atomic64_read(atomic64_t *v) +static inline long long atomic64_read(const atomic64_t *v) { long long r; asm volatile(ATOMIC64_ALTERNATIVE(read) diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h index 078ad0caefc6..b903d5ea3941 100644 --- a/arch/x86/include/asm/debugreg.h +++ b/arch/x86/include/asm/debugreg.h @@ -101,6 +101,28 @@ extern void aout_dump_debugregs(struct user *dump); extern void hw_breakpoint_restore(void); +#ifdef CONFIG_X86_64 +DECLARE_PER_CPU(int, debug_stack_usage); +static inline void debug_stack_usage_inc(void) +{ + __get_cpu_var(debug_stack_usage)++; +} +static inline void debug_stack_usage_dec(void) +{ + __get_cpu_var(debug_stack_usage)--; +} +int is_debug_stack(unsigned long addr); +void debug_stack_set_zero(void); +void debug_stack_reset(void); +#else /* !X86_64 */ +static inline int is_debug_stack(unsigned long addr) { return 0; } +static inline void debug_stack_set_zero(void) { } +static inline void debug_stack_reset(void) { } +static inline void debug_stack_usage_inc(void) { } +static inline void debug_stack_usage_dec(void) { } +#endif /* X86_64 */ + + #endif /* __KERNEL__ */ #endif /* _ASM_X86_DEBUGREG_H */ diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h index 41935fadfdfc..e95822d683f4 100644 --- a/arch/x86/include/asm/desc.h +++ b/arch/x86/include/asm/desc.h @@ -35,6 +35,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in extern struct desc_ptr idt_descr; extern gate_desc idt_table[]; +extern struct desc_ptr nmi_idt_descr; +extern gate_desc nmi_idt_table[]; struct gdt_page { struct desc_struct gdt[GDT_ENTRIES]; @@ -307,6 +309,16 @@ static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit) desc->limit = (limit >> 16) & 0xf; } +#ifdef CONFIG_X86_64 +static inline void set_nmi_gate(int gate, void *addr) +{ + gate_desc s; + + pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS); + write_idt_entry(nmi_idt_table, gate, &s); +} +#endif + static inline void _set_gate(int gate, unsigned type, void *addr, unsigned dpl, unsigned ist, unsigned seg) { diff --git a/arch/x86/include/asm/ia32_unistd.h b/arch/x86/include/asm/ia32_unistd.h index 976f6ecd2ce6..b0d5716ca1e4 100644 --- a/arch/x86/include/asm/ia32_unistd.h +++ b/arch/x86/include/asm/ia32_unistd.h @@ -2,17 +2,10 @@ #define _ASM_X86_IA32_UNISTD_H /* - * This file contains the system call numbers of the ia32 port, + * This file contains the system call numbers of the ia32 compat ABI, * this is for the kernel only. - * Only add syscalls here where some part of the kernel needs to know - * the number. This should be otherwise in sync with asm-x86/unistd_32.h. -AK */ - -#define __NR_ia32_restart_syscall 0 -#define __NR_ia32_exit 1 -#define __NR_ia32_read 3 -#define __NR_ia32_write 4 -#define __NR_ia32_sigreturn 119 -#define __NR_ia32_rt_sigreturn 173 +#define __SYSCALL_ia32_NR(x) (x) +#include <asm/unistd_32_ia32.h> #endif /* _ASM_X86_IA32_UNISTD_H */ diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index f35ce43c1a77..6aefb14cbbc5 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -151,7 +151,7 @@ static inline void enable_p5_mce(void) {} void mce_setup(struct mce *m); void mce_log(struct mce *m); -DECLARE_PER_CPU(struct device, mce_device); +extern struct device *mce_device[CONFIG_NR_CPUS]; /* * Maximum banks number. diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index c4a348f7bd43..d962e5652a73 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h @@ -15,6 +15,7 @@ #include <linux/sched.h> #include <linux/err.h> +#include <asm/asm-offsets.h> /* For NR_syscalls */ extern const unsigned long sys_call_table[]; diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h index 2a58ed3e51d8..21f77b89e47a 100644 --- a/arch/x86/include/asm/unistd.h +++ b/arch/x86/include/asm/unistd.h @@ -1,13 +1,60 @@ +#ifndef _ASM_X86_UNISTD_H +#define _ASM_X86_UNISTD_H 1 + #ifdef __KERNEL__ # ifdef CONFIG_X86_32 -# include "unistd_32.h" + +# include <asm/unistd_32.h> +# define __ARCH_WANT_IPC_PARSE_VERSION +# define __ARCH_WANT_STAT64 +# define __ARCH_WANT_SYS_IPC +# define __ARCH_WANT_SYS_OLD_MMAP +# define __ARCH_WANT_SYS_OLD_SELECT + # else -# include "unistd_64.h" + +# include <asm/unistd_64.h> +# define __ARCH_WANT_COMPAT_SYS_TIME + # endif + +# define __ARCH_WANT_OLD_READDIR +# define __ARCH_WANT_OLD_STAT +# define __ARCH_WANT_SYS_ALARM +# define __ARCH_WANT_SYS_FADVISE64 +# define __ARCH_WANT_SYS_GETHOSTNAME +# define __ARCH_WANT_SYS_GETPGRP +# define __ARCH_WANT_SYS_LLSEEK +# define __ARCH_WANT_SYS_NICE +# define __ARCH_WANT_SYS_OLDUMOUNT +# define __ARCH_WANT_SYS_OLD_GETRLIMIT +# define __ARCH_WANT_SYS_OLD_UNAME +# define __ARCH_WANT_SYS_PAUSE +# define __ARCH_WANT_SYS_RT_SIGACTION +# define __ARCH_WANT_SYS_RT_SIGSUSPEND +# define __ARCH_WANT_SYS_SGETMASK +# define __ARCH_WANT_SYS_SIGNAL +# define __ARCH_WANT_SYS_SIGPENDING +# define __ARCH_WANT_SYS_SIGPROCMASK +# define __ARCH_WANT_SYS_SOCKETCALL +# define __ARCH_WANT_SYS_TIME +# define __ARCH_WANT_SYS_UTIME +# define __ARCH_WANT_SYS_WAITPID + +/* + * "Conditional" syscalls + * + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), + * but it doesn't work on all toolchains, so we just do it by hand + */ +# define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") + #else # ifdef __i386__ -# include "unistd_32.h" +# include <asm/unistd_32.h> # else -# include "unistd_64.h" +# include <asm/unistd_64.h> # endif #endif + +#endif /* _ASM_X86_UNISTD_H */ diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h deleted file mode 100644 index 599c77d38f33..000000000000 --- a/arch/x86/include/asm/unistd_32.h +++ /dev/null @@ -1,401 +0,0 @@ -#ifndef _ASM_X86_UNISTD_32_H -#define _ASM_X86_UNISTD_32_H - -/* - * This file contains the system call numbers. - */ - -#define __NR_restart_syscall 0 -#define __NR_exit 1 -#define __NR_fork 2 -#define __NR_read 3 -#define __NR_write 4 -#define __NR_open 5 -#define __NR_close 6 -#define __NR_waitpid 7 -#define __NR_creat 8 -#define __NR_link 9 -#define __NR_unlink 10 -#define __NR_execve 11 -#define __NR_chdir 12 -#define __NR_time 13 -#define __NR_mknod 14 -#define __NR_chmod 15 -#define __NR_lchown 16 -#define __NR_break 17 -#define __NR_oldstat 18 -#define __NR_lseek 19 -#define __NR_getpid 20 -#define __NR_mount 21 -#define __NR_umount 22 -#define __NR_setuid 23 -#define __NR_getuid 24 -#define __NR_stime 25 -#define __NR_ptrace 26 -#define __NR_alarm 27 -#define __NR_oldfstat 28 -#define __NR_pause 29 -#define __NR_utime 30 -#define __NR_stty 31 -#define __NR_gtty 32 -#define __NR_access 33 -#define __NR_nice 34 -#define __NR_ftime 35 -#define __NR_sync 36 -#define __NR_kill 37 -#define __NR_rename 38 -#define __NR_mkdir 39 -#define __NR_rmdir 40 -#define __NR_dup 41 -#define __NR_pipe 42 -#define __NR_times 43 -#define __NR_prof 44 -#define __NR_brk 45 -#define __NR_setgid 46 -#define __NR_getgid 47 -#define __NR_signal 48 -#define __NR_geteuid 49 -#define __NR_getegid 50 -#define __NR_acct 51 -#define __NR_umount2 52 -#define __NR_lock 53 -#define __NR_ioctl 54 -#define __NR_fcntl 55 -#define __NR_mpx 56 -#define __NR_setpgid 57 -#define __NR_ulimit 58 -#define __NR_oldolduname 59 -#define __NR_umask 60 -#define __NR_chroot 61 -#define __NR_ustat 62 -#define __NR_dup2 63 -#define __NR_getppid 64 -#define __NR_getpgrp 65 -#define __NR_setsid 66 -#define __NR_sigaction 67 -#define __NR_sgetmask 68 -#define __NR_ssetmask 69 -#define __NR_setreuid 70 -#define __NR_setregid 71 -#define __NR_sigsuspend 72 -#define __NR_sigpending 73 -#define __NR_sethostname 74 -#define __NR_setrlimit 75 -#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ -#define __NR_getrusage 77 -#define __NR_gettimeofday 78 -#define __NR_settimeofday 79 -#define __NR_getgroups 80 -#define __NR_setgroups 81 -#define __NR_select 82 -#define __NR_symlink 83 -#define __NR_oldlstat 84 -#define __NR_readlink 85 -#define __NR_uselib 86 -#define __NR_swapon 87 -#define __NR_reboot 88 -#define __NR_readdir 89 -#define __NR_mmap 90 -#define __NR_munmap 91 -#define __NR_truncate 92 -#define __NR_ftruncate 93 -#define __NR_fchmod 94 -#define __NR_fchown 95 -#define __NR_getpriority 96 -#define __NR_setpriority 97 -#define __NR_profil 98 -#define __NR_statfs 99 -#define __NR_fstatfs 100 -#define __NR_ioperm 101 -#define __NR_socketcall 102 -#define __NR_syslog 103 -#define __NR_setitimer 104 -#define __NR_getitimer 105 -#define __NR_stat 106 -#define __NR_lstat 107 -#define __NR_fstat 108 -#define __NR_olduname 109 -#define __NR_iopl 110 -#define __NR_vhangup 111 -#define __NR_idle 112 -#define __NR_vm86old 113 -#define __NR_wait4 114 -#define __NR_swapoff 115 -#define __NR_sysinfo 116 -#define __NR_ipc 117 -#define __NR_fsync 118 -#define __NR_sigreturn 119 -#define __NR_clone 120 -#define __NR_setdomainname 121 -#define __NR_uname 122 -#define __NR_modify_ldt 123 -#define __NR_adjtimex 124 -#define __NR_mprotect 125 -#define __NR_sigprocmask 126 -#define __NR_create_module 127 -#define __NR_init_module 128 -#define __NR_delete_module 129 -#define __NR_get_kernel_syms 130 -#define __NR_quotactl 131 -#define __NR_getpgid 132 -#define __NR_fchdir 133 -#define __NR_bdflush 134 -#define __NR_sysfs 135 -#define __NR_personality 136 -#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ -#define __NR_setfsuid 138 -#define __NR_setfsgid 139 -#define __NR__llseek 140 -#define __NR_getdents 141 -#define __NR__newselect 142 -#define __NR_flock 143 -#define __NR_msync 144 -#define __NR_readv 145 -#define __NR_writev 146 -#define __NR_getsid 147 -#define __NR_fdatasync 148 -#define __NR__sysctl 149 -#define __NR_mlock 150 -#define __NR_munlock 151 -#define __NR_mlockall 152 -#define __NR_munlockall 153 -#define __NR_sched_setparam 154 -#define __NR_sched_getparam 155 -#define __NR_sched_setscheduler 156 -#define __NR_sched_getscheduler 157 -#define __NR_sched_yield 158 -#define __NR_sched_get_priority_max 159 -#define __NR_sched_get_priority_min 160 -#define __NR_sched_rr_get_interval 161 -#define __NR_nanosleep 162 -#define __NR_mremap 163 -#define __NR_setresuid 164 -#define __NR_getresuid 165 -#define __NR_vm86 166 -#define __NR_query_module 167 -#define __NR_poll 168 -#define __NR_nfsservctl 169 -#define __NR_setresgid 170 -#define __NR_getresgid 171 -#define __NR_prctl 172 -#define __NR_rt_sigreturn 173 -#define __NR_rt_sigaction 174 -#define __NR_rt_sigprocmask 175 -#define __NR_rt_sigpending 176 -#define __NR_rt_sigtimedwait 177 -#define __NR_rt_sigqueueinfo 178 -#define __NR_rt_sigsuspend 179 -#define __NR_pread64 180 -#define __NR_pwrite64 181 -#define __NR_chown 182 -#define __NR_getcwd 183 -#define __NR_capget 184 -#define __NR_capset 185 -#define __NR_sigaltstack 186 -#define __NR_sendfile 187 -#define __NR_getpmsg 188 /* some people actually want streams */ -#define __NR_putpmsg 189 /* some people actually want streams */ -#define __NR_vfork 190 -#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */ -#define __NR_mmap2 192 -#define __NR_truncate64 193 -#define __NR_ftruncate64 194 -#define __NR_stat64 195 -#define __NR_lstat64 196 -#define __NR_fstat64 197 -#define __NR_lchown32 198 -#define __NR_getuid32 199 -#define __NR_getgid32 200 -#define __NR_geteuid32 201 -#define __NR_getegid32 202 -#define __NR_setreuid32 203 -#define __NR_setregid32 204 -#define __NR_getgroups32 205 -#define __NR_setgroups32 206 -#define __NR_fchown32 207 -#define __NR_setresuid32 208 -#define __NR_getresuid32 209 -#define __NR_setresgid32 210 -#define __NR_getresgid32 211 -#define __NR_chown32 212 -#define __NR_setuid32 213 -#define __NR_setgid32 214 -#define __NR_setfsuid32 215 -#define __NR_setfsgid32 216 -#define __NR_pivot_root 217 -#define __NR_mincore 218 -#define __NR_madvise 219 -#define __NR_madvise1 219 /* delete when C lib stub is removed */ -#define __NR_getdents64 220 -#define __NR_fcntl64 221 -/* 223 is unused */ -#define __NR_gettid 224 -#define __NR_readahead 225 -#define __NR_setxattr 226 -#define __NR_lsetxattr 227 -#define __NR_fsetxattr 228 -#define __NR_getxattr 229 -#define __NR_lgetxattr 230 -#define __NR_fgetxattr 231 -#define __NR_listxattr 232 -#define __NR_llistxattr 233 -#define __NR_flistxattr 234 -#define __NR_removexattr 235 -#define __NR_lremovexattr 236 -#define __NR_fremovexattr 237 -#define __NR_tkill 238 -#define __NR_sendfile64 239 -#define __NR_futex 240 -#define __NR_sched_setaffinity 241 -#define __NR_sched_getaffinity 242 -#define __NR_set_thread_area 243 -#define __NR_get_thread_area 244 -#define __NR_io_setup 245 -#define __NR_io_destroy 246 -#define __NR_io_getevents 247 -#define __NR_io_submit 248 -#define __NR_io_cancel 249 -#define __NR_fadvise64 250 -/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */ -#define __NR_exit_group 252 -#define __NR_lookup_dcookie 253 -#define __NR_epoll_create 254 -#define __NR_epoll_ctl 255 -#define __NR_epoll_wait 256 -#define __NR_remap_file_pages 257 -#define __NR_set_tid_address 258 -#define __NR_timer_create 259 -#define __NR_timer_settime (__NR_timer_create+1) -#define __NR_timer_gettime (__NR_timer_create+2) -#define __NR_timer_getoverrun (__NR_timer_create+3) -#define __NR_timer_delete (__NR_timer_create+4) -#define __NR_clock_settime (__NR_timer_create+5) -#define __NR_clock_gettime (__NR_timer_create+6) -#define __NR_clock_getres (__NR_timer_create+7) -#define __NR_clock_nanosleep (__NR_timer_create+8) -#define __NR_statfs64 268 -#define __NR_fstatfs64 269 -#define __NR_tgkill 270 -#define __NR_utimes 271 -#define __NR_fadvise64_64 272 -#define __NR_vserver 273 -#define __NR_mbind 274 -#define __NR_get_mempolicy 275 -#define __NR_set_mempolicy 276 -#define __NR_mq_open 277 -#define __NR_mq_unlink (__NR_mq_open+1) -#define __NR_mq_timedsend (__NR_mq_open+2) -#define __NR_mq_timedreceive (__NR_mq_open+3) -#define __NR_mq_notify (__NR_mq_open+4) -#define __NR_mq_getsetattr (__NR_mq_open+5) -#define __NR_kexec_load 283 -#define __NR_waitid 284 -/* #define __NR_sys_setaltroot 285 */ -#define __NR_add_key 286 -#define __NR_request_key 287 -#define __NR_keyctl 288 -#define __NR_ioprio_set 289 -#define __NR_ioprio_get 290 -#define __NR_inotify_init 291 -#define __NR_inotify_add_watch 292 -#define __NR_inotify_rm_watch 293 -#define __NR_migrate_pages 294 -#define __NR_openat 295 -#define __NR_mkdirat 296 -#define __NR_mknodat 297 -#define __NR_fchownat 298 -#define __NR_futimesat 299 -#define __NR_fstatat64 300 -#define __NR_unlinkat 301 -#define __NR_renameat 302 -#define __NR_linkat 303 -#define __NR_symlinkat 304 -#define __NR_readlinkat 305 -#define __NR_fchmodat 306 -#define __NR_faccessat 307 -#define __NR_pselect6 308 -#define __NR_ppoll 309 -#define __NR_unshare 310 -#define __NR_set_robust_list 311 -#define __NR_get_robust_list 312 -#define __NR_splice 313 -#define __NR_sync_file_range 314 -#define __NR_tee 315 -#define __NR_vmsplice 316 -#define __NR_move_pages 317 -#define __NR_getcpu 318 -#define __NR_epoll_pwait 319 -#define __NR_utimensat 320 -#define __NR_signalfd 321 -#define __NR_timerfd_create 322 -#define __NR_eventfd 323 -#define __NR_fallocate 324 -#define __NR_timerfd_settime 325 -#define __NR_timerfd_gettime 326 -#define __NR_signalfd4 327 -#define __NR_eventfd2 328 -#define __NR_epoll_create1 329 -#define __NR_dup3 330 -#define __NR_pipe2 331 -#define __NR_inotify_init1 332 -#define __NR_preadv 333 -#define __NR_pwritev 334 -#define __NR_rt_tgsigqueueinfo 335 -#define __NR_perf_event_open 336 -#define __NR_recvmmsg 337 -#define __NR_fanotify_init 338 -#define __NR_fanotify_mark 339 -#define __NR_prlimit64 340 -#define __NR_name_to_handle_at 341 -#define __NR_open_by_handle_at 342 -#define __NR_clock_adjtime 343 -#define __NR_syncfs 344 -#define __NR_sendmmsg 345 -#define __NR_setns 346 -#define __NR_process_vm_readv 347 -#define __NR_process_vm_writev 348 - -#ifdef __KERNEL__ - -#define NR_syscalls 349 - -#define __ARCH_WANT_IPC_PARSE_VERSION -#define __ARCH_WANT_OLD_READDIR -#define __ARCH_WANT_OLD_STAT -#define __ARCH_WANT_STAT64 -#define __ARCH_WANT_SYS_ALARM -#define __ARCH_WANT_SYS_GETHOSTNAME -#define __ARCH_WANT_SYS_IPC -#define __ARCH_WANT_SYS_PAUSE -#define __ARCH_WANT_SYS_SGETMASK -#define __ARCH_WANT_SYS_SIGNAL -#define __ARCH_WANT_SYS_TIME -#define __ARCH_WANT_SYS_UTIME -#define __ARCH_WANT_SYS_WAITPID -#define __ARCH_WANT_SYS_SOCKETCALL -#define __ARCH_WANT_SYS_FADVISE64 -#define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK -#define __ARCH_WANT_SYS_NICE -#define __ARCH_WANT_SYS_OLD_GETRLIMIT -#define __ARCH_WANT_SYS_OLD_UNAME -#define __ARCH_WANT_SYS_OLD_MMAP -#define __ARCH_WANT_SYS_OLD_SELECT -#define __ARCH_WANT_SYS_OLDUMOUNT -#define __ARCH_WANT_SYS_SIGPENDING -#define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION -#define __ARCH_WANT_SYS_RT_SIGSUSPEND - -/* - * "Conditional" syscalls - * - * What we want is __attribute__((weak,alias("sys_ni_syscall"))), - * but it doesn't work on all toolchains, so we just do it by hand - */ -#ifndef cond_syscall -#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") -#endif - -#endif /* __KERNEL__ */ -#endif /* _ASM_X86_UNISTD_32_H */ diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h deleted file mode 100644 index 0431f193c3f2..000000000000 --- a/arch/x86/include/asm/unistd_64.h +++ /dev/null @@ -1,732 +0,0 @@ -#ifndef _ASM_X86_UNISTD_64_H -#define _ASM_X86_UNISTD_64_H - -#ifndef __SYSCALL -#define __SYSCALL(a, b) -#endif - -/* - * This file contains the system call numbers. - * - * Note: holes are not allowed. - */ - -/* at least 8 syscall per cacheline */ -#define __NR_read 0 -__SYSCALL(__NR_read, sys_read) -#define __NR_write 1 -__SYSCALL(__NR_write, sys_write) -#define __NR_open 2 -__SYSCALL(__NR_open, sys_open) -#define __NR_close 3 -__SYSCALL(__NR_close, sys_close) -#define __NR_stat 4 -__SYSCALL(__NR_stat, sys_newstat) -#define __NR_fstat 5 -__SYSCALL(__NR_fstat, sys_newfstat) -#define __NR_lstat 6 -__SYSCALL(__NR_lstat, sys_newlstat) -#define __NR_poll 7 -__SYSCALL(__NR_poll, sys_poll) - -#define __NR_lseek 8 -__SYSCALL(__NR_lseek, sys_lseek) -#define __NR_mmap 9 -__SYSCALL(__NR_mmap, sys_mmap) -#define __NR_mprotect 10 -__SYSCALL(__NR_mprotect, sys_mprotect) -#define __NR_munmap 11 -__SYSCALL(__NR_munmap, sys_munmap) -#define __NR_brk 12 -__SYSCALL(__NR_brk, sys_brk) -#define __NR_rt_sigaction 13 -__SYSCALL(__NR_rt_sigaction, sys_rt_sigaction) -#define __NR_rt_sigprocmask 14 -__SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask) -#define __NR_rt_sigreturn 15 -__SYSCALL(__NR_rt_sigreturn, stub_rt_sigreturn) - -#define __NR_ioctl 16 -__SYSCALL(__NR_ioctl, sys_ioctl) -#define __NR_pread64 17 -__SYSCALL(__NR_pread64, sys_pread64) -#define __NR_pwrite64 18 -__SYSCALL(__NR_pwrite64, sys_pwrite64) -#define __NR_readv 19 -__SYSCALL(__NR_readv, sys_readv) -#define __NR_writev 20 -__SYSCALL(__NR_writev, sys_writev) -#define __NR_access 21 -__SYSCALL(__NR_access, sys_access) -#define __NR_pipe 22 -__SYSCALL(__NR_pipe, sys_pipe) -#define __NR_select 23 -__SYSCALL(__NR_select, sys_select) - -#define __NR_sched_yield 24 -__SYSCALL(__NR_sched_yield, sys_sched_yield) -#define __NR_mremap 25 -__SYSCALL(__NR_mremap, sys_mremap) -#define __NR_msync 26 -__SYSCALL(__NR_msync, sys_msync) -#define __NR_mincore 27 -__SYSCALL(__NR_mincore, sys_mincore) -#define __NR_madvise 28 -__SYSCALL(__NR_madvise, sys_madvise) -#define __NR_shmget 29 -__SYSCALL(__NR_shmget, sys_shmget) -#define __NR_shmat 30 -__SYSCALL(__NR_shmat, sys_shmat) -#define __NR_shmctl 31 -__SYSCALL(__NR_shmctl, sys_shmctl) - -#define __NR_dup 32 -__SYSCALL(__NR_dup, sys_dup) -#define __NR_dup2 33 -__SYSCALL(__NR_dup2, sys_dup2) -#define __NR_pause 34 -__SYSCALL(__NR_pause, sys_pause) -#define __NR_nanosleep 35 -__SYSCALL(__NR_nanosleep, sys_nanosleep) -#define __NR_getitimer 36 -__SYSCALL(__NR_getitimer, sys_getitimer) -#define __NR_alarm 37 -__SYSCALL(__NR_alarm, sys_alarm) -#define __NR_setitimer 38 -__SYSCALL(__NR_setitimer, sys_setitimer) -#define __NR_getpid 39 -__SYSCALL(__NR_getpid, sys_getpid) - -#define __NR_sendfile 40 -__SYSCALL(__NR_sendfile, sys_sendfile64) -#define __NR_socket 41 -__SYSCALL(__NR_socket, sys_socket) -#define __NR_connect 42 -__SYSCALL(__NR_connect, sys_connect) -#define __NR_accept 43 -__SYSCALL(__NR_accept, sys_accept) -#define __NR_sendto 44 -__SYSCALL(__NR_sendto, sys_sendto) -#define __NR_recvfrom 45 -__SYSCALL(__NR_recvfrom, sys_recvfrom) -#define __NR_sendmsg 46 -__SYSCALL(__NR_sendmsg, sys_sendmsg) -#define __NR_recvmsg 47 -__SYSCALL(__NR_recvmsg, sys_recvmsg) - -#define __NR_shutdown 48 -__SYSCALL(__NR_shutdown, sys_shutdown) -#define __NR_bind 49 -__SYSCALL(__NR_bind, sys_bind) -#define __NR_listen 50 -__SYSCALL(__NR_listen, sys_listen) -#define __NR_getsockname 51 -__SYSCALL(__NR_getsockname, sys_getsockname) -#define __NR_getpeername 52 -__SYSCALL(__NR_getpeername, sys_getpeername) -#define __NR_socketpair 53 -__SYSCALL(__NR_socketpair, sys_socketpair) -#define __NR_setsockopt 54 -__SYSCALL(__NR_setsockopt, sys_setsockopt) -#define __NR_getsockopt 55 -__SYSCALL(__NR_getsockopt, sys_getsockopt) - -#define __NR_clone 56 -__SYSCALL(__NR_clone, stub_clone) -#define __NR_fork 57 -__SYSCALL(__NR_fork, stub_fork) -#define __NR_vfork 58 -__SYSCALL(__NR_vfork, stub_vfork) -#define __NR_execve 59 -__SYSCALL(__NR_execve, stub_execve) -#define __NR_exit 60 -__SYSCALL(__NR_exit, sys_exit) -#define __NR_wait4 61 -__SYSCALL(__NR_wait4, sys_wait4) -#define __NR_kill 62 -__SYSCALL(__NR_kill, sys_kill) -#define __NR_uname 63 -__SYSCALL(__NR_uname, sys_newuname) - -#define __NR_semget 64 -__SYSCALL(__NR_semget, sys_semget) -#define __NR_semop 65 -__SYSCALL(__NR_semop, sys_semop) -#define __NR_semctl 66 -__SYSCALL(__NR_semctl, sys_semctl) -#define __NR_shmdt 67 -__SYSCALL(__NR_shmdt, sys_shmdt) -#define __NR_msgget 68 -__SYSCALL(__NR_msgget, sys_msgget) -#define __NR_msgsnd 69 -__SYSCALL(__NR_msgsnd, sys_msgsnd) -#define __NR_msgrcv 70 -__SYSCALL(__NR_msgrcv, sys_msgrcv) -#define __NR_msgctl 71 -__SYSCALL(__NR_msgctl, sys_msgctl) - -#define __NR_fcntl 72 -__SYSCALL(__NR_fcntl, sys_fcntl) -#define __NR_flock 73 -__SYSCALL(__NR_flock, sys_flock) -#define __NR_fsync 74 -__SYSCALL(__NR_fsync, sys_fsync) -#define __NR_fdatasync 75 -__SYSCALL(__NR_fdatasync, sys_fdatasync) -#define __NR_truncate 76 -__SYSCALL(__NR_truncate, sys_truncate) -#define __NR_ftruncate 77 -__SYSCALL(__NR_ftruncate, sys_ftruncate) -#define __NR_getdents 78 -__SYSCALL(__NR_getdents, sys_getdents) -#define __NR_getcwd 79 -__SYSCALL(__NR_getcwd, sys_getcwd) - -#define __NR_chdir 80 -__SYSCALL(__NR_chdir, sys_chdir) -#define __NR_fchdir 81 -__SYSCALL(__NR_fchdir, sys_fchdir) -#define __NR_rename 82 -__SYSCALL(__NR_rename, sys_rename) -#define __NR_mkdir 83 -__SYSCALL(__NR_mkdir, sys_mkdir) -#define __NR_rmdir 84 -__SYSCALL(__NR_rmdir, sys_rmdir) -#define __NR_creat 85 -__SYSCALL(__NR_creat, sys_creat) -#define __NR_link 86 -__SYSCALL(__NR_link, sys_link) -#define __NR_unlink 87 -__SYSCALL(__NR_unlink, sys_unlink) - -#define __NR_symlink 88 -__SYSCALL(__NR_symlink, sys_symlink) -#define __NR_readlink 89 -__SYSCALL(__NR_readlink, sys_readlink) -#define __NR_chmod 90 -__SYSCALL(__NR_chmod, sys_chmod) -#define __NR_fchmod 91 -__SYSCALL(__NR_fchmod, sys_fchmod) -#define __NR_chown 92 -__SYSCALL(__NR_chown, sys_chown) -#define __NR_fchown 93 -__SYSCALL(__NR_fchown, sys_fchown) -#define __NR_lchown 94 -__SYSCALL(__NR_lchown, sys_lchown) -#define __NR_umask 95 -__SYSCALL(__NR_umask, sys_umask) - -#define __NR_gettimeofday 96 -__SYSCALL(__NR_gettimeofday, sys_gettimeofday) -#define __NR_getrlimit 97 -__SYSCALL(__NR_getrlimit, sys_getrlimit) -#define __NR_getrusage 98 -__SYSCALL(__NR_getrusage, sys_getrusage) -#define __NR_sysinfo 99 -__SYSCALL(__NR_sysinfo, sys_sysinfo) -#define __NR_times 100 -__SYSCALL(__NR_times, sys_times) -#define __NR_ptrace 101 -__SYSCALL(__NR_ptrace, sys_ptrace) -#define __NR_getuid 102 -__SYSCALL(__NR_getuid, sys_getuid) -#define __NR_syslog 103 -__SYSCALL(__NR_syslog, sys_syslog) - -/* at the very end the stuff that never runs during the benchmarks */ -#define __NR_getgid 104 -__SYSCALL(__NR_getgid, sys_getgid) -#define __NR_setuid 105 -__SYSCALL(__NR_setuid, sys_setuid) -#define __NR_setgid 106 -__SYSCALL(__NR_setgid, sys_setgid) -#define __NR_geteuid 107 -__SYSCALL(__NR_geteuid, sys_geteuid) -#define __NR_getegid 108 -__SYSCALL(__NR_getegid, sys_getegid) -#define __NR_setpgid 109 -__SYSCALL(__NR_setpgid, sys_setpgid) -#define __NR_getppid 110 -__SYSCALL(__NR_getppid, sys_getppid) -#define __NR_getpgrp 111 -__SYSCALL(__NR_getpgrp, sys_getpgrp) - -#define __NR_setsid 112 -__SYSCALL(__NR_setsid, sys_setsid) -#define __NR_setreuid 113 -__SYSCALL(__NR_setreuid, sys_setreuid) -#define __NR_setregid 114 -__SYSCALL(__NR_setregid, sys_setregid) -#define __NR_getgroups 115 -__SYSCALL(__NR_getgroups, sys_getgroups) -#define __NR_setgroups 116 -__SYSCALL(__NR_setgroups, sys_setgroups) -#define __NR_setresuid 117 -__SYSCALL(__NR_setresuid, sys_setresuid) -#define __NR_getresuid 118 -__SYSCALL(__NR_getresuid, sys_getresuid) -#define __NR_setresgid 119 -__SYSCALL(__NR_setresgid, sys_setresgid) - -#define __NR_getresgid 120 -__SYSCALL(__NR_getresgid, sys_getresgid) -#define __NR_getpgid 121 -__SYSCALL(__NR_getpgid, sys_getpgid) -#define __NR_setfsuid 122 -__SYSCALL(__NR_setfsuid, sys_setfsuid) -#define __NR_setfsgid 123 -__SYSCALL(__NR_setfsgid, sys_setfsgid) -#define __NR_getsid 124 -__SYSCALL(__NR_getsid, sys_getsid) -#define __NR_capget 125 -__SYSCALL(__NR_capget, sys_capget) -#define __NR_capset 126 -__SYSCALL(__NR_capset, sys_capset) - -#define __NR_rt_sigpending 127 -__SYSCALL(__NR_rt_sigpending, sys_rt_sigpending) -#define __NR_rt_sigtimedwait 128 -__SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait) -#define __NR_rt_sigqueueinfo 129 -__SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo) -#define __NR_rt_sigsuspend 130 -__SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend) -#define __NR_sigaltstack 131 -__SYSCALL(__NR_sigaltstack, stub_sigaltstack) -#define __NR_utime 132 -__SYSCALL(__NR_utime, sys_utime) -#define __NR_mknod 133 -__SYSCALL(__NR_mknod, sys_mknod) - -/* Only needed for a.out */ -#define __NR_uselib 134 -__SYSCALL(__NR_uselib, sys_ni_syscall) -#define __NR_personality 135 -__SYSCALL(__NR_personality, sys_personality) - -#define __NR_ustat 136 -__SYSCALL(__NR_ustat, sys_ustat) -#define __NR_statfs 137 -__SYSCALL(__NR_statfs, sys_statfs) -#define __NR_fstatfs 138 -__SYSCALL(__NR_fstatfs, sys_fstatfs) -#define __NR_sysfs 139 -__SYSCALL(__NR_sysfs, sys_sysfs) - -#define __NR_getpriority 140 -__SYSCALL(__NR_getpriority, sys_getpriority) -#define __NR_setpriority 141 -__SYSCALL(__NR_setpriority, sys_setpriority) -#define __NR_sched_setparam 142 -__SYSCALL(__NR_sched_setparam, sys_sched_setparam) -#define __NR_sched_getparam 143 -__SYSCALL(__NR_sched_getparam, sys_sched_getparam) -#define __NR_sched_setscheduler 144 -__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler) -#define __NR_sched_getscheduler 145 -__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler) -#define __NR_sched_get_priority_max 146 -__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max) -#define __NR_sched_get_priority_min 147 -__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min) -#define __NR_sched_rr_get_interval 148 -__SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval) - -#define __NR_mlock 149 -__SYSCALL(__NR_mlock, sys_mlock) -#define __NR_munlock 150 -__SYSCALL(__NR_munlock, sys_munlock) -#define __NR_mlockall 151 -__SYSCALL(__NR_mlockall, sys_mlockall) -#define __NR_munlockall 152 -__SYSCALL(__NR_munlockall, sys_munlockall) - -#define __NR_vhangup 153 -__SYSCALL(__NR_vhangup, sys_vhangup) - -#define __NR_modify_ldt 154 -__SYSCALL(__NR_modify_ldt, sys_modify_ldt) - -#define __NR_pivot_root 155 -__SYSCALL(__NR_pivot_root, sys_pivot_root) - -#define __NR__sysctl 156 -__SYSCALL(__NR__sysctl, sys_sysctl) - -#define __NR_prctl 157 -__SYSCALL(__NR_prctl, sys_prctl) -#define __NR_arch_prctl 158 -__SYSCALL(__NR_arch_prctl, sys_arch_prctl) - -#define __NR_adjtimex 159 -__SYSCALL(__NR_adjtimex, sys_adjtimex) - -#define __NR_setrlimit 160 -__SYSCALL(__NR_setrlimit, sys_setrlimit) - -#define __NR_chroot 161 -__SYSCALL(__NR_chroot, sys_chroot) - -#define __NR_sync 162 -__SYSCALL(__NR_sync, sys_sync) - -#define __NR_acct 163 -__SYSCALL(__NR_acct, sys_acct) - -#define __NR_settimeofday 164 -__SYSCALL(__NR_settimeofday, sys_settimeofday) - -#define __NR_mount 165 -__SYSCALL(__NR_mount, sys_mount) -#define __NR_umount2 166 -__SYSCALL(__NR_umount2, sys_umount) - -#define __NR_swapon 167 -__SYSCALL(__NR_swapon, sys_swapon) -#define __NR_swapoff 168 -__SYSCALL(__NR_swapoff, sys_swapoff) - -#define __NR_reboot 169 -__SYSCALL(__NR_reboot, sys_reboot) - -#define __NR_sethostname 170 -__SYSCALL(__NR_sethostname, sys_sethostname) -#define __NR_setdomainname 171 -__SYSCALL(__NR_setdomainname, sys_setdomainname) - -#define __NR_iopl 172 -__SYSCALL(__NR_iopl, stub_iopl) -#define __NR_ioperm 173 -__SYSCALL(__NR_ioperm, sys_ioperm) - -#define __NR_create_module 174 -__SYSCALL(__NR_create_module, sys_ni_syscall) -#define __NR_init_module 175 -__SYSCALL(__NR_init_module, sys_init_module) -#define __NR_delete_module 176 -__SYSCALL(__NR_delete_module, sys_delete_module) -#define __NR_get_kernel_syms 177 -__SYSCALL(__NR_get_kernel_syms, sys_ni_syscall) -#define __NR_query_module 178 -__SYSCALL(__NR_query_module, sys_ni_syscall) - -#define __NR_quotactl 179 -__SYSCALL(__NR_quotactl, sys_quotactl) - -#define __NR_nfsservctl 180 -__SYSCALL(__NR_nfsservctl, sys_ni_syscall) - -/* reserved for LiS/STREAMS */ -#define __NR_getpmsg 181 -__SYSCALL(__NR_getpmsg, sys_ni_syscall) -#define __NR_putpmsg 182 -__SYSCALL(__NR_putpmsg, sys_ni_syscall) - -/* reserved for AFS */ -#define __NR_afs_syscall 183 -__SYSCALL(__NR_afs_syscall, sys_ni_syscall) - -/* reserved for tux */ -#define __NR_tuxcall 184 -__SYSCALL(__NR_tuxcall, sys_ni_syscall) - -#define __NR_security 185 -__SYSCALL(__NR_security, sys_ni_syscall) - -#define __NR_gettid 186 -__SYSCALL(__NR_gettid, sys_gettid) - -#define __NR_readahead 187 -__SYSCALL(__NR_readahead, sys_readahead) -#define __NR_setxattr 188 -__SYSCALL(__NR_setxattr, sys_setxattr) -#define __NR_lsetxattr 189 -__SYSCALL(__NR_lsetxattr, sys_lsetxattr) -#define __NR_fsetxattr 190 -__SYSCALL(__NR_fsetxattr, sys_fsetxattr) -#define __NR_getxattr 191 -__SYSCALL(__NR_getxattr, sys_getxattr) -#define __NR_lgetxattr 192 -__SYSCALL(__NR_lgetxattr, sys_lgetxattr) -#define __NR_fgetxattr 193 -__SYSCALL(__NR_fgetxattr, sys_fgetxattr) -#define __NR_listxattr 194 -__SYSCALL(__NR_listxattr, sys_listxattr) -#define __NR_llistxattr 195 -__SYSCALL(__NR_llistxattr, sys_llistxattr) -#define __NR_flistxattr 196 -__SYSCALL(__NR_flistxattr, sys_flistxattr) -#define __NR_removexattr 197 -__SYSCALL(__NR_removexattr, sys_removexattr) -#define __NR_lremovexattr 198 -__SYSCALL(__NR_lremovexattr, sys_lremovexattr) -#define __NR_fremovexattr 199 -__SYSCALL(__NR_fremovexattr, sys_fremovexattr) -#define __NR_tkill 200 -__SYSCALL(__NR_tkill, sys_tkill) -#define __NR_time 201 -__SYSCALL(__NR_time, sys_time) -#define __NR_futex 202 -__SYSCALL(__NR_futex, sys_futex) -#define __NR_sched_setaffinity 203 -__SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity) -#define __NR_sched_getaffinity 204 -__SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity) -#define __NR_set_thread_area 205 -__SYSCALL(__NR_set_thread_area, sys_ni_syscall) /* use arch_prctl */ -#define __NR_io_setup 206 -__SYSCALL(__NR_io_setup, sys_io_setup) -#define __NR_io_destroy 207 -__SYSCALL(__NR_io_destroy, sys_io_destroy) -#define __NR_io_getevents 208 -__SYSCALL(__NR_io_getevents, sys_io_getevents) -#define __NR_io_submit 209 -__SYSCALL(__NR_io_submit, sys_io_submit) -#define __NR_io_cancel 210 -__SYSCALL(__NR_io_cancel, sys_io_cancel) -#define __NR_get_thread_area 211 -__SYSCALL(__NR_get_thread_area, sys_ni_syscall) /* use arch_prctl */ -#define __NR_lookup_dcookie 212 -__SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie) -#define __NR_epoll_create 213 -__SYSCALL(__NR_epoll_create, sys_epoll_create) -#define __NR_epoll_ctl_old 214 -__SYSCALL(__NR_epoll_ctl_old, sys_ni_syscall) -#define __NR_epoll_wait_old 215 -__SYSCALL(__NR_epoll_wait_old, sys_ni_syscall) -#define __NR_remap_file_pages 216 -__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages) -#define __NR_getdents64 217 -__SYSCALL(__NR_getdents64, sys_getdents64) -#define __NR_set_tid_address 218 -__SYSCALL(__NR_set_tid_address, sys_set_tid_address) -#define __NR_restart_syscall 219 -__SYSCALL(__NR_restart_syscall, sys_restart_syscall) -#define __NR_semtimedop 220 -__SYSCALL(__NR_semtimedop, sys_semtimedop) -#define __NR_fadvise64 221 -__SYSCALL(__NR_fadvise64, sys_fadvise64) -#define __NR_timer_create 222 -__SYSCALL(__NR_timer_create, sys_timer_create) -#define __NR_timer_settime 223 -__SYSCALL(__NR_timer_settime, sys_timer_settime) -#define __NR_timer_gettime 224 -__SYSCALL(__NR_timer_gettime, sys_timer_gettime) -#define __NR_timer_getoverrun 225 -__SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun) -#define __NR_timer_delete 226 -__SYSCALL(__NR_timer_delete, sys_timer_delete) -#define __NR_clock_settime 227 -__SYSCALL(__NR_clock_settime, sys_clock_settime) -#define __NR_clock_gettime 228 -__SYSCALL(__NR_clock_gettime, sys_clock_gettime) -#define __NR_clock_getres 229 -__SYSCALL(__NR_clock_getres, sys_clock_getres) -#define __NR_clock_nanosleep 230 -__SYSCALL(__NR_clock_nanosleep, sys_clock_nanosleep) -#define __NR_exit_group 231 -__SYSCALL(__NR_exit_group, sys_exit_group) -#define __NR_epoll_wait 232 -__SYSCALL(__NR_epoll_wait, sys_epoll_wait) -#define __NR_epoll_ctl 233 -__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl) -#define __NR_tgkill 234 -__SYSCALL(__NR_tgkill, sys_tgkill) -#define __NR_utimes 235 -__SYSCALL(__NR_utimes, sys_utimes) -#define __NR_vserver 236 -__SYSCALL(__NR_vserver, sys_ni_syscall) -#define __NR_mbind 237 -__SYSCALL(__NR_mbind, sys_mbind) -#define __NR_set_mempolicy 238 -__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy) -#define __NR_get_mempolicy 239 -__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy) -#define __NR_mq_open 240 -__SYSCALL(__NR_mq_open, sys_mq_open) -#define __NR_mq_unlink 241 -__SYSCALL(__NR_mq_unlink, sys_mq_unlink) -#define __NR_mq_timedsend 242 -__SYSCALL(__NR_mq_timedsend, sys_mq_timedsend) -#define __NR_mq_timedreceive 243 -__SYSCALL(__NR_mq_timedreceive, sys_mq_timedreceive) -#define __NR_mq_notify 244 -__SYSCALL(__NR_mq_notify, sys_mq_notify) -#define __NR_mq_getsetattr 245 -__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr) -#define __NR_kexec_load 246 -__SYSCALL(__NR_kexec_load, sys_kexec_load) -#define __NR_waitid 247 -__SYSCALL(__NR_waitid, sys_waitid) -#define __NR_add_key 248 -__SYSCALL(__NR_add_key, sys_add_key) -#define __NR_request_key 249 -__SYSCALL(__NR_request_key, sys_request_key) -#define __NR_keyctl 250 -__SYSCALL(__NR_keyctl, sys_keyctl) -#define __NR_ioprio_set 251 -__SYSCALL(__NR_ioprio_set, sys_ioprio_set) -#define __NR_ioprio_get 252 -__SYSCALL(__NR_ioprio_get, sys_ioprio_get) -#define __NR_inotify_init 253 -__SYSCALL(__NR_inotify_init, sys_inotify_init) -#define __NR_inotify_add_watch 254 -__SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch) -#define __NR_inotify_rm_watch 255 -__SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch) -#define __NR_migrate_pages 256 -__SYSCALL(__NR_migrate_pages, sys_migrate_pages) -#define __NR_openat 257 -__SYSCALL(__NR_openat, sys_openat) -#define __NR_mkdirat 258 -__SYSCALL(__NR_mkdirat, sys_mkdirat) -#define __NR_mknodat 259 -__SYSCALL(__NR_mknodat, sys_mknodat) -#define __NR_fchownat 260 -__SYSCALL(__NR_fchownat, sys_fchownat) -#define __NR_futimesat 261 -__SYSCALL(__NR_futimesat, sys_futimesat) -#define __NR_newfstatat 262 -__SYSCALL(__NR_newfstatat, sys_newfstatat) -#define __NR_unlinkat 263 -__SYSCALL(__NR_unlinkat, sys_unlinkat) -#define __NR_renameat 264 -__SYSCALL(__NR_renameat, sys_renameat) -#define __NR_linkat 265 -__SYSCALL(__NR_linkat, sys_linkat) -#define __NR_symlinkat 266 -__SYSCALL(__NR_symlinkat, sys_symlinkat) -#define __NR_readlinkat 267 -__SYSCALL(__NR_readlinkat, sys_readlinkat) -#define __NR_fchmodat 268 -__SYSCALL(__NR_fchmodat, sys_fchmodat) -#define __NR_faccessat 269 -__SYSCALL(__NR_faccessat, sys_faccessat) -#define __NR_pselect6 270 -__SYSCALL(__NR_pselect6, sys_pselect6) -#define __NR_ppoll 271 -__SYSCALL(__NR_ppoll, sys_ppoll) -#define __NR_unshare 272 -__SYSCALL(__NR_unshare, sys_unshare) -#define __NR_set_robust_list 273 -__SYSCALL(__NR_set_robust_list, sys_set_robust_list) -#define __NR_get_robust_list 274 -__SYSCALL(__NR_get_robust_list, sys_get_robust_list) -#define __NR_splice 275 -__SYSCALL(__NR_splice, sys_splice) -#define __NR_tee 276 -__SYSCALL(__NR_tee, sys_tee) -#define __NR_sync_file_range 277 -__SYSCALL(__NR_sync_file_range, sys_sync_file_range) -#define __NR_vmsplice 278 -__SYSCALL(__NR_vmsplice, sys_vmsplice) -#define __NR_move_pages 279 -__SYSCALL(__NR_move_pages, sys_move_pages) -#define __NR_utimensat 280 -__SYSCALL(__NR_utimensat, sys_utimensat) -#define __NR_epoll_pwait 281 -__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait) -#define __NR_signalfd 282 -__SYSCALL(__NR_signalfd, sys_signalfd) -#define __NR_timerfd_create 283 -__SYSCALL(__NR_timerfd_create, sys_timerfd_create) -#define __NR_eventfd 284 -__SYSCALL(__NR_eventfd, sys_eventfd) -#define __NR_fallocate 285 -__SYSCALL(__NR_fallocate, sys_fallocate) -#define __NR_timerfd_settime 286 -__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime) -#define __NR_timerfd_gettime 287 -__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime) -#define __NR_accept4 288 -__SYSCALL(__NR_accept4, sys_accept4) -#define __NR_signalfd4 289 -__SYSCALL(__NR_signalfd4, sys_signalfd4) -#define __NR_eventfd2 290 -__SYSCALL(__NR_eventfd2, sys_eventfd2) -#define __NR_epoll_create1 291 -__SYSCALL(__NR_epoll_create1, sys_epoll_create1) -#define __NR_dup3 292 -__SYSCALL(__NR_dup3, sys_dup3) -#define __NR_pipe2 293 -__SYSCALL(__NR_pipe2, sys_pipe2) -#define __NR_inotify_init1 294 -__SYSCALL(__NR_inotify_init1, sys_inotify_init1) -#define __NR_preadv 295 -__SYSCALL(__NR_preadv, sys_preadv) -#define __NR_pwritev 296 -__SYSCALL(__NR_pwritev, sys_pwritev) -#define __NR_rt_tgsigqueueinfo 297 -__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo) -#define __NR_perf_event_open 298 -__SYSCALL(__NR_perf_event_open, sys_perf_event_open) -#define __NR_recvmmsg 299 -__SYSCALL(__NR_recvmmsg, sys_recvmmsg) -#define __NR_fanotify_init 300 -__SYSCALL(__NR_fanotify_init, sys_fanotify_init) -#define __NR_fanotify_mark 301 -__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark) -#define __NR_prlimit64 302 -__SYSCALL(__NR_prlimit64, sys_prlimit64) -#define __NR_name_to_handle_at 303 -__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at) -#define __NR_open_by_handle_at 304 -__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at) -#define __NR_clock_adjtime 305 -__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime) -#define __NR_syncfs 306 -__SYSCALL(__NR_syncfs, sys_syncfs) -#define __NR_sendmmsg 307 -__SYSCALL(__NR_sendmmsg, sys_sendmmsg) -#define __NR_setns 308 -__SYSCALL(__NR_setns, sys_setns) -#define __NR_getcpu 309 -__SYSCALL(__NR_getcpu, sys_getcpu) -#define __NR_process_vm_readv 310 -__SYSCALL(__NR_process_vm_readv, sys_process_vm_readv) -#define __NR_process_vm_writev 311 -__SYSCALL(__NR_process_vm_writev, sys_process_vm_writev) - -#ifndef __NO_STUBS -#define __ARCH_WANT_OLD_READDIR -#define __ARCH_WANT_OLD_STAT -#define __ARCH_WANT_SYS_ALARM -#define __ARCH_WANT_SYS_GETHOSTNAME -#define __ARCH_WANT_SYS_PAUSE -#define __ARCH_WANT_SYS_SGETMASK -#define __ARCH_WANT_SYS_SIGNAL -#define __ARCH_WANT_SYS_UTIME -#define __ARCH_WANT_SYS_WAITPID -#define __ARCH_WANT_SYS_SOCKETCALL -#define __ARCH_WANT_SYS_FADVISE64 -#define __ARCH_WANT_SYS_GETPGRP -#define __ARCH_WANT_SYS_LLSEEK -#define __ARCH_WANT_SYS_NICE -#define __ARCH_WANT_SYS_OLD_GETRLIMIT -#define __ARCH_WANT_SYS_OLD_UNAME -#define __ARCH_WANT_SYS_OLDUMOUNT -#define __ARCH_WANT_SYS_SIGPENDING -#define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION -#define __ARCH_WANT_SYS_RT_SIGSUSPEND -#define __ARCH_WANT_SYS_TIME -#define __ARCH_WANT_COMPAT_SYS_TIME -#endif /* __NO_STUBS */ - -#ifdef __KERNEL__ - -#ifndef COMPILE_OFFSETS -#include <asm/asm-offsets.h> -#define NR_syscalls (__NR_syscall_max + 1) -#endif - -/* - * "Conditional" syscalls - * - * What we want is __attribute__((weak,alias("sys_ni_syscall"))), - * but it doesn't work on all toolchains, so we just do it by hand - */ -#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") -#endif /* __KERNEL__ */ - -#endif /* _ASM_X86_UNISTD_64_H */ diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index 8e862aaf0d90..becf47b81735 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h @@ -65,7 +65,7 @@ * UV2: Bit 19 selects between * (0): 10 microsecond timebase and * (1): 80 microseconds - * we're using 655us, similar to UV1: 65 units of 10us + * we're using 560us, similar to UV1: 65 units of 10us */ #define UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD (9UL) #define UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD (15UL) @@ -167,6 +167,7 @@ #define FLUSH_RETRY_TIMEOUT 2 #define FLUSH_GIVEUP 3 #define FLUSH_COMPLETE 4 +#define FLUSH_RETRY_BUSYBUG 5 /* * tuning the action when the numalink network is extremely delayed @@ -235,10 +236,10 @@ struct bau_msg_payload { /* - * Message header: 16 bytes (128 bits) (bytes 0x30-0x3f of descriptor) + * UV1 Message header: 16 bytes (128 bits) (bytes 0x30-0x3f of descriptor) * see table 4.2.3.0.1 in broacast_assist spec. */ -struct bau_msg_header { +struct uv1_bau_msg_header { unsigned int dest_subnodeid:6; /* must be 0x10, for the LB */ /* bits 5:0 */ unsigned int base_dest_nasid:15; /* nasid of the first bit */ @@ -318,19 +319,87 @@ struct bau_msg_header { }; /* + * UV2 Message header: 16 bytes (128 bits) (bytes 0x30-0x3f of descriptor) + * see figure 9-2 of harp_sys.pdf + */ +struct uv2_bau_msg_header { + unsigned int base_dest_nasid:15; /* nasid of the first bit */ + /* bits 14:0 */ /* in uvhub map */ + unsigned int dest_subnodeid:5; /* must be 0x10, for the LB */ + /* bits 19:15 */ + unsigned int rsvd_1:1; /* must be zero */ + /* bit 20 */ + /* Address bits 59:21 */ + /* bits 25:2 of address (44:21) are payload */ + /* these next 24 bits become bytes 12-14 of msg */ + /* bits 28:21 land in byte 12 */ + unsigned int replied_to:1; /* sent as 0 by the source to + byte 12 */ + /* bit 21 */ + unsigned int msg_type:3; /* software type of the + message */ + /* bits 24:22 */ + unsigned int canceled:1; /* message canceled, resource + is to be freed*/ + /* bit 25 */ + unsigned int payload_1:3; /* not currently used */ + /* bits 28:26 */ + + /* bits 36:29 land in byte 13 */ + unsigned int payload_2a:3; /* not currently used */ + unsigned int payload_2b:5; /* not currently used */ + /* bits 36:29 */ + + /* bits 44:37 land in byte 14 */ + unsigned int payload_3:8; /* not currently used */ + /* bits 44:37 */ + + unsigned int rsvd_2:7; /* reserved */ + /* bits 51:45 */ + unsigned int swack_flag:1; /* software acknowledge flag */ + /* bit 52 */ + unsigned int rsvd_3a:3; /* must be zero */ + unsigned int rsvd_3b:8; /* must be zero */ + unsigned int rsvd_3c:8; /* must be zero */ + unsigned int rsvd_3d:3; /* must be zero */ + /* bits 74:53 */ + unsigned int fairness:3; /* usually zero */ + /* bits 77:75 */ + + unsigned int sequence:16; /* message sequence number */ + /* bits 93:78 Suppl_A */ + unsigned int chaining:1; /* next descriptor is part of + this activation*/ + /* bit 94 */ + unsigned int multilevel:1; /* multi-level multicast + format */ + /* bit 95 */ + unsigned int rsvd_4:24; /* ordered / source node / + source subnode / aging + must be zero */ + /* bits 119:96 */ + unsigned int command:8; /* message type */ + /* bits 127:120 */ +}; + +/* * The activation descriptor: * The format of the message to send, plus all accompanying control * Should be 64 bytes */ struct bau_desc { - struct pnmask distribution; + struct pnmask distribution; /* * message template, consisting of header and payload: */ - struct bau_msg_header header; - struct bau_msg_payload payload; + union bau_msg_header { + struct uv1_bau_msg_header uv1_hdr; + struct uv2_bau_msg_header uv2_hdr; + } header; + + struct bau_msg_payload payload; }; -/* +/* UV1: * -payload-- ---------header------ * bytes 0-11 bits 41-56 bits 58-81 * A B (2) C (3) @@ -340,6 +409,16 @@ struct bau_desc { * bytes 0-11 bytes 12-14 bytes 16-17 (byte 15 filled in by hw as vector) * ------------payload queue----------- */ +/* UV2: + * -payload-- ---------header------ + * bytes 0-11 bits 70-78 bits 21-44 + * A B (2) C (3) + * + * A/B/C are moved to: + * A C B + * bytes 0-11 bytes 12-14 bytes 16-17 (byte 15 filled in by hw as vector) + * ------------payload queue----------- + */ /* * The payload queue on the destination side is an array of these. @@ -385,7 +464,6 @@ struct bau_pq_entry { struct msg_desc { struct bau_pq_entry *msg; int msg_slot; - int swack_slot; struct bau_pq_entry *queue_first; struct bau_pq_entry *queue_last; }; @@ -405,6 +483,7 @@ struct ptc_stats { requests */ unsigned long s_stimeout; /* source side timeouts */ unsigned long s_dtimeout; /* destination side timeouts */ + unsigned long s_strongnacks; /* number of strong nack's */ unsigned long s_time; /* time spent in sending side */ unsigned long s_retriesok; /* successful retries */ unsigned long s_ntargcpu; /* total number of cpu's @@ -439,6 +518,9 @@ struct ptc_stats { unsigned long s_retry_messages; /* retry broadcasts */ unsigned long s_bau_reenabled; /* for bau enable/disable */ unsigned long s_bau_disabled; /* for bau enable/disable */ + unsigned long s_uv2_wars; /* uv2 workaround, perm. busy */ + unsigned long s_uv2_wars_hw; /* uv2 workaround, hiwater */ + unsigned long s_uv2_war_waits; /* uv2 workaround, long waits */ /* destination statistics */ unsigned long d_alltlb; /* times all tlb's on this cpu were flushed */ @@ -511,9 +593,12 @@ struct bau_control { short osnode; short uvhub_cpu; short uvhub; + short uvhub_version; short cpus_in_socket; short cpus_in_uvhub; short partition_base_pnode; + short using_desc; /* an index, like uvhub_cpu */ + unsigned int inuse_map; unsigned short message_number; unsigned short uvhub_quiesce; short socket_acknowledge_count[DEST_Q_SIZE]; @@ -531,6 +616,7 @@ struct bau_control { int cong_response_us; int cong_reps; int cong_period; + unsigned long clocks_per_100_usec; cycles_t period_time; long period_requests; struct hub_and_pnode *thp; @@ -591,6 +677,11 @@ static inline void write_mmr_sw_ack(unsigned long mr) uv_write_local_mmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr); } +static inline void write_gmmr_sw_ack(int pnode, unsigned long mr) +{ + write_gmmr(pnode, UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, mr); +} + static inline unsigned long read_mmr_sw_ack(void) { return read_lmmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE); diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 02b2f05b371e..5369059c07a9 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -25,7 +25,8 @@ obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-y += probe_roms.o obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o -obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o +obj-y += syscall_$(BITS).o +obj-$(CONFIG_X86_64) += vsyscall_64.o obj-$(CONFIG_X86_64) += vsyscall_emu_64.o obj-y += bootflag.o e820.o obj-y += pci-dma.o quirks.o topology.o kdebugfs.o diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 9d59bbacd4e3..79b05b88aa19 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -769,7 +769,12 @@ void __init uv_system_init(void) for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) uv_possible_blades += hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8)); - printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades()); + + /* uv_num_possible_blades() is really the hub count */ + printk(KERN_INFO "UV: Found %d blades, %d hubs\n", + is_uv1_hub() ? uv_num_possible_blades() : + (uv_num_possible_blades() + 1) / 2, + uv_num_possible_blades()); bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades(); uv_blade_info = kzalloc(bytes, GFP_KERNEL); diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index a46bd383953c..f76623cbe263 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -383,21 +383,21 @@ static int ignore_sys_suspend; static int ignore_normal_resume; static int bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL; -static int debug __read_mostly; -static int smp __read_mostly; +static bool debug __read_mostly; +static bool smp __read_mostly; static int apm_disabled = -1; #ifdef CONFIG_SMP -static int power_off; +static bool power_off; #else -static int power_off = 1; +static bool power_off = 1; #endif -static int realmode_power_off; +static bool realmode_power_off; #ifdef CONFIG_APM_ALLOW_INTS -static int allow_ints = 1; +static bool allow_ints = 1; #else -static int allow_ints; +static bool allow_ints; #endif -static int broken_psr; +static bool broken_psr; static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c index 395a10e68067..85d98ab15cdc 100644 --- a/arch/x86/kernel/asm-offsets_32.c +++ b/arch/x86/kernel/asm-offsets_32.c @@ -3,6 +3,11 @@ #include <linux/lguest.h> #include "../../../drivers/lguest/lg.h" +#define __SYSCALL_I386(nr, sym, compat) [nr] = 1, +static char syscalls[] = { +#include <asm/syscalls_32.h> +}; + /* workaround for a warning with -Wmissing-prototypes */ void foo(void); @@ -76,4 +81,7 @@ void foo(void) OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode); OFFSET(LGUEST_PAGES_regs, lguest_pages, regs); #endif + BLANK(); + DEFINE(__NR_syscall_max, sizeof(syscalls) - 1); + DEFINE(NR_syscalls, sizeof(syscalls)); } diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index e72a1194af22..834e897b1e25 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -1,11 +1,12 @@ #include <asm/ia32.h> -#define __NO_STUBS 1 -#undef __SYSCALL -#undef _ASM_X86_UNISTD_64_H -#define __SYSCALL(nr, sym) [nr] = 1, -static char syscalls[] = { -#include <asm/unistd.h> +#define __SYSCALL_64(nr, sym, compat) [nr] = 1, +static char syscalls_64[] = { +#include <asm/syscalls_64.h> +}; +#define __SYSCALL_I386(nr, sym, compat) [nr] = 1, +static char syscalls_ia32[] = { +#include <asm/syscalls_32.h> }; int main(void) @@ -72,7 +73,11 @@ int main(void) OFFSET(TSS_ist, tss_struct, x86_tss.ist); BLANK(); - DEFINE(__NR_syscall_max, sizeof(syscalls) - 1); + DEFINE(__NR_syscall_max, sizeof(syscalls_64) - 1); + DEFINE(NR_syscalls, sizeof(syscalls_64)); + + DEFINE(__NR_ia32_syscall_max, sizeof(syscalls_ia32) - 1); + DEFINE(IA32_NR_syscalls, sizeof(syscalls_ia32)); return 0; } diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 850f2963a420..d43cad74f166 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1021,6 +1021,8 @@ __setup("clearcpuid=", setup_disablecpuid); #ifdef CONFIG_X86_64 struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table }; +struct desc_ptr nmi_idt_descr = { NR_VECTORS * 16 - 1, + (unsigned long) nmi_idt_table }; DEFINE_PER_CPU_FIRST(union irq_stack_union, irq_stack_union) __aligned(PAGE_SIZE); @@ -1085,6 +1087,26 @@ unsigned long kernel_eflags; */ DEFINE_PER_CPU(struct orig_ist, orig_ist); +static DEFINE_PER_CPU(unsigned long, debug_stack_addr); +DEFINE_PER_CPU(int, debug_stack_usage); + +int is_debug_stack(unsigned long addr) +{ + return __get_cpu_var(debug_stack_usage) || + (addr <= __get_cpu_var(debug_stack_addr) && + addr > (__get_cpu_var(debug_stack_addr) - DEBUG_STKSZ)); +} + +void debug_stack_set_zero(void) +{ + load_idt((const struct desc_ptr *)&nmi_idt_descr); +} + +void debug_stack_reset(void) +{ + load_idt((const struct desc_ptr *)&idt_descr); +} + #else /* CONFIG_X86_64 */ DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; @@ -1212,6 +1234,8 @@ void __cpuinit cpu_init(void) estacks += exception_stack_sizes[v]; oist->ist[v] = t->x86_tss.ist[v] = (unsigned long)estacks; + if (v == DEBUG_STACK-1) + per_cpu(debug_stack_addr, cpu) = (unsigned long)estacks; } } diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index f22a9f7f6390..5a11ae2e9e91 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1859,7 +1859,7 @@ static struct bus_type mce_subsys = { .dev_name = "machinecheck", }; -DEFINE_PER_CPU(struct device, mce_device); +struct device *mce_device[CONFIG_NR_CPUS]; __cpuinitdata void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu); @@ -2001,19 +2001,27 @@ static struct device_attribute *mce_device_attrs[] = { static cpumask_var_t mce_device_initialized; +static void mce_device_release(struct device *dev) +{ + kfree(dev); +} + /* Per cpu device init. All of the cpus still share the same ctrl bank: */ static __cpuinit int mce_device_create(unsigned int cpu) { - struct device *dev = &per_cpu(mce_device, cpu); + struct device *dev; int err; int i, j; if (!mce_available(&boot_cpu_data)) return -EIO; - memset(&dev->kobj, 0, sizeof(struct kobject)); + dev = kzalloc(sizeof *dev, GFP_KERNEL); + if (!dev) + return -ENOMEM; dev->id = cpu; dev->bus = &mce_subsys; + dev->release = &mce_device_release; err = device_register(dev); if (err) @@ -2030,6 +2038,7 @@ static __cpuinit int mce_device_create(unsigned int cpu) goto error2; } cpumask_set_cpu(cpu, mce_device_initialized); + mce_device[cpu] = dev; return 0; error2: @@ -2046,7 +2055,7 @@ error: static __cpuinit void mce_device_remove(unsigned int cpu) { - struct device *dev = &per_cpu(mce_device, cpu); + struct device *dev = mce_device[cpu]; int i; if (!cpumask_test_cpu(cpu, mce_device_initialized)) @@ -2060,6 +2069,7 @@ static __cpuinit void mce_device_remove(unsigned int cpu) device_unregister(dev); cpumask_clear_cpu(cpu, mce_device_initialized); + mce_device[cpu] = NULL; } /* Make sure there are no machine checks on offlined CPUs. */ diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index ba0b94a7e204..786e76a86322 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -523,6 +523,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) { int i, err = 0; struct threshold_bank *b = NULL; + struct device *dev = mce_device[cpu]; char name[32]; sprintf(name, "threshold_bank%i", bank); @@ -543,8 +544,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) if (!b) goto out; - err = sysfs_create_link(&per_cpu(mce_device, cpu).kobj, - b->kobj, name); + err = sysfs_create_link(&dev->kobj, b->kobj, name); if (err) goto out; @@ -565,7 +565,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) goto out; } - b->kobj = kobject_create_and_add(name, &per_cpu(mce_device, cpu).kobj); + b->kobj = kobject_create_and_add(name, &dev->kobj); if (!b->kobj) goto out_free; @@ -585,8 +585,9 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) if (i == cpu) continue; - err = sysfs_create_link(&per_cpu(mce_device, i).kobj, - b->kobj, name); + dev = mce_device[i]; + if (dev) + err = sysfs_create_link(&dev->kobj,b->kobj, name); if (err) goto out; @@ -649,6 +650,7 @@ static void deallocate_threshold_block(unsigned int cpu, static void threshold_remove_bank(unsigned int cpu, int bank) { struct threshold_bank *b; + struct device *dev; char name[32]; int i = 0; @@ -663,7 +665,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank) #ifdef CONFIG_SMP /* sibling symlink */ if (shared_bank[bank] && b->blocks->cpu != cpu) { - sysfs_remove_link(&per_cpu(mce_device, cpu).kobj, name); + sysfs_remove_link(&mce_device[cpu]->kobj, name); per_cpu(threshold_banks, cpu)[bank] = NULL; return; @@ -675,7 +677,9 @@ static void threshold_remove_bank(unsigned int cpu, int bank) if (i == cpu) continue; - sysfs_remove_link(&per_cpu(mce_device, i).kobj, name); + dev = mce_device[i]; + if (dev) + sysfs_remove_link(&dev->kobj, name); per_cpu(threshold_banks, i)[bank] = NULL; } diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 174d938d576b..62d61e9976eb 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -703,7 +703,7 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn) } #endif -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_ACPI /** * Mark ACPI NVS memory region, so that we can save/restore it during * hibernation and the subsequent resume. @@ -716,7 +716,7 @@ static int __init e820_mark_nvs_memory(void) struct e820entry *ei = &e820.map[i]; if (ei->type == E820_NVS) - suspend_nvs_register(ei->addr, ei->size); + acpi_nvs_register(ei->addr, ei->size); } return 0; diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 22d0e21b4dd7..79d97e68f042 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -42,6 +42,7 @@ */ #include <linux/linkage.h> +#include <linux/err.h> #include <asm/thread_info.h> #include <asm/irqflags.h> #include <asm/errno.h> @@ -81,8 +82,6 @@ * enough to patch inline, increasing performance. */ -#define nr_syscalls ((syscall_table_size)/4) - #ifdef CONFIG_PREEMPT #define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF #else @@ -423,7 +422,7 @@ sysenter_past_esp: testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) jnz sysenter_audit sysenter_do_call: - cmpl $(nr_syscalls), %eax + cmpl $(NR_syscalls), %eax jae syscall_badsys call *sys_call_table(,%eax,4) movl %eax,PT_EAX(%esp) @@ -455,7 +454,7 @@ sysenter_audit: movl %ebx,%ecx /* 3rd arg: 1st syscall arg */ movl %eax,%edx /* 2nd arg: syscall number */ movl $AUDIT_ARCH_I386,%eax /* 1st arg: audit arch */ - call audit_syscall_entry + call __audit_syscall_entry pushl_cfi %ebx movl PT_EAX(%esp),%eax /* reload syscall number */ jmp sysenter_do_call @@ -466,11 +465,10 @@ sysexit_audit: TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_ANY) movl %eax,%edx /* second arg, syscall return value */ - cmpl $0,%eax /* is it < 0? */ - setl %al /* 1 if so, 0 if not */ + cmpl $-MAX_ERRNO,%eax /* is it an error ? */ + setbe %al /* 1 if so, 0 if not */ movzbl %al,%eax /* zero-extend that */ - inc %eax /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ - call audit_syscall_exit + call __audit_syscall_exit DISABLE_INTERRUPTS(CLBR_ANY) TRACE_IRQS_OFF movl TI_flags(%ebp), %ecx @@ -504,7 +502,7 @@ ENTRY(system_call) # system call tracing in operation / emulation testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) jnz syscall_trace_entry - cmpl $(nr_syscalls), %eax + cmpl $(NR_syscalls), %eax jae syscall_badsys syscall_call: call *sys_call_table(,%eax,4) @@ -654,7 +652,7 @@ syscall_trace_entry: movl %esp, %eax call syscall_trace_enter /* What it returned is what we'll actually use. */ - cmpl $(nr_syscalls), %eax + cmpl $(NR_syscalls), %eax jnae syscall_call jmp syscall_exit END(syscall_trace_entry) @@ -694,29 +692,28 @@ END(syscall_badsys) * System calls that need a pt_regs pointer. */ #define PTREGSCALL0(name) \ - ALIGN; \ -ptregs_##name: \ +ENTRY(ptregs_##name) ; \ leal 4(%esp),%eax; \ - jmp sys_##name; + jmp sys_##name; \ +ENDPROC(ptregs_##name) #define PTREGSCALL1(name) \ - ALIGN; \ -ptregs_##name: \ +ENTRY(ptregs_##name) ; \ leal 4(%esp),%edx; \ movl (PT_EBX+4)(%esp),%eax; \ - jmp sys_##name; + jmp sys_##name; \ +ENDPROC(ptregs_##name) #define PTREGSCALL2(name) \ - ALIGN; \ -ptregs_##name: \ +ENTRY(ptregs_##name) ; \ leal 4(%esp),%ecx; \ movl (PT_ECX+4)(%esp),%edx; \ movl (PT_EBX+4)(%esp),%eax; \ - jmp sys_##name; + jmp sys_##name; \ +ENDPROC(ptregs_##name) #define PTREGSCALL3(name) \ - ALIGN; \ -ptregs_##name: \ +ENTRY(ptregs_##name) ; \ CFI_STARTPROC; \ leal 4(%esp),%eax; \ pushl_cfi %eax; \ @@ -741,8 +738,7 @@ PTREGSCALL2(vm86) PTREGSCALL1(vm86old) /* Clone is an oddball. The 4th arg is in %edi */ - ALIGN; -ptregs_clone: +ENTRY(ptregs_clone) CFI_STARTPROC leal 4(%esp),%eax pushl_cfi %eax @@ -1213,11 +1209,6 @@ return_to_handler: jmp *%ecx #endif -.section .rodata,"a" -#include "syscall_table_32.S" - -syscall_table_size=(.-sys_call_table) - /* * Some functions should be protected against kprobes */ diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index a20e1cb9dc87..3fe8239fd8fb 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -55,6 +55,7 @@ #include <asm/paravirt.h> #include <asm/ftrace.h> #include <asm/percpu.h> +#include <linux/err.h> /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ #include <linux/elf-em.h> @@ -548,7 +549,7 @@ badsys: #ifdef CONFIG_AUDITSYSCALL /* * Fast path for syscall audit without full syscall trace. - * We just call audit_syscall_entry() directly, and then + * We just call __audit_syscall_entry() directly, and then * jump back to the normal fast path. */ auditsys: @@ -558,22 +559,21 @@ auditsys: movq %rdi,%rdx /* 3rd arg: 1st syscall arg */ movq %rax,%rsi /* 2nd arg: syscall number */ movl $AUDIT_ARCH_X86_64,%edi /* 1st arg: audit arch */ - call audit_syscall_entry + call __audit_syscall_entry LOAD_ARGS 0 /* reload call-clobbered registers */ jmp system_call_fastpath /* - * Return fast path for syscall audit. Call audit_syscall_exit() + * Return fast path for syscall audit. Call __audit_syscall_exit() * directly and then jump back to the fast path with TIF_SYSCALL_AUDIT * masked off. */ sysret_audit: movq RAX-ARGOFFSET(%rsp),%rsi /* second arg, syscall return value */ - cmpq $0,%rsi /* is it < 0? */ - setl %al /* 1 if so, 0 if not */ + cmpq $-MAX_ERRNO,%rsi /* is it < -MAX_ERRNO? */ + setbe %al /* 1 if so, 0 if not */ movzbl %al,%edi /* zero-extend that into %edi */ - inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */ - call audit_syscall_exit + call __audit_syscall_exit movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi jmp sysret_check #endif /* CONFIG_AUDITSYSCALL */ @@ -1480,62 +1480,214 @@ ENTRY(error_exit) CFI_ENDPROC END(error_exit) +/* + * Test if a given stack is an NMI stack or not. + */ + .macro test_in_nmi reg stack nmi_ret normal_ret + cmpq %\reg, \stack + ja \normal_ret + subq $EXCEPTION_STKSZ, %\reg + cmpq %\reg, \stack + jb \normal_ret + jmp \nmi_ret + .endm /* runs on exception stack */ ENTRY(nmi) INTR_FRAME PARAVIRT_ADJUST_EXCEPTION_FRAME - pushq_cfi $-1 + /* + * We allow breakpoints in NMIs. If a breakpoint occurs, then + * the iretq it performs will take us out of NMI context. + * This means that we can have nested NMIs where the next + * NMI is using the top of the stack of the previous NMI. We + * can't let it execute because the nested NMI will corrupt the + * stack of the previous NMI. NMI handlers are not re-entrant + * anyway. + * + * To handle this case we do the following: + * Check the a special location on the stack that contains + * a variable that is set when NMIs are executing. + * The interrupted task's stack is also checked to see if it + * is an NMI stack. + * If the variable is not set and the stack is not the NMI + * stack then: + * o Set the special variable on the stack + * o Copy the interrupt frame into a "saved" location on the stack + * o Copy the interrupt frame into a "copy" location on the stack + * o Continue processing the NMI + * If the variable is set or the previous stack is the NMI stack: + * o Modify the "copy" location to jump to the repeate_nmi + * o return back to the first NMI + * + * Now on exit of the first NMI, we first clear the stack variable + * The NMI stack will tell any nested NMIs at that point that it is + * nested. Then we pop the stack normally with iret, and if there was + * a nested NMI that updated the copy interrupt stack frame, a + * jump will be made to the repeat_nmi code that will handle the second + * NMI. + */ + + /* Use %rdx as out temp variable throughout */ + pushq_cfi %rdx + + /* + * Check the special variable on the stack to see if NMIs are + * executing. + */ + cmp $1, -8(%rsp) + je nested_nmi + + /* + * Now test if the previous stack was an NMI stack. + * We need the double check. We check the NMI stack to satisfy the + * race when the first NMI clears the variable before returning. + * We check the variable because the first NMI could be in a + * breakpoint routine using a breakpoint stack. + */ + lea 6*8(%rsp), %rdx + test_in_nmi rdx, 4*8(%rsp), nested_nmi, first_nmi + +nested_nmi: + /* + * Do nothing if we interrupted the fixup in repeat_nmi. + * It's about to repeat the NMI handler, so we are fine + * with ignoring this one. + */ + movq $repeat_nmi, %rdx + cmpq 8(%rsp), %rdx + ja 1f + movq $end_repeat_nmi, %rdx + cmpq 8(%rsp), %rdx + ja nested_nmi_out + +1: + /* Set up the interrupted NMIs stack to jump to repeat_nmi */ + leaq -6*8(%rsp), %rdx + movq %rdx, %rsp + CFI_ADJUST_CFA_OFFSET 6*8 + pushq_cfi $__KERNEL_DS + pushq_cfi %rdx + pushfq_cfi + pushq_cfi $__KERNEL_CS + pushq_cfi $repeat_nmi + + /* Put stack back */ + addq $(11*8), %rsp + CFI_ADJUST_CFA_OFFSET -11*8 + +nested_nmi_out: + popq_cfi %rdx + + /* No need to check faults here */ + INTERRUPT_RETURN + +first_nmi: + /* + * Because nested NMIs will use the pushed location that we + * stored in rdx, we must keep that space available. + * Here's what our stack frame will look like: + * +-------------------------+ + * | original SS | + * | original Return RSP | + * | original RFLAGS | + * | original CS | + * | original RIP | + * +-------------------------+ + * | temp storage for rdx | + * +-------------------------+ + * | NMI executing variable | + * +-------------------------+ + * | Saved SS | + * | Saved Return RSP | + * | Saved RFLAGS | + * | Saved CS | + * | Saved RIP | + * +-------------------------+ + * | copied SS | + * | copied Return RSP | + * | copied RFLAGS | + * | copied CS | + * | copied RIP | + * +-------------------------+ + * | pt_regs | + * +-------------------------+ + * + * The saved RIP is used to fix up the copied RIP that a nested + * NMI may zero out. The original stack frame and the temp storage + * is also used by nested NMIs and can not be trusted on exit. + */ + /* Set the NMI executing variable on the stack. */ + pushq_cfi $1 + + /* Copy the stack frame to the Saved frame */ + .rept 5 + pushq_cfi 6*8(%rsp) + .endr + + /* Make another copy, this one may be modified by nested NMIs */ + .rept 5 + pushq_cfi 4*8(%rsp) + .endr + + /* Do not pop rdx, nested NMIs will corrupt it */ + movq 11*8(%rsp), %rdx + + /* + * Everything below this point can be preempted by a nested + * NMI if the first NMI took an exception. Repeated NMIs + * caused by an exception and nested NMI will start here, and + * can still be preempted by another NMI. + */ +restart_nmi: + pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ subq $ORIG_RAX-R15, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 + /* + * Use save_paranoid to handle SWAPGS, but no need to use paranoid_exit + * as we should not be calling schedule in NMI context. + * Even with normal interrupts enabled. An NMI should not be + * setting NEED_RESCHED or anything that normal interrupts and + * exceptions might do. + */ call save_paranoid DEFAULT_FRAME 0 /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ movq %rsp,%rdi movq $-1,%rsi call do_nmi -#ifdef CONFIG_TRACE_IRQFLAGS - /* paranoidexit; without TRACE_IRQS_OFF */ - /* ebx: no swapgs flag */ - DISABLE_INTERRUPTS(CLBR_NONE) testl %ebx,%ebx /* swapgs needed? */ jnz nmi_restore - testl $3,CS(%rsp) - jnz nmi_userspace nmi_swapgs: SWAPGS_UNSAFE_STACK nmi_restore: RESTORE_ALL 8 + /* Clear the NMI executing stack variable */ + movq $0, 10*8(%rsp) jmp irq_return -nmi_userspace: - GET_THREAD_INFO(%rcx) - movl TI_flags(%rcx),%ebx - andl $_TIF_WORK_MASK,%ebx - jz nmi_swapgs - movq %rsp,%rdi /* &pt_regs */ - call sync_regs - movq %rax,%rsp /* switch stack for scheduling */ - testl $_TIF_NEED_RESCHED,%ebx - jnz nmi_schedule - movl %ebx,%edx /* arg3: thread flags */ - ENABLE_INTERRUPTS(CLBR_NONE) - xorl %esi,%esi /* arg2: oldset */ - movq %rsp,%rdi /* arg1: &pt_regs */ - call do_notify_resume - DISABLE_INTERRUPTS(CLBR_NONE) - jmp nmi_userspace -nmi_schedule: - ENABLE_INTERRUPTS(CLBR_ANY) - call schedule - DISABLE_INTERRUPTS(CLBR_ANY) - jmp nmi_userspace - CFI_ENDPROC -#else - jmp paranoid_exit CFI_ENDPROC -#endif END(nmi) + /* + * If an NMI hit an iret because of an exception or breakpoint, + * it can lose its NMI context, and a nested NMI may come in. + * In that case, the nested NMI will change the preempted NMI's + * stack to jump to here when it does the final iret. + */ +repeat_nmi: + INTR_FRAME + /* Update the stack variable to say we are still in NMI */ + movq $1, 5*8(%rsp) + + /* copy the saved stack back to copy stack */ + .rept 5 + pushq_cfi 4*8(%rsp) + .endr + + jmp restart_nmi + CFI_ENDPROC +end_repeat_nmi: + ENTRY(ignore_sysret) CFI_STARTPROC mov $-ENOSYS,%eax diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index e11e39478a49..40f4eb3766d1 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -417,6 +417,10 @@ ENTRY(phys_base) ENTRY(idt_table) .skip IDT_ENTRIES * 16 + .align L1_CACHE_BYTES +ENTRY(nmi_idt_table) + .skip IDT_ENTRIES * 16 + __PAGE_ALIGNED_BSS .align PAGE_SIZE ENTRY(empty_zero_page) diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index e88f37b58ddd..47acaf319165 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c @@ -405,9 +405,108 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) unknown_nmi_error(reason, regs); } +/* + * NMIs can hit breakpoints which will cause it to lose its + * NMI context with the CPU when the breakpoint does an iret. + */ +#ifdef CONFIG_X86_32 +/* + * For i386, NMIs use the same stack as the kernel, and we can + * add a workaround to the iret problem in C. Simply have 3 states + * the NMI can be in. + * + * 1) not running + * 2) executing + * 3) latched + * + * When no NMI is in progress, it is in the "not running" state. + * When an NMI comes in, it goes into the "executing" state. + * Normally, if another NMI is triggered, it does not interrupt + * the running NMI and the HW will simply latch it so that when + * the first NMI finishes, it will restart the second NMI. + * (Note, the latch is binary, thus multiple NMIs triggering, + * when one is running, are ignored. Only one NMI is restarted.) + * + * If an NMI hits a breakpoint that executes an iret, another + * NMI can preempt it. We do not want to allow this new NMI + * to run, but we want to execute it when the first one finishes. + * We set the state to "latched", and the first NMI will perform + * an cmpxchg on the state, and if it doesn't successfully + * reset the state to "not running" it will restart the next + * NMI. + */ +enum nmi_states { + NMI_NOT_RUNNING, + NMI_EXECUTING, + NMI_LATCHED, +}; +static DEFINE_PER_CPU(enum nmi_states, nmi_state); + +#define nmi_nesting_preprocess(regs) \ + do { \ + if (__get_cpu_var(nmi_state) != NMI_NOT_RUNNING) { \ + __get_cpu_var(nmi_state) = NMI_LATCHED; \ + return; \ + } \ + nmi_restart: \ + __get_cpu_var(nmi_state) = NMI_EXECUTING; \ + } while (0) + +#define nmi_nesting_postprocess() \ + do { \ + if (cmpxchg(&__get_cpu_var(nmi_state), \ + NMI_EXECUTING, NMI_NOT_RUNNING) != NMI_EXECUTING) \ + goto nmi_restart; \ + } while (0) +#else /* x86_64 */ +/* + * In x86_64 things are a bit more difficult. This has the same problem + * where an NMI hitting a breakpoint that calls iret will remove the + * NMI context, allowing a nested NMI to enter. What makes this more + * difficult is that both NMIs and breakpoints have their own stack. + * When a new NMI or breakpoint is executed, the stack is set to a fixed + * point. If an NMI is nested, it will have its stack set at that same + * fixed address that the first NMI had, and will start corrupting the + * stack. This is handled in entry_64.S, but the same problem exists with + * the breakpoint stack. + * + * If a breakpoint is being processed, and the debug stack is being used, + * if an NMI comes in and also hits a breakpoint, the stack pointer + * will be set to the same fixed address as the breakpoint that was + * interrupted, causing that stack to be corrupted. To handle this case, + * check if the stack that was interrupted is the debug stack, and if + * so, change the IDT so that new breakpoints will use the current stack + * and not switch to the fixed address. On return of the NMI, switch back + * to the original IDT. + */ +static DEFINE_PER_CPU(int, update_debug_stack); + +static inline void nmi_nesting_preprocess(struct pt_regs *regs) +{ + /* + * If we interrupted a breakpoint, it is possible that + * the nmi handler will have breakpoints too. We need to + * change the IDT such that breakpoints that happen here + * continue to use the NMI stack. + */ + if (unlikely(is_debug_stack(regs->sp))) { + debug_stack_set_zero(); + __get_cpu_var(update_debug_stack) = 1; + } +} + +static inline void nmi_nesting_postprocess(void) +{ + if (unlikely(__get_cpu_var(update_debug_stack))) + debug_stack_reset(); +} +#endif + dotraplinkage notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code) { + nmi_nesting_preprocess(regs); + nmi_enter(); inc_irq_stat(__nmi_count); @@ -416,6 +515,9 @@ do_nmi(struct pt_regs *regs, long error_code) default_do_nmi(regs); nmi_exit(); + + /* On i386, may loop back to preprocess */ + nmi_nesting_postprocess(); } void stop_nmi(void) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 89a04c7b5bb6..50267386b766 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1392,20 +1392,18 @@ long syscall_trace_enter(struct pt_regs *regs) if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_enter(regs, regs->orig_ax); - if (unlikely(current->audit_context)) { - if (IS_IA32) - audit_syscall_entry(AUDIT_ARCH_I386, - regs->orig_ax, - regs->bx, regs->cx, - regs->dx, regs->si); + if (IS_IA32) + audit_syscall_entry(AUDIT_ARCH_I386, + regs->orig_ax, + regs->bx, regs->cx, + regs->dx, regs->si); #ifdef CONFIG_X86_64 - else - audit_syscall_entry(AUDIT_ARCH_X86_64, - regs->orig_ax, - regs->di, regs->si, - regs->dx, regs->r10); + else + audit_syscall_entry(AUDIT_ARCH_X86_64, + regs->orig_ax, + regs->di, regs->si, + regs->dx, regs->r10); #endif - } return ret ?: regs->orig_ax; } @@ -1414,8 +1412,7 @@ void syscall_trace_leave(struct pt_regs *regs) { bool step; - if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); + audit_syscall_exit(regs); if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) trace_sys_exit(regs, regs->ax); diff --git a/arch/x86/kernel/syscall_32.c b/arch/x86/kernel/syscall_32.c new file mode 100644 index 000000000000..147fcd4941c4 --- /dev/null +++ b/arch/x86/kernel/syscall_32.c @@ -0,0 +1,25 @@ +/* System call table for i386. */ + +#include <linux/linkage.h> +#include <linux/sys.h> +#include <linux/cache.h> +#include <asm/asm-offsets.h> + +#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ; +#include <asm/syscalls_32.h> +#undef __SYSCALL_I386 + +#define __SYSCALL_I386(nr, sym, compat) [nr] = sym, + +typedef asmlinkage void (*sys_call_ptr_t)(void); + +extern asmlinkage void sys_ni_syscall(void); + +const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { + /* + * Smells like a compiler bug -- it doesn't work + * when the & below is removed. + */ + [0 ... __NR_syscall_max] = &sys_ni_syscall, +#include <asm/syscalls_32.h> +}; diff --git a/arch/x86/kernel/syscall_64.c b/arch/x86/kernel/syscall_64.c index de87d6008295..7ac7943be02c 100644 --- a/arch/x86/kernel/syscall_64.c +++ b/arch/x86/kernel/syscall_64.c @@ -5,15 +5,11 @@ #include <linux/cache.h> #include <asm/asm-offsets.h> -#define __NO_STUBS +#define __SYSCALL_64(nr, sym, compat) extern asmlinkage void sym(void) ; +#include <asm/syscalls_64.h> +#undef __SYSCALL_64 -#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; -#undef _ASM_X86_UNISTD_64_H -#include <asm/unistd_64.h> - -#undef __SYSCALL -#define __SYSCALL(nr, sym) [nr] = sym, -#undef _ASM_X86_UNISTD_64_H +#define __SYSCALL_64(nr, sym, compat) [nr] = sym, typedef void (*sys_call_ptr_t)(void); @@ -21,9 +17,9 @@ extern void sys_ni_syscall(void); const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { /* - *Smells like a like a compiler bug -- it doesn't work - *when the & below is removed. - */ + * Smells like a compiler bug -- it doesn't work + * when the & below is removed. + */ [0 ... __NR_syscall_max] = &sys_ni_syscall, -#include <asm/unistd_64.h> +#include <asm/syscalls_64.h> }; diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S deleted file mode 100644 index 9a0e31293920..000000000000 --- a/arch/x86/kernel/syscall_table_32.S +++ /dev/null @@ -1,350 +0,0 @@ -ENTRY(sys_call_table) - .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ - .long sys_exit - .long ptregs_fork - .long sys_read - .long sys_write - .long sys_open /* 5 */ - .long sys_close - .long sys_waitpid - .long sys_creat - .long sys_link - .long sys_unlink /* 10 */ - .long ptregs_execve - .long sys_chdir - .long sys_time - .long sys_mknod - .long sys_chmod /* 15 */ - .long sys_lchown16 - .long sys_ni_syscall /* old break syscall holder */ - .long sys_stat - .long sys_lseek - .long sys_getpid /* 20 */ - .long sys_mount - .long sys_oldumount - .long sys_setuid16 - .long sys_getuid16 - .long sys_stime /* 25 */ - .long sys_ptrace - .long sys_alarm - .long sys_fstat - .long sys_pause - .long sys_utime /* 30 */ - .long sys_ni_syscall /* old stty syscall holder */ - .long sys_ni_syscall /* old gtty syscall holder */ - .long sys_access - .long sys_nice - .long sys_ni_syscall /* 35 - old ftime syscall holder */ - .long sys_sync - .long sys_kill - .long sys_rename - .long sys_mkdir - .long sys_rmdir /* 40 */ - .long sys_dup - .long sys_pipe - .long sys_times - .long sys_ni_syscall /* old prof syscall holder */ - .long sys_brk /* 45 */ - .long sys_setgid16 - .long sys_getgid16 - .long sys_signal - .long sys_geteuid16 - .long sys_getegid16 /* 50 */ - .long sys_acct - .long sys_umount /* recycled never used phys() */ - .long sys_ni_syscall /* old lock syscall holder */ - .long sys_ioctl - .long sys_fcntl /* 55 */ - .long sys_ni_syscall /* old mpx syscall holder */ - .long sys_setpgid - .long sys_ni_syscall /* old ulimit syscall holder */ - .long sys_olduname - .long sys_umask /* 60 */ - .long sys_chroot - .long sys_ustat - .long sys_dup2 - .long sys_getppid - .long sys_getpgrp /* 65 */ - .long sys_setsid - .long sys_sigaction - .long sys_sgetmask - .long sys_ssetmask - .long sys_setreuid16 /* 70 */ - .long sys_setregid16 - .long sys_sigsuspend - .long sys_sigpending - .long sys_sethostname - .long sys_setrlimit /* 75 */ - .long sys_old_getrlimit - .long sys_getrusage - .long sys_gettimeofday - .long sys_settimeofday - .long sys_getgroups16 /* 80 */ - .long sys_setgroups16 - .long sys_old_select - .long sys_symlink - .long sys_lstat - .long sys_readlink /* 85 */ - .long sys_uselib - .long sys_swapon - .long sys_reboot - .long sys_old_readdir - .long sys_old_mmap /* 90 */ - .long sys_munmap - .long sys_truncate - .long sys_ftruncate - .long sys_fchmod - .long sys_fchown16 /* 95 */ - .long sys_getpriority - .long sys_setpriority - .long sys_ni_syscall /* old profil syscall holder */ - .long sys_statfs - .long sys_fstatfs /* 100 */ - .long sys_ioperm - .long sys_socketcall - .long sys_syslog - .long sys_setitimer - .long sys_getitimer /* 105 */ - .long sys_newstat - .long sys_newlstat - .long sys_newfstat - .long sys_uname - .long ptregs_iopl /* 110 */ - .long sys_vhangup - .long sys_ni_syscall /* old "idle" system call */ - .long ptregs_vm86old - .long sys_wait4 - .long sys_swapoff /* 115 */ - .long sys_sysinfo - .long sys_ipc - .long sys_fsync - .long ptregs_sigreturn - .long ptregs_clone /* 120 */ - .long sys_setdomainname - .long sys_newuname - .long sys_modify_ldt - .long sys_adjtimex - .long sys_mprotect /* 125 */ - .long sys_sigprocmask - .long sys_ni_syscall /* old "create_module" */ - .long sys_init_module - .long sys_delete_module - .long sys_ni_syscall /* 130: old "get_kernel_syms" */ - .long sys_quotactl - .long sys_getpgid - .long sys_fchdir - .long sys_bdflush - .long sys_sysfs /* 135 */ - .long sys_personality - .long sys_ni_syscall /* reserved for afs_syscall */ - .long sys_setfsuid16 - .long sys_setfsgid16 - .long sys_llseek /* 140 */ - .long sys_getdents - .long sys_select - .long sys_flock - .long sys_msync - .long sys_readv /* 145 */ - .long sys_writev - .long sys_getsid - .long sys_fdatasync - .long sys_sysctl - .long sys_mlock /* 150 */ - .long sys_munlock - .long sys_mlockall - .long sys_munlockall - .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ - .long sys_sched_setscheduler - .long sys_sched_getscheduler - .long sys_sched_yield - .long sys_sched_get_priority_max - .long sys_sched_get_priority_min /* 160 */ - .long sys_sched_rr_get_interval - .long sys_nanosleep - .long sys_mremap - .long sys_setresuid16 - .long sys_getresuid16 /* 165 */ - .long ptregs_vm86 - .long sys_ni_syscall /* Old sys_query_module */ - .long sys_poll - .long sys_ni_syscall /* Old nfsservctl */ - .long sys_setresgid16 /* 170 */ - .long sys_getresgid16 - .long sys_prctl - .long ptregs_rt_sigreturn - .long sys_rt_sigaction - .long sys_rt_sigprocmask /* 175 */ - .long sys_rt_sigpending - .long sys_rt_sigtimedwait - .long sys_rt_sigqueueinfo - .long sys_rt_sigsuspend - .long sys_pread64 /* 180 */ - .long sys_pwrite64 - .long sys_chown16 - .long sys_getcwd - .long sys_capget - .long sys_capset /* 185 */ - .long ptregs_sigaltstack - .long sys_sendfile - .long sys_ni_syscall /* reserved for streams1 */ - .long sys_ni_syscall /* reserved for streams2 */ - .long ptregs_vfork /* 190 */ - .long sys_getrlimit - .long sys_mmap_pgoff - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ - .long sys_lstat64 - .long sys_fstat64 - .long sys_lchown - .long sys_getuid - .long sys_getgid /* 200 */ - .long sys_geteuid - .long sys_getegid - .long sys_setreuid - .long sys_setregid - .long sys_getgroups /* 205 */ - .long sys_setgroups - .long sys_fchown - .long sys_setresuid - .long sys_getresuid - .long sys_setresgid /* 210 */ - .long sys_getresgid - .long sys_chown - .long sys_setuid - .long sys_setgid - .long sys_setfsuid /* 215 */ - .long sys_setfsgid - .long sys_pivot_root - .long sys_mincore - .long sys_madvise - .long sys_getdents64 /* 220 */ - .long sys_fcntl64 - .long sys_ni_syscall /* reserved for TUX */ - .long sys_ni_syscall - .long sys_gettid - .long sys_readahead /* 225 */ - .long sys_setxattr - .long sys_lsetxattr - .long sys_fsetxattr - .long sys_getxattr - .long sys_lgetxattr /* 230 */ - .long sys_fgetxattr - .long sys_listxattr - .long sys_llistxattr - .long sys_flistxattr - .long sys_removexattr /* 235 */ - .long sys_lremovexattr - .long sys_fremovexattr - .long sys_tkill - .long sys_sendfile64 - .long sys_futex /* 240 */ - .long sys_sched_setaffinity - .long sys_sched_getaffinity - .long sys_set_thread_area - .long sys_get_thread_area - .long sys_io_setup /* 245 */ - .long sys_io_destroy - .long sys_io_getevents - .long sys_io_submit - .long sys_io_cancel - .long sys_fadvise64 /* 250 */ - .long sys_ni_syscall - .long sys_exit_group - .long sys_lookup_dcookie - .long sys_epoll_create - .long sys_epoll_ctl /* 255 */ - .long sys_epoll_wait - .long sys_remap_file_pages - .long sys_set_tid_address - .long sys_timer_create - .long sys_timer_settime /* 260 */ - .long sys_timer_gettime - .long sys_timer_getoverrun - .long sys_timer_delete - .long sys_clock_settime - .long sys_clock_gettime /* 265 */ - .long sys_clock_getres - .long sys_clock_nanosleep - .long sys_statfs64 - .long sys_fstatfs64 - .long sys_tgkill /* 270 */ - .long sys_utimes - .long sys_fadvise64_64 - .long sys_ni_syscall /* sys_vserver */ - .long sys_mbind - .long sys_get_mempolicy - .long sys_set_mempolicy - .long sys_mq_open - .long sys_mq_unlink - .long sys_mq_timedsend - .long sys_mq_timedreceive /* 280 */ - .long sys_mq_notify - .long sys_mq_getsetattr - .long sys_kexec_load - .long sys_waitid - .long sys_ni_syscall /* 285 */ /* available */ - .long sys_add_key - .long sys_request_key - .long sys_keyctl - .long sys_ioprio_set - .long sys_ioprio_get /* 290 */ - .long sys_inotify_init - .long sys_inotify_add_watch - .long sys_inotify_rm_watch - .long sys_migrate_pages - .long sys_openat /* 295 */ - .long sys_mkdirat - .long sys_mknodat - .long sys_fchownat - .long sys_futimesat - .long sys_fstatat64 /* 300 */ - .long sys_unlinkat - .long sys_renameat - .long sys_linkat - .long sys_symlinkat - .long sys_readlinkat /* 305 */ - .long sys_fchmodat - .long sys_faccessat - .long sys_pselect6 - .long sys_ppoll - .long sys_unshare /* 310 */ - .long sys_set_robust_list - .long sys_get_robust_list - .long sys_splice - .long sys_sync_file_range - .long sys_tee /* 315 */ - .long sys_vmsplice - .long sys_move_pages - .long sys_getcpu - .long sys_epoll_pwait - .long sys_utimensat /* 320 */ - .long sys_signalfd - .long sys_timerfd_create - .long sys_eventfd - .long sys_fallocate - .long sys_timerfd_settime /* 325 */ - .long sys_timerfd_gettime - .long sys_signalfd4 - .long sys_eventfd2 - .long sys_epoll_create1 - .long sys_dup3 /* 330 */ - .long sys_pipe2 - .long sys_inotify_init1 - .long sys_preadv - .long sys_pwritev - .long sys_rt_tgsigqueueinfo /* 335 */ - .long sys_perf_event_open - .long sys_recvmmsg - .long sys_fanotify_init - .long sys_fanotify_mark - .long sys_prlimit64 /* 340 */ - .long sys_name_to_handle_at - .long sys_open_by_handle_at - .long sys_clock_adjtime - .long sys_syncfs - .long sys_sendmmsg /* 345 */ - .long sys_setns - .long sys_process_vm_readv - .long sys_process_vm_writev diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index fa1191fb679d..482ec3af2067 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -311,9 +311,15 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) == NOTIFY_STOP) return; + /* + * Let others (NMI) know that the debug stack is in use + * as we may switch to the interrupt stack. + */ + debug_stack_usage_inc(); preempt_conditional_sti(regs); do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); preempt_conditional_cli(regs); + debug_stack_usage_dec(); } #ifdef CONFIG_X86_64 @@ -406,6 +412,12 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) SIGTRAP) == NOTIFY_STOP) return; + /* + * Let others (NMI) know that the debug stack is in use + * as we may switch to the interrupt stack. + */ + debug_stack_usage_inc(); + /* It's safe to allow irq's after DR6 has been saved */ preempt_conditional_sti(regs); @@ -413,6 +425,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); preempt_conditional_cli(regs); + debug_stack_usage_dec(); return; } @@ -432,6 +445,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp) send_sigtrap(tsk, regs, error_code, si_code); preempt_conditional_cli(regs); + debug_stack_usage_dec(); return; } @@ -718,4 +732,10 @@ void __init trap_init(void) cpu_init(); x86_init.irqs.trap_init(); + +#ifdef CONFIG_X86_64 + memcpy(&nmi_idt_table, &idt_table, IDT_ENTRIES * 16); + set_nmi_gate(1, &debug); + set_nmi_gate(3, &int3); +#endif } diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index c0dd5b603749..a62c201c97ec 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -290,14 +290,15 @@ static inline int pit_verify_msb(unsigned char val) static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *deltap) { int count; - u64 tsc = 0; + u64 tsc = 0, prev_tsc = 0; for (count = 0; count < 50000; count++) { if (!pit_verify_msb(val)) break; + prev_tsc = tsc; tsc = get_cycles(); } - *deltap = get_cycles() - tsc; + *deltap = get_cycles() - prev_tsc; *tscp = tsc; /* @@ -311,9 +312,9 @@ static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *de * How many MSB values do we want to see? We aim for * a maximum error rate of 500ppm (in practice the * real error is much smaller), but refuse to spend - * more than 25ms on it. + * more than 50ms on it. */ -#define MAX_QUICK_PIT_MS 25 +#define MAX_QUICK_PIT_MS 50 #define MAX_QUICK_PIT_ITERATIONS (MAX_QUICK_PIT_MS * PIT_TICK_RATE / 1000 / 256) static unsigned long quick_pit_calibrate(void) @@ -383,15 +384,12 @@ success: * * As a result, we can depend on there not being * any odd delays anywhere, and the TSC reads are - * reliable (within the error). We also adjust the - * delta to the middle of the error bars, just - * because it looks nicer. + * reliable (within the error). * * kHz = ticks / time-in-seconds / 1000; * kHz = (t2 - t1) / (I * 256 / PIT_TICK_RATE) / 1000 * kHz = ((t2 - t1) * PIT_TICK_RATE) / (I * 256 * 1000) */ - delta += (long)(d2 - d1)/2; delta *= PIT_TICK_RATE; do_div(delta, i*256*1000); printk("Fast TSC calibration using PIT\n"); diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 863f8753ab0a..b466cab5ba15 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -335,9 +335,11 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk if (info->flags & VM86_SCREEN_BITMAP) mark_screen_rdonly(tsk->mm); - /*call audit_syscall_exit since we do not exit via the normal paths */ + /*call __audit_syscall_exit since we do not exit via the normal paths */ +#ifdef CONFIG_AUDITSYSCALL if (unlikely(current->audit_context)) - audit_syscall_exit(AUDITSC_RESULT(0), 0); + __audit_syscall_exit(1, 0); +#endif __asm__ __volatile__( "movl %0,%%esp\n\t" diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 2a2a9b40db19..224b02c3cda9 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -74,7 +74,7 @@ enum { #endif #ifdef MMU_DEBUG -static int dbg = 0; +static bool dbg = 0; module_param(dbg, bool, 0644); #endif diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 906a7e84200f..d29216c462b3 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -51,29 +51,29 @@ MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); -static int __read_mostly enable_vpid = 1; +static bool __read_mostly enable_vpid = 1; module_param_named(vpid, enable_vpid, bool, 0444); -static int __read_mostly flexpriority_enabled = 1; +static bool __read_mostly flexpriority_enabled = 1; module_param_named(flexpriority, flexpriority_enabled, bool, S_IRUGO); -static int __read_mostly enable_ept = 1; +static bool __read_mostly enable_ept = 1; module_param_named(ept, enable_ept, bool, S_IRUGO); -static int __read_mostly enable_unrestricted_guest = 1; +static bool __read_mostly enable_unrestricted_guest = 1; module_param_named(unrestricted_guest, enable_unrestricted_guest, bool, S_IRUGO); -static int __read_mostly emulate_invalid_guest_state = 0; +static bool __read_mostly emulate_invalid_guest_state = 0; module_param(emulate_invalid_guest_state, bool, S_IRUGO); -static int __read_mostly vmm_exclusive = 1; +static bool __read_mostly vmm_exclusive = 1; module_param(vmm_exclusive, bool, S_IRUGO); -static int __read_mostly yield_on_hlt = 1; +static bool __read_mostly yield_on_hlt = 1; module_param(yield_on_hlt, bool, S_IRUGO); -static int __read_mostly fasteoi = 1; +static bool __read_mostly fasteoi = 1; module_param(fasteoi, bool, S_IRUGO); /* @@ -81,7 +81,7 @@ module_param(fasteoi, bool, S_IRUGO); * VMX and be a hypervisor for its own guests. If nested=0, guests may not * use VMX instructions. */ -static int __read_mostly nested = 0; +static bool __read_mostly nested = 0; module_param(nested, bool, S_IRUGO); #define KVM_GUEST_CR0_MASK_UNRESTRICTED_GUEST \ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1171def5f96b..14d6cadc4ba6 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -88,8 +88,8 @@ static void process_nmi(struct kvm_vcpu *vcpu); struct kvm_x86_ops *kvm_x86_ops; EXPORT_SYMBOL_GPL(kvm_x86_ops); -int ignore_msrs = 0; -module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR); +static bool ignore_msrs = 0; +module_param(ignore_msrs, bool, S_IRUGO | S_IWUSR); bool kvm_has_tsc_control; EXPORT_SYMBOL_GPL(kvm_has_tsc_control); diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 5b83c51c12e0..819137904428 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -219,7 +219,9 @@ ab: STOS/W/D/Q Yv,rAX ac: LODS/B AL,Xb ad: LODS/W/D/Q rAX,Xv ae: SCAS/B AL,Yb -af: SCAS/W/D/Q rAX,Xv +# Note: The May 2011 Intel manual shows Xv for the second parameter of the +# next instruction but Yv is correct +af: SCAS/W/D/Q rAX,Yv # 0xb0 - 0xbf b0: MOV AL/R8L,Ib b1: MOV CL/R9L,Ib @@ -729,8 +731,8 @@ de: VAESDEC Vdq,Hdq,Wdq (66),(v1) df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) -f3: ANDN Gy,By,Ey (v) -f4: Grp17 (1A) +f2: ANDN Gy,By,Ey (v) +f3: Grp17 (1A) f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) f6: MULX By,Gy,rDX,Ey (F2),(v) f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) diff --git a/arch/x86/mm/mmio-mod.c b/arch/x86/mm/mmio-mod.c index de54b9b278a7..dc0b727742f4 100644 --- a/arch/x86/mm/mmio-mod.c +++ b/arch/x86/mm/mmio-mod.c @@ -75,8 +75,8 @@ static LIST_HEAD(trace_list); /* struct remap_trace */ /* module parameters */ static unsigned long filter_offset; -static int nommiotrace; -static int trace_pc; +static bool nommiotrace; +static bool trace_pc; module_param(filter_offset, ulong, 0); module_param(nommiotrace, bool, 0); diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index fd61b3fb7341..1c1c4f46a7c1 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c @@ -109,6 +109,8 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) return; pxm = pa->proximity_domain_lo; + if (acpi_srat_revision >= 2) + pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; node = setup_node(pxm); if (node < 0) { printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); @@ -160,6 +162,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) start = ma->base_address; end = start + ma->length; pxm = ma->proximity_domain; + if (acpi_srat_revision <= 1) + pxm &= 0xff; node = setup_node(pxm); if (node < 0) { printk(KERN_ERR "SRAT: Too many proximity domains.\n"); diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 7b65f752c5f8..7c1b765ecc59 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -151,17 +151,18 @@ void bpf_jit_compile(struct sk_filter *fp) cleanup_addr = proglen; /* epilogue address */ for (pass = 0; pass < 10; pass++) { + u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen; /* no prologue/epilogue for trivial filters (RET something) */ proglen = 0; prog = temp; - if (seen) { + if (seen_or_pass0) { EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */ EMIT4(0x48, 0x83, 0xec, 96); /* subq $96,%rsp */ /* note : must save %rbx in case bpf_error is hit */ - if (seen & (SEEN_XREG | SEEN_DATAREF)) + if (seen_or_pass0 & (SEEN_XREG | SEEN_DATAREF)) EMIT4(0x48, 0x89, 0x5d, 0xf8); /* mov %rbx, -8(%rbp) */ - if (seen & SEEN_XREG) + if (seen_or_pass0 & SEEN_XREG) CLEAR_X(); /* make sure we dont leek kernel memory */ /* @@ -170,7 +171,7 @@ void bpf_jit_compile(struct sk_filter *fp) * r9 = skb->len - skb->data_len * r8 = skb->data */ - if (seen & SEEN_DATAREF) { + if (seen_or_pass0 & SEEN_DATAREF) { if (offsetof(struct sk_buff, len) <= 127) /* mov off8(%rdi),%r9d */ EMIT4(0x44, 0x8b, 0x4f, offsetof(struct sk_buff, len)); @@ -260,9 +261,14 @@ void bpf_jit_compile(struct sk_filter *fp) case BPF_S_ALU_DIV_X: /* A /= X; */ seen |= SEEN_XREG; EMIT2(0x85, 0xdb); /* test %ebx,%ebx */ - if (pc_ret0 != -1) - EMIT_COND_JMP(X86_JE, addrs[pc_ret0] - (addrs[i] - 4)); - else { + if (pc_ret0 > 0) { + /* addrs[pc_ret0 - 1] is start address of target + * (addrs[i] - 4) is the address following this jmp + * ("xor %edx,%edx; div %ebx" being 4 bytes long) + */ + EMIT_COND_JMP(X86_JE, addrs[pc_ret0 - 1] - + (addrs[i] - 4)); + } else { EMIT_COND_JMP(X86_JNE, 2 + 5); CLEAR_A(); EMIT1_off32(0xe9, cleanup_addr - (addrs[i] - 4)); /* jmp .+off32 */ @@ -335,12 +341,12 @@ void bpf_jit_compile(struct sk_filter *fp) } /* fallinto */ case BPF_S_RET_A: - if (seen) { + if (seen_or_pass0) { if (i != flen - 1) { EMIT_JMP(cleanup_addr - addrs[i]); break; } - if (seen & SEEN_XREG) + if (seen_or_pass0 & SEEN_XREG) EMIT4(0x48, 0x8b, 0x5d, 0xf8); /* mov -8(%rbp),%rbx */ EMIT1(0xc9); /* leaveq */ } @@ -483,8 +489,9 @@ common_load: seen |= SEEN_DATAREF; goto common_load; case BPF_S_LDX_B_MSH: if ((int)K < 0) { - if (pc_ret0 != -1) { - EMIT_JMP(addrs[pc_ret0] - addrs[i]); + if (pc_ret0 > 0) { + /* addrs[pc_ret0 - 1] is the start address */ + EMIT_JMP(addrs[pc_ret0 - 1] - addrs[i]); break; } CLEAR_A(); @@ -599,13 +606,14 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; * use it to give the cleanup instruction(s) addr */ cleanup_addr = proglen - 1; /* ret */ - if (seen) + if (seen_or_pass0) cleanup_addr -= 1; /* leaveq */ - if (seen & SEEN_XREG) + if (seen_or_pass0 & SEEN_XREG) cleanup_addr -= 4; /* mov -8(%rbp),%rbx */ if (image) { - WARN_ON(proglen != oldproglen); + if (proglen != oldproglen) + pr_err("bpb_jit_compile proglen=%u != oldproglen=%u\n", proglen, oldproglen); break; } if (proglen == oldproglen) { diff --git a/arch/x86/platform/geode/alix.c b/arch/x86/platform/geode/alix.c index ca1973699d3d..dc5f1d32aced 100644 --- a/arch/x86/platform/geode/alix.c +++ b/arch/x86/platform/geode/alix.c @@ -27,7 +27,7 @@ #include <asm/geode.h> -static int force = 0; +static bool force = 0; module_param(force, bool, 0444); /* FIXME: Award bios is not automatically detected as Alix platform */ MODULE_PARM_DESC(force, "Force detection as ALIX.2/ALIX.3 platform"); diff --git a/arch/x86/platform/iris/iris.c b/arch/x86/platform/iris/iris.c index 1ba7f5ed8c9b..5917eb56b313 100644 --- a/arch/x86/platform/iris/iris.c +++ b/arch/x86/platform/iris/iris.c @@ -42,7 +42,7 @@ MODULE_AUTHOR("SĂ©bastien Hinderer <Sebastien.Hinderer@ens-lyon.org>"); MODULE_DESCRIPTION("A power_off handler for Iris devices from EuroBraille"); MODULE_SUPPORTED_DEVICE("Eurobraille/Iris"); -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Set to one to force poweroff handler installation."); diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 5b552198f774..9be4cff00a2d 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -157,13 +157,14 @@ static int __init uvhub_to_first_apicid(int uvhub) * clear of the Timeout bit (as well) will free the resource. No reply will * be sent (the hardware will only do one reply per message). */ -static void reply_to_message(struct msg_desc *mdp, struct bau_control *bcp) +static void reply_to_message(struct msg_desc *mdp, struct bau_control *bcp, + int do_acknowledge) { unsigned long dw; struct bau_pq_entry *msg; msg = mdp->msg; - if (!msg->canceled) { + if (!msg->canceled && do_acknowledge) { dw = (msg->swack_vec << UV_SW_ACK_NPENDING) | msg->swack_vec; write_mmr_sw_ack(dw); } @@ -212,8 +213,8 @@ static void bau_process_retry_msg(struct msg_desc *mdp, if (mmr & (msg_res << UV_SW_ACK_NPENDING)) { unsigned long mr; /* - * is the resource timed out? - * make everyone ignore the cancelled message. + * Is the resource timed out? + * Make everyone ignore the cancelled message. */ msg2->canceled = 1; stat->d_canceled++; @@ -231,8 +232,8 @@ static void bau_process_retry_msg(struct msg_desc *mdp, * Do all the things a cpu should do for a TLB shootdown message. * Other cpu's may come here at the same time for this message. */ -static void bau_process_message(struct msg_desc *mdp, - struct bau_control *bcp) +static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp, + int do_acknowledge) { short socket_ack_count = 0; short *sp; @@ -284,8 +285,9 @@ static void bau_process_message(struct msg_desc *mdp, if (msg_ack_count == bcp->cpus_in_uvhub) { /* * All cpus in uvhub saw it; reply + * (unless we are in the UV2 workaround) */ - reply_to_message(mdp, bcp); + reply_to_message(mdp, bcp, do_acknowledge); } } @@ -491,27 +493,138 @@ static int uv1_wait_completion(struct bau_desc *bau_desc, /* * UV2 has an extra bit of status in the ACTIVATION_STATUS_2 register. */ -static unsigned long uv2_read_status(unsigned long offset, int rshft, int cpu) +static unsigned long uv2_read_status(unsigned long offset, int rshft, int desc) { unsigned long descriptor_status; unsigned long descriptor_status2; descriptor_status = ((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK); - descriptor_status2 = (read_mmr_uv2_status() >> cpu) & 0x1UL; + descriptor_status2 = (read_mmr_uv2_status() >> desc) & 0x1UL; descriptor_status = (descriptor_status << 1) | descriptor_status2; return descriptor_status; } +/* + * Return whether the status of the descriptor that is normally used for this + * cpu (the one indexed by its hub-relative cpu number) is busy. + * The status of the original 32 descriptors is always reflected in the 64 + * bits of UVH_LB_BAU_SB_ACTIVATION_STATUS_0. + * The bit provided by the activation_status_2 register is irrelevant to + * the status if it is only being tested for busy or not busy. + */ +int normal_busy(struct bau_control *bcp) +{ + int cpu = bcp->uvhub_cpu; + int mmr_offset; + int right_shift; + + mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0; + right_shift = cpu * UV_ACT_STATUS_SIZE; + return (((((read_lmmr(mmr_offset) >> right_shift) & + UV_ACT_STATUS_MASK)) << 1) == UV2H_DESC_BUSY); +} + +/* + * Entered when a bau descriptor has gone into a permanent busy wait because + * of a hardware bug. + * Workaround the bug. + */ +int handle_uv2_busy(struct bau_control *bcp) +{ + int busy_one = bcp->using_desc; + int normal = bcp->uvhub_cpu; + int selected = -1; + int i; + unsigned long descriptor_status; + unsigned long status; + int mmr_offset; + struct bau_desc *bau_desc_old; + struct bau_desc *bau_desc_new; + struct bau_control *hmaster = bcp->uvhub_master; + struct ptc_stats *stat = bcp->statp; + cycles_t ttm; + + stat->s_uv2_wars++; + spin_lock(&hmaster->uvhub_lock); + /* try for the original first */ + if (busy_one != normal) { + if (!normal_busy(bcp)) + selected = normal; + } + if (selected < 0) { + /* can't use the normal, select an alternate */ + mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1; + descriptor_status = read_lmmr(mmr_offset); + + /* scan available descriptors 32-63 */ + for (i = 0; i < UV_CPUS_PER_AS; i++) { + if ((hmaster->inuse_map & (1 << i)) == 0) { + status = ((descriptor_status >> + (i * UV_ACT_STATUS_SIZE)) & + UV_ACT_STATUS_MASK) << 1; + if (status != UV2H_DESC_BUSY) { + selected = i + UV_CPUS_PER_AS; + break; + } + } + } + } + + if (busy_one != normal) + /* mark the busy alternate as not in-use */ + hmaster->inuse_map &= ~(1 << (busy_one - UV_CPUS_PER_AS)); + + if (selected >= 0) { + /* switch to the selected descriptor */ + if (selected != normal) { + /* set the selected alternate as in-use */ + hmaster->inuse_map |= + (1 << (selected - UV_CPUS_PER_AS)); + if (selected > stat->s_uv2_wars_hw) + stat->s_uv2_wars_hw = selected; + } + bau_desc_old = bcp->descriptor_base; + bau_desc_old += (ITEMS_PER_DESC * busy_one); + bcp->using_desc = selected; + bau_desc_new = bcp->descriptor_base; + bau_desc_new += (ITEMS_PER_DESC * selected); + *bau_desc_new = *bau_desc_old; + } else { + /* + * All are busy. Wait for the normal one for this cpu to + * free up. + */ + stat->s_uv2_war_waits++; + spin_unlock(&hmaster->uvhub_lock); + ttm = get_cycles(); + do { + cpu_relax(); + } while (normal_busy(bcp)); + spin_lock(&hmaster->uvhub_lock); + /* switch to the original descriptor */ + bcp->using_desc = normal; + bau_desc_old = bcp->descriptor_base; + bau_desc_old += (ITEMS_PER_DESC * bcp->using_desc); + bcp->using_desc = (ITEMS_PER_DESC * normal); + bau_desc_new = bcp->descriptor_base; + bau_desc_new += (ITEMS_PER_DESC * normal); + *bau_desc_new = *bau_desc_old; /* copy the entire descriptor */ + } + spin_unlock(&hmaster->uvhub_lock); + return FLUSH_RETRY_BUSYBUG; +} + static int uv2_wait_completion(struct bau_desc *bau_desc, unsigned long mmr_offset, int right_shift, struct bau_control *bcp, long try) { unsigned long descriptor_stat; cycles_t ttm; - int cpu = bcp->uvhub_cpu; + int desc = bcp->using_desc; + long busy_reps = 0; struct ptc_stats *stat = bcp->statp; - descriptor_stat = uv2_read_status(mmr_offset, right_shift, cpu); + descriptor_stat = uv2_read_status(mmr_offset, right_shift, desc); /* spin on the status MMR, waiting for it to go idle */ while (descriptor_stat != UV2H_DESC_IDLE) { @@ -522,32 +635,35 @@ static int uv2_wait_completion(struct bau_desc *bau_desc, * our message and its state will stay IDLE. */ if ((descriptor_stat == UV2H_DESC_SOURCE_TIMEOUT) || - (descriptor_stat == UV2H_DESC_DEST_STRONG_NACK) || (descriptor_stat == UV2H_DESC_DEST_PUT_ERR)) { stat->s_stimeout++; return FLUSH_GIVEUP; + } else if (descriptor_stat == UV2H_DESC_DEST_STRONG_NACK) { + stat->s_strongnacks++; + bcp->conseccompletes = 0; + return FLUSH_GIVEUP; } else if (descriptor_stat == UV2H_DESC_DEST_TIMEOUT) { stat->s_dtimeout++; - ttm = get_cycles(); - /* - * Our retries may be blocked by all destination - * swack resources being consumed, and a timeout - * pending. In that case hardware returns the - * ERROR that looks like a destination timeout. - */ - if (cycles_2_us(ttm - bcp->send_message) < timeout_us) { - bcp->conseccompletes = 0; - return FLUSH_RETRY_PLUGGED; - } bcp->conseccompletes = 0; return FLUSH_RETRY_TIMEOUT; } else { + busy_reps++; + if (busy_reps > 1000000) { + /* not to hammer on the clock */ + busy_reps = 0; + ttm = get_cycles(); + if ((ttm - bcp->send_message) > + (bcp->clocks_per_100_usec)) { + return handle_uv2_busy(bcp); + } + } /* * descriptor_stat is still BUSY */ cpu_relax(); } - descriptor_stat = uv2_read_status(mmr_offset, right_shift, cpu); + descriptor_stat = uv2_read_status(mmr_offset, right_shift, + desc); } bcp->conseccompletes++; return FLUSH_COMPLETE; @@ -563,17 +679,17 @@ static int wait_completion(struct bau_desc *bau_desc, { int right_shift; unsigned long mmr_offset; - int cpu = bcp->uvhub_cpu; + int desc = bcp->using_desc; - if (cpu < UV_CPUS_PER_AS) { + if (desc < UV_CPUS_PER_AS) { mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0; - right_shift = cpu * UV_ACT_STATUS_SIZE; + right_shift = desc * UV_ACT_STATUS_SIZE; } else { mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1; - right_shift = ((cpu - UV_CPUS_PER_AS) * UV_ACT_STATUS_SIZE); + right_shift = ((desc - UV_CPUS_PER_AS) * UV_ACT_STATUS_SIZE); } - if (is_uv1_hub()) + if (bcp->uvhub_version == 1) return uv1_wait_completion(bau_desc, mmr_offset, right_shift, bcp, try); else @@ -752,19 +868,22 @@ static void handle_cmplt(int completion_status, struct bau_desc *bau_desc, * Returns 1 if it gives up entirely and the original cpu mask is to be * returned to the kernel. */ -int uv_flush_send_and_wait(struct bau_desc *bau_desc, - struct cpumask *flush_mask, struct bau_control *bcp) +int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp) { int seq_number = 0; int completion_stat = 0; + int uv1 = 0; long try = 0; unsigned long index; cycles_t time1; cycles_t time2; struct ptc_stats *stat = bcp->statp; struct bau_control *hmaster = bcp->uvhub_master; + struct uv1_bau_msg_header *uv1_hdr = NULL; + struct uv2_bau_msg_header *uv2_hdr = NULL; + struct bau_desc *bau_desc; - if (is_uv1_hub()) + if (bcp->uvhub_version == 1) uv1_throttle(hmaster, stat); while (hmaster->uvhub_quiesce) @@ -772,22 +891,39 @@ int uv_flush_send_and_wait(struct bau_desc *bau_desc, time1 = get_cycles(); do { - if (try == 0) { - bau_desc->header.msg_type = MSG_REGULAR; + bau_desc = bcp->descriptor_base; + bau_desc += (ITEMS_PER_DESC * bcp->using_desc); + if (bcp->uvhub_version == 1) { + uv1 = 1; + uv1_hdr = &bau_desc->header.uv1_hdr; + } else + uv2_hdr = &bau_desc->header.uv2_hdr; + if ((try == 0) || (completion_stat == FLUSH_RETRY_BUSYBUG)) { + if (uv1) + uv1_hdr->msg_type = MSG_REGULAR; + else + uv2_hdr->msg_type = MSG_REGULAR; seq_number = bcp->message_number++; } else { - bau_desc->header.msg_type = MSG_RETRY; + if (uv1) + uv1_hdr->msg_type = MSG_RETRY; + else + uv2_hdr->msg_type = MSG_RETRY; stat->s_retry_messages++; } - bau_desc->header.sequence = seq_number; - index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu; + if (uv1) + uv1_hdr->sequence = seq_number; + else + uv2_hdr->sequence = seq_number; + index = (1UL << AS_PUSH_SHIFT) | bcp->using_desc; bcp->send_message = get_cycles(); write_mmr_activation(index); try++; completion_stat = wait_completion(bau_desc, bcp, try); + /* UV2: wait_completion() may change the bcp->using_desc */ handle_cmplt(completion_stat, bau_desc, bcp, hmaster, stat); @@ -798,6 +934,7 @@ int uv_flush_send_and_wait(struct bau_desc *bau_desc, } cpu_relax(); } while ((completion_stat == FLUSH_RETRY_PLUGGED) || + (completion_stat == FLUSH_RETRY_BUSYBUG) || (completion_stat == FLUSH_RETRY_TIMEOUT)); time2 = get_cycles(); @@ -812,6 +949,7 @@ int uv_flush_send_and_wait(struct bau_desc *bau_desc, record_send_stats(time1, time2, bcp, stat, completion_stat, try); if (completion_stat == FLUSH_GIVEUP) + /* FLUSH_GIVEUP will fall back to using IPI's for tlb flush */ return 1; return 0; } @@ -967,7 +1105,7 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, stat->s_ntargself++; bau_desc = bcp->descriptor_base; - bau_desc += ITEMS_PER_DESC * bcp->uvhub_cpu; + bau_desc += (ITEMS_PER_DESC * bcp->using_desc); bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE); if (set_distrib_bits(flush_mask, bcp, bau_desc, &locals, &remotes)) return NULL; @@ -980,13 +1118,86 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, * uv_flush_send_and_wait returns 0 if all cpu's were messaged, * or 1 if it gave up and the original cpumask should be returned. */ - if (!uv_flush_send_and_wait(bau_desc, flush_mask, bcp)) + if (!uv_flush_send_and_wait(flush_mask, bcp)) return NULL; else return cpumask; } /* + * Search the message queue for any 'other' message with the same software + * acknowledge resource bit vector. + */ +struct bau_pq_entry *find_another_by_swack(struct bau_pq_entry *msg, + struct bau_control *bcp, unsigned char swack_vec) +{ + struct bau_pq_entry *msg_next = msg + 1; + + if (msg_next > bcp->queue_last) + msg_next = bcp->queue_first; + while ((msg_next->swack_vec != 0) && (msg_next != msg)) { + if (msg_next->swack_vec == swack_vec) + return msg_next; + msg_next++; + if (msg_next > bcp->queue_last) + msg_next = bcp->queue_first; + } + return NULL; +} + +/* + * UV2 needs to work around a bug in which an arriving message has not + * set a bit in the UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE register. + * Such a message must be ignored. + */ +void process_uv2_message(struct msg_desc *mdp, struct bau_control *bcp) +{ + unsigned long mmr_image; + unsigned char swack_vec; + struct bau_pq_entry *msg = mdp->msg; + struct bau_pq_entry *other_msg; + + mmr_image = read_mmr_sw_ack(); + swack_vec = msg->swack_vec; + + if ((swack_vec & mmr_image) == 0) { + /* + * This message was assigned a swack resource, but no + * reserved acknowlegment is pending. + * The bug has prevented this message from setting the MMR. + * And no other message has used the same sw_ack resource. + * Do the requested shootdown but do not reply to the msg. + * (the 0 means make no acknowledge) + */ + bau_process_message(mdp, bcp, 0); + return; + } + + /* + * Some message has set the MMR 'pending' bit; it might have been + * another message. Look for that message. + */ + other_msg = find_another_by_swack(msg, bcp, msg->swack_vec); + if (other_msg) { + /* There is another. Do not ack the current one. */ + bau_process_message(mdp, bcp, 0); + /* + * Let the natural processing of that message acknowledge + * it. Don't get the processing of sw_ack's out of order. + */ + return; + } + + /* + * There is no other message using this sw_ack, so it is safe to + * acknowledge it. + */ + bau_process_message(mdp, bcp, 1); + + return; +} + +/* * The BAU message interrupt comes here. (registered by set_intr_gate) * See entry_64.S * @@ -1009,6 +1220,7 @@ void uv_bau_message_interrupt(struct pt_regs *regs) struct ptc_stats *stat; struct msg_desc msgdesc; + ack_APIC_irq(); time_start = get_cycles(); bcp = &per_cpu(bau_control, smp_processor_id()); @@ -1022,9 +1234,11 @@ void uv_bau_message_interrupt(struct pt_regs *regs) count++; msgdesc.msg_slot = msg - msgdesc.queue_first; - msgdesc.swack_slot = ffs(msg->swack_vec) - 1; msgdesc.msg = msg; - bau_process_message(&msgdesc, bcp); + if (bcp->uvhub_version == 2) + process_uv2_message(&msgdesc, bcp); + else + bau_process_message(&msgdesc, bcp, 1); msg++; if (msg > msgdesc.queue_last) @@ -1036,8 +1250,6 @@ void uv_bau_message_interrupt(struct pt_regs *regs) stat->d_nomsg++; else if (count > 1) stat->d_multmsg++; - - ack_APIC_irq(); } /* @@ -1083,7 +1295,7 @@ static void __init enable_timeouts(void) */ mmr_image |= (1L << SOFTACK_MSHIFT); if (is_uv2_hub()) { - mmr_image |= (1L << UV2_LEG_SHFT); + mmr_image &= ~(1L << UV2_LEG_SHFT); mmr_image |= (1L << UV2_EXT_SHFT); } write_mmr_misc_control(pnode, mmr_image); @@ -1136,13 +1348,13 @@ static int ptc_seq_show(struct seq_file *file, void *data) seq_printf(file, "remotehub numuvhubs numuvhubs16 numuvhubs8 "); seq_printf(file, - "numuvhubs4 numuvhubs2 numuvhubs1 dto retries rok "); + "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries rok "); seq_printf(file, "resetp resett giveup sto bz throt swack recv rtime "); seq_printf(file, "all one mult none retry canc nocan reset rcan "); seq_printf(file, - "disable enable\n"); + "disable enable wars warshw warwaits\n"); } if (cpu < num_possible_cpus() && cpu_online(cpu)) { stat = &per_cpu(ptcstats, cpu); @@ -1154,10 +1366,10 @@ static int ptc_seq_show(struct seq_file *file, void *data) stat->s_ntargremotes, stat->s_ntargcpu, stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub, stat->s_ntarguvhub, stat->s_ntarguvhub16); - seq_printf(file, "%ld %ld %ld %ld %ld ", + seq_printf(file, "%ld %ld %ld %ld %ld %ld ", stat->s_ntarguvhub8, stat->s_ntarguvhub4, stat->s_ntarguvhub2, stat->s_ntarguvhub1, - stat->s_dtimeout); + stat->s_dtimeout, stat->s_strongnacks); seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld ", stat->s_retry_messages, stat->s_retriesok, stat->s_resets_plug, stat->s_resets_timeout, @@ -1173,8 +1385,10 @@ static int ptc_seq_show(struct seq_file *file, void *data) stat->d_nomsg, stat->d_retries, stat->d_canceled, stat->d_nocanceled, stat->d_resets, stat->d_rcanceled); - seq_printf(file, "%ld %ld\n", - stat->s_bau_disabled, stat->s_bau_reenabled); + seq_printf(file, "%ld %ld %ld %ld %ld\n", + stat->s_bau_disabled, stat->s_bau_reenabled, + stat->s_uv2_wars, stat->s_uv2_wars_hw, + stat->s_uv2_war_waits); } return 0; } @@ -1432,12 +1646,15 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode) { int i; int cpu; + int uv1 = 0; unsigned long gpa; unsigned long m; unsigned long n; size_t dsize; struct bau_desc *bau_desc; struct bau_desc *bd2; + struct uv1_bau_msg_header *uv1_hdr; + struct uv2_bau_msg_header *uv2_hdr; struct bau_control *bcp; /* @@ -1451,6 +1668,8 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode) gpa = uv_gpa(bau_desc); n = uv_gpa_to_gnode(gpa); m = uv_gpa_to_offset(gpa); + if (is_uv1_hub()) + uv1 = 1; /* the 14-bit pnode */ write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m)); @@ -1461,21 +1680,33 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode) */ for (i = 0, bd2 = bau_desc; i < (ADP_SZ * ITEMS_PER_DESC); i++, bd2++) { memset(bd2, 0, sizeof(struct bau_desc)); - bd2->header.swack_flag = 1; - /* - * The base_dest_nasid set in the message header is the nasid - * of the first uvhub in the partition. The bit map will - * indicate destination pnode numbers relative to that base. - * They may not be consecutive if nasid striding is being used. - */ - bd2->header.base_dest_nasid = UV_PNODE_TO_NASID(base_pnode); - bd2->header.dest_subnodeid = UV_LB_SUBNODEID; - bd2->header.command = UV_NET_ENDPOINT_INTD; - bd2->header.int_both = 1; - /* - * all others need to be set to zero: - * fairness chaining multilevel count replied_to - */ + if (uv1) { + uv1_hdr = &bd2->header.uv1_hdr; + uv1_hdr->swack_flag = 1; + /* + * The base_dest_nasid set in the message header + * is the nasid of the first uvhub in the partition. + * The bit map will indicate destination pnode numbers + * relative to that base. They may not be consecutive + * if nasid striding is being used. + */ + uv1_hdr->base_dest_nasid = + UV_PNODE_TO_NASID(base_pnode); + uv1_hdr->dest_subnodeid = UV_LB_SUBNODEID; + uv1_hdr->command = UV_NET_ENDPOINT_INTD; + uv1_hdr->int_both = 1; + /* + * all others need to be set to zero: + * fairness chaining multilevel count replied_to + */ + } else { + uv2_hdr = &bd2->header.uv2_hdr; + uv2_hdr->swack_flag = 1; + uv2_hdr->base_dest_nasid = + UV_PNODE_TO_NASID(base_pnode); + uv2_hdr->dest_subnodeid = UV_LB_SUBNODEID; + uv2_hdr->command = UV_NET_ENDPOINT_INTD; + } } for_each_present_cpu(cpu) { if (pnode != uv_blade_to_pnode(uv_cpu_to_blade_id(cpu))) @@ -1531,6 +1762,7 @@ static void pq_init(int node, int pnode) write_mmr_payload_first(pnode, pn_first); write_mmr_payload_tail(pnode, first); write_mmr_payload_last(pnode, last); + write_gmmr_sw_ack(pnode, 0xffffUL); /* in effect, all msg_type's are set to MSG_NOOP */ memset(pqp, 0, sizeof(struct bau_pq_entry) * DEST_Q_SIZE); @@ -1584,14 +1816,14 @@ static int calculate_destination_timeout(void) ts_ns = base * mult1 * mult2; ret = ts_ns / 1000; } else { - /* 4 bits 0/1 for 10/80us, 3 bits of multiplier */ - mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL); + /* 4 bits 0/1 for 10/80us base, 3 bits of multiplier */ + mmr_image = uv_read_local_mmr(UVH_LB_BAU_MISC_CONTROL); mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT; if (mmr_image & (1L << UV2_ACK_UNITS_SHFT)) - mult1 = 80; + base = 80; else - mult1 = 10; - base = mmr_image & UV2_ACK_MASK; + base = 10; + mult1 = mmr_image & UV2_ACK_MASK; ret = mult1 * base; } return ret; @@ -1618,6 +1850,7 @@ static void __init init_per_cpu_tunables(void) bcp->cong_response_us = congested_respns_us; bcp->cong_reps = congested_reps; bcp->cong_period = congested_period; + bcp->clocks_per_100_usec = usec_2_cycles(100); } } @@ -1728,8 +1961,17 @@ static int scan_sock(struct socket_desc *sdp, struct uvhub_desc *bdp, bcp->cpus_in_socket = sdp->num_cpus; bcp->socket_master = *smasterp; bcp->uvhub = bdp->uvhub; + if (is_uv1_hub()) + bcp->uvhub_version = 1; + else if (is_uv2_hub()) + bcp->uvhub_version = 2; + else { + printk(KERN_EMERG "uvhub version not 1 or 2\n"); + return 1; + } bcp->uvhub_master = *hmasterp; bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->blade_processor_id; + bcp->using_desc = bcp->uvhub_cpu; if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) { printk(KERN_EMERG "%d cpus per uvhub invalid\n", bcp->uvhub_cpu); @@ -1845,6 +2087,8 @@ static int __init uv_bau_init(void) uv_base_pnode = uv_blade_to_pnode(uvhub); } + enable_timeouts(); + if (init_per_cpu(nuvhubs, uv_base_pnode)) { nobau = 1; return 0; @@ -1855,7 +2099,6 @@ static int __init uv_bau_init(void) if (uv_blade_nr_possible_cpus(uvhub)) init_uvhub(uvhub, vector, uv_base_pnode); - enable_timeouts(); alloc_intr_gate(vector, uv_bau_message_intr1); for_each_possible_blade(uvhub) { @@ -1867,7 +2110,8 @@ static int __init uv_bau_init(void) val = 1L << 63; write_gmmr_activation(pnode, val); mmr = 1; /* should be 1 to broadcast to both sockets */ - write_mmr_data_broadcast(pnode, mmr); + if (!is_uv1_hub()) + write_mmr_data_broadcast(pnode, mmr); } } diff --git a/arch/x86/syscalls/Makefile b/arch/x86/syscalls/Makefile new file mode 100644 index 000000000000..564b2476fede --- /dev/null +++ b/arch/x86/syscalls/Makefile @@ -0,0 +1,43 @@ +out := $(obj)/../include/generated/asm + +# Create output directory if not already present +_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') + +syscall32 := $(srctree)/$(src)/syscall_32.tbl +syscall64 := $(srctree)/$(src)/syscall_64.tbl + +syshdr := $(srctree)/$(src)/syscallhdr.sh +systbl := $(srctree)/$(src)/syscalltbl.sh + +quiet_cmd_syshdr = SYSHDR $@ + cmd_syshdr = $(CONFIG_SHELL) '$(syshdr)' $< $@ \ + $(syshdr_abi_$(basetarget)) $(syshdr_pfx_$(basetarget)) +quiet_cmd_systbl = SYSTBL $@ + cmd_systbl = $(CONFIG_SHELL) '$(systbl)' $< $@ + +syshdr_abi_unistd_32 := i386 +$(out)/unistd_32.h: $(syscall32) $(syshdr) + $(call if_changed,syshdr) + +syshdr_abi_unistd_32_ia32 := i386 +syshdr_pfx_unistd_32_ia32 := ia32_ +$(out)/unistd_32_ia32.h: $(syscall32) $(syshdr) + $(call if_changed,syshdr) + +syshdr_abi_unistd_64 := 64 +$(out)/unistd_64.h: $(syscall64) $(syshdr) + $(call if_changed,syshdr) + +$(out)/syscalls_32.h: $(syscall32) $(systbl) + $(call if_changed,systbl) +$(out)/syscalls_64.h: $(syscall64) $(systbl) + $(call if_changed,systbl) + +syshdr-y += unistd_32.h unistd_64.h +syshdr-y += syscalls_32.h +syshdr-$(CONFIG_X86_64) += unistd_32_ia32.h +syshdr-$(CONFIG_X86_64) += syscalls_64.h + +targets += $(syshdr-y) + +all: $(addprefix $(out)/,$(targets)) diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl new file mode 100644 index 000000000000..ce98e287c066 --- /dev/null +++ b/arch/x86/syscalls/syscall_32.tbl @@ -0,0 +1,357 @@ +# +# 32-bit system call numbers and entry vectors +# +# The format is: +# <number> <abi> <name> <entry point> <compat entry point> +# +# The abi is always "i386" for this file. +# +0 i386 restart_syscall sys_restart_syscall +1 i386 exit sys_exit +2 i386 fork ptregs_fork stub32_fork +3 i386 read sys_read +4 i386 write sys_write +5 i386 open sys_open compat_sys_open +6 i386 close sys_close +7 i386 waitpid sys_waitpid sys32_waitpid +8 i386 creat sys_creat +9 i386 link sys_link +10 i386 unlink sys_unlink +11 i386 execve ptregs_execve stub32_execve +12 i386 chdir sys_chdir +13 i386 time sys_time compat_sys_time +14 i386 mknod sys_mknod +15 i386 chmod sys_chmod +16 i386 lchown sys_lchown16 +17 i386 break +18 i386 oldstat sys_stat +19 i386 lseek sys_lseek sys32_lseek +20 i386 getpid sys_getpid +21 i386 mount sys_mount compat_sys_mount +22 i386 umount sys_oldumount +23 i386 setuid sys_setuid16 +24 i386 getuid sys_getuid16 +25 i386 stime sys_stime compat_sys_stime +26 i386 ptrace sys_ptrace compat_sys_ptrace +27 i386 alarm sys_alarm +28 i386 oldfstat sys_fstat +29 i386 pause sys_pause +30 i386 utime sys_utime compat_sys_utime +31 i386 stty +32 i386 gtty +33 i386 access sys_access +34 i386 nice sys_nice +35 i386 ftime +36 i386 sync sys_sync +37 i386 kill sys_kill sys32_kill +38 i386 rename sys_rename +39 i386 mkdir sys_mkdir +40 i386 rmdir sys_rmdir +41 i386 dup sys_dup +42 i386 pipe sys_pipe +43 i386 times sys_times compat_sys_times +44 i386 prof +45 i386 brk sys_brk +46 i386 setgid sys_setgid16 +47 i386 getgid sys_getgid16 +48 i386 signal sys_signal +49 i386 geteuid sys_geteuid16 +50 i386 getegid sys_getegid16 +51 i386 acct sys_acct +52 i386 umount2 sys_umount +53 i386 lock +54 i386 ioctl sys_ioctl compat_sys_ioctl +55 i386 fcntl sys_fcntl compat_sys_fcntl64 +56 i386 mpx +57 i386 setpgid sys_setpgid +58 i386 ulimit +59 i386 oldolduname sys_olduname +60 i386 umask sys_umask +61 i386 chroot sys_chroot +62 i386 ustat sys_ustat compat_sys_ustat +63 i386 dup2 sys_dup2 +64 i386 getppid sys_getppid +65 i386 getpgrp sys_getpgrp +66 i386 setsid sys_setsid +67 i386 sigaction sys_sigaction sys32_sigaction +68 i386 sgetmask sys_sgetmask +69 i386 ssetmask sys_ssetmask +70 i386 setreuid sys_setreuid16 +71 i386 setregid sys_setregid16 +72 i386 sigsuspend sys_sigsuspend sys32_sigsuspend +73 i386 sigpending sys_sigpending compat_sys_sigpending +74 i386 sethostname sys_sethostname +75 i386 setrlimit sys_setrlimit compat_sys_setrlimit +76 i386 getrlimit sys_old_getrlimit compat_sys_old_getrlimit +77 i386 getrusage sys_getrusage compat_sys_getrusage +78 i386 gettimeofday sys_gettimeofday compat_sys_gettimeofday +79 i386 settimeofday sys_settimeofday compat_sys_settimeofday +80 i386 getgroups sys_getgroups16 +81 i386 setgroups sys_setgroups16 +82 i386 select sys_old_select compat_sys_old_select +83 i386 symlink sys_symlink +84 i386 oldlstat sys_lstat +85 i386 readlink sys_readlink +86 i386 uselib sys_uselib +87 i386 swapon sys_swapon +88 i386 reboot sys_reboot +89 i386 readdir sys_old_readdir compat_sys_old_readdir +90 i386 mmap sys_old_mmap sys32_mmap +91 i386 munmap sys_munmap +92 i386 truncate sys_truncate +93 i386 ftruncate sys_ftruncate +94 i386 fchmod sys_fchmod +95 i386 fchown sys_fchown16 +96 i386 getpriority sys_getpriority +97 i386 setpriority sys_setpriority +98 i386 profil +99 i386 statfs sys_statfs compat_sys_statfs +100 i386 fstatfs sys_fstatfs compat_sys_fstatfs +101 i386 ioperm sys_ioperm +102 i386 socketcall sys_socketcall compat_sys_socketcall +103 i386 syslog sys_syslog +104 i386 setitimer sys_setitimer compat_sys_setitimer +105 i386 getitimer sys_getitimer compat_sys_getitimer +106 i386 stat sys_newstat compat_sys_newstat +107 i386 lstat sys_newlstat compat_sys_newlstat +108 i386 fstat sys_newfstat compat_sys_newfstat +109 i386 olduname sys_uname +110 i386 iopl ptregs_iopl stub32_iopl +111 i386 vhangup sys_vhangup +112 i386 idle +113 i386 vm86old ptregs_vm86old sys32_vm86_warning +114 i386 wait4 sys_wait4 compat_sys_wait4 +115 i386 swapoff sys_swapoff +116 i386 sysinfo sys_sysinfo compat_sys_sysinfo +117 i386 ipc sys_ipc sys32_ipc +118 i386 fsync sys_fsync +119 i386 sigreturn ptregs_sigreturn stub32_sigreturn +120 i386 clone ptregs_clone stub32_clone +121 i386 setdomainname sys_setdomainname +122 i386 uname sys_newuname +123 i386 modify_ldt sys_modify_ldt +124 i386 adjtimex sys_adjtimex compat_sys_adjtimex +125 i386 mprotect sys_mprotect sys32_mprotect +126 i386 sigprocmask sys_sigprocmask compat_sys_sigprocmask +127 i386 create_module +128 i386 init_module sys_init_module +129 i386 delete_module sys_delete_module +130 i386 get_kernel_syms +131 i386 quotactl sys_quotactl sys32_quotactl +132 i386 getpgid sys_getpgid +133 i386 fchdir sys_fchdir +134 i386 bdflush sys_bdflush +135 i386 sysfs sys_sysfs +136 i386 personality sys_personality +137 i386 afs_syscall +138 i386 setfsuid sys_setfsuid16 +139 i386 setfsgid sys_setfsgid16 +140 i386 _llseek sys_llseek +141 i386 getdents sys_getdents compat_sys_getdents +142 i386 _newselect sys_select compat_sys_select +143 i386 flock sys_flock +144 i386 msync sys_msync +145 i386 readv sys_readv compat_sys_readv +146 i386 writev sys_writev compat_sys_writev +147 i386 getsid sys_getsid +148 i386 fdatasync sys_fdatasync +149 i386 _sysctl sys_sysctl compat_sys_sysctl +150 i386 mlock sys_mlock +151 i386 munlock sys_munlock +152 i386 mlockall sys_mlockall +153 i386 munlockall sys_munlockall +154 i386 sched_setparam sys_sched_setparam +155 i386 sched_getparam sys_sched_getparam +156 i386 sched_setscheduler sys_sched_setscheduler +157 i386 sched_getscheduler sys_sched_getscheduler +158 i386 sched_yield sys_sched_yield +159 i386 sched_get_priority_max sys_sched_get_priority_max +160 i386 sched_get_priority_min sys_sched_get_priority_min +161 i386 sched_rr_get_interval sys_sched_rr_get_interval sys32_sched_rr_get_interval +162 i386 nanosleep sys_nanosleep compat_sys_nanosleep +163 i386 mremap sys_mremap +164 i386 setresuid sys_setresuid16 +165 i386 getresuid sys_getresuid16 +166 i386 vm86 ptregs_vm86 sys32_vm86_warning +167 i386 query_module +168 i386 poll sys_poll +169 i386 nfsservctl +170 i386 setresgid sys_setresgid16 +171 i386 getresgid sys_getresgid16 +172 i386 prctl sys_prctl +173 i386 rt_sigreturn ptregs_rt_sigreturn stub32_rt_sigreturn +174 i386 rt_sigaction sys_rt_sigaction sys32_rt_sigaction +175 i386 rt_sigprocmask sys_rt_sigprocmask sys32_rt_sigprocmask +176 i386 rt_sigpending sys_rt_sigpending sys32_rt_sigpending +177 i386 rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait +178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo sys32_rt_sigqueueinfo +179 i386 rt_sigsuspend sys_rt_sigsuspend +180 i386 pread64 sys_pread64 sys32_pread +181 i386 pwrite64 sys_pwrite64 sys32_pwrite +182 i386 chown sys_chown16 +183 i386 getcwd sys_getcwd +184 i386 capget sys_capget +185 i386 capset sys_capset +186 i386 sigaltstack ptregs_sigaltstack stub32_sigaltstack +187 i386 sendfile sys_sendfile sys32_sendfile +188 i386 getpmsg +189 i386 putpmsg +190 i386 vfork ptregs_vfork stub32_vfork +191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit +192 i386 mmap2 sys_mmap_pgoff +193 i386 truncate64 sys_truncate64 sys32_truncate64 +194 i386 ftruncate64 sys_ftruncate64 sys32_ftruncate64 +195 i386 stat64 sys_stat64 sys32_stat64 +196 i386 lstat64 sys_lstat64 sys32_lstat64 +197 i386 fstat64 sys_fstat64 sys32_fstat64 +198 i386 lchown32 sys_lchown +199 i386 getuid32 sys_getuid +200 i386 getgid32 sys_getgid +201 i386 geteuid32 sys_geteuid +202 i386 getegid32 sys_getegid +203 i386 setreuid32 sys_setreuid +204 i386 setregid32 sys_setregid +205 i386 getgroups32 sys_getgroups +206 i386 setgroups32 sys_setgroups +207 i386 fchown32 sys_fchown +208 i386 setresuid32 sys_setresuid +209 i386 getresuid32 sys_getresuid +210 i386 setresgid32 sys_setresgid +211 i386 getresgid32 sys_getresgid +212 i386 chown32 sys_chown +213 i386 setuid32 sys_setuid +214 i386 setgid32 sys_setgid +215 i386 setfsuid32 sys_setfsuid +216 i386 setfsgid32 sys_setfsgid +217 i386 pivot_root sys_pivot_root +218 i386 mincore sys_mincore +219 i386 madvise sys_madvise +220 i386 getdents64 sys_getdents64 compat_sys_getdents64 +221 i386 fcntl64 sys_fcntl64 compat_sys_fcntl64 +# 222 is unused +# 223 is unused +224 i386 gettid sys_gettid +225 i386 readahead sys_readahead sys32_readahead +226 i386 setxattr sys_setxattr +227 i386 lsetxattr sys_lsetxattr +228 i386 fsetxattr sys_fsetxattr +229 i386 getxattr sys_getxattr +230 i386 lgetxattr sys_lgetxattr +231 i386 fgetxattr sys_fgetxattr +232 i386 listxattr sys_listxattr +233 i386 llistxattr sys_llistxattr +234 i386 flistxattr sys_flistxattr +235 i386 removexattr sys_removexattr +236 i386 lremovexattr sys_lremovexattr +237 i386 fremovexattr sys_fremovexattr +238 i386 tkill sys_tkill +239 i386 sendfile64 sys_sendfile64 +240 i386 futex sys_futex compat_sys_futex +241 i386 sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity +242 i386 sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity +243 i386 set_thread_area sys_set_thread_area +244 i386 get_thread_area sys_get_thread_area +245 i386 io_setup sys_io_setup compat_sys_io_setup +246 i386 io_destroy sys_io_destroy +247 i386 io_getevents sys_io_getevents compat_sys_io_getevents +248 i386 io_submit sys_io_submit compat_sys_io_submit +249 i386 io_cancel sys_io_cancel +250 i386 fadvise64 sys_fadvise64 sys32_fadvise64 +# 251 is available for reuse (was briefly sys_set_zone_reclaim) +252 i386 exit_group sys_exit_group +253 i386 lookup_dcookie sys_lookup_dcookie sys32_lookup_dcookie +254 i386 epoll_create sys_epoll_create +255 i386 epoll_ctl sys_epoll_ctl +256 i386 epoll_wait sys_epoll_wait +257 i386 remap_file_pages sys_remap_file_pages +258 i386 set_tid_address sys_set_tid_address +259 i386 timer_create sys_timer_create compat_sys_timer_create +260 i386 timer_settime sys_timer_settime compat_sys_timer_settime +261 i386 timer_gettime sys_timer_gettime compat_sys_timer_gettime +262 i386 timer_getoverrun sys_timer_getoverrun +263 i386 timer_delete sys_timer_delete +264 i386 clock_settime sys_clock_settime compat_sys_clock_settime +265 i386 clock_gettime sys_clock_gettime compat_sys_clock_gettime +266 i386 clock_getres sys_clock_getres compat_sys_clock_getres +267 i386 clock_nanosleep sys_clock_nanosleep compat_sys_clock_nanosleep +268 i386 statfs64 sys_statfs64 compat_sys_statfs64 +269 i386 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 +270 i386 tgkill sys_tgkill +271 i386 utimes sys_utimes compat_sys_utimes +272 i386 fadvise64_64 sys_fadvise64_64 sys32_fadvise64_64 +273 i386 vserver +274 i386 mbind sys_mbind +275 i386 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy +276 i386 set_mempolicy sys_set_mempolicy +277 i386 mq_open sys_mq_open compat_sys_mq_open +278 i386 mq_unlink sys_mq_unlink +279 i386 mq_timedsend sys_mq_timedsend compat_sys_mq_timedsend +280 i386 mq_timedreceive sys_mq_timedreceive compat_sys_mq_timedreceive +281 i386 mq_notify sys_mq_notify compat_sys_mq_notify +282 i386 mq_getsetaddr sys_mq_getsetattr compat_sys_mq_getsetattr +283 i386 kexec_load sys_kexec_load compat_sys_kexec_load +284 i386 waitid sys_waitid compat_sys_waitid +# 285 sys_setaltroot +286 i386 add_key sys_add_key +287 i386 request_key sys_request_key +288 i386 keyctl sys_keyctl +289 i386 ioprio_set sys_ioprio_set +290 i386 ioprio_get sys_ioprio_get +291 i386 inotify_init sys_inotify_init +292 i386 inotify_add_watch sys_inotify_add_watch +293 i386 inotify_rm_watch sys_inotify_rm_watch +294 i386 migrate_pages sys_migrate_pages +295 i386 openat sys_openat compat_sys_openat +296 i386 mkdirat sys_mkdirat +297 i386 mknodat sys_mknodat +298 i386 fchownat sys_fchownat +299 i386 futimesat sys_futimesat compat_sys_futimesat +300 i386 fstatat64 sys_fstatat64 sys32_fstatat +301 i386 unlinkat sys_unlinkat +302 i386 renameat sys_renameat +303 i386 linkat sys_linkat +304 i386 symlinkat sys_symlinkat +305 i386 readlinkat sys_readlinkat +306 i386 fchmodat sys_fchmodat +307 i386 faccessat sys_faccessat +308 i386 pselect6 sys_pselect6 compat_sys_pselect6 +309 i386 ppoll sys_ppoll compat_sys_ppoll +310 i386 unshare sys_unshare +311 i386 set_robust_list sys_set_robust_list compat_sys_set_robust_list +312 i386 get_robust_list sys_get_robust_list compat_sys_get_robust_list +313 i386 splice sys_splice +314 i386 sync_file_range sys_sync_file_range sys32_sync_file_range +315 i386 tee sys_tee +316 i386 vmsplice sys_vmsplice compat_sys_vmsplice +317 i386 move_pages sys_move_pages compat_sys_move_pages +318 i386 getcpu sys_getcpu +319 i386 epoll_pwait sys_epoll_pwait +320 i386 utimensat sys_utimensat compat_sys_utimensat +321 i386 signalfd sys_signalfd compat_sys_signalfd +322 i386 timerfd_create sys_timerfd_create +323 i386 eventfd sys_eventfd +324 i386 fallocate sys_fallocate sys32_fallocate +325 i386 timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime +326 i386 timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime +327 i386 signalfd4 sys_signalfd4 compat_sys_signalfd4 +328 i386 eventfd2 sys_eventfd2 +329 i386 epoll_create1 sys_epoll_create1 +330 i386 dup3 sys_dup3 +331 i386 pipe2 sys_pipe2 +332 i386 inotify_init1 sys_inotify_init1 +333 i386 preadv sys_preadv compat_sys_preadv +334 i386 pwritev sys_pwritev compat_sys_pwritev +335 i386 rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo +336 i386 perf_event_open sys_perf_event_open +337 i386 recvmmsg sys_recvmmsg compat_sys_recvmmsg +338 i386 fanotify_init sys_fanotify_init +339 i386 fanotify_mark sys_fanotify_mark sys32_fanotify_mark +340 i386 prlimit64 sys_prlimit64 +341 i386 name_to_handle_at sys_name_to_handle_at +342 i386 open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at +343 i386 clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime +344 i386 syncfs sys_syncfs +345 i386 sendmmsg sys_sendmmsg compat_sys_sendmmsg +346 i386 setns sys_setns +347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv +348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl new file mode 100644 index 000000000000..b440a8f7eefa --- /dev/null +++ b/arch/x86/syscalls/syscall_64.tbl @@ -0,0 +1,320 @@ +# +# 64-bit system call numbers and entry vectors +# +# The format is: +# <number> <abi> <name> <entry point> +# +# The abi is always "64" for this file (for now.) +# +0 64 read sys_read +1 64 write sys_write +2 64 open sys_open +3 64 close sys_close +4 64 stat sys_newstat +5 64 fstat sys_newfstat +6 64 lstat sys_newlstat +7 64 poll sys_poll +8 64 lseek sys_lseek +9 64 mmap sys_mmap +10 64 mprotect sys_mprotect +11 64 munmap sys_munmap +12 64 brk sys_brk +13 64 rt_sigaction sys_rt_sigaction +14 64 rt_sigprocmask sys_rt_sigprocmask +15 64 rt_sigreturn stub_rt_sigreturn +16 64 ioctl sys_ioctl +17 64 pread64 sys_pread64 +18 64 pwrite64 sys_pwrite64 +19 64 readv sys_readv +20 64 writev sys_writev +21 64 access sys_access +22 64 pipe sys_pipe +23 64 select sys_select +24 64 sched_yield sys_sched_yield +25 64 mremap sys_mremap +26 64 msync sys_msync +27 64 mincore sys_mincore +28 64 madvise sys_madvise +29 64 shmget sys_shmget +30 64 shmat sys_shmat +31 64 shmctl sys_shmctl +32 64 dup sys_dup +33 64 dup2 sys_dup2 +34 64 pause sys_pause +35 64 nanosleep sys_nanosleep +36 64 getitimer sys_getitimer +37 64 alarm sys_alarm +38 64 setitimer sys_setitimer +39 64 getpid sys_getpid +40 64 sendfile sys_sendfile64 +41 64 socket sys_socket +42 64 connect sys_connect +43 64 accept sys_accept +44 64 sendto sys_sendto +45 64 recvfrom sys_recvfrom +46 64 sendmsg sys_sendmsg +47 64 recvmsg sys_recvmsg +48 64 shutdown sys_shutdown +49 64 bind sys_bind +50 64 listen sys_listen +51 64 getsockname sys_getsockname +52 64 getpeername sys_getpeername +53 64 socketpair sys_socketpair +54 64 setsockopt sys_setsockopt +55 64 getsockopt sys_getsockopt +56 64 clone stub_clone +57 64 fork stub_fork +58 64 vfork stub_vfork +59 64 execve stub_execve +60 64 exit sys_exit +61 64 wait4 sys_wait4 +62 64 kill sys_kill +63 64 uname sys_newuname +64 64 semget sys_semget +65 64 semop sys_semop +66 64 semctl sys_semctl +67 64 shmdt sys_shmdt +68 64 msgget sys_msgget +69 64 msgsnd sys_msgsnd +70 64 msgrcv sys_msgrcv +71 64 msgctl sys_msgctl +72 64 fcntl sys_fcntl +73 64 flock sys_flock +74 64 fsync sys_fsync +75 64 fdatasync sys_fdatasync +76 64 truncate sys_truncate +77 64 ftruncate sys_ftruncate +78 64 getdents sys_getdents +79 64 getcwd sys_getcwd +80 64 chdir sys_chdir +81 64 fchdir sys_fchdir +82 64 rename sys_rename +83 64 mkdir sys_mkdir +84 64 rmdir sys_rmdir +85 64 creat sys_creat +86 64 link sys_link +87 64 unlink sys_unlink +88 64 symlink sys_symlink +89 64 readlink sys_readlink +90 64 chmod sys_chmod +91 64 fchmod sys_fchmod +92 64 chown sys_chown +93 64 fchown sys_fchown +94 64 lchown sys_lchown +95 64 umask sys_umask +96 64 gettimeofday sys_gettimeofday +97 64 getrlimit sys_getrlimit +98 64 getrusage sys_getrusage +99 64 sysinfo sys_sysinfo +100 64 times sys_times +101 64 ptrace sys_ptrace +102 64 getuid sys_getuid +103 64 syslog sys_syslog +104 64 getgid sys_getgid +105 64 setuid sys_setuid +106 64 setgid sys_setgid +107 64 geteuid sys_geteuid +108 64 getegid sys_getegid +109 64 setpgid sys_setpgid +110 64 getppid sys_getppid +111 64 getpgrp sys_getpgrp +112 64 setsid sys_setsid +113 64 setreuid sys_setreuid +114 64 setregid sys_setregid +115 64 getgroups sys_getgroups +116 64 setgroups sys_setgroups +117 64 setresuid sys_setresuid +118 64 getresuid sys_getresuid +119 64 setresgid sys_setresgid +120 64 getresgid sys_getresgid +121 64 getpgid sys_getpgid +122 64 setfsuid sys_setfsuid +123 64 setfsgid sys_setfsgid +124 64 getsid sys_getsid +125 64 capget sys_capget +126 64 capset sys_capset +127 64 rt_sigpending sys_rt_sigpending +128 64 rt_sigtimedwait sys_rt_sigtimedwait +129 64 rt_sigqueueinfo sys_rt_sigqueueinfo +130 64 rt_sigsuspend sys_rt_sigsuspend +131 64 sigaltstack stub_sigaltstack +132 64 utime sys_utime +133 64 mknod sys_mknod +134 64 uselib +135 64 personality sys_personality +136 64 ustat sys_ustat +137 64 statfs sys_statfs +138 64 fstatfs sys_fstatfs +139 64 sysfs sys_sysfs +140 64 getpriority sys_getpriority +141 64 setpriority sys_setpriority +142 64 sched_setparam sys_sched_setparam +143 64 sched_getparam sys_sched_getparam +144 64 sched_setscheduler sys_sched_setscheduler +145 64 sched_getscheduler sys_sched_getscheduler +146 64 sched_get_priority_max sys_sched_get_priority_max +147 64 sched_get_priority_min sys_sched_get_priority_min +148 64 sched_rr_get_interval sys_sched_rr_get_interval +149 64 mlock sys_mlock +150 64 munlock sys_munlock +151 64 mlockall sys_mlockall +152 64 munlockall sys_munlockall +153 64 vhangup sys_vhangup +154 64 modify_ldt sys_modify_ldt +155 64 pivot_root sys_pivot_root +156 64 _sysctl sys_sysctl +157 64 prctl sys_prctl +158 64 arch_prctl sys_arch_prctl +159 64 adjtimex sys_adjtimex +160 64 setrlimit sys_setrlimit +161 64 chroot sys_chroot +162 64 sync sys_sync +163 64 acct sys_acct +164 64 settimeofday sys_settimeofday +165 64 mount sys_mount +166 64 umount2 sys_umount +167 64 swapon sys_swapon +168 64 swapoff sys_swapoff +169 64 reboot sys_reboot +170 64 sethostname sys_sethostname +171 64 setdomainname sys_setdomainname +172 64 iopl stub_iopl +173 64 ioperm sys_ioperm +174 64 create_module +175 64 init_module sys_init_module +176 64 delete_module sys_delete_module +177 64 get_kernel_syms +178 64 query_module +179 64 quotactl sys_quotactl +180 64 nfsservctl +181 64 getpmsg +182 64 putpmsg +183 64 afs_syscall +184 64 tuxcall +185 64 security +186 64 gettid sys_gettid +187 64 readahead sys_readahead +188 64 setxattr sys_setxattr +189 64 lsetxattr sys_lsetxattr +190 64 fsetxattr sys_fsetxattr +191 64 getxattr sys_getxattr +192 64 lgetxattr sys_lgetxattr +193 64 fgetxattr sys_fgetxattr +194 64 listxattr sys_listxattr +195 64 llistxattr sys_llistxattr +196 64 flistxattr sys_flistxattr +197 64 removexattr sys_removexattr +198 64 lremovexattr sys_lremovexattr +199 64 fremovexattr sys_fremovexattr +200 64 tkill sys_tkill +201 64 time sys_time +202 64 futex sys_futex +203 64 sched_setaffinity sys_sched_setaffinity +204 64 sched_getaffinity sys_sched_getaffinity +205 64 set_thread_area +206 64 io_setup sys_io_setup +207 64 io_destroy sys_io_destroy +208 64 io_getevents sys_io_getevents +209 64 io_submit sys_io_submit +210 64 io_cancel sys_io_cancel +211 64 get_thread_area +212 64 lookup_dcookie sys_lookup_dcookie +213 64 epoll_create sys_epoll_create +214 64 epoll_ctl_old +215 64 epoll_wait_old +216 64 remap_file_pages sys_remap_file_pages +217 64 getdents64 sys_getdents64 +218 64 set_tid_address sys_set_tid_address +219 64 restart_syscall sys_restart_syscall +220 64 semtimedop sys_semtimedop +221 64 fadvise64 sys_fadvise64 +222 64 timer_create sys_timer_create +223 64 timer_settime sys_timer_settime +224 64 timer_gettime sys_timer_gettime +225 64 timer_getoverrun sys_timer_getoverrun +226 64 timer_delete sys_timer_delete +227 64 clock_settime sys_clock_settime +228 64 clock_gettime sys_clock_gettime +229 64 clock_getres sys_clock_getres +230 64 clock_nanosleep sys_clock_nanosleep +231 64 exit_group sys_exit_group +232 64 epoll_wait sys_epoll_wait +233 64 epoll_ctl sys_epoll_ctl +234 64 tgkill sys_tgkill +235 64 utimes sys_utimes +236 64 vserver +237 64 mbind sys_mbind +238 64 set_mempolicy sys_set_mempolicy +239 64 get_mempolicy sys_get_mempolicy +240 64 mq_open sys_mq_open +241 64 mq_unlink sys_mq_unlink +242 64 mq_timedsend sys_mq_timedsend +243 64 mq_timedreceive sys_mq_timedreceive +244 64 mq_notify sys_mq_notify +245 64 mq_getsetattr sys_mq_getsetattr +246 64 kexec_load sys_kexec_load +247 64 waitid sys_waitid +248 64 add_key sys_add_key +249 64 request_key sys_request_key +250 64 keyctl sys_keyctl +251 64 ioprio_set sys_ioprio_set +252 64 ioprio_get sys_ioprio_get +253 64 inotify_init sys_inotify_init +254 64 inotify_add_watch sys_inotify_add_watch +255 64 inotify_rm_watch sys_inotify_rm_watch +256 64 migrate_pages sys_migrate_pages +257 64 openat sys_openat +258 64 mkdirat sys_mkdirat +259 64 mknodat sys_mknodat +260 64 fchownat sys_fchownat +261 64 futimesat sys_futimesat +262 64 newfstatat sys_newfstatat +263 64 unlinkat sys_unlinkat +264 64 renameat sys_renameat +265 64 linkat sys_linkat +266 64 symlinkat sys_symlinkat +267 64 readlinkat sys_readlinkat +268 64 fchmodat sys_fchmodat +269 64 faccessat sys_faccessat +270 64 pselect6 sys_pselect6 +271 64 ppoll sys_ppoll +272 64 unshare sys_unshare +273 64 set_robust_list sys_set_robust_list +274 64 get_robust_list sys_get_robust_list +275 64 splice sys_splice +276 64 tee sys_tee +277 64 sync_file_range sys_sync_file_range +278 64 vmsplice sys_vmsplice +279 64 move_pages sys_move_pages +280 64 utimensat sys_utimensat +281 64 epoll_pwait sys_epoll_pwait +282 64 signalfd sys_signalfd +283 64 timerfd_create sys_timerfd_create +284 64 eventfd sys_eventfd +285 64 fallocate sys_fallocate +286 64 timerfd_settime sys_timerfd_settime +287 64 timerfd_gettime sys_timerfd_gettime +288 64 accept4 sys_accept4 +289 64 signalfd4 sys_signalfd4 +290 64 eventfd2 sys_eventfd2 +291 64 epoll_create1 sys_epoll_create1 +292 64 dup3 sys_dup3 +293 64 pipe2 sys_pipe2 +294 64 inotify_init1 sys_inotify_init1 +295 64 preadv sys_preadv +296 64 pwritev sys_pwritev +297 64 rt_tgsigqueueinfo sys_rt_tgsigqueueinfo +298 64 perf_event_open sys_perf_event_open +299 64 recvmmsg sys_recvmmsg +300 64 fanotify_init sys_fanotify_init +301 64 fanotify_mark sys_fanotify_mark +302 64 prlimit64 sys_prlimit64 +303 64 name_to_handle_at sys_name_to_handle_at +304 64 open_by_handle_at sys_open_by_handle_at +305 64 clock_adjtime sys_clock_adjtime +306 64 syncfs sys_syncfs +307 64 sendmmsg sys_sendmmsg +308 64 setns sys_setns +309 64 getcpu sys_getcpu +310 64 process_vm_readv sys_process_vm_readv +311 64 process_vm_writev sys_process_vm_writev diff --git a/arch/x86/syscalls/syscallhdr.sh b/arch/x86/syscalls/syscallhdr.sh new file mode 100644 index 000000000000..31fd5f1f38f7 --- /dev/null +++ b/arch/x86/syscalls/syscallhdr.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +in="$1" +out="$2" +my_abis=`echo "($3)" | tr ',' '|'` +prefix="$4" +offset="$5" + +fileguard=_ASM_X86_`basename "$out" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'` +grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | ( + echo "#ifndef ${fileguard}" + echo "#define ${fileguard} 1" + echo "" + + while read nr abi name entry ; do + if [ -z "$offset" ]; then + echo "#define __NR_${prefix}${name} $nr" + else + echo "#define __NR_${prefix}${name} ($offset + $nr)" + fi + done + + echo "" + echo "#endif /* ${fileguard} */" +) > "$out" diff --git a/arch/x86/syscalls/syscalltbl.sh b/arch/x86/syscalls/syscalltbl.sh new file mode 100644 index 000000000000..0e7f8ec071e7 --- /dev/null +++ b/arch/x86/syscalls/syscalltbl.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +in="$1" +out="$2" + +grep '^[0-9]' "$in" | sort -n | ( + while read nr abi name entry compat; do + abi=`echo "$abi" | tr '[a-z]' '[A-Z]'` + if [ -n "$compat" ]; then + echo "__SYSCALL_${abi}($nr, $entry, $compat)" + elif [ -n "$entry" ]; then + echo "__SYSCALL_${abi}($nr, $entry, $entry)" + fi + done +) > "$out" diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile index 8fb58400e415..5d065b2222d3 100644 --- a/arch/x86/um/Makefile +++ b/arch/x86/um/Makefile @@ -37,7 +37,8 @@ subarch-$(CONFIG_MODULES) += ../kernel/module.o USER_OBJS := bugs_$(BITS).o ptrace_user.o fault.o extra-y += user-offsets.s -$(obj)/user-offsets.s: c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) +$(obj)/user-offsets.s: c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \ + -Iarch/x86/include/generated UNPROFILE_OBJS := stub_segv.o CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING) diff --git a/arch/x86/um/shared/sysdep/ptrace.h b/arch/x86/um/shared/sysdep/ptrace.h index 711b1621747f..2bbe1ec2d96a 100644 --- a/arch/x86/um/shared/sysdep/ptrace.h +++ b/arch/x86/um/shared/sysdep/ptrace.h @@ -1,5 +1,15 @@ +#ifndef __SYSDEP_X86_PTRACE_H +#define __SYSDEP_X86_PTRACE_H + #ifdef __i386__ #include "ptrace_32.h" #else #include "ptrace_64.h" #endif + +static inline long regs_return_value(struct uml_pt_regs *regs) +{ + return UPT_SYSCALL_RET(regs); +} + +#endif /* __SYSDEP_X86_PTRACE_H */ diff --git a/arch/x86/um/sys_call_table_32.S b/arch/x86/um/sys_call_table_32.S deleted file mode 100644 index a7ca80d2dceb..000000000000 --- a/arch/x86/um/sys_call_table_32.S +++ /dev/null @@ -1,26 +0,0 @@ -#include <linux/linkage.h> -/* Steal i386 syscall table for our purposes, but with some slight changes.*/ - -#define sys_iopl sys_ni_syscall -#define sys_ioperm sys_ni_syscall - -#define sys_vm86old sys_ni_syscall -#define sys_vm86 sys_ni_syscall - -#define old_mmap sys_old_mmap - -#define ptregs_fork sys_fork -#define ptregs_execve sys_execve -#define ptregs_iopl sys_iopl -#define ptregs_vm86old sys_vm86old -#define ptregs_clone sys_clone -#define ptregs_vm86 sys_vm86 -#define ptregs_sigaltstack sys_sigaltstack -#define ptregs_vfork sys_vfork - -.section .rodata,"a" - -#include "../kernel/syscall_table_32.S" - -ENTRY(syscall_table_size) -.long .-sys_call_table diff --git a/arch/x86/um/sys_call_table_32.c b/arch/x86/um/sys_call_table_32.c new file mode 100644 index 000000000000..416bd40c0eba --- /dev/null +++ b/arch/x86/um/sys_call_table_32.c @@ -0,0 +1,55 @@ +/* + * System call table for UML/i386, copied from arch/x86/kernel/syscall_*.c + * with some changes for UML. + */ + +#include <linux/linkage.h> +#include <linux/sys.h> +#include <linux/cache.h> +#include <generated/user_constants.h> + +#define __NO_STUBS + +/* + * Below you can see, in terms of #define's, the differences between the x86-64 + * and the UML syscall table. + */ + +/* Not going to be implemented by UML, since we have no hardware. */ +#define sys_iopl sys_ni_syscall +#define sys_ioperm sys_ni_syscall + +#define sys_vm86old sys_ni_syscall +#define sys_vm86 sys_ni_syscall + +#define old_mmap sys_old_mmap + +#define ptregs_fork sys_fork +#define ptregs_execve sys_execve +#define ptregs_iopl sys_iopl +#define ptregs_vm86old sys_vm86old +#define ptregs_clone sys_clone +#define ptregs_vm86 sys_vm86 +#define ptregs_sigaltstack sys_sigaltstack +#define ptregs_vfork sys_vfork + +#define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ; +#include <asm/syscalls_32.h> + +#undef __SYSCALL_I386 +#define __SYSCALL_I386(nr, sym, compat) [ nr ] = sym, + +typedef void (*sys_call_ptr_t)(void); + +extern void sys_ni_syscall(void); + +const sys_call_ptr_t sys_call_table[] __cacheline_aligned = { + /* + * Smells like a compiler bug -- it doesn't work + * when the & below is removed. + */ + [0 ... __NR_syscall_max] = &sys_ni_syscall, +#include <asm/syscalls_32.h> +}; + +int syscall_table_size = sizeof(sys_call_table); diff --git a/arch/x86/um/sys_call_table_64.c b/arch/x86/um/sys_call_table_64.c index 99522f78b162..fe626c3ba01b 100644 --- a/arch/x86/um/sys_call_table_64.c +++ b/arch/x86/um/sys_call_table_64.c @@ -1,11 +1,12 @@ /* - * System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c + * System call table for UML/x86-64, copied from arch/x86/kernel/syscall_*.c * with some changes for UML. */ #include <linux/linkage.h> #include <linux/sys.h> #include <linux/cache.h> +#include <generated/user_constants.h> #define __NO_STUBS @@ -34,31 +35,23 @@ #define stub_sigaltstack sys_sigaltstack #define stub_rt_sigreturn sys_rt_sigreturn -#define __SYSCALL(nr, sym) extern asmlinkage void sym(void) ; -#undef _ASM_X86_UNISTD_64_H -#include "../../x86/include/asm/unistd_64.h" +#define __SYSCALL_64(nr, sym, compat) extern asmlinkage void sym(void) ; +#include <asm/syscalls_64.h> -#undef __SYSCALL -#define __SYSCALL(nr, sym) [ nr ] = sym, -#undef _ASM_X86_UNISTD_64_H +#undef __SYSCALL_64 +#define __SYSCALL_64(nr, sym, compat) [ nr ] = sym, typedef void (*sys_call_ptr_t)(void); extern void sys_ni_syscall(void); -/* - * We used to have a trick here which made sure that holes in the - * x86_64 table were filled in with sys_ni_syscall, but a comment in - * unistd_64.h says that holes aren't allowed, so the trick was - * removed. - * The trick looked like this - * [0 ... UM_NR_syscall_max] = &sys_ni_syscall - * before including unistd_64.h - the later initializations overwrote - * the sys_ni_syscall filler. - */ - -sys_call_ptr_t sys_call_table[] __cacheline_aligned = { -#include <asm/unistd_64.h> +const sys_call_ptr_t sys_call_table[] __cacheline_aligned = { + /* + * Smells like a compiler bug -- it doesn't work + * when the & below is removed. + */ + [0 ... __NR_syscall_max] = &sys_ni_syscall, +#include <asm/syscalls_64.h> }; int syscall_table_size = sizeof(sys_call_table); diff --git a/arch/x86/um/user-offsets.c b/arch/x86/um/user-offsets.c index ca49be8ddd0c..5edf4f4bbf53 100644 --- a/arch/x86/um/user-offsets.c +++ b/arch/x86/um/user-offsets.c @@ -8,6 +8,18 @@ #include <asm/ptrace.h> #include <asm/types.h> +#ifdef __i386__ +#define __SYSCALL_I386(nr, sym, compat) [nr] = 1, +static char syscalls[] = { +#include <asm/syscalls_32.h> +}; +#else +#define __SYSCALL_64(nr, sym, compat) [nr] = 1, +static char syscalls[] = { +#include <asm/syscalls_64.h> +}; +#endif + #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -77,4 +89,7 @@ void foo(void) DEFINE(UM_PROT_READ, PROT_READ); DEFINE(UM_PROT_WRITE, PROT_WRITE); DEFINE(UM_PROT_EXEC, PROT_EXEC); + + DEFINE(__NR_syscall_max, sizeof(syscalls) - 1); + DEFINE(NR_syscalls, sizeof(syscalls)); } diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index a0d042aa2967..2dff698ab02e 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -334,8 +334,7 @@ void do_syscall_trace_enter(struct pt_regs *regs) do_syscall_trace(); #if 0 - if (unlikely(current->audit_context)) - audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); + audit_syscall_entry(current, AUDIT_ARCH_XTENSA..); #endif } diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index b8c143d68ee0..fa8f26309444 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1655,11 +1655,12 @@ static void blkiocg_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, struct io_context *ioc; cgroup_taskset_for_each(task, cgrp, tset) { - task_lock(task); - ioc = task->io_context; - if (ioc) - ioc->cgroup_changed = 1; - task_unlock(task); + /* we don't lose anything even if ioc allocation fails */ + ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE); + if (ioc) { + ioc_cgroup_changed(ioc); + put_io_context(ioc, NULL); + } } } diff --git a/block/blk-core.c b/block/blk-core.c index 15de223c7f93..e6c05a97ee2b 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -39,6 +39,8 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete); +DEFINE_IDA(blk_queue_ida); + /* * For the allocated request tables */ @@ -358,7 +360,8 @@ EXPORT_SYMBOL(blk_put_queue); void blk_drain_queue(struct request_queue *q, bool drain_all) { while (true) { - int nr_rqs; + bool drain = false; + int i; spin_lock_irq(q->queue_lock); @@ -375,14 +378,25 @@ void blk_drain_queue(struct request_queue *q, bool drain_all) if (!list_empty(&q->queue_head)) __blk_run_queue(q); - if (drain_all) - nr_rqs = q->rq.count[0] + q->rq.count[1]; - else - nr_rqs = q->rq.elvpriv; + drain |= q->rq.elvpriv; + + /* + * Unfortunately, requests are queued at and tracked from + * multiple places and there's no single counter which can + * be drained. Check all the queues and counters. + */ + if (drain_all) { + drain |= !list_empty(&q->queue_head); + for (i = 0; i < 2; i++) { + drain |= q->rq.count[i]; + drain |= q->in_flight[i]; + drain |= !list_empty(&q->flush_queue[i]); + } + } spin_unlock_irq(q->queue_lock); - if (!nr_rqs) + if (!drain) break; msleep(10); } @@ -469,6 +483,10 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) if (!q) return NULL; + q->id = ida_simple_get(&blk_queue_ida, 0, 0, GFP_KERNEL); + if (q->id < 0) + goto fail_q; + q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; q->backing_dev_info.state = 0; @@ -477,20 +495,17 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) q->node = node_id; err = bdi_init(&q->backing_dev_info); - if (err) { - kmem_cache_free(blk_requestq_cachep, q); - return NULL; - } + if (err) + goto fail_id; - if (blk_throtl_init(q)) { - kmem_cache_free(blk_requestq_cachep, q); - return NULL; - } + if (blk_throtl_init(q)) + goto fail_id; setup_timer(&q->backing_dev_info.laptop_mode_wb_timer, laptop_mode_timer_fn, (unsigned long) q); setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); INIT_LIST_HEAD(&q->timeout_list); + INIT_LIST_HEAD(&q->icq_list); INIT_LIST_HEAD(&q->flush_queue[0]); INIT_LIST_HEAD(&q->flush_queue[1]); INIT_LIST_HEAD(&q->flush_data_in_flight); @@ -508,6 +523,12 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) q->queue_lock = &q->__queue_lock; return q; + +fail_id: + ida_simple_remove(&blk_queue_ida, q->id); +fail_q: + kmem_cache_free(blk_requestq_cachep, q); + return NULL; } EXPORT_SYMBOL(blk_alloc_queue_node); @@ -605,26 +626,31 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn, } EXPORT_SYMBOL(blk_init_allocated_queue); -int blk_get_queue(struct request_queue *q) +bool blk_get_queue(struct request_queue *q) { - if (likely(!test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) { - kobject_get(&q->kobj); - return 0; + if (likely(!blk_queue_dead(q))) { + __blk_get_queue(q); + return true; } - return 1; + return false; } EXPORT_SYMBOL(blk_get_queue); static inline void blk_free_request(struct request_queue *q, struct request *rq) { - if (rq->cmd_flags & REQ_ELVPRIV) + if (rq->cmd_flags & REQ_ELVPRIV) { elv_put_request(q, rq); + if (rq->elv.icq) + put_io_context(rq->elv.icq->ioc, q); + } + mempool_free(rq, q->rq.rq_pool); } static struct request * -blk_alloc_request(struct request_queue *q, unsigned int flags, gfp_t gfp_mask) +blk_alloc_request(struct request_queue *q, struct io_cq *icq, + unsigned int flags, gfp_t gfp_mask) { struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); @@ -635,10 +661,15 @@ blk_alloc_request(struct request_queue *q, unsigned int flags, gfp_t gfp_mask) rq->cmd_flags = flags | REQ_ALLOCED; - if ((flags & REQ_ELVPRIV) && - unlikely(elv_set_request(q, rq, gfp_mask))) { - mempool_free(rq, q->rq.rq_pool); - return NULL; + if (flags & REQ_ELVPRIV) { + rq->elv.icq = icq; + if (unlikely(elv_set_request(q, rq, gfp_mask))) { + mempool_free(rq, q->rq.rq_pool); + return NULL; + } + /* @rq->elv.icq holds on to io_context until @rq is freed */ + if (icq) + get_io_context(icq->ioc); } return rq; @@ -750,11 +781,17 @@ static struct request *get_request(struct request_queue *q, int rw_flags, { struct request *rq = NULL; struct request_list *rl = &q->rq; - struct io_context *ioc = NULL; + struct elevator_type *et; + struct io_context *ioc; + struct io_cq *icq = NULL; const bool is_sync = rw_is_sync(rw_flags) != 0; + bool retried = false; int may_queue; +retry: + et = q->elevator->type; + ioc = current->io_context; - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) + if (unlikely(blk_queue_dead(q))) return NULL; may_queue = elv_may_queue(q, rw_flags); @@ -763,7 +800,20 @@ static struct request *get_request(struct request_queue *q, int rw_flags, if (rl->count[is_sync]+1 >= queue_congestion_on_threshold(q)) { if (rl->count[is_sync]+1 >= q->nr_requests) { - ioc = current_io_context(GFP_ATOMIC, q->node); + /* + * We want ioc to record batching state. If it's + * not already there, creating a new one requires + * dropping queue_lock, which in turn requires + * retesting conditions to avoid queue hang. + */ + if (!ioc && !retried) { + spin_unlock_irq(q->queue_lock); + create_io_context(current, gfp_mask, q->node); + spin_lock_irq(q->queue_lock); + retried = true; + goto retry; + } + /* * The queue will fill after this allocation, so set * it as full, and mark this process as "batching". @@ -799,17 +849,36 @@ static struct request *get_request(struct request_queue *q, int rw_flags, rl->count[is_sync]++; rl->starved[is_sync] = 0; + /* + * Decide whether the new request will be managed by elevator. If + * so, mark @rw_flags and increment elvpriv. Non-zero elvpriv will + * prevent the current elevator from being destroyed until the new + * request is freed. This guarantees icq's won't be destroyed and + * makes creating new ones safe. + * + * Also, lookup icq while holding queue_lock. If it doesn't exist, + * it will be created after releasing queue_lock. + */ if (blk_rq_should_init_elevator(bio) && !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags)) { rw_flags |= REQ_ELVPRIV; rl->elvpriv++; + if (et->icq_cache && ioc) + icq = ioc_lookup_icq(ioc, q); } if (blk_queue_io_stat(q)) rw_flags |= REQ_IO_STAT; spin_unlock_irq(q->queue_lock); - rq = blk_alloc_request(q, rw_flags, gfp_mask); + /* create icq if missing */ + if (unlikely(et->icq_cache && !icq)) + icq = ioc_create_icq(q, gfp_mask); + + /* rqs are guaranteed to have icq on elv_set_request() if requested */ + if (likely(!et->icq_cache || icq)) + rq = blk_alloc_request(q, icq, rw_flags, gfp_mask); + if (unlikely(!rq)) { /* * Allocation failed presumably due to memory. Undo anything @@ -871,10 +940,9 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags, rq = get_request(q, rw_flags, bio, GFP_NOIO); while (!rq) { DEFINE_WAIT(wait); - struct io_context *ioc; struct request_list *rl = &q->rq; - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) + if (unlikely(blk_queue_dead(q))) return NULL; prepare_to_wait_exclusive(&rl->wait[is_sync], &wait, @@ -891,8 +959,8 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags, * up to a big batch of them for a small period time. * See ioc_batching, ioc_set_batching */ - ioc = current_io_context(GFP_NOIO, q->node); - ioc_set_batching(q, ioc); + create_io_context(current, GFP_NOIO, q->node); + ioc_set_batching(q, current->io_context); spin_lock_irq(q->queue_lock); finish_wait(&rl->wait[is_sync], &wait); @@ -1009,54 +1077,6 @@ static void add_acct_request(struct request_queue *q, struct request *rq, __elv_add_request(q, rq, where); } -/** - * blk_insert_request - insert a special request into a request queue - * @q: request queue where request should be inserted - * @rq: request to be inserted - * @at_head: insert request at head or tail of queue - * @data: private data - * - * Description: - * Many block devices need to execute commands asynchronously, so they don't - * block the whole kernel from preemption during request execution. This is - * accomplished normally by inserting aritficial requests tagged as - * REQ_TYPE_SPECIAL in to the corresponding request queue, and letting them - * be scheduled for actual execution by the request queue. - * - * We have the option of inserting the head or the tail of the queue. - * Typically we use the tail for new ioctls and so forth. We use the head - * of the queue for things like a QUEUE_FULL message from a device, or a - * host that is unable to accept a particular command. - */ -void blk_insert_request(struct request_queue *q, struct request *rq, - int at_head, void *data) -{ - int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; - unsigned long flags; - - /* - * tell I/O scheduler that this isn't a regular read/write (ie it - * must not attempt merges on this) and that it acts as a soft - * barrier - */ - rq->cmd_type = REQ_TYPE_SPECIAL; - - rq->special = data; - - spin_lock_irqsave(q->queue_lock, flags); - - /* - * If command is tagged, release the tag - */ - if (blk_rq_tagged(rq)) - blk_queue_end_tag(q, rq); - - add_acct_request(q, rq, where); - __blk_run_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); -} -EXPORT_SYMBOL(blk_insert_request); - static void part_round_stats_single(int cpu, struct hd_struct *part, unsigned long now) { @@ -1766,6 +1786,10 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq) return -EIO; spin_lock_irqsave(q->queue_lock, flags); + if (unlikely(blk_queue_dead(q))) { + spin_unlock_irqrestore(q->queue_lock, flags); + return -ENODEV; + } /* * Submitting request must be dequeued before calling this function @@ -2740,6 +2764,14 @@ static void queue_unplugged(struct request_queue *q, unsigned int depth, trace_block_unplug(q, depth, !from_schedule); /* + * Don't mess with dead queue. + */ + if (unlikely(blk_queue_dead(q))) { + spin_unlock(q->queue_lock); + return; + } + + /* * If we are punting this to kblockd, then we can safely drop * the queue_lock before waking kblockd (which needs to take * this lock). @@ -2815,6 +2847,15 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) depth = 0; spin_lock(q->queue_lock); } + + /* + * Short-circuit if @q is dead + */ + if (unlikely(blk_queue_dead(q))) { + __blk_end_request_all(rq, -ENODEV); + continue; + } + /* * rq is already accounted, so use raw insert */ diff --git a/block/blk-exec.c b/block/blk-exec.c index a1ebceb332f9..fb2cbd551621 100644 --- a/block/blk-exec.c +++ b/block/blk-exec.c @@ -50,7 +50,11 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, { int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) { + WARN_ON(irqs_disabled()); + spin_lock_irq(q->queue_lock); + + if (unlikely(blk_queue_dead(q))) { + spin_unlock_irq(q->queue_lock); rq->errors = -ENXIO; if (rq->end_io) rq->end_io(rq, rq->errors); @@ -59,8 +63,6 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, rq->rq_disk = bd_disk; rq->end_io = done; - WARN_ON(irqs_disabled()); - spin_lock_irq(q->queue_lock); __elv_add_request(q, rq, where); __blk_run_queue(q); /* the queue is stopped so it won't be run */ diff --git a/block/blk-ioc.c b/block/blk-ioc.c index 6f9bbd978653..27a06e00eaec 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c @@ -16,53 +16,214 @@ */ static struct kmem_cache *iocontext_cachep; -static void cfq_dtor(struct io_context *ioc) +/** + * get_io_context - increment reference count to io_context + * @ioc: io_context to get + * + * Increment reference count to @ioc. + */ +void get_io_context(struct io_context *ioc) +{ + BUG_ON(atomic_long_read(&ioc->refcount) <= 0); + atomic_long_inc(&ioc->refcount); +} +EXPORT_SYMBOL(get_io_context); + +/* + * Releasing ioc may nest into another put_io_context() leading to nested + * fast path release. As the ioc's can't be the same, this is okay but + * makes lockdep whine. Keep track of nesting and use it as subclass. + */ +#ifdef CONFIG_LOCKDEP +#define ioc_release_depth(q) ((q) ? (q)->ioc_release_depth : 0) +#define ioc_release_depth_inc(q) (q)->ioc_release_depth++ +#define ioc_release_depth_dec(q) (q)->ioc_release_depth-- +#else +#define ioc_release_depth(q) 0 +#define ioc_release_depth_inc(q) do { } while (0) +#define ioc_release_depth_dec(q) do { } while (0) +#endif + +static void icq_free_icq_rcu(struct rcu_head *head) +{ + struct io_cq *icq = container_of(head, struct io_cq, __rcu_head); + + kmem_cache_free(icq->__rcu_icq_cache, icq); +} + +/* + * Exit and free an icq. Called with both ioc and q locked. + */ +static void ioc_exit_icq(struct io_cq *icq) { - if (!hlist_empty(&ioc->cic_list)) { - struct cfq_io_context *cic; + struct io_context *ioc = icq->ioc; + struct request_queue *q = icq->q; + struct elevator_type *et = q->elevator->type; + + lockdep_assert_held(&ioc->lock); + lockdep_assert_held(q->queue_lock); + + radix_tree_delete(&ioc->icq_tree, icq->q->id); + hlist_del_init(&icq->ioc_node); + list_del_init(&icq->q_node); + + /* + * Both setting lookup hint to and clearing it from @icq are done + * under queue_lock. If it's not pointing to @icq now, it never + * will. Hint assignment itself can race safely. + */ + if (rcu_dereference_raw(ioc->icq_hint) == icq) + rcu_assign_pointer(ioc->icq_hint, NULL); - cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context, - cic_list); - cic->dtor(ioc); + if (et->ops.elevator_exit_icq_fn) { + ioc_release_depth_inc(q); + et->ops.elevator_exit_icq_fn(icq); + ioc_release_depth_dec(q); } + + /* + * @icq->q might have gone away by the time RCU callback runs + * making it impossible to determine icq_cache. Record it in @icq. + */ + icq->__rcu_icq_cache = et->icq_cache; + call_rcu(&icq->__rcu_head, icq_free_icq_rcu); } /* - * IO Context helper functions. put_io_context() returns 1 if there are no - * more users of this io context, 0 otherwise. + * Slow path for ioc release in put_io_context(). Performs double-lock + * dancing to unlink all icq's and then frees ioc. */ -int put_io_context(struct io_context *ioc) +static void ioc_release_fn(struct work_struct *work) { - if (ioc == NULL) - return 1; + struct io_context *ioc = container_of(work, struct io_context, + release_work); + struct request_queue *last_q = NULL; - BUG_ON(atomic_long_read(&ioc->refcount) == 0); + spin_lock_irq(&ioc->lock); - if (atomic_long_dec_and_test(&ioc->refcount)) { - rcu_read_lock(); - cfq_dtor(ioc); - rcu_read_unlock(); + while (!hlist_empty(&ioc->icq_list)) { + struct io_cq *icq = hlist_entry(ioc->icq_list.first, + struct io_cq, ioc_node); + struct request_queue *this_q = icq->q; - kmem_cache_free(iocontext_cachep, ioc); - return 1; + if (this_q != last_q) { + /* + * Need to switch to @this_q. Once we release + * @ioc->lock, it can go away along with @cic. + * Hold on to it. + */ + __blk_get_queue(this_q); + + /* + * blk_put_queue() might sleep thanks to kobject + * idiocy. Always release both locks, put and + * restart. + */ + if (last_q) { + spin_unlock(last_q->queue_lock); + spin_unlock_irq(&ioc->lock); + blk_put_queue(last_q); + } else { + spin_unlock_irq(&ioc->lock); + } + + last_q = this_q; + spin_lock_irq(this_q->queue_lock); + spin_lock(&ioc->lock); + continue; + } + ioc_exit_icq(icq); } - return 0; + + if (last_q) { + spin_unlock(last_q->queue_lock); + spin_unlock_irq(&ioc->lock); + blk_put_queue(last_q); + } else { + spin_unlock_irq(&ioc->lock); + } + + kmem_cache_free(iocontext_cachep, ioc); } -EXPORT_SYMBOL(put_io_context); -static void cfq_exit(struct io_context *ioc) +/** + * put_io_context - put a reference of io_context + * @ioc: io_context to put + * @locked_q: request_queue the caller is holding queue_lock of (hint) + * + * Decrement reference count of @ioc and release it if the count reaches + * zero. If the caller is holding queue_lock of a queue, it can indicate + * that with @locked_q. This is an optimization hint and the caller is + * allowed to pass in %NULL even when it's holding a queue_lock. + */ +void put_io_context(struct io_context *ioc, struct request_queue *locked_q) { - rcu_read_lock(); + struct request_queue *last_q = locked_q; + unsigned long flags; + + if (ioc == NULL) + return; + + BUG_ON(atomic_long_read(&ioc->refcount) <= 0); + if (locked_q) + lockdep_assert_held(locked_q->queue_lock); - if (!hlist_empty(&ioc->cic_list)) { - struct cfq_io_context *cic; + if (!atomic_long_dec_and_test(&ioc->refcount)) + return; + + /* + * Destroy @ioc. This is a bit messy because icq's are chained + * from both ioc and queue, and ioc->lock nests inside queue_lock. + * The inner ioc->lock should be held to walk our icq_list and then + * for each icq the outer matching queue_lock should be grabbed. + * ie. We need to do reverse-order double lock dancing. + * + * Another twist is that we are often called with one of the + * matching queue_locks held as indicated by @locked_q, which + * prevents performing double-lock dance for other queues. + * + * So, we do it in two stages. The fast path uses the queue_lock + * the caller is holding and, if other queues need to be accessed, + * uses trylock to avoid introducing locking dependency. This can + * handle most cases, especially if @ioc was performing IO on only + * single device. + * + * If trylock doesn't cut it, we defer to @ioc->release_work which + * can do all the double-locking dancing. + */ + spin_lock_irqsave_nested(&ioc->lock, flags, + ioc_release_depth(locked_q)); - cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context, - cic_list); - cic->exit(ioc); + while (!hlist_empty(&ioc->icq_list)) { + struct io_cq *icq = hlist_entry(ioc->icq_list.first, + struct io_cq, ioc_node); + struct request_queue *this_q = icq->q; + + if (this_q != last_q) { + if (last_q && last_q != locked_q) + spin_unlock(last_q->queue_lock); + last_q = NULL; + + if (!spin_trylock(this_q->queue_lock)) + break; + last_q = this_q; + continue; + } + ioc_exit_icq(icq); } - rcu_read_unlock(); + + if (last_q && last_q != locked_q) + spin_unlock(last_q->queue_lock); + + spin_unlock_irqrestore(&ioc->lock, flags); + + /* if no icq is left, we're done; otherwise, kick release_work */ + if (hlist_empty(&ioc->icq_list)) + kmem_cache_free(iocontext_cachep, ioc); + else + schedule_work(&ioc->release_work); } +EXPORT_SYMBOL(put_io_context); /* Called by the exiting task */ void exit_io_context(struct task_struct *task) @@ -74,86 +235,240 @@ void exit_io_context(struct task_struct *task) task->io_context = NULL; task_unlock(task); - if (atomic_dec_and_test(&ioc->nr_tasks)) - cfq_exit(ioc); + atomic_dec(&ioc->nr_tasks); + put_io_context(ioc, NULL); +} + +/** + * ioc_clear_queue - break any ioc association with the specified queue + * @q: request_queue being cleared + * + * Walk @q->icq_list and exit all io_cq's. Must be called with @q locked. + */ +void ioc_clear_queue(struct request_queue *q) +{ + lockdep_assert_held(q->queue_lock); + + while (!list_empty(&q->icq_list)) { + struct io_cq *icq = list_entry(q->icq_list.next, + struct io_cq, q_node); + struct io_context *ioc = icq->ioc; - put_io_context(ioc); + spin_lock(&ioc->lock); + ioc_exit_icq(icq); + spin_unlock(&ioc->lock); + } } -struct io_context *alloc_io_context(gfp_t gfp_flags, int node) +void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_flags, + int node) { struct io_context *ioc; - ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node); - if (ioc) { - atomic_long_set(&ioc->refcount, 1); - atomic_set(&ioc->nr_tasks, 1); - spin_lock_init(&ioc->lock); - ioc->ioprio_changed = 0; - ioc->ioprio = 0; - ioc->last_waited = 0; /* doesn't matter... */ - ioc->nr_batch_requests = 0; /* because this is 0 */ - INIT_RADIX_TREE(&ioc->radix_root, GFP_ATOMIC | __GFP_HIGH); - INIT_HLIST_HEAD(&ioc->cic_list); - ioc->ioc_data = NULL; -#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE) - ioc->cgroup_changed = 0; -#endif - } + ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags | __GFP_ZERO, + node); + if (unlikely(!ioc)) + return; - return ioc; + /* initialize */ + atomic_long_set(&ioc->refcount, 1); + atomic_set(&ioc->nr_tasks, 1); + spin_lock_init(&ioc->lock); + INIT_RADIX_TREE(&ioc->icq_tree, GFP_ATOMIC | __GFP_HIGH); + INIT_HLIST_HEAD(&ioc->icq_list); + INIT_WORK(&ioc->release_work, ioc_release_fn); + + /* + * Try to install. ioc shouldn't be installed if someone else + * already did or @task, which isn't %current, is exiting. Note + * that we need to allow ioc creation on exiting %current as exit + * path may issue IOs from e.g. exit_files(). The exit path is + * responsible for not issuing IO after exit_io_context(). + */ + task_lock(task); + if (!task->io_context && + (task == current || !(task->flags & PF_EXITING))) + task->io_context = ioc; + else + kmem_cache_free(iocontext_cachep, ioc); + task_unlock(task); } -/* - * If the current task has no IO context then create one and initialise it. - * Otherwise, return its existing IO context. +/** + * get_task_io_context - get io_context of a task + * @task: task of interest + * @gfp_flags: allocation flags, used if allocation is necessary + * @node: allocation node, used if allocation is necessary * - * This returned IO context doesn't have a specifically elevated refcount, - * but since the current task itself holds a reference, the context can be - * used in general code, so long as it stays within `current` context. + * Return io_context of @task. If it doesn't exist, it is created with + * @gfp_flags and @node. The returned io_context has its reference count + * incremented. + * + * This function always goes through task_lock() and it's better to use + * %current->io_context + get_io_context() for %current. */ -struct io_context *current_io_context(gfp_t gfp_flags, int node) +struct io_context *get_task_io_context(struct task_struct *task, + gfp_t gfp_flags, int node) { - struct task_struct *tsk = current; - struct io_context *ret; - - ret = tsk->io_context; - if (likely(ret)) - return ret; - - ret = alloc_io_context(gfp_flags, node); - if (ret) { - /* make sure set_task_ioprio() sees the settings above */ - smp_wmb(); - tsk->io_context = ret; - } + struct io_context *ioc; - return ret; + might_sleep_if(gfp_flags & __GFP_WAIT); + + do { + task_lock(task); + ioc = task->io_context; + if (likely(ioc)) { + get_io_context(ioc); + task_unlock(task); + return ioc; + } + task_unlock(task); + } while (create_io_context(task, gfp_flags, node)); + + return NULL; } +EXPORT_SYMBOL(get_task_io_context); -/* - * If the current task has no IO context then create one and initialise it. - * If it does have a context, take a ref on it. +/** + * ioc_lookup_icq - lookup io_cq from ioc + * @ioc: the associated io_context + * @q: the associated request_queue * - * This is always called in the context of the task which submitted the I/O. + * Look up io_cq associated with @ioc - @q pair from @ioc. Must be called + * with @q->queue_lock held. */ -struct io_context *get_io_context(gfp_t gfp_flags, int node) +struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q) { - struct io_context *ioc = NULL; + struct io_cq *icq; + + lockdep_assert_held(q->queue_lock); /* - * Check for unlikely race with exiting task. ioc ref count is - * zero when ioc is being detached. + * icq's are indexed from @ioc using radix tree and hint pointer, + * both of which are protected with RCU. All removals are done + * holding both q and ioc locks, and we're holding q lock - if we + * find a icq which points to us, it's guaranteed to be valid. */ - do { - ioc = current_io_context(gfp_flags, node); - if (unlikely(!ioc)) - break; - } while (!atomic_long_inc_not_zero(&ioc->refcount)); + rcu_read_lock(); + icq = rcu_dereference(ioc->icq_hint); + if (icq && icq->q == q) + goto out; - return ioc; + icq = radix_tree_lookup(&ioc->icq_tree, q->id); + if (icq && icq->q == q) + rcu_assign_pointer(ioc->icq_hint, icq); /* allowed to race */ + else + icq = NULL; +out: + rcu_read_unlock(); + return icq; } -EXPORT_SYMBOL(get_io_context); +EXPORT_SYMBOL(ioc_lookup_icq); + +/** + * ioc_create_icq - create and link io_cq + * @q: request_queue of interest + * @gfp_mask: allocation mask + * + * Make sure io_cq linking %current->io_context and @q exists. If either + * io_context and/or icq don't exist, they will be created using @gfp_mask. + * + * The caller is responsible for ensuring @ioc won't go away and @q is + * alive and will stay alive until this function returns. + */ +struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask) +{ + struct elevator_type *et = q->elevator->type; + struct io_context *ioc; + struct io_cq *icq; + + /* allocate stuff */ + ioc = create_io_context(current, gfp_mask, q->node); + if (!ioc) + return NULL; + + icq = kmem_cache_alloc_node(et->icq_cache, gfp_mask | __GFP_ZERO, + q->node); + if (!icq) + return NULL; + + if (radix_tree_preload(gfp_mask) < 0) { + kmem_cache_free(et->icq_cache, icq); + return NULL; + } + + icq->ioc = ioc; + icq->q = q; + INIT_LIST_HEAD(&icq->q_node); + INIT_HLIST_NODE(&icq->ioc_node); + + /* lock both q and ioc and try to link @icq */ + spin_lock_irq(q->queue_lock); + spin_lock(&ioc->lock); + + if (likely(!radix_tree_insert(&ioc->icq_tree, q->id, icq))) { + hlist_add_head(&icq->ioc_node, &ioc->icq_list); + list_add(&icq->q_node, &q->icq_list); + if (et->ops.elevator_init_icq_fn) + et->ops.elevator_init_icq_fn(icq); + } else { + kmem_cache_free(et->icq_cache, icq); + icq = ioc_lookup_icq(ioc, q); + if (!icq) + printk(KERN_ERR "cfq: icq link failed!\n"); + } + + spin_unlock(&ioc->lock); + spin_unlock_irq(q->queue_lock); + radix_tree_preload_end(); + return icq; +} + +void ioc_set_changed(struct io_context *ioc, int which) +{ + struct io_cq *icq; + struct hlist_node *n; + + hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node) + set_bit(which, &icq->changed); +} + +/** + * ioc_ioprio_changed - notify ioprio change + * @ioc: io_context of interest + * @ioprio: new ioprio + * + * @ioc's ioprio has changed to @ioprio. Set %ICQ_IOPRIO_CHANGED for all + * icq's. iosched is responsible for checking the bit and applying it on + * request issue path. + */ +void ioc_ioprio_changed(struct io_context *ioc, int ioprio) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->lock, flags); + ioc->ioprio = ioprio; + ioc_set_changed(ioc, ICQ_IOPRIO_CHANGED); + spin_unlock_irqrestore(&ioc->lock, flags); +} + +/** + * ioc_cgroup_changed - notify cgroup change + * @ioc: io_context of interest + * + * @ioc's cgroup has changed. Set %ICQ_CGROUP_CHANGED for all icq's. + * iosched is responsible for checking the bit and applying it on request + * issue path. + */ +void ioc_cgroup_changed(struct io_context *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->lock, flags); + ioc_set_changed(ioc, ICQ_CGROUP_CHANGED); + spin_unlock_irqrestore(&ioc->lock, flags); +} +EXPORT_SYMBOL(ioc_cgroup_changed); static int __init blk_ioc_init(void) { diff --git a/block/blk-settings.c b/block/blk-settings.c index fa1eb0449a05..d3234fc494ad 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -104,9 +104,7 @@ EXPORT_SYMBOL_GPL(blk_queue_lld_busy); * @lim: the queue_limits structure to reset * * Description: - * Returns a queue_limit struct to its default state. Can be used by - * stacking drivers like DM that stage table swaps and reuse an - * existing device queue. + * Returns a queue_limit struct to its default state. */ void blk_set_default_limits(struct queue_limits *lim) { @@ -114,13 +112,12 @@ void blk_set_default_limits(struct queue_limits *lim) lim->max_integrity_segments = 0; lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; lim->max_segment_size = BLK_MAX_SEGMENT_SIZE; - lim->max_sectors = BLK_DEF_MAX_SECTORS; - lim->max_hw_sectors = INT_MAX; + lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS; lim->max_discard_sectors = 0; lim->discard_granularity = 0; lim->discard_alignment = 0; lim->discard_misaligned = 0; - lim->discard_zeroes_data = 1; + lim->discard_zeroes_data = 0; lim->logical_block_size = lim->physical_block_size = lim->io_min = 512; lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT); lim->alignment_offset = 0; @@ -131,6 +128,27 @@ void blk_set_default_limits(struct queue_limits *lim) EXPORT_SYMBOL(blk_set_default_limits); /** + * blk_set_stacking_limits - set default limits for stacking devices + * @lim: the queue_limits structure to reset + * + * Description: + * Returns a queue_limit struct to its default state. Should be used + * by stacking drivers like DM that have no internal limits. + */ +void blk_set_stacking_limits(struct queue_limits *lim) +{ + blk_set_default_limits(lim); + + /* Inherit limits from component devices */ + lim->discard_zeroes_data = 1; + lim->max_segments = USHRT_MAX; + lim->max_hw_sectors = UINT_MAX; + + lim->max_sectors = BLK_DEF_MAX_SECTORS; +} +EXPORT_SYMBOL(blk_set_stacking_limits); + +/** * blk_queue_make_request - define an alternate make_request function for a device * @q: the request queue for the device to be affected * @mfn: the alternate make_request function @@ -165,8 +183,6 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) q->nr_batching = BLK_BATCH_REQ; blk_set_default_limits(&q->limits); - blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS); - q->limits.discard_zeroes_data = 0; /* * by default assume old behaviour and bounce for any highmem page diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index e7f9f657f105..cf150011d808 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -425,7 +425,7 @@ queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page) if (!entry->show) return -EIO; mutex_lock(&q->sysfs_lock); - if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) { + if (blk_queue_dead(q)) { mutex_unlock(&q->sysfs_lock); return -ENOENT; } @@ -447,7 +447,7 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr, q = container_of(kobj, struct request_queue, kobj); mutex_lock(&q->sysfs_lock); - if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) { + if (blk_queue_dead(q)) { mutex_unlock(&q->sysfs_lock); return -ENOENT; } @@ -479,8 +479,12 @@ static void blk_release_queue(struct kobject *kobj) blk_sync_queue(q); - if (q->elevator) + if (q->elevator) { + spin_lock_irq(q->queue_lock); + ioc_clear_queue(q); + spin_unlock_irq(q->queue_lock); elevator_exit(q->elevator); + } blk_throtl_exit(q); @@ -494,6 +498,8 @@ static void blk_release_queue(struct kobject *kobj) blk_trace_shutdown(q); bdi_destroy(&q->backing_dev_info); + + ida_simple_remove(&blk_queue_ida, q->id); kmem_cache_free(blk_requestq_cachep, q); } diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 4553245d9317..5eed6a76721d 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -310,7 +310,7 @@ static struct throtl_grp * throtl_get_tg(struct throtl_data *td) struct request_queue *q = td->queue; /* no throttling for dead queue */ - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) + if (unlikely(blk_queue_dead(q))) return NULL; rcu_read_lock(); @@ -335,7 +335,7 @@ static struct throtl_grp * throtl_get_tg(struct throtl_data *td) spin_lock_irq(q->queue_lock); /* Make sure @q is still alive */ - if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) { + if (unlikely(blk_queue_dead(q))) { kfree(tg); return NULL; } diff --git a/block/blk.h b/block/blk.h index 3f6551b3c92d..7efd772336de 100644 --- a/block/blk.h +++ b/block/blk.h @@ -1,6 +1,8 @@ #ifndef BLK_INTERNAL_H #define BLK_INTERNAL_H +#include <linux/idr.h> + /* Amount of time in which a process may batch requests */ #define BLK_BATCH_TIME (HZ/50UL) @@ -9,6 +11,12 @@ extern struct kmem_cache *blk_requestq_cachep; extern struct kobj_type blk_queue_ktype; +extern struct ida blk_queue_ida; + +static inline void __blk_get_queue(struct request_queue *q) +{ + kobject_get(&q->kobj); +} void init_request_from_bio(struct request *req, struct bio *bio); void blk_rq_bio_prep(struct request_queue *q, struct request *rq, @@ -85,8 +93,8 @@ static inline struct request *__elv_next_request(struct request_queue *q) q->flush_queue_delayed = 1; return NULL; } - if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags) || - !q->elevator->ops->elevator_dispatch_fn(q, 0)) + if (unlikely(blk_queue_dead(q)) || + !q->elevator->type->ops.elevator_dispatch_fn(q, 0)) return NULL; } } @@ -95,16 +103,16 @@ static inline void elv_activate_rq(struct request_queue *q, struct request *rq) { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_activate_req_fn) - e->ops->elevator_activate_req_fn(q, rq); + if (e->type->ops.elevator_activate_req_fn) + e->type->ops.elevator_activate_req_fn(q, rq); } static inline void elv_deactivate_rq(struct request_queue *q, struct request *rq) { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_deactivate_req_fn) - e->ops->elevator_deactivate_req_fn(q, rq); + if (e->type->ops.elevator_deactivate_req_fn) + e->type->ops.elevator_deactivate_req_fn(q, rq); } #ifdef CONFIG_FAIL_IO_TIMEOUT @@ -119,8 +127,6 @@ static inline int blk_should_fake_timeout(struct request_queue *q) } #endif -struct io_context *current_io_context(gfp_t gfp_flags, int node); - int ll_back_merge_fn(struct request_queue *q, struct request *req, struct bio *bio); int ll_front_merge_fn(struct request_queue *q, struct request *req, @@ -189,6 +195,42 @@ static inline int blk_do_io_stat(struct request *rq) (rq->cmd_flags & REQ_DISCARD)); } +/* + * Internal io_context interface + */ +void get_io_context(struct io_context *ioc); +struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q); +struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask); +void ioc_clear_queue(struct request_queue *q); + +void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_mask, + int node); + +/** + * create_io_context - try to create task->io_context + * @task: target task + * @gfp_mask: allocation mask + * @node: allocation node + * + * If @task->io_context is %NULL, allocate a new io_context and install it. + * Returns the current @task->io_context which may be %NULL if allocation + * failed. + * + * Note that this function can't be called with IRQ disabled because + * task_lock which protects @task->io_context is IRQ-unsafe. + */ +static inline struct io_context *create_io_context(struct task_struct *task, + gfp_t gfp_mask, int node) +{ + WARN_ON_ONCE(irqs_disabled()); + if (unlikely(!task->io_context)) + create_io_context_slowpath(task, gfp_mask, node); + return task->io_context; +} + +/* + * Internal throttling interface + */ #ifdef CONFIG_BLK_DEV_THROTTLING extern bool blk_throtl_bio(struct request_queue *q, struct bio *bio); extern void blk_throtl_drain(struct request_queue *q); diff --git a/block/bsg.c b/block/bsg.c index 9651ec7b87c2..4cf703fd98bb 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -769,12 +769,10 @@ static struct bsg_device *bsg_add_device(struct inode *inode, struct file *file) { struct bsg_device *bd; - int ret; #ifdef BSG_DEBUG unsigned char buf[32]; #endif - ret = blk_get_queue(rq); - if (ret) + if (!blk_get_queue(rq)) return ERR_PTR(-ENXIO); bd = bsg_alloc_device(); diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3548705b04e4..ee55019066a1 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -14,6 +14,7 @@ #include <linux/rbtree.h> #include <linux/ioprio.h> #include <linux/blktrace_api.h> +#include "blk.h" #include "cfq.h" /* @@ -53,20 +54,11 @@ static const int cfq_hist_divisor = 4; #define CFQQ_SECT_THR_NONROT (sector_t)(2 * 32) #define CFQQ_SEEKY(cfqq) (hweight32(cfqq->seek_history) > 32/8) -#define RQ_CIC(rq) \ - ((struct cfq_io_context *) (rq)->elevator_private[0]) -#define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elevator_private[1]) -#define RQ_CFQG(rq) (struct cfq_group *) ((rq)->elevator_private[2]) +#define RQ_CIC(rq) icq_to_cic((rq)->elv.icq) +#define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elv.priv[0]) +#define RQ_CFQG(rq) (struct cfq_group *) ((rq)->elv.priv[1]) static struct kmem_cache *cfq_pool; -static struct kmem_cache *cfq_ioc_pool; - -static DEFINE_PER_CPU(unsigned long, cfq_ioc_count); -static struct completion *ioc_gone; -static DEFINE_SPINLOCK(ioc_gone_lock); - -static DEFINE_SPINLOCK(cic_index_lock); -static DEFINE_IDA(cic_index_ida); #define CFQ_PRIO_LISTS IOPRIO_BE_NR #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) @@ -75,6 +67,14 @@ static DEFINE_IDA(cic_index_ida); #define sample_valid(samples) ((samples) > 80) #define rb_entry_cfqg(node) rb_entry((node), struct cfq_group, rb_node) +struct cfq_ttime { + unsigned long last_end_request; + + unsigned long ttime_total; + unsigned long ttime_samples; + unsigned long ttime_mean; +}; + /* * Most of our rbtree usage is for sorting with min extraction, so * if we cache the leftmost node we don't have to walk down the tree @@ -216,6 +216,12 @@ struct cfq_group { struct cfq_ttime ttime; }; +struct cfq_io_cq { + struct io_cq icq; /* must be the first member */ + struct cfq_queue *cfqq[2]; + struct cfq_ttime ttime; +}; + /* * Per block device queue structure */ @@ -267,7 +273,7 @@ struct cfq_data { struct work_struct unplug_work; struct cfq_queue *active_queue; - struct cfq_io_context *active_cic; + struct cfq_io_cq *active_cic; /* * async queue for each priority case @@ -290,9 +296,6 @@ struct cfq_data { unsigned int cfq_group_idle; unsigned int cfq_latency; - unsigned int cic_index; - struct list_head cic_list; - /* * Fallback dummy cfqq for extreme OOM conditions */ @@ -464,37 +467,35 @@ static inline int cfqg_busy_async_queues(struct cfq_data *cfqd, static void cfq_dispatch_insert(struct request_queue *, struct request *); static struct cfq_queue *cfq_get_queue(struct cfq_data *, bool, struct io_context *, gfp_t); -static struct cfq_io_context *cfq_cic_lookup(struct cfq_data *, - struct io_context *); -static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic, - bool is_sync) +static inline struct cfq_io_cq *icq_to_cic(struct io_cq *icq) { - return cic->cfqq[is_sync]; + /* cic->icq is the first member, %NULL will convert to %NULL */ + return container_of(icq, struct cfq_io_cq, icq); } -static inline void cic_set_cfqq(struct cfq_io_context *cic, - struct cfq_queue *cfqq, bool is_sync) +static inline struct cfq_io_cq *cfq_cic_lookup(struct cfq_data *cfqd, + struct io_context *ioc) { - cic->cfqq[is_sync] = cfqq; + if (ioc) + return icq_to_cic(ioc_lookup_icq(ioc, cfqd->queue)); + return NULL; } -#define CIC_DEAD_KEY 1ul -#define CIC_DEAD_INDEX_SHIFT 1 - -static inline void *cfqd_dead_key(struct cfq_data *cfqd) +static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_cq *cic, bool is_sync) { - return (void *)(cfqd->cic_index << CIC_DEAD_INDEX_SHIFT | CIC_DEAD_KEY); + return cic->cfqq[is_sync]; } -static inline struct cfq_data *cic_to_cfqd(struct cfq_io_context *cic) +static inline void cic_set_cfqq(struct cfq_io_cq *cic, struct cfq_queue *cfqq, + bool is_sync) { - struct cfq_data *cfqd = cic->key; - - if (unlikely((unsigned long) cfqd & CIC_DEAD_KEY)) - return NULL; + cic->cfqq[is_sync] = cfqq; +} - return cfqd; +static inline struct cfq_data *cic_to_cfqd(struct cfq_io_cq *cic) +{ + return cic->icq.q->elevator->elevator_data; } /* @@ -1561,7 +1562,7 @@ static struct request * cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio) { struct task_struct *tsk = current; - struct cfq_io_context *cic; + struct cfq_io_cq *cic; struct cfq_queue *cfqq; cic = cfq_cic_lookup(cfqd, tsk->io_context); @@ -1687,7 +1688,7 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq, struct bio *bio) { struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_io_context *cic; + struct cfq_io_cq *cic; struct cfq_queue *cfqq; /* @@ -1697,12 +1698,19 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq, return false; /* - * Lookup the cfqq that this bio will be queued with. Allow - * merge only if rq is queued there. + * Lookup the cfqq that this bio will be queued with and allow + * merge only if rq is queued there. This function can be called + * from plug merge without queue_lock. In such cases, ioc of @rq + * and %current are guaranteed to be equal. Avoid lookup which + * requires queue_lock by using @rq's cic. */ - cic = cfq_cic_lookup(cfqd, current->io_context); - if (!cic) - return false; + if (current->io_context == RQ_CIC(rq)->icq.ioc) { + cic = RQ_CIC(rq); + } else { + cic = cfq_cic_lookup(cfqd, current->io_context); + if (!cic) + return false; + } cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio)); return cfqq == RQ_CFQQ(rq); @@ -1786,7 +1794,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, cfqd->active_queue = NULL; if (cfqd->active_cic) { - put_io_context(cfqd->active_cic->ioc); + put_io_context(cfqd->active_cic->icq.ioc, cfqd->queue); cfqd->active_cic = NULL; } } @@ -2006,7 +2014,7 @@ static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq) static void cfq_arm_slice_timer(struct cfq_data *cfqd) { struct cfq_queue *cfqq = cfqd->active_queue; - struct cfq_io_context *cic; + struct cfq_io_cq *cic; unsigned long sl, group_idle = 0; /* @@ -2041,7 +2049,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) * task has exited, don't wait */ cic = cfqd->active_cic; - if (!cic || !atomic_read(&cic->ioc->nr_tasks)) + if (!cic || !atomic_read(&cic->icq.ioc->nr_tasks)) return; /* @@ -2592,9 +2600,9 @@ static bool cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq) cfq_dispatch_insert(cfqd->queue, rq); if (!cfqd->active_cic) { - struct cfq_io_context *cic = RQ_CIC(rq); + struct cfq_io_cq *cic = RQ_CIC(rq); - atomic_long_inc(&cic->ioc->refcount); + atomic_long_inc(&cic->icq.ioc->refcount); cfqd->active_cic = cic; } @@ -2677,84 +2685,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq) cfq_put_cfqg(cfqg); } -/* - * Call func for each cic attached to this ioc. - */ -static void -call_for_each_cic(struct io_context *ioc, - void (*func)(struct io_context *, struct cfq_io_context *)) -{ - struct cfq_io_context *cic; - struct hlist_node *n; - - rcu_read_lock(); - - hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list) - func(ioc, cic); - - rcu_read_unlock(); -} - -static void cfq_cic_free_rcu(struct rcu_head *head) -{ - struct cfq_io_context *cic; - - cic = container_of(head, struct cfq_io_context, rcu_head); - - kmem_cache_free(cfq_ioc_pool, cic); - elv_ioc_count_dec(cfq_ioc_count); - - if (ioc_gone) { - /* - * CFQ scheduler is exiting, grab exit lock and check - * the pending io context count. If it hits zero, - * complete ioc_gone and set it back to NULL - */ - spin_lock(&ioc_gone_lock); - if (ioc_gone && !elv_ioc_count_read(cfq_ioc_count)) { - complete(ioc_gone); - ioc_gone = NULL; - } - spin_unlock(&ioc_gone_lock); - } -} - -static void cfq_cic_free(struct cfq_io_context *cic) -{ - call_rcu(&cic->rcu_head, cfq_cic_free_rcu); -} - -static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic) -{ - unsigned long flags; - unsigned long dead_key = (unsigned long) cic->key; - - BUG_ON(!(dead_key & CIC_DEAD_KEY)); - - spin_lock_irqsave(&ioc->lock, flags); - radix_tree_delete(&ioc->radix_root, dead_key >> CIC_DEAD_INDEX_SHIFT); - hlist_del_rcu(&cic->cic_list); - spin_unlock_irqrestore(&ioc->lock, flags); - - cfq_cic_free(cic); -} - -/* - * Must be called with rcu_read_lock() held or preemption otherwise disabled. - * Only two callers of this - ->dtor() which is called with the rcu_read_lock(), - * and ->trim() which is called with the task lock held - */ -static void cfq_free_io_context(struct io_context *ioc) -{ - /* - * ioc->refcount is zero here, or we are called from elv_unregister(), - * so no more cic's are allowed to be linked into this ioc. So it - * should be ok to iterate over the known list, we will see all cic's - * since no new ones are added. - */ - call_for_each_cic(ioc, cic_free_func); -} - static void cfq_put_cooperator(struct cfq_queue *cfqq) { struct cfq_queue *__cfqq, *next; @@ -2788,27 +2718,17 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) cfq_put_queue(cfqq); } -static void __cfq_exit_single_io_context(struct cfq_data *cfqd, - struct cfq_io_context *cic) +static void cfq_init_icq(struct io_cq *icq) { - struct io_context *ioc = cic->ioc; + struct cfq_io_cq *cic = icq_to_cic(icq); - list_del_init(&cic->queue_list); - - /* - * Make sure dead mark is seen for dead queues - */ - smp_wmb(); - cic->key = cfqd_dead_key(cfqd); + cic->ttime.last_end_request = jiffies; +} - rcu_read_lock(); - if (rcu_dereference(ioc->ioc_data) == cic) { - rcu_read_unlock(); - spin_lock(&ioc->lock); - rcu_assign_pointer(ioc->ioc_data, NULL); - spin_unlock(&ioc->lock); - } else - rcu_read_unlock(); +static void cfq_exit_icq(struct io_cq *icq) +{ + struct cfq_io_cq *cic = icq_to_cic(icq); + struct cfq_data *cfqd = cic_to_cfqd(cic); if (cic->cfqq[BLK_RW_ASYNC]) { cfq_exit_cfqq(cfqd, cic->cfqq[BLK_RW_ASYNC]); @@ -2821,57 +2741,6 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd, } } -static void cfq_exit_single_io_context(struct io_context *ioc, - struct cfq_io_context *cic) -{ - struct cfq_data *cfqd = cic_to_cfqd(cic); - - if (cfqd) { - struct request_queue *q = cfqd->queue; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - - /* - * Ensure we get a fresh copy of the ->key to prevent - * race between exiting task and queue - */ - smp_read_barrier_depends(); - if (cic->key == cfqd) - __cfq_exit_single_io_context(cfqd, cic); - - spin_unlock_irqrestore(q->queue_lock, flags); - } -} - -/* - * The process that ioc belongs to has exited, we need to clean up - * and put the internal structures we have that belongs to that process. - */ -static void cfq_exit_io_context(struct io_context *ioc) -{ - call_for_each_cic(ioc, cfq_exit_single_io_context); -} - -static struct cfq_io_context * -cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) -{ - struct cfq_io_context *cic; - - cic = kmem_cache_alloc_node(cfq_ioc_pool, gfp_mask | __GFP_ZERO, - cfqd->queue->node); - if (cic) { - cic->ttime.last_end_request = jiffies; - INIT_LIST_HEAD(&cic->queue_list); - INIT_HLIST_NODE(&cic->cic_list); - cic->dtor = cfq_free_io_context; - cic->exit = cfq_exit_io_context; - elv_ioc_count_inc(cfq_ioc_count); - } - - return cic; -} - static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc) { struct task_struct *tsk = current; @@ -2914,21 +2783,18 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc) cfq_clear_cfqq_prio_changed(cfqq); } -static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic) +static void changed_ioprio(struct cfq_io_cq *cic) { struct cfq_data *cfqd = cic_to_cfqd(cic); struct cfq_queue *cfqq; - unsigned long flags; if (unlikely(!cfqd)) return; - spin_lock_irqsave(cfqd->queue->queue_lock, flags); - cfqq = cic->cfqq[BLK_RW_ASYNC]; if (cfqq) { struct cfq_queue *new_cfqq; - new_cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic->ioc, + new_cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic->icq.ioc, GFP_ATOMIC); if (new_cfqq) { cic->cfqq[BLK_RW_ASYNC] = new_cfqq; @@ -2939,14 +2805,6 @@ static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic) cfqq = cic->cfqq[BLK_RW_SYNC]; if (cfqq) cfq_mark_cfqq_prio_changed(cfqq); - - spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); -} - -static void cfq_ioc_set_ioprio(struct io_context *ioc) -{ - call_for_each_cic(ioc, changed_ioprio); - ioc->ioprio_changed = 0; } static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, @@ -2970,11 +2828,10 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, } #ifdef CONFIG_CFQ_GROUP_IOSCHED -static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic) +static void changed_cgroup(struct cfq_io_cq *cic) { struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1); struct cfq_data *cfqd = cic_to_cfqd(cic); - unsigned long flags; struct request_queue *q; if (unlikely(!cfqd)) @@ -2982,8 +2839,6 @@ static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic) q = cfqd->queue; - spin_lock_irqsave(q->queue_lock, flags); - if (sync_cfqq) { /* * Drop reference to sync queue. A new sync queue will be @@ -2993,14 +2848,6 @@ static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic) cic_set_cfqq(cic, NULL, 1); cfq_put_queue(sync_cfqq); } - - spin_unlock_irqrestore(q->queue_lock, flags); -} - -static void cfq_ioc_set_cgroup(struct io_context *ioc) -{ - call_for_each_cic(ioc, changed_cgroup); - ioc->cgroup_changed = 0; } #endif /* CONFIG_CFQ_GROUP_IOSCHED */ @@ -3009,7 +2856,7 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc, gfp_t gfp_mask) { struct cfq_queue *cfqq, *new_cfqq = NULL; - struct cfq_io_context *cic; + struct cfq_io_cq *cic; struct cfq_group *cfqg; retry: @@ -3100,160 +2947,6 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc, return cfqq; } -/* - * We drop cfq io contexts lazily, so we may find a dead one. - */ -static void -cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc, - struct cfq_io_context *cic) -{ - unsigned long flags; - - WARN_ON(!list_empty(&cic->queue_list)); - BUG_ON(cic->key != cfqd_dead_key(cfqd)); - - spin_lock_irqsave(&ioc->lock, flags); - - BUG_ON(rcu_dereference_check(ioc->ioc_data, - lockdep_is_held(&ioc->lock)) == cic); - - radix_tree_delete(&ioc->radix_root, cfqd->cic_index); - hlist_del_rcu(&cic->cic_list); - spin_unlock_irqrestore(&ioc->lock, flags); - - cfq_cic_free(cic); -} - -static struct cfq_io_context * -cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc) -{ - struct cfq_io_context *cic; - unsigned long flags; - - if (unlikely(!ioc)) - return NULL; - - rcu_read_lock(); - - /* - * we maintain a last-hit cache, to avoid browsing over the tree - */ - cic = rcu_dereference(ioc->ioc_data); - if (cic && cic->key == cfqd) { - rcu_read_unlock(); - return cic; - } - - do { - cic = radix_tree_lookup(&ioc->radix_root, cfqd->cic_index); - rcu_read_unlock(); - if (!cic) - break; - if (unlikely(cic->key != cfqd)) { - cfq_drop_dead_cic(cfqd, ioc, cic); - rcu_read_lock(); - continue; - } - - spin_lock_irqsave(&ioc->lock, flags); - rcu_assign_pointer(ioc->ioc_data, cic); - spin_unlock_irqrestore(&ioc->lock, flags); - break; - } while (1); - - return cic; -} - -/* - * Add cic into ioc, using cfqd as the search key. This enables us to lookup - * the process specific cfq io context when entered from the block layer. - * Also adds the cic to a per-cfqd list, used when this queue is removed. - */ -static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc, - struct cfq_io_context *cic, gfp_t gfp_mask) -{ - unsigned long flags; - int ret; - - ret = radix_tree_preload(gfp_mask); - if (!ret) { - cic->ioc = ioc; - cic->key = cfqd; - - spin_lock_irqsave(&ioc->lock, flags); - ret = radix_tree_insert(&ioc->radix_root, - cfqd->cic_index, cic); - if (!ret) - hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list); - spin_unlock_irqrestore(&ioc->lock, flags); - - radix_tree_preload_end(); - - if (!ret) { - spin_lock_irqsave(cfqd->queue->queue_lock, flags); - list_add(&cic->queue_list, &cfqd->cic_list); - spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); - } - } - - if (ret && ret != -EEXIST) - printk(KERN_ERR "cfq: cic link failed!\n"); - - return ret; -} - -/* - * Setup general io context and cfq io context. There can be several cfq - * io contexts per general io context, if this process is doing io to more - * than one device managed by cfq. - */ -static struct cfq_io_context * -cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) -{ - struct io_context *ioc = NULL; - struct cfq_io_context *cic; - int ret; - - might_sleep_if(gfp_mask & __GFP_WAIT); - - ioc = get_io_context(gfp_mask, cfqd->queue->node); - if (!ioc) - return NULL; - -retry: - cic = cfq_cic_lookup(cfqd, ioc); - if (cic) - goto out; - - cic = cfq_alloc_io_context(cfqd, gfp_mask); - if (cic == NULL) - goto err; - - ret = cfq_cic_link(cfqd, ioc, cic, gfp_mask); - if (ret == -EEXIST) { - /* someone has linked cic to ioc already */ - cfq_cic_free(cic); - goto retry; - } else if (ret) - goto err_free; - -out: - smp_read_barrier_depends(); - if (unlikely(ioc->ioprio_changed)) - cfq_ioc_set_ioprio(ioc); - -#ifdef CONFIG_CFQ_GROUP_IOSCHED - if (unlikely(ioc->cgroup_changed)) - cfq_ioc_set_cgroup(ioc); -#endif - return cic; -err_free: - cfq_cic_free(cic); -err: - put_io_context(ioc); - return NULL; -} - static void __cfq_update_io_thinktime(struct cfq_ttime *ttime, unsigned long slice_idle) { @@ -3267,7 +2960,7 @@ __cfq_update_io_thinktime(struct cfq_ttime *ttime, unsigned long slice_idle) static void cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_queue *cfqq, - struct cfq_io_context *cic) + struct cfq_io_cq *cic) { if (cfq_cfqq_sync(cfqq)) { __cfq_update_io_thinktime(&cic->ttime, cfqd->cfq_slice_idle); @@ -3305,7 +2998,7 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_queue *cfqq, */ static void cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, - struct cfq_io_context *cic) + struct cfq_io_cq *cic) { int old_idle, enable_idle; @@ -3322,8 +3015,9 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (cfqq->next_rq && (cfqq->next_rq->cmd_flags & REQ_NOIDLE)) enable_idle = 0; - else if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle || - (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq))) + else if (!atomic_read(&cic->icq.ioc->nr_tasks) || + !cfqd->cfq_slice_idle || + (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq))) enable_idle = 0; else if (sample_valid(cic->ttime.ttime_samples)) { if (cic->ttime.ttime_mean > cfqd->cfq_slice_idle) @@ -3423,18 +3117,17 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, */ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - struct cfq_queue *old_cfqq = cfqd->active_queue; - cfq_log_cfqq(cfqd, cfqq, "preempt"); - cfq_slice_expired(cfqd, 1); /* * workload type is changed, don't save slice, otherwise preempt * doesn't happen */ - if (cfqq_type(old_cfqq) != cfqq_type(cfqq)) + if (cfqq_type(cfqd->active_queue) != cfqq_type(cfqq)) cfqq->cfqg->saved_workload_slice = 0; + cfq_slice_expired(cfqd, 1); + /* * Put the new queue at the front of the of the current list, * so we know that it will be selected next. @@ -3455,7 +3148,7 @@ static void cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct request *rq) { - struct cfq_io_context *cic = RQ_CIC(rq); + struct cfq_io_cq *cic = RQ_CIC(rq); cfqd->rq_queued++; if (rq->cmd_flags & REQ_PRIO) @@ -3508,7 +3201,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq) struct cfq_queue *cfqq = RQ_CFQQ(rq); cfq_log_cfqq(cfqd, cfqq, "insert_request"); - cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc); + cfq_init_prio_data(cfqq, RQ_CIC(rq)->icq.ioc); rq_set_fifo_time(rq, jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)]); list_add_tail(&rq->queuelist, &cfqq->fifo); @@ -3558,7 +3251,7 @@ static void cfq_update_hw_tag(struct cfq_data *cfqd) static bool cfq_should_wait_busy(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - struct cfq_io_context *cic = cfqd->active_cic; + struct cfq_io_cq *cic = cfqd->active_cic; /* If the queue already has requests, don't wait */ if (!RB_EMPTY_ROOT(&cfqq->sort_list)) @@ -3695,7 +3388,7 @@ static int cfq_may_queue(struct request_queue *q, int rw) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; - struct cfq_io_context *cic; + struct cfq_io_cq *cic; struct cfq_queue *cfqq; /* @@ -3710,7 +3403,7 @@ static int cfq_may_queue(struct request_queue *q, int rw) cfqq = cic_to_cfqq(cic, rw_is_sync(rw)); if (cfqq) { - cfq_init_prio_data(cfqq, cic->ioc); + cfq_init_prio_data(cfqq, cic->icq.ioc); return __cfq_may_queue(cfqq); } @@ -3731,21 +3424,17 @@ static void cfq_put_request(struct request *rq) BUG_ON(!cfqq->allocated[rw]); cfqq->allocated[rw]--; - put_io_context(RQ_CIC(rq)->ioc); - - rq->elevator_private[0] = NULL; - rq->elevator_private[1] = NULL; - /* Put down rq reference on cfqg */ cfq_put_cfqg(RQ_CFQG(rq)); - rq->elevator_private[2] = NULL; + rq->elv.priv[0] = NULL; + rq->elv.priv[1] = NULL; cfq_put_queue(cfqq); } } static struct cfq_queue * -cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_context *cic, +cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_cq *cic, struct cfq_queue *cfqq) { cfq_log_cfqq(cfqd, cfqq, "merging with queue %p", cfqq->new_cfqq); @@ -3760,7 +3449,7 @@ cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_context *cic, * was the last process referring to said cfqq. */ static struct cfq_queue * -split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq) +split_cfqq(struct cfq_io_cq *cic, struct cfq_queue *cfqq) { if (cfqq_process_refs(cfqq) == 1) { cfqq->pid = current->pid; @@ -3783,25 +3472,29 @@ static int cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) { struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_io_context *cic; + struct cfq_io_cq *cic = icq_to_cic(rq->elv.icq); const int rw = rq_data_dir(rq); const bool is_sync = rq_is_sync(rq); struct cfq_queue *cfqq; - unsigned long flags; might_sleep_if(gfp_mask & __GFP_WAIT); - cic = cfq_get_io_context(cfqd, gfp_mask); - - spin_lock_irqsave(q->queue_lock, flags); + spin_lock_irq(q->queue_lock); - if (!cic) - goto queue_fail; + /* handle changed notifications */ + if (unlikely(cic->icq.changed)) { + if (test_and_clear_bit(ICQ_IOPRIO_CHANGED, &cic->icq.changed)) + changed_ioprio(cic); +#ifdef CONFIG_CFQ_GROUP_IOSCHED + if (test_and_clear_bit(ICQ_CGROUP_CHANGED, &cic->icq.changed)) + changed_cgroup(cic); +#endif + } new_queue: cfqq = cic_to_cfqq(cic, is_sync); if (!cfqq || cfqq == &cfqd->oom_cfqq) { - cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask); + cfqq = cfq_get_queue(cfqd, is_sync, cic->icq.ioc, gfp_mask); cic_set_cfqq(cic, cfqq, is_sync); } else { /* @@ -3827,17 +3520,10 @@ new_queue: cfqq->allocated[rw]++; cfqq->ref++; - rq->elevator_private[0] = cic; - rq->elevator_private[1] = cfqq; - rq->elevator_private[2] = cfq_ref_get_cfqg(cfqq->cfqg); - spin_unlock_irqrestore(q->queue_lock, flags); + rq->elv.priv[0] = cfqq; + rq->elv.priv[1] = cfq_ref_get_cfqg(cfqq->cfqg); + spin_unlock_irq(q->queue_lock); return 0; - -queue_fail: - cfq_schedule_dispatch(cfqd); - spin_unlock_irqrestore(q->queue_lock, flags); - cfq_log(cfqd, "set_request fail"); - return 1; } static void cfq_kick_queue(struct work_struct *work) @@ -3941,14 +3627,6 @@ static void cfq_exit_queue(struct elevator_queue *e) if (cfqd->active_queue) __cfq_slice_expired(cfqd, cfqd->active_queue, 0); - while (!list_empty(&cfqd->cic_list)) { - struct cfq_io_context *cic = list_entry(cfqd->cic_list.next, - struct cfq_io_context, - queue_list); - - __cfq_exit_single_io_context(cfqd, cic); - } - cfq_put_async_queues(cfqd); cfq_release_cfq_groups(cfqd); @@ -3963,10 +3641,6 @@ static void cfq_exit_queue(struct elevator_queue *e) cfq_shutdown_timer_wq(cfqd); - spin_lock(&cic_index_lock); - ida_remove(&cic_index_ida, cfqd->cic_index); - spin_unlock(&cic_index_lock); - /* * Wait for cfqg->blkg->key accessors to exit their grace periods. * Do this wait only if there are other unlinked groups out @@ -3988,24 +3662,6 @@ static void cfq_exit_queue(struct elevator_queue *e) kfree(cfqd); } -static int cfq_alloc_cic_index(void) -{ - int index, error; - - do { - if (!ida_pre_get(&cic_index_ida, GFP_KERNEL)) - return -ENOMEM; - - spin_lock(&cic_index_lock); - error = ida_get_new(&cic_index_ida, &index); - spin_unlock(&cic_index_lock); - if (error && error != -EAGAIN) - return error; - } while (error); - - return index; -} - static void *cfq_init_queue(struct request_queue *q) { struct cfq_data *cfqd; @@ -4013,23 +3669,9 @@ static void *cfq_init_queue(struct request_queue *q) struct cfq_group *cfqg; struct cfq_rb_root *st; - i = cfq_alloc_cic_index(); - if (i < 0) - return NULL; - cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node); - if (!cfqd) { - spin_lock(&cic_index_lock); - ida_remove(&cic_index_ida, i); - spin_unlock(&cic_index_lock); + if (!cfqd) return NULL; - } - - /* - * Don't need take queue_lock in the routine, since we are - * initializing the ioscheduler, and nobody is using cfqd - */ - cfqd->cic_index = i; /* Init root service tree */ cfqd->grp_service_tree = CFQ_RB_ROOT; @@ -4055,11 +3697,6 @@ static void *cfq_init_queue(struct request_queue *q) if (blkio_alloc_blkg_stats(&cfqg->blkg)) { kfree(cfqg); - - spin_lock(&cic_index_lock); - ida_remove(&cic_index_ida, cfqd->cic_index); - spin_unlock(&cic_index_lock); - kfree(cfqd); return NULL; } @@ -4091,8 +3728,6 @@ static void *cfq_init_queue(struct request_queue *q) cfqd->oom_cfqq.ref++; cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, &cfqd->root_group); - INIT_LIST_HEAD(&cfqd->cic_list); - cfqd->queue = q; init_timer(&cfqd->idle_slice_timer); @@ -4121,34 +3756,6 @@ static void *cfq_init_queue(struct request_queue *q) return cfqd; } -static void cfq_slab_kill(void) -{ - /* - * Caller already ensured that pending RCU callbacks are completed, - * so we should have no busy allocations at this point. - */ - if (cfq_pool) - kmem_cache_destroy(cfq_pool); - if (cfq_ioc_pool) - kmem_cache_destroy(cfq_ioc_pool); -} - -static int __init cfq_slab_setup(void) -{ - cfq_pool = KMEM_CACHE(cfq_queue, 0); - if (!cfq_pool) - goto fail; - - cfq_ioc_pool = KMEM_CACHE(cfq_io_context, 0); - if (!cfq_ioc_pool) - goto fail; - - return 0; -fail: - cfq_slab_kill(); - return -ENOMEM; -} - /* * sysfs parts below --> */ @@ -4254,15 +3861,18 @@ static struct elevator_type iosched_cfq = { .elevator_completed_req_fn = cfq_completed_request, .elevator_former_req_fn = elv_rb_former_request, .elevator_latter_req_fn = elv_rb_latter_request, + .elevator_init_icq_fn = cfq_init_icq, + .elevator_exit_icq_fn = cfq_exit_icq, .elevator_set_req_fn = cfq_set_request, .elevator_put_req_fn = cfq_put_request, .elevator_may_queue_fn = cfq_may_queue, .elevator_init_fn = cfq_init_queue, .elevator_exit_fn = cfq_exit_queue, - .trim = cfq_free_io_context, }, + .icq_size = sizeof(struct cfq_io_cq), + .icq_align = __alignof__(struct cfq_io_cq), .elevator_attrs = cfq_attrs, - .elevator_name = "cfq", + .elevator_name = "cfq", .elevator_owner = THIS_MODULE, }; @@ -4280,6 +3890,8 @@ static struct blkio_policy_type blkio_policy_cfq; static int __init cfq_init(void) { + int ret; + /* * could be 0 on HZ < 1000 setups */ @@ -4294,10 +3906,16 @@ static int __init cfq_init(void) #else cfq_group_idle = 0; #endif - if (cfq_slab_setup()) + cfq_pool = KMEM_CACHE(cfq_queue, 0); + if (!cfq_pool) return -ENOMEM; - elv_register(&iosched_cfq); + ret = elv_register(&iosched_cfq); + if (ret) { + kmem_cache_destroy(cfq_pool); + return ret; + } + blkio_policy_register(&blkio_policy_cfq); return 0; @@ -4305,21 +3923,9 @@ static int __init cfq_init(void) static void __exit cfq_exit(void) { - DECLARE_COMPLETION_ONSTACK(all_gone); blkio_policy_unregister(&blkio_policy_cfq); elv_unregister(&iosched_cfq); - ioc_gone = &all_gone; - /* ioc_gone's update must be visible before reading ioc_count */ - smp_wmb(); - - /* - * this also protects us from entering cfq_slab_kill() with - * pending RCU callbacks - */ - if (elv_ioc_count_read(cfq_ioc_count)) - wait_for_completion(&all_gone); - ida_destroy(&cic_index_ida); - cfq_slab_kill(); + kmem_cache_destroy(cfq_pool); } module_init(cfq_init); diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c index 7b725020823c..7c668c8a6f95 100644 --- a/block/compat_ioctl.c +++ b/block/compat_ioctl.c @@ -719,6 +719,9 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) case BLKSECTGET: return compat_put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev))); + case BLKROTATIONAL: + return compat_put_ushort(arg, + !blk_queue_nonrot(bdev_get_queue(bdev))); case BLKRASET: /* compatible, but no compat_ptr (!) */ case BLKFRASET: if (!capable(CAP_SYS_ADMIN)) diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index c644137d9cd6..7bf12d793fcd 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -448,9 +448,7 @@ static struct elevator_type iosched_deadline = { static int __init deadline_init(void) { - elv_register(&iosched_deadline); - - return 0; + return elv_register(&iosched_deadline); } static void __exit deadline_exit(void) diff --git a/block/elevator.c b/block/elevator.c index 66343d6917d0..91e18f8af9be 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -61,8 +61,8 @@ static int elv_iosched_allow_merge(struct request *rq, struct bio *bio) struct request_queue *q = rq->q; struct elevator_queue *e = q->elevator; - if (e->ops->elevator_allow_merge_fn) - return e->ops->elevator_allow_merge_fn(q, rq, bio); + if (e->type->ops.elevator_allow_merge_fn) + return e->type->ops.elevator_allow_merge_fn(q, rq, bio); return 1; } @@ -168,17 +168,13 @@ static struct elevator_type *elevator_get(const char *name) return e; } -static void *elevator_init_queue(struct request_queue *q, - struct elevator_queue *eq) +static int elevator_init_queue(struct request_queue *q, + struct elevator_queue *eq) { - return eq->ops->elevator_init_fn(q); -} - -static void elevator_attach(struct request_queue *q, struct elevator_queue *eq, - void *data) -{ - q->elevator = eq; - eq->elevator_data = data; + eq->elevator_data = eq->type->ops.elevator_init_fn(q); + if (eq->elevator_data) + return 0; + return -ENOMEM; } static char chosen_elevator[ELV_NAME_MAX]; @@ -207,8 +203,7 @@ static struct elevator_queue *elevator_alloc(struct request_queue *q, if (unlikely(!eq)) goto err; - eq->ops = &e->ops; - eq->elevator_type = e; + eq->type = e; kobject_init(&eq->kobj, &elv_ktype); mutex_init(&eq->sysfs_lock); @@ -232,7 +227,7 @@ static void elevator_release(struct kobject *kobj) struct elevator_queue *e; e = container_of(kobj, struct elevator_queue, kobj); - elevator_put(e->elevator_type); + elevator_put(e->type); kfree(e->hash); kfree(e); } @@ -241,7 +236,7 @@ int elevator_init(struct request_queue *q, char *name) { struct elevator_type *e = NULL; struct elevator_queue *eq; - void *data; + int err; if (unlikely(q->elevator)) return 0; @@ -278,13 +273,13 @@ int elevator_init(struct request_queue *q, char *name) if (!eq) return -ENOMEM; - data = elevator_init_queue(q, eq); - if (!data) { + err = elevator_init_queue(q, eq); + if (err) { kobject_put(&eq->kobj); - return -ENOMEM; + return err; } - elevator_attach(q, eq, data); + q->elevator = eq; return 0; } EXPORT_SYMBOL(elevator_init); @@ -292,9 +287,8 @@ EXPORT_SYMBOL(elevator_init); void elevator_exit(struct elevator_queue *e) { mutex_lock(&e->sysfs_lock); - if (e->ops->elevator_exit_fn) - e->ops->elevator_exit_fn(e); - e->ops = NULL; + if (e->type->ops.elevator_exit_fn) + e->type->ops.elevator_exit_fn(e); mutex_unlock(&e->sysfs_lock); kobject_put(&e->kobj); @@ -504,8 +498,8 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) return ELEVATOR_BACK_MERGE; } - if (e->ops->elevator_merge_fn) - return e->ops->elevator_merge_fn(q, req, bio); + if (e->type->ops.elevator_merge_fn) + return e->type->ops.elevator_merge_fn(q, req, bio); return ELEVATOR_NO_MERGE; } @@ -548,8 +542,8 @@ void elv_merged_request(struct request_queue *q, struct request *rq, int type) { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_merged_fn) - e->ops->elevator_merged_fn(q, rq, type); + if (e->type->ops.elevator_merged_fn) + e->type->ops.elevator_merged_fn(q, rq, type); if (type == ELEVATOR_BACK_MERGE) elv_rqhash_reposition(q, rq); @@ -563,8 +557,8 @@ void elv_merge_requests(struct request_queue *q, struct request *rq, struct elevator_queue *e = q->elevator; const int next_sorted = next->cmd_flags & REQ_SORTED; - if (next_sorted && e->ops->elevator_merge_req_fn) - e->ops->elevator_merge_req_fn(q, rq, next); + if (next_sorted && e->type->ops.elevator_merge_req_fn) + e->type->ops.elevator_merge_req_fn(q, rq, next); elv_rqhash_reposition(q, rq); @@ -581,8 +575,8 @@ void elv_bio_merged(struct request_queue *q, struct request *rq, { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_bio_merged_fn) - e->ops->elevator_bio_merged_fn(q, rq, bio); + if (e->type->ops.elevator_bio_merged_fn) + e->type->ops.elevator_bio_merged_fn(q, rq, bio); } void elv_requeue_request(struct request_queue *q, struct request *rq) @@ -608,12 +602,12 @@ void elv_drain_elevator(struct request_queue *q) lockdep_assert_held(q->queue_lock); - while (q->elevator->ops->elevator_dispatch_fn(q, 1)) + while (q->elevator->type->ops.elevator_dispatch_fn(q, 1)) ; if (q->nr_sorted && printed++ < 10) { printk(KERN_ERR "%s: forced dispatching is broken " "(nr_sorted=%u), please report this\n", - q->elevator->elevator_type->elevator_name, q->nr_sorted); + q->elevator->type->elevator_name, q->nr_sorted); } } @@ -702,7 +696,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where) * rq cannot be accessed after calling * elevator_add_req_fn. */ - q->elevator->ops->elevator_add_req_fn(q, rq); + q->elevator->type->ops.elevator_add_req_fn(q, rq); break; case ELEVATOR_INSERT_FLUSH: @@ -731,8 +725,8 @@ struct request *elv_latter_request(struct request_queue *q, struct request *rq) { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_latter_req_fn) - return e->ops->elevator_latter_req_fn(q, rq); + if (e->type->ops.elevator_latter_req_fn) + return e->type->ops.elevator_latter_req_fn(q, rq); return NULL; } @@ -740,8 +734,8 @@ struct request *elv_former_request(struct request_queue *q, struct request *rq) { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_former_req_fn) - return e->ops->elevator_former_req_fn(q, rq); + if (e->type->ops.elevator_former_req_fn) + return e->type->ops.elevator_former_req_fn(q, rq); return NULL; } @@ -749,10 +743,8 @@ int elv_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_set_req_fn) - return e->ops->elevator_set_req_fn(q, rq, gfp_mask); - - rq->elevator_private[0] = NULL; + if (e->type->ops.elevator_set_req_fn) + return e->type->ops.elevator_set_req_fn(q, rq, gfp_mask); return 0; } @@ -760,16 +752,16 @@ void elv_put_request(struct request_queue *q, struct request *rq) { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_put_req_fn) - e->ops->elevator_put_req_fn(rq); + if (e->type->ops.elevator_put_req_fn) + e->type->ops.elevator_put_req_fn(rq); } int elv_may_queue(struct request_queue *q, int rw) { struct elevator_queue *e = q->elevator; - if (e->ops->elevator_may_queue_fn) - return e->ops->elevator_may_queue_fn(q, rw); + if (e->type->ops.elevator_may_queue_fn) + return e->type->ops.elevator_may_queue_fn(q, rw); return ELV_MQUEUE_MAY; } @@ -804,8 +796,8 @@ void elv_completed_request(struct request_queue *q, struct request *rq) if (blk_account_rq(rq)) { q->in_flight[rq_is_sync(rq)]--; if ((rq->cmd_flags & REQ_SORTED) && - e->ops->elevator_completed_req_fn) - e->ops->elevator_completed_req_fn(q, rq); + e->type->ops.elevator_completed_req_fn) + e->type->ops.elevator_completed_req_fn(q, rq); } } @@ -823,7 +815,7 @@ elv_attr_show(struct kobject *kobj, struct attribute *attr, char *page) e = container_of(kobj, struct elevator_queue, kobj); mutex_lock(&e->sysfs_lock); - error = e->ops ? entry->show(e, page) : -ENOENT; + error = e->type ? entry->show(e, page) : -ENOENT; mutex_unlock(&e->sysfs_lock); return error; } @@ -841,7 +833,7 @@ elv_attr_store(struct kobject *kobj, struct attribute *attr, e = container_of(kobj, struct elevator_queue, kobj); mutex_lock(&e->sysfs_lock); - error = e->ops ? entry->store(e, page, length) : -ENOENT; + error = e->type ? entry->store(e, page, length) : -ENOENT; mutex_unlock(&e->sysfs_lock); return error; } @@ -856,14 +848,13 @@ static struct kobj_type elv_ktype = { .release = elevator_release, }; -int elv_register_queue(struct request_queue *q) +int __elv_register_queue(struct request_queue *q, struct elevator_queue *e) { - struct elevator_queue *e = q->elevator; int error; error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); if (!error) { - struct elv_fs_entry *attr = e->elevator_type->elevator_attrs; + struct elv_fs_entry *attr = e->type->elevator_attrs; if (attr) { while (attr->attr.name) { if (sysfs_create_file(&e->kobj, &attr->attr)) @@ -876,31 +867,55 @@ int elv_register_queue(struct request_queue *q) } return error; } -EXPORT_SYMBOL(elv_register_queue); -static void __elv_unregister_queue(struct elevator_queue *e) +int elv_register_queue(struct request_queue *q) { - kobject_uevent(&e->kobj, KOBJ_REMOVE); - kobject_del(&e->kobj); - e->registered = 0; + return __elv_register_queue(q, q->elevator); } +EXPORT_SYMBOL(elv_register_queue); void elv_unregister_queue(struct request_queue *q) { - if (q) - __elv_unregister_queue(q->elevator); + if (q) { + struct elevator_queue *e = q->elevator; + + kobject_uevent(&e->kobj, KOBJ_REMOVE); + kobject_del(&e->kobj); + e->registered = 0; + } } EXPORT_SYMBOL(elv_unregister_queue); -void elv_register(struct elevator_type *e) +int elv_register(struct elevator_type *e) { char *def = ""; + /* create icq_cache if requested */ + if (e->icq_size) { + if (WARN_ON(e->icq_size < sizeof(struct io_cq)) || + WARN_ON(e->icq_align < __alignof__(struct io_cq))) + return -EINVAL; + + snprintf(e->icq_cache_name, sizeof(e->icq_cache_name), + "%s_io_cq", e->elevator_name); + e->icq_cache = kmem_cache_create(e->icq_cache_name, e->icq_size, + e->icq_align, 0, NULL); + if (!e->icq_cache) + return -ENOMEM; + } + + /* register, don't allow duplicate names */ spin_lock(&elv_list_lock); - BUG_ON(elevator_find(e->elevator_name)); + if (elevator_find(e->elevator_name)) { + spin_unlock(&elv_list_lock); + if (e->icq_cache) + kmem_cache_destroy(e->icq_cache); + return -EBUSY; + } list_add_tail(&e->list, &elv_list); spin_unlock(&elv_list_lock); + /* print pretty message */ if (!strcmp(e->elevator_name, chosen_elevator) || (!*chosen_elevator && !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED))) @@ -908,30 +923,26 @@ void elv_register(struct elevator_type *e) printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name, def); + return 0; } EXPORT_SYMBOL_GPL(elv_register); void elv_unregister(struct elevator_type *e) { - struct task_struct *g, *p; + /* unregister */ + spin_lock(&elv_list_lock); + list_del_init(&e->list); + spin_unlock(&elv_list_lock); /* - * Iterate every thread in the process to remove the io contexts. + * Destroy icq_cache if it exists. icq's are RCU managed. Make + * sure all RCU operations are complete before proceeding. */ - if (e->ops.trim) { - read_lock(&tasklist_lock); - do_each_thread(g, p) { - task_lock(p); - if (p->io_context) - e->ops.trim(p->io_context); - task_unlock(p); - } while_each_thread(g, p); - read_unlock(&tasklist_lock); + if (e->icq_cache) { + rcu_barrier(); + kmem_cache_destroy(e->icq_cache); + e->icq_cache = NULL; } - - spin_lock(&elv_list_lock); - list_del_init(&e->list); - spin_unlock(&elv_list_lock); } EXPORT_SYMBOL_GPL(elv_unregister); @@ -944,54 +955,41 @@ EXPORT_SYMBOL_GPL(elv_unregister); static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) { struct elevator_queue *old_elevator, *e; - void *data; int err; - /* - * Allocate new elevator - */ + /* allocate new elevator */ e = elevator_alloc(q, new_e); if (!e) return -ENOMEM; - data = elevator_init_queue(q, e); - if (!data) { + err = elevator_init_queue(q, e); + if (err) { kobject_put(&e->kobj); - return -ENOMEM; + return err; } - /* - * Turn on BYPASS and drain all requests w/ elevator private data - */ + /* turn on BYPASS and drain all requests w/ elevator private data */ elv_quiesce_start(q); - /* - * Remember old elevator. - */ - old_elevator = q->elevator; - - /* - * attach and start new elevator - */ - spin_lock_irq(q->queue_lock); - elevator_attach(q, e, data); - spin_unlock_irq(q->queue_lock); - - if (old_elevator->registered) { - __elv_unregister_queue(old_elevator); - - err = elv_register_queue(q); + /* unregister old queue, register new one and kill old elevator */ + if (q->elevator->registered) { + elv_unregister_queue(q); + err = __elv_register_queue(q, e); if (err) goto fail_register; } - /* - * finally exit old elevator and turn off BYPASS. - */ + /* done, clear io_cq's, switch elevators and turn off BYPASS */ + spin_lock_irq(q->queue_lock); + ioc_clear_queue(q); + old_elevator = q->elevator; + q->elevator = e; + spin_unlock_irq(q->queue_lock); + elevator_exit(old_elevator); elv_quiesce_end(q); - blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name); + blk_add_trace_msg(q, "elv switch: %s", e->type->elevator_name); return 0; @@ -1001,7 +999,6 @@ fail_register: * one again (along with re-adding the sysfs dir) */ elevator_exit(e); - q->elevator = old_elevator; elv_register_queue(q); elv_quiesce_end(q); @@ -1026,7 +1023,7 @@ int elevator_change(struct request_queue *q, const char *name) return -EINVAL; } - if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) { + if (!strcmp(elevator_name, q->elevator->type->elevator_name)) { elevator_put(e); return 0; } @@ -1061,7 +1058,7 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name) if (!q->elevator || !blk_queue_stackable(q)) return sprintf(name, "none\n"); - elv = e->elevator_type; + elv = e->type; spin_lock(&elv_list_lock); list_for_each_entry(__e, &elv_list, list) { diff --git a/block/genhd.c b/block/genhd.c index 83e7c04015e1..23b4f7063322 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -614,7 +614,7 @@ void add_disk(struct gendisk *disk) * Take an extra ref on queue which will be put on disk_release() * so that it sticks around as long as @disk is there. */ - WARN_ON_ONCE(blk_get_queue(disk->queue)); + WARN_ON_ONCE(!blk_get_queue(disk->queue)); retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj, "bdi"); diff --git a/block/ioctl.c b/block/ioctl.c index 4828fa349813..ba15b2dbfb98 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -296,6 +296,8 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, return put_uint(arg, bdev_discard_zeroes_data(bdev)); case BLKSECTGET: return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev))); + case BLKROTATIONAL: + return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev))); case BLKRASET: case BLKFRASET: if(!capable(CAP_SYS_ADMIN)) diff --git a/block/noop-iosched.c b/block/noop-iosched.c index 06389e9ef96d..413a0b1d788c 100644 --- a/block/noop-iosched.c +++ b/block/noop-iosched.c @@ -94,9 +94,7 @@ static struct elevator_type elevator_noop = { static int __init noop_init(void) { - elv_register(&elevator_noop); - - return 0; + return elv_register(&elevator_noop); } static void __exit noop_exit(void) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index fbdf0d802ec4..260fa80ef575 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -24,6 +24,7 @@ #include <linux/capability.h> #include <linux/completion.h> #include <linux/cdrom.h> +#include <linux/ratelimit.h> #include <linux/slab.h> #include <linux/times.h> #include <asm/uaccess.h> @@ -690,6 +691,57 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod } EXPORT_SYMBOL(scsi_cmd_ioctl); +int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) +{ + if (bd && bd == bd->bd_contains) + return 0; + + /* Actually none of these is particularly useful on a partition, + * but they are safe. + */ + switch (cmd) { + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: + case SCSI_IOCTL_GET_PCI: + case SCSI_IOCTL_PROBE_HOST: + case SG_GET_VERSION_NUM: + case SG_SET_TIMEOUT: + case SG_GET_TIMEOUT: + case SG_GET_RESERVED_SIZE: + case SG_SET_RESERVED_SIZE: + case SG_EMULATED_HOST: + return 0; + case CDROM_GET_CAPABILITY: + /* Keep this until we remove the printk below. udev sends it + * and we do not want to spam dmesg about it. CD-ROMs do + * not have partitions, so we get here only for disks. + */ + return -ENOIOCTLCMD; + default: + break; + } + + /* In particular, rule out all resets and host-specific ioctls. */ + printk_ratelimited(KERN_WARNING + "%s: sending ioctl %x to a partition!\n", current->comm, cmd); + + return capable(CAP_SYS_RAWIO) ? 0 : -ENOIOCTLCMD; +} +EXPORT_SYMBOL(scsi_verify_blk_ioctl); + +int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode, + unsigned int cmd, void __user *arg) +{ + int ret; + + ret = scsi_verify_blk_ioctl(bd, cmd); + if (ret < 0) + return ret; + + return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg); +} +EXPORT_SYMBOL(scsi_cmd_blk_ioctl); + static int __init blk_scsi_ioctl_init(void) { blk_set_cmd_filter_defaults(&blk_default_cmd_filter); diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 3ba6ef508869..16f8693cc147 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -382,7 +382,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) type -= CRYPTO_MSG_BASE; link = &crypto_dispatch[type]; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) && diff --git a/drivers/Makefile b/drivers/Makefile index 1b3142127bf5..c07be024b962 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -97,7 +97,7 @@ obj-$(CONFIG_EISA) += eisa/ obj-y += lguest/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_CPU_IDLE) += cpuidle/ -obj-$(CONFIG_MMC) += mmc/ +obj-y += mmc/ obj-$(CONFIG_MEMSTICK) += memstick/ obj-y += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index cb423f5aef24..c339a0880e6e 100644 --- a/drivers/accessibility/braille/braille_console.c +++ b/drivers/accessibility/braille/braille_console.c @@ -44,7 +44,7 @@ MODULE_LICENSE("GPL"); */ /* Emit various sounds */ -static int sound; +static bool sound; module_param(sound, bool, 0); MODULE_PARM_DESC(sound, "emit sounds"); diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index ecb26b4f29a0..c07f44f05f9d 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -20,11 +20,12 @@ obj-y += acpi.o \ # All the builtin files are in the "acpi." module_param namespace. acpi-y += osl.o utils.o reboot.o acpi-y += atomicio.o +acpi-y += nvs.o # sleep related files acpi-y += wakeup.o acpi-y += sleep.o -acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o +acpi-$(CONFIG_ACPI_SLEEP) += proc.o # diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 301bd2d388ad..0ca208b6dcf0 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -8,41 +8,151 @@ ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT # use acpi.o to put all files here into acpi.o modparam namespace obj-y += acpi.o -acpi-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ - dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ - dsinit.o dsargs.o dscontrol.o dswload2.o +acpi-y := \ + dsargs.o \ + dscontrol.o \ + dsfield.o \ + dsinit.o \ + dsmethod.o \ + dsmthdat.o \ + dsobject.o \ + dsopcode.o \ + dsutils.o \ + dswexec.o \ + dswload.o \ + dswload2.o \ + dswscope.o \ + dswstate.o -acpi-y += evevent.o evregion.o evsci.o evxfevnt.o \ - evmisc.o evrgnini.o evxface.o evxfregn.o \ - evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o evxfgpe.o evglock.o +acpi-y += \ + evevent.o \ + evgpe.o \ + evgpeblk.o \ + evgpeinit.o \ + evgpeutil.o \ + evglock.o \ + evmisc.o \ + evregion.o \ + evrgnini.o \ + evsci.o \ + evxface.o \ + evxfevnt.o \ + evxfgpe.o \ + evxfregn.o -acpi-y += exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\ - exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\ - excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \ - exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o exdebug.o +acpi-y += \ + exconfig.o \ + exconvrt.o \ + excreate.o \ + exdebug.o \ + exdump.o \ + exfield.o \ + exfldio.o \ + exmutex.o \ + exnames.o \ + exoparg1.o \ + exoparg2.o \ + exoparg3.o \ + exoparg6.o \ + exprep.o \ + exmisc.o \ + exregion.o \ + exresnte.o \ + exresolv.o \ + exresop.o \ + exstore.o \ + exstoren.o \ + exstorob.o \ + exsystem.o \ + exutils.o -acpi-y += hwacpi.o hwgpe.o hwregs.o hwsleep.o hwxface.o hwvalid.o hwpci.o +acpi-y += \ + hwacpi.o \ + hwgpe.o \ + hwpci.o \ + hwregs.o \ + hwsleep.o \ + hwvalid.o \ + hwxface.o acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o -acpi-y += nsaccess.o nsload.o nssearch.o nsxfeval.o \ - nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \ - nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \ - nsparse.o nspredef.o nsrepair.o nsrepair2.o +acpi-y += \ + nsaccess.o \ + nsalloc.o \ + nsdump.o \ + nseval.o \ + nsinit.o \ + nsload.o \ + nsnames.o \ + nsobject.o \ + nsparse.o \ + nspredef.o \ + nsrepair.o \ + nsrepair2.o \ + nssearch.o \ + nsutils.o \ + nswalk.o \ + nsxfeval.o \ + nsxfname.o \ + nsxfobj.o acpi-$(ACPI_FUTURE_USAGE) += nsdumpdv.o -acpi-y += psargs.o psparse.o psloop.o pstree.o pswalk.o \ - psopcode.o psscope.o psutils.o psxface.o +acpi-y += \ + psargs.o \ + psloop.o \ + psopcode.o \ + psparse.o \ + psscope.o \ + pstree.o \ + psutils.o \ + pswalk.o \ + psxface.o -acpi-y += rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \ - rscalc.o rsirq.o rsmemory.o rsutils.o +acpi-y += \ + rsaddr.o \ + rscalc.o \ + rscreate.o \ + rsinfo.o \ + rsio.o \ + rsirq.o \ + rslist.o \ + rsmemory.o \ + rsmisc.o \ + rsserial.o \ + rsutils.o \ + rsxface.o acpi-$(ACPI_FUTURE_USAGE) += rsdump.o -acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o +acpi-y += \ + tbfadt.o \ + tbfind.o \ + tbinstal.o \ + tbutils.o \ + tbxface.o \ + tbxfroot.o -acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ - utcopy.o utdelete.o utglobal.o utmath.o utobject.o \ - utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o \ - utosi.o utxferror.o utdecode.o +acpi-y += \ + utaddress.o \ + utalloc.o \ + utcopy.o \ + utdebug.o \ + utdecode.o \ + utdelete.o \ + uteval.o \ + utglobal.o \ + utids.o \ + utinit.o \ + utlock.o \ + utmath.o \ + utmisc.o \ + utmutex.o \ + utobject.o \ + utosi.o \ + utresrc.o \ + utstate.o \ + utxface.o \ + utxferror.o \ + utxfmutex.o diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index e0ba17f0a7c8..a44bd424f9f4 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index f895a244ca7e..1f30af613e87 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -123,6 +123,10 @@ #define ACPI_MAX_SLEEP 2000 /* Two seconds */ +/* Address Range lists are per-space_id (Memory and I/O only) */ + +#define ACPI_ADDRESS_RANGE_MAX 2 + /****************************************************************************** * * ACPI Specification constants (Do not change unless the specification changes) @@ -202,9 +206,10 @@ #define ACPI_RSDP_CHECKSUM_LENGTH 20 #define ACPI_RSDP_XCHECKSUM_LENGTH 36 -/* SMBus and IPMI bidirectional buffer size */ +/* SMBus, GSBus and IPMI bidirectional buffer size */ #define ACPI_SMBUS_BUFFER_SIZE 34 +#define ACPI_GSBUS_BUFFER_SIZE 34 #define ACPI_IPMI_BUFFER_SIZE 66 /* _sx_d and _sx_w control methods */ diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index eb0b1f8dee6d..deaa81979561 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 2d1b7ffa377a..5935ba6707e2 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index bea3b4899183..c53caa521a30 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -162,6 +162,7 @@ acpi_status acpi_ev_initialize_op_regions(void); acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + union acpi_operand_object *field_obj, u32 function, u32 region_offset, u32 bit_width, u64 *value); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 76dc02f15574..2853f7673f3b 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -108,7 +108,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); /* * Optionally enable output from the AML Debug Object. */ -u32 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); +bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); /* * Optionally copy the entire DSDT to local memory (instead of simply @@ -140,8 +140,19 @@ u32 acpi_gbl_trace_flags; acpi_name acpi_gbl_trace_method_name; u8 acpi_gbl_system_awake_and_running; +/* + * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning + * that the ACPI hardware is no longer required. A flag in the FADT indicates + * a reduced HW machine, and that flag is duplicated here for convenience. + */ +u8 acpi_gbl_reduced_hardware; + #endif +/* Do not disassemble buffers to resource descriptors */ + +ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE); + /***************************************************************************** * * Debug support @@ -207,7 +218,7 @@ ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock; /***************************************************************************** * - * Mutual exlusion within ACPICA subsystem + * Mutual exclusion within ACPICA subsystem * ****************************************************************************/ @@ -295,6 +306,8 @@ ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; ACPI_EXTERN u8 acpi_gbl_events_initialized; ACPI_EXTERN u8 acpi_gbl_osi_data; ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces; +ACPI_EXTERN struct acpi_address_range + *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX]; #ifndef DEFINE_ACPI_GLOBALS diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index e7213beaafc7..677793e938f5 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 3731e1c34b83..eb308635da72 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -468,6 +468,8 @@ void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id); void acpi_ex_integer_to_string(char *dest, u64 value); +u8 acpi_is_valid_space_id(u8 space_id); + /* * exregion - default op_region handlers */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 5552125d8340..3f24068837d5 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,7 +53,7 @@ typedef u32 acpi_mutex_handle; /* Total number of aml opcodes defined */ -#define AML_NUM_OPCODES 0x7F +#define AML_NUM_OPCODES 0x81 /* Forward declarations */ @@ -249,12 +249,16 @@ struct acpi_create_field_info { struct acpi_namespace_node *field_node; struct acpi_namespace_node *register_node; struct acpi_namespace_node *data_register_node; + struct acpi_namespace_node *connection_node; + u8 *resource_buffer; u32 bank_value; u32 field_bit_position; u32 field_bit_length; + u16 resource_length; u8 field_flags; u8 attribute; u8 field_type; + u8 access_length; }; typedef @@ -315,7 +319,8 @@ struct acpi_name_info { /* * Used for ACPI_PTYPE1_FIXED, ACPI_PTYPE1_VAR, ACPI_PTYPE2, - * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT + * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT, + * ACPI_PTYPE2_FIX_VAR */ struct acpi_package_info { u8 type; @@ -625,6 +630,15 @@ union acpi_generic_state { typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state); +/* Address Range info block */ + +struct acpi_address_range { + struct acpi_address_range *next; + struct acpi_namespace_node *region_node; + acpi_physical_address start_address; + acpi_physical_address end_address; +}; + /***************************************************************************** * * Parser typedefs and structs @@ -951,7 +965,7 @@ struct acpi_port_info { #define ACPI_RESOURCE_NAME_END_DEPENDENT 0x38 #define ACPI_RESOURCE_NAME_IO 0x40 #define ACPI_RESOURCE_NAME_FIXED_IO 0x48 -#define ACPI_RESOURCE_NAME_RESERVED_S1 0x50 +#define ACPI_RESOURCE_NAME_FIXED_DMA 0x50 #define ACPI_RESOURCE_NAME_RESERVED_S2 0x58 #define ACPI_RESOURCE_NAME_RESERVED_S3 0x60 #define ACPI_RESOURCE_NAME_RESERVED_S4 0x68 @@ -973,7 +987,9 @@ struct acpi_port_info { #define ACPI_RESOURCE_NAME_EXTENDED_IRQ 0x89 #define ACPI_RESOURCE_NAME_ADDRESS64 0x8A #define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 0x8B -#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8B +#define ACPI_RESOURCE_NAME_GPIO 0x8C +#define ACPI_RESOURCE_NAME_SERIAL_BUS 0x8E +#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8E /***************************************************************************** * diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index b7491ee1fba6..ef338a96f5b2 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 79a598c67fe3..2c9e0f049523 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 1055769f2f01..c065078ca83b 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -254,6 +254,7 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; u32 base_byte_offset; /* Byte offset within containing object */\ u32 value; /* Value to store into the Bank or Index register */\ u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\ + u8 access_length; /* For serial regions/fields */ struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ @@ -261,7 +262,9 @@ struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and }; struct acpi_object_region_field { - ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing op_region object */ + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length; + union acpi_operand_object *region_obj; /* Containing op_region object */ + u8 *resource_buffer; /* resource_template for serial regions/fields */ }; struct acpi_object_bank_field { @@ -358,6 +361,7 @@ typedef enum { */ struct acpi_object_extra { ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */ + struct acpi_namespace_node *scope_node; void *region_context; /* Region-specific data */ u8 *aml_start; u32 aml_length; diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index bb2ccfad7376..9440d053fbb3 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -93,6 +93,7 @@ #define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME) +#define ARGP_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_CONTINUE_OP ARG_NONE #define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) #define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) @@ -164,6 +165,7 @@ #define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG) #define ARGP_REVISION_OP ARG_NONE #define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST) +#define ARGP_SERIALFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME) @@ -223,6 +225,7 @@ #define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF) #define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) #define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) +#define ARGI_CONNECTFIELD_OP ARGI_INVALID_OPCODE #define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE #define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET) #define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) @@ -294,6 +297,7 @@ #define ARGI_RETURN_OP ARGI_INVALID_OPCODE #define ARGI_REVISION_OP ARG_NONE #define ARGI_SCOPE_OP ARGI_INVALID_OPCODE +#define ARGI_SERIALFIELD_OP ARGI_INVALID_OPCODE #define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT) diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 5ea1e06afa20..b725d780d34d 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index c445cca490ea..bbb34c9be4e8 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -94,6 +94,14 @@ * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length * (Used for _ART, _FPS) * + * ACPI_PTYPE2_FIX_VAR: Each subpackage consists of some fixed-length elements + * followed by an optional element + * object type + * count + * object type + * count = 0 (optional) + * (Used for _DLM) + * *****************************************************************************/ enum acpi_return_package_types { @@ -105,7 +113,8 @@ enum acpi_return_package_types { ACPI_PTYPE2_PKG_COUNT = 6, ACPI_PTYPE2_FIXED = 7, ACPI_PTYPE2_MIN = 8, - ACPI_PTYPE2_REV_FIXED = 9 + ACPI_PTYPE2_REV_FIXED = 9, + ACPI_PTYPE2_FIX_VAR = 10 }; #ifdef ACPI_CREATE_PREDEFINED_TABLE @@ -154,6 +163,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_AC8", 0, ACPI_RTYPE_INTEGER}}, {{"_AC9", 0, ACPI_RTYPE_INTEGER}}, {{"_ADR", 0, ACPI_RTYPE_INTEGER}}, + {{"_AEI", 0, ACPI_RTYPE_BUFFER}}, {{"_AL0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, @@ -229,6 +239,13 @@ static const union acpi_predefined_info predefined_names[] = {{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0}, 0,0}}, + {{"_CLS", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}}, + + {{"_CPC", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Bufs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0, 0}, 0, + 0}}, + {{"_CRS", 0, ACPI_RTYPE_BUFFER}}, {{"_CRT", 0, ACPI_RTYPE_INTEGER}}, {{"_CSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n-1 Int) */ @@ -237,12 +254,21 @@ static const union acpi_predefined_info predefined_names[] = {{"_CST", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */ {{{ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,0}}, + {{"_CWS", 1, ACPI_RTYPE_INTEGER}}, {{"_DCK", 1, ACPI_RTYPE_INTEGER}}, {{"_DCS", 0, ACPI_RTYPE_INTEGER}}, {{"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}}, {{"_DDN", 0, ACPI_RTYPE_STRING}}, + {{"_DEP", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + {{"_DGS", 0, ACPI_RTYPE_INTEGER}}, {{"_DIS", 0, 0}}, + + {{"_DLM", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (1 Ref, 0/1 Optional Buf/Ref) */ + {{{ACPI_PTYPE2_FIX_VAR, ACPI_RTYPE_REFERENCE, 1, + ACPI_RTYPE_REFERENCE | ACPI_RTYPE_BUFFER}, 0, 0}}, + {{"_DMA", 0, ACPI_RTYPE_BUFFER}}, {{"_DOD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}}, @@ -262,6 +288,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_EJ3", 1, 0}}, {{"_EJ4", 1, 0}}, {{"_EJD", 0, ACPI_RTYPE_STRING}}, + {{"_EVT", 1, 0}}, {{"_FDE", 0, ACPI_RTYPE_BUFFER}}, {{"_FDI", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int) */ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0}, 0,0}}, @@ -281,14 +308,17 @@ static const union acpi_predefined_info predefined_names[] = {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}}, {{"_GAI", 0, ACPI_RTYPE_INTEGER}}, + {{"_GCP", 0, ACPI_RTYPE_INTEGER}}, {{"_GHL", 0, ACPI_RTYPE_INTEGER}}, {{"_GLK", 0, ACPI_RTYPE_INTEGER}}, {{"_GPD", 0, ACPI_RTYPE_INTEGER}}, {{"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */ + {{"_GRT", 0, ACPI_RTYPE_BUFFER}}, {{"_GSB", 0, ACPI_RTYPE_INTEGER}}, {{"_GTF", 0, ACPI_RTYPE_BUFFER}}, {{"_GTM", 0, ACPI_RTYPE_BUFFER}}, {{"_GTS", 1, 0}}, + {{"_GWS", 1, ACPI_RTYPE_INTEGER}}, {{"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}}, {{"_HOT", 0, ACPI_RTYPE_INTEGER}}, {{"_HPP", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */ @@ -303,6 +333,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_HPX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (var Ints) */ {{{ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5,0}, 0,0}}, + {{"_HRV", 0, ACPI_RTYPE_INTEGER}}, {{"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */ {{"_INI", 0, 0}}, {{"_IRC", 0, 0}}, @@ -361,6 +392,9 @@ static const union acpi_predefined_info predefined_names[] = {{"_PR3", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + {{"_PRE", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + {{"_PRL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, @@ -391,6 +425,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_PSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (5 Int) with count */ {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER,0,0}, 0,0}}, + {{"_PSE", 1, 0}}, {{"_PSL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, @@ -457,6 +492,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_SLI", 0, ACPI_RTYPE_BUFFER}}, {{"_SPD", 1, ACPI_RTYPE_INTEGER}}, {{"_SRS", 1, 0}}, + {{"_SRT", 1, ACPI_RTYPE_INTEGER}}, {{"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */ {{"_SST", 1, 0}}, {{"_STA", 0, ACPI_RTYPE_INTEGER}}, @@ -464,6 +500,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_STP", 2, ACPI_RTYPE_INTEGER}}, {{"_STR", 0, ACPI_RTYPE_BUFFER}}, {{"_STV", 2, ACPI_RTYPE_INTEGER}}, + {{"_SUB", 0, ACPI_RTYPE_STRING}}, {{"_SUN", 0, ACPI_RTYPE_INTEGER}}, {{"_SWS", 0, ACPI_RTYPE_INTEGER}}, {{"_TC1", 0, ACPI_RTYPE_INTEGER}}, diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index f08b55b7f3a0..0347d0993497 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,28 +73,40 @@ typedef const struct acpi_rsconvert_info { /* Resource conversion opcodes */ -#define ACPI_RSC_INITGET 0 -#define ACPI_RSC_INITSET 1 -#define ACPI_RSC_FLAGINIT 2 -#define ACPI_RSC_1BITFLAG 3 -#define ACPI_RSC_2BITFLAG 4 -#define ACPI_RSC_COUNT 5 -#define ACPI_RSC_COUNT16 6 -#define ACPI_RSC_LENGTH 7 -#define ACPI_RSC_MOVE8 8 -#define ACPI_RSC_MOVE16 9 -#define ACPI_RSC_MOVE32 10 -#define ACPI_RSC_MOVE64 11 -#define ACPI_RSC_SET8 12 -#define ACPI_RSC_DATA8 13 -#define ACPI_RSC_ADDRESS 14 -#define ACPI_RSC_SOURCE 15 -#define ACPI_RSC_SOURCEX 16 -#define ACPI_RSC_BITMASK 17 -#define ACPI_RSC_BITMASK16 18 -#define ACPI_RSC_EXIT_NE 19 -#define ACPI_RSC_EXIT_LE 20 -#define ACPI_RSC_EXIT_EQ 21 +typedef enum { + ACPI_RSC_INITGET = 0, + ACPI_RSC_INITSET, + ACPI_RSC_FLAGINIT, + ACPI_RSC_1BITFLAG, + ACPI_RSC_2BITFLAG, + ACPI_RSC_3BITFLAG, + ACPI_RSC_ADDRESS, + ACPI_RSC_BITMASK, + ACPI_RSC_BITMASK16, + ACPI_RSC_COUNT, + ACPI_RSC_COUNT16, + ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RSC_COUNT_GPIO_RES, + ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RSC_DATA8, + ACPI_RSC_EXIT_EQ, + ACPI_RSC_EXIT_LE, + ACPI_RSC_EXIT_NE, + ACPI_RSC_LENGTH, + ACPI_RSC_MOVE_GPIO_PIN, + ACPI_RSC_MOVE_GPIO_RES, + ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RSC_MOVE8, + ACPI_RSC_MOVE16, + ACPI_RSC_MOVE32, + ACPI_RSC_MOVE64, + ACPI_RSC_SET8, + ACPI_RSC_SOURCE, + ACPI_RSC_SOURCEX +} ACPI_RSCONVERT_OPCODES; /* Resource Conversion sub-opcodes */ @@ -106,6 +118,9 @@ typedef const struct acpi_rsconvert_info { #define ACPI_RS_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_resource,f) #define AML_OFFSET(f) (u8) ACPI_OFFSET (union aml_resource,f) +/* + * Individual entry for the resource dump tables + */ typedef const struct acpi_rsdump_info { u8 opcode; u8 offset; @@ -116,20 +131,25 @@ typedef const struct acpi_rsdump_info { /* Values for the Opcode field above */ -#define ACPI_RSD_TITLE 0 -#define ACPI_RSD_LITERAL 1 -#define ACPI_RSD_STRING 2 -#define ACPI_RSD_UINT8 3 -#define ACPI_RSD_UINT16 4 -#define ACPI_RSD_UINT32 5 -#define ACPI_RSD_UINT64 6 -#define ACPI_RSD_1BITFLAG 7 -#define ACPI_RSD_2BITFLAG 8 -#define ACPI_RSD_SHORTLIST 9 -#define ACPI_RSD_LONGLIST 10 -#define ACPI_RSD_DWORDLIST 11 -#define ACPI_RSD_ADDRESS 12 -#define ACPI_RSD_SOURCE 13 +typedef enum { + ACPI_RSD_TITLE = 0, + ACPI_RSD_1BITFLAG, + ACPI_RSD_2BITFLAG, + ACPI_RSD_3BITFLAG, + ACPI_RSD_ADDRESS, + ACPI_RSD_DWORDLIST, + ACPI_RSD_LITERAL, + ACPI_RSD_LONGLIST, + ACPI_RSD_SHORTLIST, + ACPI_RSD_SHORTLISTX, + ACPI_RSD_SOURCE, + ACPI_RSD_STRING, + ACPI_RSD_UINT8, + ACPI_RSD_UINT16, + ACPI_RSD_UINT32, + ACPI_RSD_UINT64, + ACPI_RSD_WORDLIST +} ACPI_RSDUMP_OPCODES; /* restore default alignment */ @@ -138,13 +158,18 @@ typedef const struct acpi_rsdump_info { /* Resource tables indexed by internal resource type */ extern const u8 acpi_gbl_aml_resource_sizes[]; +extern const u8 acpi_gbl_aml_resource_serial_bus_sizes[]; extern struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[]; /* Resource tables indexed by raw AML resource descriptor type */ extern const u8 acpi_gbl_resource_struct_sizes[]; +extern const u8 acpi_gbl_resource_struct_serial_bus_sizes[]; extern struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[]; +extern struct acpi_rsconvert_info + *acpi_gbl_convert_resource_serial_bus_dispatch[]; + struct acpi_vendor_walk_info { struct acpi_vendor_uuid *uuid; struct acpi_buffer *buffer; @@ -190,6 +215,10 @@ acpi_status acpi_rs_set_srs_method_data(struct acpi_namespace_node *node, struct acpi_buffer *ret_buffer); +acpi_status +acpi_rs_get_aei_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); + /* * rscalc */ @@ -293,6 +322,11 @@ extern struct acpi_rsconvert_info acpi_rs_convert_address16[]; extern struct acpi_rsconvert_info acpi_rs_convert_ext_irq[]; extern struct acpi_rsconvert_info acpi_rs_convert_address64[]; extern struct acpi_rsconvert_info acpi_rs_convert_ext_address64[]; +extern struct acpi_rsconvert_info acpi_rs_convert_gpio[]; +extern struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[]; +extern struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[]; +extern struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[]; +extern struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[]; /* These resources require separate get/set tables */ @@ -310,6 +344,7 @@ extern struct acpi_rsconvert_info acpi_rs_set_vendor[]; * rsinfo */ extern struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[]; +extern struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[]; /* * rsdump @@ -331,6 +366,12 @@ extern struct acpi_rsdump_info acpi_rs_dump_address64[]; extern struct acpi_rsdump_info acpi_rs_dump_ext_address64[]; extern struct acpi_rsdump_info acpi_rs_dump_ext_irq[]; extern struct acpi_rsdump_info acpi_rs_dump_generic_reg[]; +extern struct acpi_rsdump_info acpi_rs_dump_gpio[]; +extern struct acpi_rsdump_info acpi_rs_dump_fixed_dma[]; +extern struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[]; +extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[]; +extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[]; +extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[]; #endif #endif /* __ACRESRC_H__ */ diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 1623b245dde2..0404df605bc1 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 967f08124eba..d5bec304c823 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 99c140d8e348..925ccf22101b 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #define _ACUTILS_H extern const u8 acpi_gbl_resource_aml_sizes[]; +extern const u8 acpi_gbl_resource_aml_serial_bus_sizes[]; /* Strings used by the disassembler and debugger resource dump routines */ @@ -579,6 +580,24 @@ acpi_ut_create_list(char *list_name, #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ /* + * utaddress - address range check + */ +acpi_status +acpi_ut_add_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, + u32 length, struct acpi_namespace_node *region_node); + +void +acpi_ut_remove_address_range(acpi_adr_space_type space_id, + struct acpi_namespace_node *region_node); + +u32 +acpi_ut_check_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, u32 length, u8 warn); + +void acpi_ut_delete_address_lists(void); + +/* * utxferror - various error/warning output functions */ void ACPI_INTERNAL_VAR_XFACE diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 1077f17859ed..905280fec0fa 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -189,6 +189,14 @@ #define AML_LNOTEQUAL_OP (u16) 0x9293 /* + * Opcodes for "Field" operators + */ +#define AML_FIELD_OFFSET_OP (u8) 0x00 +#define AML_FIELD_ACCESS_OP (u8) 0x01 +#define AML_FIELD_CONNECTION_OP (u8) 0x02 /* ACPI 5.0 */ +#define AML_FIELD_EXT_ACCESS_OP (u8) 0x03 /* ACPI 5.0 */ + +/* * Internal opcodes * Use only "Unknown" AML opcodes, don't attempt to use * any valid ACPI ASCII values (A-Z, 0-9, '-') @@ -202,6 +210,8 @@ #define AML_INT_METHODCALL_OP (u16) 0x0035 #define AML_INT_RETURN_VALUE_OP (u16) 0x0036 #define AML_INT_EVAL_SUBTREE_OP (u16) 0x0037 +#define AML_INT_CONNECTION_OP (u16) 0x0038 +#define AML_INT_EXTACCESSFIELD_OP (u16) 0x0039 #define ARG_NONE 0x0 @@ -456,13 +466,16 @@ typedef enum { * access_as keyword */ typedef enum { - AML_FIELD_ATTRIB_SMB_QUICK = 0x02, - AML_FIELD_ATTRIB_SMB_SEND_RCV = 0x04, - AML_FIELD_ATTRIB_SMB_BYTE = 0x06, - AML_FIELD_ATTRIB_SMB_WORD = 0x08, - AML_FIELD_ATTRIB_SMB_BLOCK = 0x0A, - AML_FIELD_ATTRIB_SMB_WORD_CALL = 0x0C, - AML_FIELD_ATTRIB_SMB_BLOCK_CALL = 0x0D + AML_FIELD_ATTRIB_QUICK = 0x02, + AML_FIELD_ATTRIB_SEND_RCV = 0x04, + AML_FIELD_ATTRIB_BYTE = 0x06, + AML_FIELD_ATTRIB_WORD = 0x08, + AML_FIELD_ATTRIB_BLOCK = 0x0A, + AML_FIELD_ATTRIB_MULTIBYTE = 0x0B, + AML_FIELD_ATTRIB_WORD_CALL = 0x0C, + AML_FIELD_ATTRIB_BLOCK_CALL = 0x0D, + AML_FIELD_ATTRIB_RAW_BYTES = 0x0E, + AML_FIELD_ATTRIB_RAW_PROCESS = 0x0F } AML_ACCESS_ATTRIBUTE; /* Bit fields in the AML method_flags byte */ diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 59122cde247c..7b2128f274e7 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,29 +58,48 @@ #define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT" #define ACPI_RESTAG_BASEADDRESS "_BAS" #define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */ +#define ACPI_RESTAG_DEBOUNCETIME "_DBT" #define ACPI_RESTAG_DECODE "_DEC" +#define ACPI_RESTAG_DEVICEPOLARITY "_DPL" #define ACPI_RESTAG_DMA "_DMA" #define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ +#define ACPI_RESTAG_DRIVESTRENGTH "_DRS" +#define ACPI_RESTAG_ENDIANNESS "_END" +#define ACPI_RESTAG_FLOWCONTROL "_FLC" #define ACPI_RESTAG_GRANULARITY "_GRA" #define ACPI_RESTAG_INTERRUPT "_INT" #define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ #define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */ #define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ +#define ACPI_RESTAG_IORESTRICTION "_IOR" #define ACPI_RESTAG_LENGTH "_LEN" +#define ACPI_RESTAG_LINE "_LIN" #define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ #define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ #define ACPI_RESTAG_MAXADDR "_MAX" #define ACPI_RESTAG_MINADDR "_MIN" #define ACPI_RESTAG_MAXTYPE "_MAF" #define ACPI_RESTAG_MINTYPE "_MIF" +#define ACPI_RESTAG_MODE "_MOD" +#define ACPI_RESTAG_PARITY "_PAR" +#define ACPI_RESTAG_PHASE "_PHA" +#define ACPI_RESTAG_PIN "_PIN" +#define ACPI_RESTAG_PINCONFIG "_PPI" +#define ACPI_RESTAG_POLARITY "_POL" #define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" #define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" #define ACPI_RESTAG_RANGETYPE "_RNG" #define ACPI_RESTAG_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */ +#define ACPI_RESTAG_LENGTH_RX "_RXL" +#define ACPI_RESTAG_LENGTH_TX "_TXL" +#define ACPI_RESTAG_SLAVEMODE "_SLV" +#define ACPI_RESTAG_SPEED "_SPE" +#define ACPI_RESTAG_STOPBITS "_STB" #define ACPI_RESTAG_TRANSLATION "_TRA" #define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ #define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */ #define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8_and16(1), 16(2) */ +#define ACPI_RESTAG_VENDORDATA "_VEN" /* Default sizes for "small" resource descriptors */ @@ -90,6 +109,7 @@ #define ASL_RDESC_END_DEPEND_SIZE 0x00 #define ASL_RDESC_IO_SIZE 0x07 #define ASL_RDESC_FIXED_IO_SIZE 0x03 +#define ASL_RDESC_FIXED_DMA_SIZE 0x05 #define ASL_RDESC_END_TAG_SIZE 0x01 struct asl_resource_node { @@ -164,6 +184,12 @@ struct aml_resource_end_tag { AML_RESOURCE_SMALL_HEADER_COMMON u8 checksum; }; +struct aml_resource_fixed_dma { + AML_RESOURCE_SMALL_HEADER_COMMON u16 request_lines; + u16 channels; + u8 width; +}; + /* * LARGE descriptors */ @@ -263,6 +289,110 @@ struct aml_resource_generic_register { u64 address; }; +/* Common descriptor for gpio_int and gpio_io (ACPI 5.0) */ + +struct aml_resource_gpio { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u8 connection_type; + u16 flags; + u16 int_flags; + u8 pin_config; + u16 drive_strength; + u16 debounce_timeout; + u16 pin_table_offset; + u8 res_source_index; + u16 res_source_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_GPIO_REVISION 1 /* ACPI 5.0 */ + +/* Values for connection_type above */ + +#define AML_RESOURCE_GPIO_TYPE_INT 0 +#define AML_RESOURCE_GPIO_TYPE_IO 1 +#define AML_RESOURCE_MAX_GPIOTYPE 1 + +/* Common preamble for all serial descriptors (ACPI 5.0) */ + +#define AML_RESOURCE_SERIAL_COMMON \ + u8 revision_id; \ + u8 res_source_index; \ + u8 type; \ + u8 flags; \ + u16 type_specific_flags; \ + u8 type_revision_id; \ + u16 type_data_length; \ + +/* Values for the type field above */ + +#define AML_RESOURCE_I2C_SERIALBUSTYPE 1 +#define AML_RESOURCE_SPI_SERIALBUSTYPE 2 +#define AML_RESOURCE_UART_SERIALBUSTYPE 3 +#define AML_RESOURCE_MAX_SERIALBUSTYPE 3 +#define AML_RESOURCE_VENDOR_SERIALBUSTYPE 192 /* Vendor defined is 0xC0-0xFF (NOT SUPPORTED) */ + +struct aml_resource_common_serialbus { +AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_SERIAL_COMMON}; + +struct aml_resource_i2c_serialbus { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON u32 connection_speed; + u16 slave_address; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ +}; + +#define AML_RESOURCE_I2C_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_I2C_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_I2C_MIN_DATA_LEN 6 + +struct aml_resource_spi_serialbus { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON u32 connection_speed; + u8 data_bit_length; + u8 clock_phase; + u8 clock_polarity; + u16 device_selection; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ +}; + +#define AML_RESOURCE_SPI_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_SPI_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_SPI_MIN_DATA_LEN 9 + +struct aml_resource_uart_serialbus { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON u32 default_baud_rate; + u16 rx_fifo_size; + u16 tx_fifo_size; + u8 parity; + u8 lines_enabled; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ +}; + +#define AML_RESOURCE_UART_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_UART_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_UART_MIN_DATA_LEN 10 + /* restore default alignment */ #pragma pack() @@ -284,6 +414,7 @@ union aml_resource { struct aml_resource_end_dependent end_dpf; struct aml_resource_io io; struct aml_resource_fixed_io fixed_io; + struct aml_resource_fixed_dma fixed_dma; struct aml_resource_vendor_small vendor_small; struct aml_resource_end_tag end_tag; @@ -299,6 +430,11 @@ union aml_resource { struct aml_resource_address64 address64; struct aml_resource_extended_address64 ext_address64; struct aml_resource_extended_irq extended_irq; + struct aml_resource_gpio gpio; + struct aml_resource_i2c_serialbus i2c_serial_bus; + struct aml_resource_spi_serialbus spi_serial_bus; + struct aml_resource_uart_serialbus uart_serial_bus; + struct aml_resource_common_serialbus common_serial_bus; /* Utility overlays */ diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 8c7b99728aa2..80eb1900297f 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -250,6 +250,13 @@ acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc) status = acpi_ds_execute_arguments(node, node->parent, extra_desc->extra.aml_length, extra_desc->extra.aml_start); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_ut_add_address_range(obj_desc->region.space_id, + obj_desc->region.address, + obj_desc->region.length, node); return_ACPI_STATUS(status); } @@ -384,8 +391,15 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) /* Execute the argument AML */ - status = acpi_ds_execute_arguments(node, node->parent, + status = acpi_ds_execute_arguments(node, extra_desc->extra.scope_node, extra_desc->extra.aml_length, extra_desc->extra.aml_start); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_ut_add_address_range(obj_desc->region.space_id, + obj_desc->region.address, + obj_desc->region.length, node); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 26c49fff58da..effe4ca1133f 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 34be60c0e448..cd243cf2cab2 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -221,6 +221,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, { acpi_status status; u64 position; + union acpi_parse_object *child; ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info); @@ -232,10 +233,11 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, while (arg) { /* - * Three types of field elements are handled: - * 1) Offset - specifies a bit offset - * 2) access_as - changes the access mode - * 3) Name - Enters a new named field into the namespace + * Four types of field elements are handled: + * 1) Name - Enters a new named field into the namespace + * 2) Offset - specifies a bit offset + * 3) access_as - changes the access mode/attributes + * 4) Connection - Associate a resource template with the field */ switch (arg->common.aml_opcode) { case AML_INT_RESERVEDFIELD_OP: @@ -253,21 +255,70 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, break; case AML_INT_ACCESSFIELD_OP: - + case AML_INT_EXTACCESSFIELD_OP: /* - * Get a new access_type and access_attribute -- to be used for all - * field units that follow, until field end or another access_as - * keyword. + * Get new access_type, access_attribute, and access_length fields + * -- to be used for all field units that follow, until the + * end-of-field or another access_as keyword is encountered. + * NOTE. These three bytes are encoded in the integer value + * of the parseop for convenience. * * In field_flags, preserve the flag bits other than the - * ACCESS_TYPE bits + * ACCESS_TYPE bits. */ + + /* access_type (byte_acc, word_acc, etc.) */ + info->field_flags = (u8) ((info-> field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | - ((u8) ((u32) arg->common.value.integer >> 8))); + ((u8)((u32)(arg->common.value.integer & 0x07)))); + + /* access_attribute (attrib_quick, attrib_byte, etc.) */ + + info->attribute = + (u8)((arg->common.value.integer >> 8) & 0xFF); + + /* access_length (for serial/buffer protocols) */ + + info->access_length = + (u8)((arg->common.value.integer >> 16) & 0xFF); + break; + + case AML_INT_CONNECTION_OP: + /* + * Clear any previous connection. New connection is used for all + * fields that follow, similar to access_as + */ + info->resource_buffer = NULL; + info->connection_node = NULL; - info->attribute = (u8) (arg->common.value.integer); + /* + * A Connection() is either an actual resource descriptor (buffer) + * or a named reference to a resource template + */ + child = arg->common.value.arg; + if (child->common.aml_opcode == AML_INT_BYTELIST_OP) { + info->resource_buffer = child->named.data; + info->resource_length = + (u16)child->named.value.integer; + } else { + /* Lookup the Connection() namepath, it should already exist */ + + status = acpi_ns_lookup(walk_state->scope_info, + child->common.value. + name, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, + ACPI_NS_DONT_OPEN_SCOPE, + walk_state, + &info->connection_node); + if (ACPI_FAILURE(status)) { + ACPI_ERROR_NAMESPACE(child->common. + value.name, + status); + return_ACPI_STATUS(status); + } + } break; case AML_INT_NAMEDFIELD_OP: @@ -374,6 +425,8 @@ acpi_ds_create_field(union acpi_parse_object *op, } } + ACPI_MEMSET(&info, 0, sizeof(struct acpi_create_field_info)); + /* Second arg is the field flags */ arg = arg->common.next; @@ -386,7 +439,6 @@ acpi_ds_create_field(union acpi_parse_object *op, info.region_node = region_node; status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); - return_ACPI_STATUS(status); } @@ -474,8 +526,8 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, */ while (arg) { /* - * Ignore OFFSET and ACCESSAS terms here; we are only interested in the - * field names in order to enter them into the namespace. + * Ignore OFFSET/ACCESSAS/CONNECTION terms here; we are only interested + * in the field names in order to enter them into the namespace. */ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { status = acpi_ns_lookup(walk_state->scope_info, @@ -651,6 +703,5 @@ acpi_ds_create_index_field(union acpi_parse_object *op, info.region_node = region_node; status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); - return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index a7718bf2b9a1..9e5ac7f780a7 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 5d797751e205..00f5dab5bcc0 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 905ce29a92e1..b40bd507be5d 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index f42e17e5c252..d7045ca3e32a 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index c627a288e027..e5eff7585102 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 2c477ce172fa..1abcda31037f 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index fe40e4c6554f..642f3c053e87 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 324acec1179a..552aa3a50c84 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 976318138c56..ae7147724763 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index 76a661fc1e09..9e9490a9cbf0 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index a6c374ef9914..c9c2ac13e7cc 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index d458b041e651..6729ebe2f1e6 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,6 +71,12 @@ acpi_status acpi_ev_initialize_events(void) ACPI_FUNCTION_TRACE(ev_initialize_events); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* * Initialize the Fixed and General Purpose Events. This is done prior to * enabling SCIs to prevent interrupts from occurring before the handlers @@ -111,6 +117,12 @@ acpi_status acpi_ev_install_xrupt_handlers(void) ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers); + /* If Hardware Reduced flag is set, there is no ACPI h/w */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Install the SCI handler */ status = acpi_ev_install_sci_handler(); diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c index 56a562a1e5d7..5e5683cb1f0d 100644 --- a/drivers/acpi/acpica/evglock.c +++ b/drivers/acpi/acpica/evglock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,6 +70,12 @@ acpi_status acpi_ev_init_global_lock_handler(void) ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); + /* If Hardware Reduced flag is set, there is no global lock */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Attempt installation of the global lock handler */ status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 65c79add3b19..9e88cb6fb25e 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index ca2c41a53311..be75339cd5dd 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index ce9aa9f9a972..adf7494da9db 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 80a81d0c4a80..25073932aa10 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index d0b331844427..84966f416463 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index f0edf5c43c03..1b0180a1b798 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -329,6 +329,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) * FUNCTION: acpi_ev_address_space_dispatch * * PARAMETERS: region_obj - Internal region object + * field_obj - Corresponding field. Can be NULL. * Function - Read or Write operation * region_offset - Where in the region to read or write * bit_width - Field width in bits (8, 16, 32, or 64) @@ -344,6 +345,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + union acpi_operand_object *field_obj, u32 function, u32 region_offset, u32 bit_width, u64 *value) { @@ -353,6 +355,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, union acpi_operand_object *handler_desc; union acpi_operand_object *region_obj2; void *region_context = NULL; + struct acpi_connection_info *context; ACPI_FUNCTION_TRACE(ev_address_space_dispatch); @@ -375,6 +378,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, return_ACPI_STATUS(AE_NOT_EXIST); } + context = handler_desc->address_space.context; + /* * It may be the case that the region has never been initialized. * Some types of regions require special init code @@ -404,8 +409,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, acpi_ex_exit_interpreter(); status = region_setup(region_obj, ACPI_REGION_ACTIVATE, - handler_desc->address_space.context, - ®ion_context); + context, ®ion_context); /* Re-enter the interpreter */ @@ -455,6 +459,25 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, acpi_ut_get_region_name(region_obj->region. space_id))); + /* + * Special handling for generic_serial_bus and general_purpose_io: + * There are three extra parameters that must be passed to the + * handler via the context: + * 1) Connection buffer, a resource template from Connection() op. + * 2) Length of the above buffer. + * 3) Actual access length from the access_as() op. + */ + if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) || + (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) && + context && field_obj) { + + /* Get the Connection (resource_template) buffer */ + + context->connection = field_obj->field.resource_buffer; + context->length = field_obj->field.resource_length; + context->access_length = field_obj->field.access_length; + } + if (!(handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* @@ -469,7 +492,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, status = handler(function, (region_obj->region.address + region_offset), - bit_width, value, handler_desc->address_space.context, + bit_width, value, context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 55a5d35ef34a..819c17f5897a 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 2ebd40e1a3ef..26065c612e76 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index f4f523bf5939..61944e89565a 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 20516e599476..1768bbec1002 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index f06a3ee356ba..33388fd69df4 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index aee887e3ca5c..6019208cd4b6 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 745a42b401f5..c86d44e41bc8 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -297,9 +297,9 @@ acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) /* Bytewise reads */ for (i = 0; i < length; i++) { - status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, - region_offset, 8, - &value); + status = + acpi_ev_address_space_dispatch(obj_desc, NULL, ACPI_READ, + region_offset, 8, &value); if (ACPI_FAILURE(status)) { return status; } diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 74162a11817d..e385436bd424 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 110711afada8..3f5bc998c1cb 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -267,7 +267,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) * * PARAMETERS: aml_start - Pointer to the region declaration AML * aml_length - Max length of the declaration AML - * region_space - space_iD for the region + * space_id - Address space ID for the region * walk_state - Current state * * RETURN: Status @@ -279,7 +279,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) acpi_status acpi_ex_create_region(u8 * aml_start, u32 aml_length, - u8 region_space, struct acpi_walk_state *walk_state) + u8 space_id, struct acpi_walk_state *walk_state) { acpi_status status; union acpi_operand_object *obj_desc; @@ -304,16 +304,19 @@ acpi_ex_create_region(u8 * aml_start, * Space ID must be one of the predefined IDs, or in the user-defined * range */ - if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) && - (region_space < ACPI_USER_REGION_BEGIN) && - (region_space != ACPI_ADR_SPACE_DATA_TABLE)) { - ACPI_ERROR((AE_INFO, "Invalid AddressSpace type 0x%X", - region_space)); - return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID); + if (!acpi_is_valid_space_id(space_id)) { + /* + * Print an error message, but continue. We don't want to abort + * a table load for this exception. Instead, if the region is + * actually used at runtime, abort the executing method. + */ + ACPI_ERROR((AE_INFO, + "Invalid/unknown Address Space ID: 0x%2.2X", + space_id)); } ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n", - acpi_ut_get_region_name(region_space), region_space)); + acpi_ut_get_region_name(space_id), space_id)); /* Create the region descriptor */ @@ -330,10 +333,16 @@ acpi_ex_create_region(u8 * aml_start, region_obj2 = obj_desc->common.next_object; region_obj2->extra.aml_start = aml_start; region_obj2->extra.aml_length = aml_length; + if (walk_state->scope_info) { + region_obj2->extra.scope_node = + walk_state->scope_info->scope.node; + } else { + region_obj2->extra.scope_node = node; + } /* Init the region from the operands */ - obj_desc->region.space_id = region_space; + obj_desc->region.space_id = space_id; obj_desc->region.address = 0; obj_desc->region.length = 0; obj_desc->region.node = node; diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index c7a2f1edd282..e211e9c19215 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 61b8c0e8b74d..2a6ac0a3bc1e 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -192,10 +192,13 @@ static struct acpi_exdump_info acpi_ex_dump_buffer_field[3] = { "Buffer Object"} }; -static struct acpi_exdump_info acpi_ex_dump_region_field[3] = { +static struct acpi_exdump_info acpi_ex_dump_region_field[5] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_region_field), NULL}, {ACPI_EXD_FIELD, 0, NULL}, - {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.region_obj), "Region Object"} + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(field.access_length), "AccessLength"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.region_obj), "Region Object"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.resource_buffer), + "ResourceBuffer"} }; static struct acpi_exdump_info acpi_ex_dump_bank_field[5] = { diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 0bde2230c028..dc092f5b35d6 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -100,18 +100,25 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS + || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* - * This is an SMBus or IPMI read. We must create a buffer to hold + * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold * the data and then directly access the region handler. * - * Note: Smbus protocol value is passed in upper 16-bits of Function + * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function */ if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_READ | (obj_desc->field.attribute << 16); + } else if (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS) { + length = ACPI_GSBUS_BUFFER_SIZE; + function = + ACPI_READ | (obj_desc->field.attribute << 16); } else { /* IPMI */ length = ACPI_IPMI_BUFFER_SIZE; @@ -248,21 +255,23 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS + || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* - * This is an SMBus or IPMI write. We will bypass the entire field + * This is an SMBus, GSBus or IPMI write. We will bypass the entire field * mechanism and handoff the buffer directly to the handler. For * these address spaces, the buffer is bi-directional; on a write, * return data is returned in the same buffer. * * Source must be a buffer of sufficient size: - * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE. + * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. * - * Note: SMBus protocol type is passed in upper 16-bits of Function + * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function */ if (source_desc->common.type != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, - "SMBus or IPMI write requires Buffer, found type %s", + "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", acpi_ut_get_object_type_name(source_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); @@ -273,6 +282,11 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_WRITE | (obj_desc->field.attribute << 16); + } else if (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS) { + length = ACPI_GSBUS_BUFFER_SIZE; + function = + ACPI_WRITE | (obj_desc->field.attribute << 16); } else { /* IPMI */ length = ACPI_IPMI_BUFFER_SIZE; @@ -281,7 +295,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, if (source_desc->buffer.length < length) { ACPI_ERROR((AE_INFO, - "SMBus or IPMI write requires Buffer of length %u, found length %u", + "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", length, source_desc->buffer.length)); return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index f915a7f3f921..149de45fdadd 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -86,6 +86,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, { acpi_status status = AE_OK; union acpi_operand_object *rgn_desc; + u8 space_id; ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset); @@ -101,6 +102,17 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } + space_id = rgn_desc->region.space_id; + + /* Validate the Space ID */ + + if (!acpi_is_valid_space_id(space_id)) { + ACPI_ERROR((AE_INFO, + "Invalid/unknown Address Space ID: 0x%2.2X", + space_id)); + return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID); + } + /* * If the Region Address and Length have not been previously evaluated, * evaluate them now and save the results. @@ -119,11 +131,12 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, } /* - * Exit now for SMBus or IPMI address space, it has a non-linear + * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear * address space and the request cannot be directly validated */ - if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS || - rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) { + if (space_id == ACPI_ADR_SPACE_SMBUS || + space_id == ACPI_ADR_SPACE_GSBUS || + space_id == ACPI_ADR_SPACE_IPMI) { /* SMBus or IPMI has a non-linear address space */ @@ -271,11 +284,12 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, /* Invoke the appropriate address_space/op_region handler */ - status = - acpi_ev_address_space_dispatch(rgn_desc, function, region_offset, - ACPI_MUL_8(obj_desc->common_field. - access_byte_width), - value); + status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc, + function, region_offset, + ACPI_MUL_8(obj_desc-> + common_field. + access_byte_width), + value); if (ACPI_FAILURE(status)) { if (status == AE_NOT_IMPLEMENTED) { @@ -316,6 +330,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, static u8 acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value) { + ACPI_FUNCTION_NAME(ex_register_overflow); if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) { /* @@ -330,6 +345,11 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value) * The Value is larger than the maximum value that can fit into * the register. */ + ACPI_ERROR((AE_INFO, + "Index value 0x%8.8X%8.8X overflows field width 0x%X", + ACPI_FORMAT_UINT64(value), + obj_desc->common_field.bit_length)); + return (TRUE); } diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 703d88ed0b3d..0a0893310348 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index be1c56ead653..60933e9dc3c0 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index 49ec049c157e..fcc75fa27d32 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 236ead14b7f7..9ba8c73cea16 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 2571b4a310f4..879e8a277b94 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 1b48d9d28c9a..71fcc65c9ffa 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index f4a2787e8e92..0786b8659061 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index cc95e2000406..30157f5a12d7 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,6 +47,7 @@ #include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" +#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exprep") @@ -455,6 +456,30 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) obj_desc->field.region_obj = acpi_ns_get_attached_object(info->region_node); + /* Fields specific to generic_serial_bus fields */ + + obj_desc->field.access_length = info->access_length; + + if (info->connection_node) { + second_desc = info->connection_node->object; + if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = + acpi_ds_get_buffer_arguments(second_desc); + if (ACPI_FAILURE(status)) { + acpi_ut_delete_object_desc(obj_desc); + return_ACPI_STATUS(status); + } + } + + obj_desc->field.resource_buffer = + second_desc->buffer.pointer; + obj_desc->field.resource_length = + (u16)second_desc->buffer.length; + } else if (info->resource_buffer) { + obj_desc->field.resource_buffer = info->resource_buffer; + obj_desc->field.resource_length = info->resource_length; + } + /* Allow full data read from EC address space */ if ((obj_desc->field.region_obj->region.space_id == diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index f0d5e14f1f2c..12d51df6d3bf 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index 55997e46948b..fa50e77e64a8 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index db502cd7d934..6e335dc34528 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index e3bb00ccdff5..a67b1d925ddd 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index c0c8842dd344..c6cf843cc4c9 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index a979017d56b8..b35bed52e061 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index dc665cc554de..65a45d8335c8 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index df66e7b686be..191a12945226 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 8ad93146dd32..eb6798ba8b59 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -435,4 +435,29 @@ void acpi_ex_integer_to_string(char *out_string, u64 value) } } +/******************************************************************************* + * + * FUNCTION: acpi_is_valid_space_id + * + * PARAMETERS: space_id - ID to be validated + * + * RETURN: TRUE if valid/supported ID. + * + * DESCRIPTION: Validate an operation region space_iD. + * + ******************************************************************************/ + +u8 acpi_is_valid_space_id(u8 space_id) +{ + + if ((space_id >= ACPI_NUM_PREDEFINED_REGIONS) && + (space_id < ACPI_USER_REGION_BEGIN) && + (space_id != ACPI_ADR_SPACE_DATA_TABLE) && + (space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { + return (FALSE); + } + + return (TRUE); +} + #endif diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index fc380d3d45ab..d21ec5f0b3a9 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index f610d88a66be..1a6894afef79 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index 050fd227951b..1455ddcdc32c 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index cc70f3fdcdd1..4ea4eeb51bfd 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -7,7 +7,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index d52da3073650..3c4a922a9fc2 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 50d21c40b5c1..d4973d9da9f1 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 5f1605874655..6e5c43a60bb7 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -134,6 +134,8 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) /* Supported widths are 8/16/32 */ if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) { + ACPI_ERROR((AE_INFO, + "Bad BitWidth parameter: %8.8X", bit_width)); return AE_BAD_PARAMETER; } diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index d707756228c2..9d38eb6c0d0b 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index d93172fd15a8..61623f3f6826 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 1d0ef15d158f..7c3d3ceb98b3 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index b683cc2ff9d3..b7f2b3be79ac 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 2ed294b7a4db..30ea5bc53a78 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index c1bd02b1a058..f375cb82e321 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index fd7c6380e294..9d84ec2f0211 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 5f7dc691c183..5cbf15ffe7d8 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index d5fa520c3de5..b20e7c8c3ffb 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 3bb8bf105ea2..dd77a3ce6e50 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index b3234fa795b8..ec7ba2d3463c 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index c845c8089f39..bbe46a447d34 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -620,6 +620,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data, case ACPI_PTYPE2_FIXED: case ACPI_PTYPE2_MIN: case ACPI_PTYPE2_COUNT: + case ACPI_PTYPE2_FIX_VAR: /* * These types all return a single Package that consists of a @@ -759,6 +760,34 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, } break; + case ACPI_PTYPE2_FIX_VAR: + /* + * Each subpackage has a fixed number of elements and an + * optional element + */ + expected_count = + package->ret_info.count1 + package->ret_info.count2; + if (sub_package->package.count < expected_count) { + goto package_too_small; + } + + status = + acpi_ns_check_package_elements(data, sub_elements, + package->ret_info. + object_type1, + package->ret_info. + count1, + package->ret_info. + object_type2, + sub_package->package. + count - + package->ret_info. + count1, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + break; + case ACPI_PTYPE2_FIXED: /* Each sub-package has a fixed length */ diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index ac7b854b0bd7..9c35d20eb52b 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -634,6 +634,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data, case ACPI_PTYPE2_FIXED: case ACPI_PTYPE2_MIN: case ACPI_PTYPE2_REV_FIXED: + case ACPI_PTYPE2_FIX_VAR: break; default: diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 024c4f263f87..726bc8e687f7 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -467,11 +467,12 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data, } /* - * Copy and uppercase the string. From the ACPI specification: + * Copy and uppercase the string. From the ACPI 5.0 specification: * * A valid PNP ID must be of the form "AAA####" where A is an uppercase * letter and # is a hex digit. A valid ACPI ID must be of the form - * "ACPI####" where # is a hex digit. + * "NNNN####" where N is an uppercase letter or decimal digit, and + * # is a hex digit. */ for (dest = new_string->string.pointer; *source; dest++, source++) { *dest = (char)ACPI_TOUPPER(*source); diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 28b0d7a62b99..507043d66114 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index cb1b104a69a2..a535b7afda5c 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 345f0c3c6ad2..f69895a54895 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index e7f016d1b226..71d15f61807b 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 83bf93024303..af401c9c4dfc 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 57e6d825ed84..880a605cee20 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index e1fad0ee0136..5ac36aba507c 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -484,34 +484,54 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state *parser_state) { - u32 aml_offset = (u32) - ACPI_PTR_DIFF(parser_state->aml, - parser_state->aml_start); + u32 aml_offset; union acpi_parse_object *field; + union acpi_parse_object *arg = NULL; u16 opcode; u32 name; + u8 access_type; + u8 access_attribute; + u8 access_length; + u32 pkg_length; + u8 *pkg_end; + u32 buffer_length; ACPI_FUNCTION_TRACE(ps_get_next_field); + aml_offset = + (u32)ACPI_PTR_DIFF(parser_state->aml, parser_state->aml_start); + /* Determine field type */ switch (ACPI_GET8(parser_state->aml)) { - default: + case AML_FIELD_OFFSET_OP: - opcode = AML_INT_NAMEDFIELD_OP; + opcode = AML_INT_RESERVEDFIELD_OP; + parser_state->aml++; break; - case 0x00: + case AML_FIELD_ACCESS_OP: - opcode = AML_INT_RESERVEDFIELD_OP; + opcode = AML_INT_ACCESSFIELD_OP; parser_state->aml++; break; - case 0x01: + case AML_FIELD_CONNECTION_OP: - opcode = AML_INT_ACCESSFIELD_OP; + opcode = AML_INT_CONNECTION_OP; + parser_state->aml++; + break; + + case AML_FIELD_EXT_ACCESS_OP: + + opcode = AML_INT_EXTACCESSFIELD_OP; parser_state->aml++; break; + + default: + + opcode = AML_INT_NAMEDFIELD_OP; + break; } /* Allocate a new field op */ @@ -549,16 +569,111 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state break; case AML_INT_ACCESSFIELD_OP: + case AML_INT_EXTACCESSFIELD_OP: /* * Get access_type and access_attrib and merge into the field Op - * access_type is first operand, access_attribute is second + * access_type is first operand, access_attribute is second. stuff + * these bytes into the node integer value for convenience. */ - field->common.value.integer = - (((u32) ACPI_GET8(parser_state->aml) << 8)); + + /* Get the two bytes (Type/Attribute) */ + + access_type = ACPI_GET8(parser_state->aml); parser_state->aml++; - field->common.value.integer |= ACPI_GET8(parser_state->aml); + access_attribute = ACPI_GET8(parser_state->aml); parser_state->aml++; + + field->common.value.integer = (u8)access_type; + field->common.value.integer |= (u16)(access_attribute << 8); + + /* This opcode has a third byte, access_length */ + + if (opcode == AML_INT_EXTACCESSFIELD_OP) { + access_length = ACPI_GET8(parser_state->aml); + parser_state->aml++; + + field->common.value.integer |= + (u32)(access_length << 16); + } + break; + + case AML_INT_CONNECTION_OP: + + /* + * Argument for Connection operator can be either a Buffer + * (resource descriptor), or a name_string. + */ + if (ACPI_GET8(parser_state->aml) == AML_BUFFER_OP) { + parser_state->aml++; + + pkg_end = parser_state->aml; + pkg_length = + acpi_ps_get_next_package_length(parser_state); + pkg_end += pkg_length; + + if (parser_state->aml < pkg_end) { + + /* Non-empty list */ + + arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP); + if (!arg) { + return_PTR(NULL); + } + + /* Get the actual buffer length argument */ + + opcode = ACPI_GET8(parser_state->aml); + parser_state->aml++; + + switch (opcode) { + case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ + buffer_length = + ACPI_GET8(parser_state->aml); + parser_state->aml += 1; + break; + + case AML_WORD_OP: /* AML_WORDDATA_ARG */ + buffer_length = + ACPI_GET16(parser_state->aml); + parser_state->aml += 2; + break; + + case AML_DWORD_OP: /* AML_DWORDATA_ARG */ + buffer_length = + ACPI_GET32(parser_state->aml); + parser_state->aml += 4; + break; + + default: + buffer_length = 0; + break; + } + + /* Fill in bytelist data */ + + arg->named.value.size = buffer_length; + arg->named.data = parser_state->aml; + } + + /* Skip to End of byte data */ + + parser_state->aml = pkg_end; + } else { + arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); + if (!arg) { + return_PTR(NULL); + } + + /* Get the Namestring argument */ + + arg->common.value.name = + acpi_ps_get_next_namestring(parser_state); + } + + /* Link the buffer/namestring to parent (CONNECTION_OP) */ + + acpi_ps_append_arg(field, arg); break; default: diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 01dd70d1de51..9547ad8a620b 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index bed08de7528c..a0226fdcf75c 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -638,7 +638,16 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, - AML_FLAGS_EXEC_0A_0T_1R) + AML_FLAGS_EXEC_0A_0T_1R), + +/* ACPI 5.0 opcodes */ + +/* 7F */ ACPI_OP("-ConnectField-", ARGP_CONNECTFIELD_OP, + ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS), +/* 80 */ ACPI_OP("-ExtAccessField-", ARGP_CONNECTFIELD_OP, + ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0) /*! [End] no source code translation !*/ }; @@ -657,7 +666,7 @@ static const u8 acpi_gbl_short_op_index[256] = { /* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, /* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D, -/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, /* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, /* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 9bb0cbd37b5e..2ff9c35a1968 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c index a5faa1323a02..c872aa4b926e 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index f1464c03aa42..2b03cdbbe1c0 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -74,6 +74,12 @@ union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn) ACPI_FUNCTION_ENTRY(); +/* + if (Op->Common.aml_opcode == AML_INT_CONNECTION_OP) + { + return (Op->Common.Value.Arg); + } +*/ /* Get the info structure for this opcode */ op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 7eda78503422..13bb131ae125 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index 3312d6368bf1..ab96cf47896d 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 8086805d4494..9d98c5ff66a5 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 9e66f9078426..a0305652394f 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 3a8a89ec2ca4..3c6df4b7eb2d 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -313,6 +313,38 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) resource_source)); break; + case ACPI_RESOURCE_TYPE_GPIO: + + total_size = + (acpi_rs_length) (total_size + + (resource->data.gpio. + pin_table_length * 2) + + resource->data.gpio. + resource_source.string_length + + resource->data.gpio. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_SERIAL_BUS: + + total_size = + acpi_gbl_aml_resource_serial_bus_sizes[resource-> + data. + common_serial_bus. + type]; + + total_size = (acpi_rs_length) (total_size + + resource->data. + i2c_serial_bus. + resource_source. + string_length + + resource->data. + i2c_serial_bus. + vendor_length); + + break; + default: break; } @@ -362,10 +394,11 @@ acpi_rs_get_list_length(u8 * aml_buffer, u32 extra_struct_bytes; u8 resource_index; u8 minimum_aml_resource_length; + union aml_resource *aml_resource; ACPI_FUNCTION_TRACE(rs_get_list_length); - *size_needed = 0; + *size_needed = ACPI_RS_SIZE_MIN; /* Minimum size is one end_tag */ end_aml = aml_buffer + aml_buffer_length; /* Walk the list of AML resource descriptors */ @@ -376,9 +409,15 @@ acpi_rs_get_list_length(u8 * aml_buffer, status = acpi_ut_validate_resource(aml_buffer, &resource_index); if (ACPI_FAILURE(status)) { + /* + * Exit on failure. Cannot continue because the descriptor length + * may be bogus also. + */ return_ACPI_STATUS(status); } + aml_resource = (void *)aml_buffer; + /* Get the resource length and base (minimum) AML size */ resource_length = acpi_ut_get_resource_length(aml_buffer); @@ -422,10 +461,8 @@ acpi_rs_get_list_length(u8 * aml_buffer, case ACPI_RESOURCE_NAME_END_TAG: /* - * End Tag: - * This is the normal exit, add size of end_tag + * End Tag: This is the normal exit */ - *size_needed += ACPI_RS_SIZE_MIN; return_ACPI_STATUS(AE_OK); case ACPI_RESOURCE_NAME_ADDRESS32: @@ -457,6 +494,33 @@ acpi_rs_get_list_length(u8 * aml_buffer, minimum_aml_resource_length); break; + case ACPI_RESOURCE_NAME_GPIO: + + /* Vendor data is optional */ + + if (aml_resource->gpio.vendor_length) { + extra_struct_bytes += + aml_resource->gpio.vendor_offset - + aml_resource->gpio.pin_table_offset + + aml_resource->gpio.vendor_length; + } else { + extra_struct_bytes += + aml_resource->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + aml_resource->gpio.pin_table_offset; + } + break; + + case ACPI_RESOURCE_NAME_SERIAL_BUS: + + minimum_aml_resource_length = + acpi_gbl_resource_aml_serial_bus_sizes + [aml_resource->common_serial_bus.type]; + extra_struct_bytes += + aml_resource->common_serial_bus.resource_length - + minimum_aml_resource_length; + break; + default: break; } @@ -467,9 +531,18 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Important: Round the size up for the appropriate alignment. This * is a requirement on IA64. */ - buffer_size = acpi_gbl_resource_struct_sizes[resource_index] + - extra_struct_bytes; - buffer_size = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); + if (acpi_ut_get_resource_type(aml_buffer) == + ACPI_RESOURCE_NAME_SERIAL_BUS) { + buffer_size = + acpi_gbl_resource_struct_serial_bus_sizes + [aml_resource->common_serial_bus.type] + + extra_struct_bytes; + } else { + buffer_size = + acpi_gbl_resource_struct_sizes[resource_index] + + extra_struct_bytes; + } + buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); *size_needed += buffer_size; diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 4ce6e1147e80..46d6eb38ae66 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,6 +51,70 @@ ACPI_MODULE_NAME("rscreate") /******************************************************************************* * + * FUNCTION: acpi_buffer_to_resource + * + * PARAMETERS: aml_buffer - Pointer to the resource byte stream + * aml_buffer_length - Length of the aml_buffer + * resource_ptr - Where the converted resource is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert a raw AML buffer to a resource list + * + ******************************************************************************/ +acpi_status +acpi_buffer_to_resource(u8 *aml_buffer, + u16 aml_buffer_length, + struct acpi_resource **resource_ptr) +{ + acpi_status status; + acpi_size list_size_needed; + void *resource; + void *current_resource_ptr; + + /* + * Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag + * is not required here. + */ + + /* Get the required length for the converted resource */ + + status = acpi_rs_get_list_length(aml_buffer, aml_buffer_length, + &list_size_needed); + if (status == AE_AML_NO_RESOURCE_END_TAG) { + status = AE_OK; + } + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Allocate a buffer for the converted resource */ + + resource = ACPI_ALLOCATE_ZEROED(list_size_needed); + current_resource_ptr = resource; + if (!resource) { + return (AE_NO_MEMORY); + } + + /* Perform the AML-to-Resource conversion */ + + status = acpi_ut_walk_aml_resources(aml_buffer, aml_buffer_length, + acpi_rs_convert_aml_to_resources, + ¤t_resource_ptr); + if (status == AE_AML_NO_RESOURCE_END_TAG) { + status = AE_OK; + } + if (ACPI_FAILURE(status)) { + ACPI_FREE(resource); + } else { + *resource_ptr = resource; + } + + return (status); +} + +/******************************************************************************* + * * FUNCTION: acpi_rs_create_resource_list * * PARAMETERS: aml_buffer - Pointer to the resource byte stream @@ -66,9 +130,10 @@ ACPI_MODULE_NAME("rscreate") * of device resources. * ******************************************************************************/ + acpi_status acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, - struct acpi_buffer *output_buffer) + struct acpi_buffer * output_buffer) { acpi_status status; diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index 33db7520c74b..b4c581132393 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,11 +61,13 @@ static void acpi_rs_out_integer64(char *title, u64 value); static void acpi_rs_out_title(char *title); -static void acpi_rs_dump_byte_list(u16 length, u8 * data); +static void acpi_rs_dump_byte_list(u16 length, u8 *data); -static void acpi_rs_dump_dword_list(u8 length, u32 * data); +static void acpi_rs_dump_word_list(u16 length, u16 *data); -static void acpi_rs_dump_short_byte_list(u8 length, u8 * data); +static void acpi_rs_dump_dword_list(u8 length, u32 *data); + +static void acpi_rs_dump_short_byte_list(u8 length, u8 *data); static void acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source); @@ -309,6 +311,125 @@ struct acpi_rsdump_info acpi_rs_dump_generic_reg[6] = { {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(generic_reg.address), "Address", NULL} }; +struct acpi_rsdump_info acpi_rs_dump_gpio[16] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_gpio), "GPIO", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.revision_id), "RevisionId", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.connection_type), + "ConnectionType", acpi_gbl_ct_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.pin_config), "PinConfig", + acpi_gbl_ppc_decode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.sharable), "Sharable", + acpi_gbl_shr_decode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.io_restriction), + "IoRestriction", acpi_gbl_ior_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.triggering), "Triggering", + acpi_gbl_he_decode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.polarity), "Polarity", + acpi_gbl_ll_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.drive_strength), "DriveStrength", + NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.debounce_timeout), + "DebounceTimeout", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(gpio.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.pin_table_length), + "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(gpio.pin_table), "PinTable", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.vendor_length), "VendorLength", + NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(gpio.vendor_data), "VendorData", + NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma), + "FixedDma", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.request_lines), + "RequestLines", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.channels), "Channels", + NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_dma.width), "TransferWidth", + acpi_gbl_dts_decode}, +}; + +#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.revision_id), "RevisionId", NULL}, \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type), "Type", acpi_gbl_sbt_decode}, \ + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.producer_consumer), "ProducerConsumer", acpi_gbl_consume_decode}, \ + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.slave_mode), "SlaveMode", acpi_gbl_sm_decode}, \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type_revision_id), "TypeRevisionId", NULL}, \ + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.type_data_length), "TypeDataLength", NULL}, \ + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (common_serial_bus.resource_source), "ResourceSource", NULL}, \ + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.vendor_length), "VendorLength", NULL}, \ + {ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (common_serial_bus.vendor_data), "VendorData", NULL}, + +struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[10] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_common_serial_bus), + "Common Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS +}; + +struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[13] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus), + "I2C Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG, + ACPI_RSD_OFFSET(i2c_serial_bus. + access_mode), + "AccessMode", acpi_gbl_am_decode}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(i2c_serial_bus.connection_speed), + "ConnectionSpeed", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(i2c_serial_bus.slave_address), + "SlaveAddress", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[17] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_spi_serial_bus), + "Spi Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG, + ACPI_RSD_OFFSET(spi_serial_bus. + wire_mode), "WireMode", + acpi_gbl_wm_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(spi_serial_bus.device_polarity), + "DevicePolarity", acpi_gbl_dp_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.data_bit_length), + "DataBitLength", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_phase), + "ClockPhase", acpi_gbl_cph_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_polarity), + "ClockPolarity", acpi_gbl_cpo_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(spi_serial_bus.device_selection), + "DeviceSelection", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(spi_serial_bus.connection_speed), + "ConnectionSpeed", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[19] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_uart_serial_bus), + "Uart Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_2BITFLAG, + ACPI_RSD_OFFSET(uart_serial_bus. + flow_control), + "FlowControl", acpi_gbl_fc_decode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.stop_bits), + "StopBits", acpi_gbl_sb_decode}, + {ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.data_bits), + "DataBits", acpi_gbl_bpb_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.endian), "Endian", + acpi_gbl_ed_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.parity), "Parity", + acpi_gbl_pt_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.lines_enabled), + "LinesEnabled", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.rx_fifo_size), + "RxFifoSize", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.tx_fifo_size), + "TxFifoSize", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(uart_serial_bus.default_baud_rate), + "ConnectionSpeed", NULL}, +}; + /* * Tables used for common address descriptor flag fields */ @@ -413,7 +534,14 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) /* Data items, 8/16/32/64 bit */ case ACPI_RSD_UINT8: - acpi_rs_out_integer8(name, ACPI_GET8(target)); + if (table->pointer) { + acpi_rs_out_string(name, ACPI_CAST_PTR(char, + table-> + pointer + [*target])); + } else { + acpi_rs_out_integer8(name, ACPI_GET8(target)); + } break; case ACPI_RSD_UINT16: @@ -444,6 +572,13 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) 0x03])); break; + case ACPI_RSD_3BITFLAG: + acpi_rs_out_string(name, ACPI_CAST_PTR(char, + table-> + pointer[*target & + 0x07])); + break; + case ACPI_RSD_SHORTLIST: /* * Short byte list (single line output) for DMA and IRQ resources @@ -456,6 +591,20 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) } break; + case ACPI_RSD_SHORTLISTX: + /* + * Short byte list (single line output) for GPIO vendor data + * Note: The list length is obtained from the previous table entry + */ + if (previous_target) { + acpi_rs_out_title(name); + acpi_rs_dump_short_byte_list(*previous_target, + * + (ACPI_CAST_INDIRECT_PTR + (u8, target))); + } + break; + case ACPI_RSD_LONGLIST: /* * Long byte list for Vendor resource data @@ -480,6 +629,18 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) } break; + case ACPI_RSD_WORDLIST: + /* + * Word list for GPIO Pin Table + * Note: The list length is obtained from the previous table entry + */ + if (previous_target) { + acpi_rs_dump_word_list(*previous_target, + *(ACPI_CAST_INDIRECT_PTR + (u16, target))); + } + break; + case ACPI_RSD_ADDRESS: /* * Common flags for all Address resources @@ -627,14 +788,20 @@ void acpi_rs_dump_resource_list(struct acpi_resource *resource_list) /* Dump the resource descriptor */ - acpi_rs_dump_descriptor(&resource_list->data, - acpi_gbl_dump_resource_dispatch[type]); + if (type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + acpi_rs_dump_descriptor(&resource_list->data, + acpi_gbl_dump_serial_bus_dispatch + [resource_list->data. + common_serial_bus.type]); + } else { + acpi_rs_dump_descriptor(&resource_list->data, + acpi_gbl_dump_resource_dispatch + [type]); + } /* Point to the next resource structure */ - resource_list = - ACPI_ADD_PTR(struct acpi_resource, resource_list, - resource_list->length); + resource_list = ACPI_NEXT_RESOURCE(resource_list); /* Exit when END_TAG descriptor is reached */ @@ -768,4 +935,13 @@ static void acpi_rs_dump_dword_list(u8 length, u32 * data) } } +static void acpi_rs_dump_word_list(u16 length, u16 *data) +{ + u16 i; + + for (i = 0; i < length; i++) { + acpi_os_printf("%25s%2.2X : %4.4X\n", "Word", i, data[i]); + } +} + #endif diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index f9ea60872aa4..a9fa5158200b 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -76,7 +76,10 @@ struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[] = { acpi_rs_convert_address64, /* 0x0D, ACPI_RESOURCE_TYPE_ADDRESS64 */ acpi_rs_convert_ext_address64, /* 0x0E, ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ acpi_rs_convert_ext_irq, /* 0x0F, ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ - acpi_rs_convert_generic_reg /* 0x10, ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + acpi_rs_convert_generic_reg, /* 0x10, ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + acpi_rs_convert_gpio, /* 0x11, ACPI_RESOURCE_TYPE_GPIO */ + acpi_rs_convert_fixed_dma, /* 0x12, ACPI_RESOURCE_TYPE_FIXED_DMA */ + NULL, /* 0x13, ACPI_RESOURCE_TYPE_SERIAL_BUS - Use subtype table below */ }; /* Dispatch tables for AML-to-resource (Get Resource) conversion functions */ @@ -94,7 +97,7 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = { acpi_rs_convert_end_dpf, /* 0x07, ACPI_RESOURCE_NAME_END_DEPENDENT */ acpi_rs_convert_io, /* 0x08, ACPI_RESOURCE_NAME_IO */ acpi_rs_convert_fixed_io, /* 0x09, ACPI_RESOURCE_NAME_FIXED_IO */ - NULL, /* 0x0A, Reserved */ + acpi_rs_convert_fixed_dma, /* 0x0A, ACPI_RESOURCE_NAME_FIXED_DMA */ NULL, /* 0x0B, Reserved */ NULL, /* 0x0C, Reserved */ NULL, /* 0x0D, Reserved */ @@ -114,7 +117,19 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = { acpi_rs_convert_address16, /* 0x08, ACPI_RESOURCE_NAME_ADDRESS16 */ acpi_rs_convert_ext_irq, /* 0x09, ACPI_RESOURCE_NAME_EXTENDED_IRQ */ acpi_rs_convert_address64, /* 0x0A, ACPI_RESOURCE_NAME_ADDRESS64 */ - acpi_rs_convert_ext_address64 /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */ + acpi_rs_convert_ext_address64, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */ + acpi_rs_convert_gpio, /* 0x0C, ACPI_RESOURCE_NAME_GPIO */ + NULL, /* 0x0D, Reserved */ + NULL, /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS - Use subtype table below */ +}; + +/* Subtype table for serial_bus -- I2C, SPI, and UART */ + +struct acpi_rsconvert_info *acpi_gbl_convert_resource_serial_bus_dispatch[] = { + NULL, + acpi_rs_convert_i2c_serial_bus, + acpi_rs_convert_spi_serial_bus, + acpi_rs_convert_uart_serial_bus, }; #ifdef ACPI_FUTURE_USAGE @@ -140,6 +155,16 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = { acpi_rs_dump_ext_address64, /* ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ acpi_rs_dump_ext_irq, /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ acpi_rs_dump_generic_reg, /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + acpi_rs_dump_gpio, /* ACPI_RESOURCE_TYPE_GPIO */ + acpi_rs_dump_fixed_dma, /* ACPI_RESOURCE_TYPE_FIXED_DMA */ + NULL, /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ +}; + +struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = { + NULL, + acpi_rs_dump_i2c_serial_bus, /* AML_RESOURCE_I2C_BUS_TYPE */ + acpi_rs_dump_spi_serial_bus, /* AML_RESOURCE_SPI_BUS_TYPE */ + acpi_rs_dump_uart_serial_bus, /* AML_RESOURCE_UART_BUS_TYPE */ }; #endif @@ -166,7 +191,10 @@ const u8 acpi_gbl_aml_resource_sizes[] = { sizeof(struct aml_resource_address64), /* ACPI_RESOURCE_TYPE_ADDRESS64 */ sizeof(struct aml_resource_extended_address64), /*ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ sizeof(struct aml_resource_extended_irq), /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ - sizeof(struct aml_resource_generic_register) /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + sizeof(struct aml_resource_generic_register), /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + sizeof(struct aml_resource_gpio), /* ACPI_RESOURCE_TYPE_GPIO */ + sizeof(struct aml_resource_fixed_dma), /* ACPI_RESOURCE_TYPE_FIXED_DMA */ + sizeof(struct aml_resource_common_serialbus), /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ }; const u8 acpi_gbl_resource_struct_sizes[] = { @@ -182,7 +210,7 @@ const u8 acpi_gbl_resource_struct_sizes[] = { ACPI_RS_SIZE_MIN, ACPI_RS_SIZE(struct acpi_resource_io), ACPI_RS_SIZE(struct acpi_resource_fixed_io), - 0, + ACPI_RS_SIZE(struct acpi_resource_fixed_dma), 0, 0, 0, @@ -202,5 +230,21 @@ const u8 acpi_gbl_resource_struct_sizes[] = { ACPI_RS_SIZE(struct acpi_resource_address16), ACPI_RS_SIZE(struct acpi_resource_extended_irq), ACPI_RS_SIZE(struct acpi_resource_address64), - ACPI_RS_SIZE(struct acpi_resource_extended_address64) + ACPI_RS_SIZE(struct acpi_resource_extended_address64), + ACPI_RS_SIZE(struct acpi_resource_gpio), + ACPI_RS_SIZE(struct acpi_resource_common_serialbus) +}; + +const u8 acpi_gbl_aml_resource_serial_bus_sizes[] = { + 0, + sizeof(struct aml_resource_i2c_serialbus), + sizeof(struct aml_resource_spi_serialbus), + sizeof(struct aml_resource_uart_serialbus), +}; + +const u8 acpi_gbl_resource_struct_serial_bus_sizes[] = { + 0, + ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus), + ACPI_RS_SIZE(struct acpi_resource_spi_serialbus), + ACPI_RS_SIZE(struct acpi_resource_uart_serialbus), }; diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c index 0c7efef008be..f6a081057a22 100644 --- a/drivers/acpi/acpica/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c index 50b8ad211167..e23a9ec248cb 100644 --- a/drivers/acpi/acpica/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -264,3 +264,34 @@ struct acpi_rsconvert_info acpi_rs_convert_dma[6] = { AML_OFFSET(dma.dma_channel_mask), ACPI_RS_OFFSET(data.dma.channel_count)} }; + +/******************************************************************************* + * + * acpi_rs_convert_fixed_dma + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[4] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_DMA, + ACPI_RS_SIZE(struct acpi_resource_fixed_dma), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_fixed_dma)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_DMA, + sizeof(struct aml_resource_fixed_dma), + 0}, + + /* + * These fields are contiguous in both the source and destination: + * request_lines + * Channels + */ + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.fixed_dma.request_lines), + AML_OFFSET(fixed_dma.request_lines), + 2}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.fixed_dma.width), + AML_OFFSET(fixed_dma.width), + 1}, + +}; diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 1bfcef736c50..9be129f5d6f4 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,6 +70,8 @@ acpi_rs_convert_aml_to_resources(u8 * aml, struct acpi_resource **resource_ptr = ACPI_CAST_INDIRECT_PTR(struct acpi_resource, context); struct acpi_resource *resource; + union aml_resource *aml_resource; + struct acpi_rsconvert_info *conversion_table; acpi_status status; ACPI_FUNCTION_TRACE(rs_convert_aml_to_resources); @@ -84,14 +86,37 @@ acpi_rs_convert_aml_to_resources(u8 * aml, "Misaligned resource pointer %p", resource)); } + /* Get the appropriate conversion info table */ + + aml_resource = ACPI_CAST_PTR(union aml_resource, aml); + if (acpi_ut_get_resource_type(aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { + if (aml_resource->common_serial_bus.type > + AML_RESOURCE_MAX_SERIALBUSTYPE) { + conversion_table = NULL; + } else { + /* This is an I2C, SPI, or UART serial_bus descriptor */ + + conversion_table = + acpi_gbl_convert_resource_serial_bus_dispatch + [aml_resource->common_serial_bus.type]; + } + } else { + conversion_table = + acpi_gbl_get_resource_dispatch[resource_index]; + } + + if (!conversion_table) { + ACPI_ERROR((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + resource_index)); + return (AE_AML_INVALID_RESOURCE_TYPE); + } + /* Convert the AML byte stream resource to a local resource struct */ status = - acpi_rs_convert_aml_to_resource(resource, - ACPI_CAST_PTR(union aml_resource, - aml), - acpi_gbl_get_resource_dispatch - [resource_index]); + acpi_rs_convert_aml_to_resource(resource, aml_resource, + conversion_table); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not convert AML resource (Type 0x%X)", @@ -106,7 +131,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, /* Point to the next structure in the output buffer */ - *resource_ptr = ACPI_ADD_PTR(void, resource, resource->length); + *resource_ptr = ACPI_NEXT_RESOURCE(resource); return_ACPI_STATUS(AE_OK); } @@ -135,6 +160,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, { u8 *aml = output_buffer; u8 *end_aml = output_buffer + aml_size_needed; + struct acpi_rsconvert_info *conversion_table; acpi_status status; ACPI_FUNCTION_TRACE(rs_convert_resources_to_aml); @@ -154,11 +180,34 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, /* Perform the conversion */ - status = acpi_rs_convert_resource_to_aml(resource, ACPI_CAST_PTR(union - aml_resource, - aml), - acpi_gbl_set_resource_dispatch - [resource->type]); + if (resource->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + if (resource->data.common_serial_bus.type > + AML_RESOURCE_MAX_SERIALBUSTYPE) { + conversion_table = NULL; + } else { + /* This is an I2C, SPI, or UART serial_bus descriptor */ + + conversion_table = + acpi_gbl_convert_resource_serial_bus_dispatch + [resource->data.common_serial_bus.type]; + } + } else { + conversion_table = + acpi_gbl_set_resource_dispatch[resource->type]; + } + + if (!conversion_table) { + ACPI_ERROR((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + resource->type)); + return (AE_AML_INVALID_RESOURCE_TYPE); + } + + status = acpi_rs_convert_resource_to_aml(resource, + ACPI_CAST_PTR(union + aml_resource, + aml), + conversion_table); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not convert resource (type 0x%X) to AML", @@ -192,9 +241,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, /* Point to the next input resource descriptor */ - resource = - ACPI_ADD_PTR(struct acpi_resource, resource, - resource->length); + resource = ACPI_NEXT_RESOURCE(resource); } /* Completed buffer, but did not find an end_tag resource descriptor */ diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index 7cc6d8625f1e..4fd611ad02b4 100644 --- a/drivers/acpi/acpica/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 410264b22a29..8073b371cc7c 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -83,6 +83,10 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource); + if (!info) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + if (((acpi_size) resource) & 0x3) { /* Each internal resource struct is expected to be 32-bit aligned */ @@ -101,7 +105,6 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, * table length (# of table entries) */ count = INIT_TABLE_LENGTH(info); - while (count) { /* * Source is the external AML byte stream buffer, @@ -145,6 +148,14 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, ((ACPI_GET8(source) >> info->value) & 0x03); break; + case ACPI_RSC_3BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET8(destination) = (u8) + ((ACPI_GET8(source) >> info->value) & 0x07); + break; + case ACPI_RSC_COUNT: item_count = ACPI_GET8(source); @@ -163,6 +174,69 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, (info->value * (item_count - 1)); break; + case ACPI_RSC_COUNT_GPIO_PIN: + + target = ACPI_ADD_PTR(void, aml, info->value); + item_count = ACPI_GET16(target) - ACPI_GET16(source); + + resource->length = resource->length + item_count; + item_count = item_count / 2; + ACPI_SET16(destination) = item_count; + break; + + case ACPI_RSC_COUNT_GPIO_VEN: + + item_count = ACPI_GET8(source); + ACPI_SET8(destination) = (u8)item_count; + + resource->length = resource->length + + (info->value * item_count); + break; + + case ACPI_RSC_COUNT_GPIO_RES: + + /* + * Vendor data is optional (length/offset may both be zero) + * Examine vendor data length field first + */ + target = ACPI_ADD_PTR(void, aml, (info->value + 2)); + if (ACPI_GET16(target)) { + + /* Use vendor offset to get resource source length */ + + target = ACPI_ADD_PTR(void, aml, info->value); + item_count = + ACPI_GET16(target) - ACPI_GET16(source); + } else { + /* No vendor data to worry about */ + + item_count = aml->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + ACPI_GET16(source); + } + + resource->length = resource->length + item_count; + ACPI_SET16(destination) = item_count; + break; + + case ACPI_RSC_COUNT_SERIAL_VEN: + + item_count = ACPI_GET16(source) - info->value; + + resource->length = resource->length + item_count; + ACPI_SET16(destination) = item_count; + break; + + case ACPI_RSC_COUNT_SERIAL_RES: + + item_count = (aml_resource_length + + sizeof(struct aml_resource_large_header)) + - ACPI_GET16(source) - info->value; + + resource->length = resource->length + item_count; + ACPI_SET16(destination) = item_count; + break; + case ACPI_RSC_LENGTH: resource->length = resource->length + info->value; @@ -183,6 +257,72 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, info->opcode); break; + case ACPI_RSC_MOVE_GPIO_PIN: + + /* Generate and set the PIN data pointer */ + + target = (char *)ACPI_ADD_PTR(void, resource, + (resource->length - + item_count * 2)); + *(u16 **)destination = ACPI_CAST_PTR(u16, target); + + /* Copy the PIN data */ + + source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); + acpi_rs_move_data(target, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_GPIO_RES: + + /* Generate and set the resource_source string pointer */ + + target = (char *)ACPI_ADD_PTR(void, resource, + (resource->length - + item_count)); + *(u8 **)destination = ACPI_CAST_PTR(u8, target); + + /* Copy the resource_source string */ + + source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); + acpi_rs_move_data(target, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_VEN: + + /* Generate and set the Vendor Data pointer */ + + target = (char *)ACPI_ADD_PTR(void, resource, + (resource->length - + item_count)); + *(u8 **)destination = ACPI_CAST_PTR(u8, target); + + /* Copy the Vendor Data */ + + source = ACPI_ADD_PTR(void, aml, info->value); + acpi_rs_move_data(target, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_RES: + + /* Generate and set the resource_source string pointer */ + + target = (char *)ACPI_ADD_PTR(void, resource, + (resource->length - + item_count)); + *(u8 **)destination = ACPI_CAST_PTR(u8, target); + + /* Copy the resource_source string */ + + source = + ACPI_ADD_PTR(void, aml, + (ACPI_GET16(source) + info->value)); + acpi_rs_move_data(target, source, item_count, + info->opcode); + break; + case ACPI_RSC_SET8: ACPI_MEMSET(destination, info->aml_offset, info->value); @@ -219,13 +359,18 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, * Optional resource_source (Index and String). This is the more * complicated case used by the Interrupt() macro */ - target = - ACPI_ADD_PTR(char, resource, - info->aml_offset + (item_count * 4)); + target = ACPI_ADD_PTR(char, resource, + info->aml_offset + + (item_count * 4)); resource->length += acpi_rs_get_resource_source(aml_resource_length, - (acpi_rs_length) (((item_count - 1) * sizeof(u32)) + info->value), destination, aml, target); + (acpi_rs_length) + (((item_count - + 1) * sizeof(u32)) + + info->value), + destination, aml, + target); break; case ACPI_RSC_BITMASK: @@ -327,6 +472,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, { void *source = NULL; void *destination; + char *target; acpi_rsdesc_size aml_length = 0; u8 count; u16 temp16 = 0; @@ -334,6 +480,10 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml); + if (!info) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + /* * First table entry must be ACPI_RSC_INITxxx and must contain the * table length (# of table entries) @@ -383,6 +533,14 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, ((ACPI_GET8(source) & 0x03) << info->value); break; + case ACPI_RSC_3BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET8(destination) |= (u8) + ((ACPI_GET8(source) & 0x07) << info->value); + break; + case ACPI_RSC_COUNT: item_count = ACPI_GET8(source); @@ -400,6 +558,63 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, acpi_rs_set_resource_length(aml_length, aml); break; + case ACPI_RSC_COUNT_GPIO_PIN: + + item_count = ACPI_GET16(source); + ACPI_SET16(destination) = (u16)aml_length; + + aml_length = (u16)(aml_length + item_count * 2); + target = ACPI_ADD_PTR(void, aml, info->value); + ACPI_SET16(target) = (u16)aml_length; + acpi_rs_set_resource_length(aml_length, aml); + break; + + case ACPI_RSC_COUNT_GPIO_VEN: + + item_count = ACPI_GET16(source); + ACPI_SET16(destination) = (u16)item_count; + + aml_length = + (u16)(aml_length + (info->value * item_count)); + acpi_rs_set_resource_length(aml_length, aml); + break; + + case ACPI_RSC_COUNT_GPIO_RES: + + /* Set resource source string length */ + + item_count = ACPI_GET16(source); + ACPI_SET16(destination) = (u16)aml_length; + + /* Compute offset for the Vendor Data */ + + aml_length = (u16)(aml_length + item_count); + target = ACPI_ADD_PTR(void, aml, info->value); + + /* Set vendor offset only if there is vendor data */ + + if (resource->data.gpio.vendor_length) { + ACPI_SET16(target) = (u16)aml_length; + } + + acpi_rs_set_resource_length(aml_length, aml); + break; + + case ACPI_RSC_COUNT_SERIAL_VEN: + + item_count = ACPI_GET16(source); + ACPI_SET16(destination) = item_count + info->value; + aml_length = (u16)(aml_length + item_count); + acpi_rs_set_resource_length(aml_length, aml); + break; + + case ACPI_RSC_COUNT_SERIAL_RES: + + item_count = ACPI_GET16(source); + aml_length = (u16)(aml_length + item_count); + acpi_rs_set_resource_length(aml_length, aml); + break; + case ACPI_RSC_LENGTH: acpi_rs_set_resource_length(info->value, aml); @@ -417,6 +632,48 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, info->opcode); break; + case ACPI_RSC_MOVE_GPIO_PIN: + + destination = (char *)ACPI_ADD_PTR(void, aml, + ACPI_GET16 + (destination)); + source = *(u16 **)source; + acpi_rs_move_data(destination, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_GPIO_RES: + + /* Used for both resource_source string and vendor_data */ + + destination = (char *)ACPI_ADD_PTR(void, aml, + ACPI_GET16 + (destination)); + source = *(u8 **)source; + acpi_rs_move_data(destination, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_VEN: + + destination = (char *)ACPI_ADD_PTR(void, aml, + (aml_length - + item_count)); + source = *(u8 **)source; + acpi_rs_move_data(destination, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_RES: + + destination = (char *)ACPI_ADD_PTR(void, aml, + (aml_length - + item_count)); + source = *(u8 **)source; + acpi_rs_move_data(destination, source, item_count, + info->opcode); + break; + case ACPI_RSC_ADDRESS: /* Set the Resource Type, General Flags, and Type-Specific Flags */ diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c new file mode 100644 index 000000000000..9aa5e689b444 --- /dev/null +++ b/drivers/acpi/acpica/rsserial.c @@ -0,0 +1,441 @@ +/******************************************************************************* + * + * Module Name: rsserial - GPIO/serial_bus resource descriptors + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES +ACPI_MODULE_NAME("rsserial") + +/******************************************************************************* + * + * acpi_rs_convert_gpio + * + ******************************************************************************/ +struct acpi_rsconvert_info acpi_rs_convert_gpio[17] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GPIO, + ACPI_RS_SIZE(struct acpi_resource_gpio), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_gpio)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_GPIO, + sizeof(struct aml_resource_gpio), + 0}, + + /* + * These fields are contiguous in both the source and destination: + * revision_id + * connection_type + */ + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.revision_id), + AML_OFFSET(gpio.revision_id), + 2}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.producer_consumer), + AML_OFFSET(gpio.flags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.sharable), + AML_OFFSET(gpio.int_flags), + 3}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.io_restriction), + AML_OFFSET(gpio.int_flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.triggering), + AML_OFFSET(gpio.int_flags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.polarity), + AML_OFFSET(gpio.int_flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.pin_config), + AML_OFFSET(gpio.pin_config), + 1}, + + /* + * These fields are contiguous in both the source and destination: + * drive_strength + * debounce_timeout + */ + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.gpio.drive_strength), + AML_OFFSET(gpio.drive_strength), + 2}, + + /* Pin Table */ + + {ACPI_RSC_COUNT_GPIO_PIN, ACPI_RS_OFFSET(data.gpio.pin_table_length), + AML_OFFSET(gpio.pin_table_offset), + AML_OFFSET(gpio.res_source_offset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.gpio.pin_table), + AML_OFFSET(gpio.pin_table_offset), + 0}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.resource_source.index), + AML_OFFSET(gpio.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.gpio.resource_source.string_length), + AML_OFFSET(gpio.res_source_offset), + AML_OFFSET(gpio.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.gpio.resource_source.string_ptr), + AML_OFFSET(gpio.res_source_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET(data.gpio.vendor_length), + AML_OFFSET(gpio.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.gpio.vendor_data), + AML_OFFSET(gpio.vendor_offset), + 0}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_i2c_serial_bus + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[16] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_i2c_serial_bus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof(struct aml_resource_i2c_serialbus), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), + AML_OFFSET(common_serial_bus.revision_id), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), + AML_OFFSET(common_serial_bus.type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), + AML_OFFSET(common_serial_bus.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), + AML_OFFSET(common_serial_bus.flags), + 1}, + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), + AML_OFFSET(common_serial_bus.type_revision_id), + 1}, + + {ACPI_RSC_MOVE16, + ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), + AML_OFFSET(common_serial_bus.type_data_length), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), + AML_OFFSET(common_serial_bus.type_data_length), + AML_RESOURCE_I2C_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), + 0, + sizeof(struct aml_resource_i2c_serialbus)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), + AML_OFFSET(common_serial_bus.res_source_index), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + {ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + /* I2C bus type specific */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.i2c_serial_bus.access_mode), + AML_OFFSET(i2c_serial_bus.type_specific_flags), + 0}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.i2c_serial_bus.connection_speed), + AML_OFFSET(i2c_serial_bus.connection_speed), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.i2c_serial_bus.slave_address), + AML_OFFSET(i2c_serial_bus.slave_address), + 1}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_spi_serial_bus + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[20] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE(struct acpi_resource_spi_serialbus), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_spi_serial_bus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof(struct aml_resource_spi_serialbus), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), + AML_OFFSET(common_serial_bus.revision_id), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), + AML_OFFSET(common_serial_bus.type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), + AML_OFFSET(common_serial_bus.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), + AML_OFFSET(common_serial_bus.flags), + 1}, + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), + AML_OFFSET(common_serial_bus.type_revision_id), + 1}, + + {ACPI_RSC_MOVE16, + ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), + AML_OFFSET(common_serial_bus.type_data_length), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), + AML_OFFSET(common_serial_bus.type_data_length), + AML_RESOURCE_SPI_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), + 0, + sizeof(struct aml_resource_spi_serialbus)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), + AML_OFFSET(common_serial_bus.res_source_index), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + {ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + /* Spi bus type specific */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.spi_serial_bus.wire_mode), + AML_OFFSET(spi_serial_bus.type_specific_flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.spi_serial_bus.device_polarity), + AML_OFFSET(spi_serial_bus.type_specific_flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.data_bit_length), + AML_OFFSET(spi_serial_bus.data_bit_length), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.clock_phase), + AML_OFFSET(spi_serial_bus.clock_phase), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.clock_polarity), + AML_OFFSET(spi_serial_bus.clock_polarity), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.spi_serial_bus.device_selection), + AML_OFFSET(spi_serial_bus.device_selection), + 1}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.spi_serial_bus.connection_speed), + AML_OFFSET(spi_serial_bus.connection_speed), + 1}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_uart_serial_bus + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[22] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE(struct acpi_resource_uart_serialbus), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_uart_serial_bus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof(struct aml_resource_uart_serialbus), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), + AML_OFFSET(common_serial_bus.revision_id), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), + AML_OFFSET(common_serial_bus.type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), + AML_OFFSET(common_serial_bus.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), + AML_OFFSET(common_serial_bus.flags), + 1}, + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), + AML_OFFSET(common_serial_bus.type_revision_id), + 1}, + + {ACPI_RSC_MOVE16, + ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), + AML_OFFSET(common_serial_bus.type_data_length), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), + AML_OFFSET(common_serial_bus.type_data_length), + AML_RESOURCE_UART_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), + 0, + sizeof(struct aml_resource_uart_serialbus)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), + AML_OFFSET(common_serial_bus.res_source_index), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + {ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + /* Uart bus type specific */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.flow_control), + AML_OFFSET(uart_serial_bus.type_specific_flags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.stop_bits), + AML_OFFSET(uart_serial_bus.type_specific_flags), + 2}, + + {ACPI_RSC_3BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.data_bits), + AML_OFFSET(uart_serial_bus.type_specific_flags), + 4}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.endian), + AML_OFFSET(uart_serial_bus.type_specific_flags), + 7}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.uart_serial_bus.parity), + AML_OFFSET(uart_serial_bus.parity), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.uart_serial_bus.lines_enabled), + AML_OFFSET(uart_serial_bus.lines_enabled), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.uart_serial_bus.rx_fifo_size), + AML_OFFSET(uart_serial_bus.rx_fifo_size), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.uart_serial_bus.tx_fifo_size), + AML_OFFSET(uart_serial_bus.tx_fifo_size), + 1}, + + {ACPI_RSC_MOVE32, + ACPI_RS_OFFSET(data.uart_serial_bus.default_baud_rate), + AML_OFFSET(uart_serial_bus.default_baud_rate), + 1}, +}; diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index 231811e56939..433a375deb93 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -144,6 +144,9 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type) * since there are no alignment or endian issues */ case ACPI_RSC_MOVE8: + case ACPI_RSC_MOVE_GPIO_RES: + case ACPI_RSC_MOVE_SERIAL_VEN: + case ACPI_RSC_MOVE_SERIAL_RES: ACPI_MEMCPY(destination, source, item_count); return; @@ -153,6 +156,7 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type) * misaligned memory transfers */ case ACPI_RSC_MOVE16: + case ACPI_RSC_MOVE_GPIO_PIN: ACPI_MOVE_16_TO_16(&ACPI_CAST_PTR(u16, destination)[i], &ACPI_CAST_PTR(u16, source)[i]); break; @@ -590,6 +594,56 @@ acpi_rs_get_prs_method_data(struct acpi_namespace_node *node, /******************************************************************************* * + * FUNCTION: acpi_rs_get_aei_method_data + * + * PARAMETERS: Node - Device node + * ret_buffer - Pointer to a buffer structure for the + * results + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the _AEI value of an object + * contained in an object specified by the handle passed in + * + * If the function fails an appropriate status will be returned + * and the contents of the callers buffer is undefined. + * + ******************************************************************************/ + +acpi_status +acpi_rs_get_aei_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + ACPI_FUNCTION_TRACE(rs_get_aei_method_data); + + /* Parameters guaranteed valid by caller */ + + /* Execute the method, no parameters */ + + status = acpi_ut_evaluate_object(node, METHOD_NAME__AEI, + ACPI_BTYPE_BUFFER, &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* + * Make the call to create a resource linked list from the + * byte stream buffer that comes back from the _CRS method + * execution. + */ + status = acpi_rs_create_resource_list(obj_desc, ret_buffer); + + /* On exit, we must delete the object returned by evaluate_object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * * FUNCTION: acpi_rs_get_method_data * * PARAMETERS: Handle - Handle to the containing object diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index fe86b37b16ce..f58c098c7aeb 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -307,6 +307,46 @@ acpi_set_current_resources(acpi_handle device_handle, ACPI_EXPORT_SYMBOL(acpi_set_current_resources) +/******************************************************************************* + * + * FUNCTION: acpi_get_event_resources + * + * PARAMETERS: device_handle - Handle to the device object for the + * device we are getting resources + * in_buffer - Pointer to a buffer containing the + * resources to be set for the device + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the event resources for a + * specific device. The caller must first acquire a handle for + * the desired device. The resource data is passed to the routine + * the buffer pointed to by the in_buffer variable. Uses the + * _AEI method. + * + ******************************************************************************/ +acpi_status +acpi_get_event_resources(acpi_handle device_handle, + struct acpi_buffer *ret_buffer) +{ + acpi_status status; + struct acpi_namespace_node *node; + + ACPI_FUNCTION_TRACE(acpi_get_event_resources); + + /* Validate parameters then dispatch to internal routine */ + + status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_rs_get_aei_method_data(node, ret_buffer); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_get_event_resources) + /****************************************************************************** * * FUNCTION: acpi_resource_to_address64 @@ -486,8 +526,9 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) * * PARAMETERS: device_handle - Handle to the device object for the * device we are querying - * Name - Method name of the resources we want - * (METHOD_NAME__CRS or METHOD_NAME__PRS) + * Name - Method name of the resources we want. + * (METHOD_NAME__CRS, METHOD_NAME__PRS, or + * METHOD_NAME__AEI) * user_function - Called for each resource * Context - Passed to user_function * @@ -514,11 +555,12 @@ acpi_walk_resources(acpi_handle device_handle, if (!device_handle || !user_function || !name || (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) && - !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS))) { + !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) && + !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) { return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Get the _CRS or _PRS resource list */ + /* Get the _CRS/_PRS/_AEI resource list */ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; status = acpi_rs_get_method_data(device_handle, name, &buffer); diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 6f5588e62c0a..c5d870406f41 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,14 +63,15 @@ static void acpi_tb_setup_fadt_registers(void); typedef struct acpi_fadt_info { char *name; - u8 address64; - u8 address32; - u8 length; + u16 address64; + u16 address32; + u16 length; u8 default_length; u8 type; } acpi_fadt_info; +#define ACPI_FADT_OPTIONAL 0 #define ACPI_FADT_REQUIRED 1 #define ACPI_FADT_SEPARATE_LENGTH 2 @@ -87,7 +88,7 @@ static struct acpi_fadt_info fadt_info_table[] = { ACPI_FADT_OFFSET(pm1b_event_block), ACPI_FADT_OFFSET(pm1_event_length), ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ - 0}, + ACPI_FADT_OPTIONAL}, {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block), @@ -101,7 +102,7 @@ static struct acpi_fadt_info fadt_info_table[] = { ACPI_FADT_OFFSET(pm1b_control_block), ACPI_FADT_OFFSET(pm1_control_length), ACPI_PM1_REGISTER_WIDTH, - 0}, + ACPI_FADT_OPTIONAL}, {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block), @@ -139,7 +140,7 @@ static struct acpi_fadt_info fadt_info_table[] = { typedef struct acpi_fadt_pm_info { struct acpi_generic_address *target; - u8 source; + u16 source; u8 register_num; } acpi_fadt_pm_info; @@ -253,8 +254,13 @@ void acpi_tb_parse_fadt(u32 table_index) acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); - acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, - ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); + /* If Hardware Reduced flag is set, there is no FACS */ + + if (!acpi_gbl_reduced_hardware) { + acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT. + Xfacs, ACPI_SIG_FACS, + ACPI_TABLE_INDEX_FACS); + } } /******************************************************************************* @@ -277,12 +283,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) { /* * Check if the FADT is larger than the largest table that we expect - * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue + * (the ACPI 5.0 version). If so, truncate the table, and issue * a warning. */ if (length > sizeof(struct acpi_table_fadt)) { ACPI_WARNING((AE_INFO, - "FADT (revision %u) is longer than ACPI 2.0 version, " + "FADT (revision %u) is longer than ACPI 5.0 version, " "truncating length %u to %u", table->revision, length, (u32)sizeof(struct acpi_table_fadt))); @@ -297,6 +303,13 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) ACPI_MEMCPY(&acpi_gbl_FADT, table, ACPI_MIN(length, sizeof(struct acpi_table_fadt))); + /* Take a copy of the Hardware Reduced flag */ + + acpi_gbl_reduced_hardware = FALSE; + if (acpi_gbl_FADT.flags & ACPI_FADT_HW_REDUCED) { + acpi_gbl_reduced_hardware = TRUE; + } + /* Convert the local copy of the FADT to the common internal format */ acpi_tb_convert_fadt(); @@ -502,6 +515,12 @@ static void acpi_tb_validate_fadt(void) acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; } + /* If Hardware Reduced flag is set, we are all done */ + + if (acpi_gbl_reduced_hardware) { + return; + } + /* Examine all of the 64-bit extended address fields (X fields) */ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index a55cb2bb5abb..4903e36ea75a 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 62365f6075dd..1aecf7baa4e0 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 0f2d395feaba..09ca39e14337 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -135,6 +135,13 @@ acpi_status acpi_tb_initialize_facs(void) { acpi_status status; + /* If Hardware Reduced flag is set, there is no FACS */ + + if (acpi_gbl_reduced_hardware) { + acpi_gbl_FACS = NULL; + return (AE_OK); + } + status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, ACPI_CAST_INDIRECT_PTR(struct acpi_table_header, diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index e7d13f5d3f2d..abcc6412c244 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 7eb6c6cc1edf..4258f647ca3d 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c new file mode 100644 index 000000000000..67932aebe6dd --- /dev/null +++ b/drivers/acpi/acpica/utaddress.c @@ -0,0 +1,294 @@ +/****************************************************************************** + * + * Module Name: utaddress - op_region address range check + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utaddress") + +/******************************************************************************* + * + * FUNCTION: acpi_ut_add_address_range + * + * PARAMETERS: space_id - Address space ID + * Address - op_region start address + * Length - op_region length + * region_node - op_region namespace node + * + * RETURN: Status + * + * DESCRIPTION: Add the Operation Region address range to the global list. + * The only supported Space IDs are Memory and I/O. Called when + * the op_region address/length operands are fully evaluated. + * + * MUTEX: Locks the namespace + * + * NOTE: Because this interface is only called when an op_region argument + * list is evaluated, there cannot be any duplicate region_nodes. + * Duplicate Address/Length values are allowed, however, so that multiple + * address conflicts can be detected. + * + ******************************************************************************/ +acpi_status +acpi_ut_add_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, + u32 length, struct acpi_namespace_node *region_node) +{ + struct acpi_address_range *range_info; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_add_address_range); + + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + return_ACPI_STATUS(AE_OK); + } + + /* Allocate/init a new info block, add it to the appropriate list */ + + range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range)); + if (!range_info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + range_info->start_address = address; + range_info->end_address = (address + length - 1); + range_info->region_node = region_node; + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + ACPI_FREE(range_info); + return_ACPI_STATUS(status); + } + + range_info->next = acpi_gbl_address_range_list[space_id]; + acpi_gbl_address_range_list[space_id] = range_info; + + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, + "\nAdded [%4.4s] address range: 0x%p-0x%p\n", + acpi_ut_get_node_name(range_info->region_node), + ACPI_CAST_PTR(void, address), + ACPI_CAST_PTR(void, range_info->end_address))); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_remove_address_range + * + * PARAMETERS: space_id - Address space ID + * region_node - op_region namespace node + * + * RETURN: None + * + * DESCRIPTION: Remove the Operation Region from the global list. The only + * supported Space IDs are Memory and I/O. Called when an + * op_region is deleted. + * + * MUTEX: Assumes the namespace is locked + * + ******************************************************************************/ + +void +acpi_ut_remove_address_range(acpi_adr_space_type space_id, + struct acpi_namespace_node *region_node) +{ + struct acpi_address_range *range_info; + struct acpi_address_range *prev; + + ACPI_FUNCTION_TRACE(ut_remove_address_range); + + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + return_VOID; + } + + /* Get the appropriate list head and check the list */ + + range_info = prev = acpi_gbl_address_range_list[space_id]; + while (range_info) { + if (range_info->region_node == region_node) { + if (range_info == prev) { /* Found at list head */ + acpi_gbl_address_range_list[space_id] = + range_info->next; + } else { + prev->next = range_info->next; + } + + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, + "\nRemoved [%4.4s] address range: 0x%p-0x%p\n", + acpi_ut_get_node_name(range_info-> + region_node), + ACPI_CAST_PTR(void, + range_info-> + start_address), + ACPI_CAST_PTR(void, + range_info-> + end_address))); + + ACPI_FREE(range_info); + return_VOID; + } + + prev = range_info; + range_info = range_info->next; + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_check_address_range + * + * PARAMETERS: space_id - Address space ID + * Address - Start address + * Length - Length of address range + * Warn - TRUE if warning on overlap desired + * + * RETURN: Count of the number of conflicts detected. Zero is always + * returned for Space IDs other than Memory or I/O. + * + * DESCRIPTION: Check if the input address range overlaps any of the + * ASL operation region address ranges. The only supported + * Space IDs are Memory and I/O. + * + * MUTEX: Assumes the namespace is locked. + * + ******************************************************************************/ + +u32 +acpi_ut_check_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, u32 length, u8 warn) +{ + struct acpi_address_range *range_info; + acpi_physical_address end_address; + char *pathname; + u32 overlap_count = 0; + + ACPI_FUNCTION_TRACE(ut_check_address_range); + + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + return_UINT32(0); + } + + range_info = acpi_gbl_address_range_list[space_id]; + end_address = address + length - 1; + + /* Check entire list for all possible conflicts */ + + while (range_info) { + /* + * Check if the requested Address/Length overlaps this address_range. + * Four cases to consider: + * + * 1) Input address/length is contained completely in the address range + * 2) Input address/length overlaps range at the range start + * 3) Input address/length overlaps range at the range end + * 4) Input address/length completely encompasses the range + */ + if ((address <= range_info->end_address) && + (end_address >= range_info->start_address)) { + + /* Found an address range overlap */ + + overlap_count++; + if (warn) { /* Optional warning message */ + pathname = + acpi_ns_get_external_pathname(range_info-> + region_node); + + ACPI_WARNING((AE_INFO, + "0x%p-0x%p %s conflicts with Region %s %d", + ACPI_CAST_PTR(void, address), + ACPI_CAST_PTR(void, end_address), + acpi_ut_get_region_name(space_id), + pathname, overlap_count)); + ACPI_FREE(pathname); + } + } + + range_info = range_info->next; + } + + return_UINT32(overlap_count); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_address_lists + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all global address range lists (called during + * subsystem shutdown). + * + ******************************************************************************/ + +void acpi_ut_delete_address_lists(void) +{ + struct acpi_address_range *next; + struct acpi_address_range *range_info; + int i; + + /* Delete all elements in all address range lists */ + + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { + next = acpi_gbl_address_range_list[i]; + + while (next) { + range_info = next; + next = range_info->next; + ACPI_FREE(range_info); + } + + acpi_gbl_address_range_list[i] = NULL; + } +} diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 0a697351cf69..9982d2ea66fb 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index aded299a2fa8..3317c0a406ee 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index a1f8d7509e66..a0998a886318 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 8b087e2d64f4..d42ede5260c7 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -171,7 +171,9 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { "SMBus", "SystemCMOS", "PCIBARTarget", - "IPMI" + "IPMI", + "GeneralPurposeIo", + "GenericSerialBus" }; char *acpi_ut_get_region_name(u8 space_id) diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 31f5a7832ef1..2a6c3e183697 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -215,11 +215,14 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object)); - /* Invalidate the region address/length via the host OS */ - - acpi_os_invalidate_address(object->region.space_id, - object->region.address, - (acpi_size) object->region.length); + /* + * Update address_range list. However, only permanent regions + * are installed in this list. (Not created within a method) + */ + if (!(object->region.node->flags & ANOBJ_TEMPORARY)) { + acpi_ut_remove_address_range(object->region.space_id, + object->region.node); + } second_desc = acpi_ns_get_secondary_object(object); if (second_desc) { diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 18f73c9d10bc..479f32b33415 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index ffba0a39c3e8..4153584cf526 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -264,6 +264,12 @@ acpi_status acpi_ut_init_globals(void) return_ACPI_STATUS(status); } + /* Address Range lists */ + + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { + acpi_gbl_address_range_list[i] = NULL; + } + /* Mutex locked flags */ for (i = 0; i < ACPI_NUM_MUTEX; i++) { diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index b679ea693545..c92eb1d93785 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 191b6828cce9..8359c0c5dc98 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,6 +92,7 @@ static void acpi_ut_terminate(void) gpe_xrupt_info = next_gpe_xrupt_info; } + acpi_ut_delete_address_lists(); return_VOID; } diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index f6bb75c6faf5..155fd786d0f2 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index ce481da9bb45..2491a552b0e6 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index c33a852d4f42..86f19db74e05 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 7d797e2baecd..43174df33121 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -293,14 +293,10 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) { - acpi_thread_id this_thread_id; - ACPI_FUNCTION_NAME(ut_release_mutex); - this_thread_id = acpi_os_get_thread_id(); - ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n", - (u32)this_thread_id, + (u32)acpi_os_get_thread_id(), acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { @@ -329,7 +325,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) * the ACPI subsystem code. */ for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { - if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { + if (acpi_gbl_mutex_info[i].thread_id == + acpi_os_get_thread_id()) { if (i == mutex_id) { continue; } diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 188340a017b4..b112744fc9ae 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 1fb10cb8f11d..2360cf70c18c 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index 6ffd3a8bdaa5..9d441ea70305 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,7 +43,7 @@ #include <acpi/acpi.h> #include "accommon.h" -#include "amlresrc.h" +#include "acresrc.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utresrc") @@ -154,6 +154,138 @@ const char *acpi_gbl_typ_decode[] = { "TypeF" }; +const char *acpi_gbl_ppc_decode[] = { + "PullDefault", + "PullUp", + "PullDown", + "PullNone" +}; + +const char *acpi_gbl_ior_decode[] = { + "IoRestrictionNone", + "IoRestrictionInputOnly", + "IoRestrictionOutputOnly", + "IoRestrictionNoneAndPreserve" +}; + +const char *acpi_gbl_dts_decode[] = { + "Width8bit", + "Width16bit", + "Width32bit", + "Width64bit", + "Width128bit", + "Width256bit", +}; + +/* GPIO connection type */ + +const char *acpi_gbl_ct_decode[] = { + "Interrupt", + "I/O" +}; + +/* Serial bus type */ + +const char *acpi_gbl_sbt_decode[] = { + "/* UNKNOWN serial bus type */", + "I2C", + "SPI", + "UART" +}; + +/* I2C serial bus access mode */ + +const char *acpi_gbl_am_decode[] = { + "AddressingMode7Bit", + "AddressingMode10Bit" +}; + +/* I2C serial bus slave mode */ + +const char *acpi_gbl_sm_decode[] = { + "ControllerInitiated", + "DeviceInitiated" +}; + +/* SPI serial bus wire mode */ + +const char *acpi_gbl_wm_decode[] = { + "FourWireMode", + "ThreeWireMode" +}; + +/* SPI serial clock phase */ + +const char *acpi_gbl_cph_decode[] = { + "ClockPhaseFirst", + "ClockPhaseSecond" +}; + +/* SPI serial bus clock polarity */ + +const char *acpi_gbl_cpo_decode[] = { + "ClockPolarityLow", + "ClockPolarityHigh" +}; + +/* SPI serial bus device polarity */ + +const char *acpi_gbl_dp_decode[] = { + "PolarityLow", + "PolarityHigh" +}; + +/* UART serial bus endian */ + +const char *acpi_gbl_ed_decode[] = { + "LittleEndian", + "BigEndian" +}; + +/* UART serial bus bits per byte */ + +const char *acpi_gbl_bpb_decode[] = { + "DataBitsFive", + "DataBitsSix", + "DataBitsSeven", + "DataBitsEight", + "DataBitsNine", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */" +}; + +/* UART serial bus stop bits */ + +const char *acpi_gbl_sb_decode[] = { + "StopBitsNone", + "StopBitsOne", + "StopBitsOnePlusHalf", + "StopBitsTwo" +}; + +/* UART serial bus flow control */ + +const char *acpi_gbl_fc_decode[] = { + "FlowControlNone", + "FlowControlHardware", + "FlowControlXON", + "/* UNKNOWN flow control keyword */" +}; + +/* UART serial bus parity type */ + +const char *acpi_gbl_pt_decode[] = { + "ParityTypeNone", + "ParityTypeEven", + "ParityTypeOdd", + "ParityTypeMark", + "ParityTypeSpace", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */" +}; + #endif /* @@ -173,7 +305,7 @@ const u8 acpi_gbl_resource_aml_sizes[] = { ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent), ACPI_AML_SIZE_SMALL(struct aml_resource_io), ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io), - 0, + ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma), 0, 0, 0, @@ -193,7 +325,17 @@ const u8 acpi_gbl_resource_aml_sizes[] = { ACPI_AML_SIZE_LARGE(struct aml_resource_address16), ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq), ACPI_AML_SIZE_LARGE(struct aml_resource_address64), - ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64) + ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64), + ACPI_AML_SIZE_LARGE(struct aml_resource_gpio), + 0, + ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus), +}; + +const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = { + 0, + ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus), + ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus), + ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus), }; /* @@ -209,35 +351,49 @@ static const u8 acpi_gbl_resource_types[] = { 0, 0, 0, - ACPI_SMALL_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_SMALL_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_FIXED_LENGTH, - 0, + ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */ + ACPI_FIXED_LENGTH, /* 05 DMA */ + ACPI_SMALL_VARIABLE_LENGTH, /* 06 start_dependent_functions */ + ACPI_FIXED_LENGTH, /* 07 end_dependent_functions */ + ACPI_FIXED_LENGTH, /* 08 IO */ + ACPI_FIXED_LENGTH, /* 09 fixed_iO */ + ACPI_FIXED_LENGTH, /* 0_a fixed_dMA */ 0, 0, 0, - ACPI_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH, + ACPI_VARIABLE_LENGTH, /* 0_e vendor_short */ + ACPI_FIXED_LENGTH, /* 0_f end_tag */ /* Large descriptors */ 0, - ACPI_FIXED_LENGTH, - ACPI_FIXED_LENGTH, + ACPI_FIXED_LENGTH, /* 01 Memory24 */ + ACPI_FIXED_LENGTH, /* 02 generic_register */ 0, - ACPI_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_VARIABLE_LENGTH, - ACPI_VARIABLE_LENGTH, - ACPI_VARIABLE_LENGTH, - ACPI_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH + ACPI_VARIABLE_LENGTH, /* 04 vendor_long */ + ACPI_FIXED_LENGTH, /* 05 Memory32 */ + ACPI_FIXED_LENGTH, /* 06 memory32_fixed */ + ACPI_VARIABLE_LENGTH, /* 07 Dword* address */ + ACPI_VARIABLE_LENGTH, /* 08 Word* address */ + ACPI_VARIABLE_LENGTH, /* 09 extended_iRQ */ + ACPI_VARIABLE_LENGTH, /* 0_a Qword* address */ + ACPI_FIXED_LENGTH, /* 0_b Extended* address */ + ACPI_VARIABLE_LENGTH, /* 0_c Gpio* */ + 0, + ACPI_VARIABLE_LENGTH /* 0_e *serial_bus */ }; +/* + * For the i_aSL compiler/disassembler, we don't want any error messages + * because the disassembler uses the resource validation code to determine + * if Buffer objects are actually Resource Templates. + */ +#ifdef ACPI_ASL_COMPILER +#define ACPI_RESOURCE_ERROR(plist) +#else +#define ACPI_RESOURCE_ERROR(plist) ACPI_ERROR(plist) +#endif + /******************************************************************************* * * FUNCTION: acpi_ut_walk_aml_resources @@ -265,6 +421,7 @@ acpi_ut_walk_aml_resources(u8 * aml, u8 resource_index; u32 length; u32 offset = 0; + u8 end_tag[2] = { 0x79, 0x00 }; ACPI_FUNCTION_TRACE(ut_walk_aml_resources); @@ -286,6 +443,10 @@ acpi_ut_walk_aml_resources(u8 * aml, status = acpi_ut_validate_resource(aml, &resource_index); if (ACPI_FAILURE(status)) { + /* + * Exit on failure. Cannot continue because the descriptor length + * may be bogus also. + */ return_ACPI_STATUS(status); } @@ -300,7 +461,7 @@ acpi_ut_walk_aml_resources(u8 * aml, user_function(aml, length, offset, resource_index, context); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } } @@ -333,7 +494,19 @@ acpi_ut_walk_aml_resources(u8 * aml, /* Did not find an end_tag descriptor */ - return (AE_AML_NO_RESOURCE_END_TAG); + if (user_function) { + + /* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */ + + (void)acpi_ut_validate_resource(end_tag, &resource_index); + status = + user_function(end_tag, 2, offset, resource_index, context); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } + + return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } /******************************************************************************* @@ -354,6 +527,7 @@ acpi_ut_walk_aml_resources(u8 * aml, acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) { + union aml_resource *aml_resource; u8 resource_type; u8 resource_index; acpi_rs_length resource_length; @@ -375,7 +549,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) /* Verify the large resource type (name) against the max */ if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) { - return (AE_AML_INVALID_RESOURCE_TYPE); + goto invalid_resource; } /* @@ -392,15 +566,17 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) ((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3); } - /* Check validity of the resource type, zero indicates name is invalid */ - + /* + * Check validity of the resource type, via acpi_gbl_resource_types. Zero + * indicates an invalid resource. + */ if (!acpi_gbl_resource_types[resource_index]) { - return (AE_AML_INVALID_RESOURCE_TYPE); + goto invalid_resource; } /* - * 2) Validate the resource_length field. This ensures that the length - * is at least reasonable, and guarantees that it is non-zero. + * Validate the resource_length field. This ensures that the length + * is at least reasonable, and guarantees that it is non-zero. */ resource_length = acpi_ut_get_resource_length(aml); minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index]; @@ -413,7 +589,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) /* Fixed length resource, length must match exactly */ if (resource_length != minimum_resource_length) { - return (AE_AML_BAD_RESOURCE_LENGTH); + goto bad_resource_length; } break; @@ -422,7 +598,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) /* Variable length resource, length must be at least the minimum */ if (resource_length < minimum_resource_length) { - return (AE_AML_BAD_RESOURCE_LENGTH); + goto bad_resource_length; } break; @@ -432,7 +608,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) if ((resource_length > minimum_resource_length) || (resource_length < (minimum_resource_length - 1))) { - return (AE_AML_BAD_RESOURCE_LENGTH); + goto bad_resource_length; } break; @@ -440,7 +616,23 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) /* Shouldn't happen (because of validation earlier), but be sure */ - return (AE_AML_INVALID_RESOURCE_TYPE); + goto invalid_resource; + } + + aml_resource = ACPI_CAST_PTR(union aml_resource, aml); + if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) { + + /* Validate the bus_type field */ + + if ((aml_resource->common_serial_bus.type == 0) || + (aml_resource->common_serial_bus.type > + AML_RESOURCE_MAX_SERIALBUSTYPE)) { + ACPI_RESOURCE_ERROR((AE_INFO, + "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X", + aml_resource->common_serial_bus. + type)); + return (AE_AML_INVALID_RESOURCE_TYPE); + } } /* Optionally return the resource table index */ @@ -450,6 +642,22 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) } return (AE_OK); + + invalid_resource: + + ACPI_RESOURCE_ERROR((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + resource_type)); + return (AE_AML_INVALID_RESOURCE_TYPE); + + bad_resource_length: + + ACPI_RESOURCE_ERROR((AE_INFO, + "Invalid resource descriptor length: Type " + "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X", + resource_type, resource_length, + minimum_resource_length)); + return (AE_AML_BAD_RESOURCE_LENGTH); } /******************************************************************************* diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index 30c21e1a9360..4267477c2797 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 420ebfe08c72..644e8c8ebc4b 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,7 @@ #include "acnamesp.h" #include "acdebug.h" #include "actables.h" +#include "acinterp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utxface") @@ -640,4 +641,41 @@ acpi_status acpi_install_interface_handler(acpi_interface_handler handler) } ACPI_EXPORT_SYMBOL(acpi_install_interface_handler) + +/***************************************************************************** + * + * FUNCTION: acpi_check_address_range + * + * PARAMETERS: space_id - Address space ID + * Address - Start address + * Length - Length + * Warn - TRUE if warning on overlap desired + * + * RETURN: Count of the number of conflicts detected. + * + * DESCRIPTION: Check if the input address range overlaps any of the + * ASL operation region address ranges. + * + ****************************************************************************/ +u32 +acpi_check_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, + acpi_size length, u8 warn) +{ + u32 overlaps; + acpi_status status; + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return (0); + } + + overlaps = acpi_ut_check_address_range(space_id, address, + (u32)length, warn); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return (overlaps); +} + +ACPI_EXPORT_SYMBOL(acpi_check_address_range) #endif /* !ACPI_ASL_COMPILER */ diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 8d0245ec4315..52b568af1819 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c new file mode 100644 index 000000000000..1427d191d15a --- /dev/null +++ b/drivers/acpi/acpica/utxfmutex.c @@ -0,0 +1,187 @@ +/******************************************************************************* + * + * Module Name: utxfmutex - external AML mutex access functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utxfmutex") + +/* Local prototypes */ +static acpi_status +acpi_ut_get_mutex_object(acpi_handle handle, + acpi_string pathname, + union acpi_operand_object **ret_obj); + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_mutex_object + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * ret_obj - Where the mutex object is returned + * + * RETURN: Status + * + * DESCRIPTION: Get an AML mutex object. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_get_mutex_object(acpi_handle handle, + acpi_string pathname, + union acpi_operand_object **ret_obj) +{ + struct acpi_namespace_node *mutex_node; + union acpi_operand_object *mutex_obj; + acpi_status status; + + /* Parameter validation */ + + if (!ret_obj || (!handle && !pathname)) { + return (AE_BAD_PARAMETER); + } + + /* Get a the namespace node for the mutex */ + + mutex_node = handle; + if (pathname != NULL) { + status = acpi_get_handle(handle, pathname, + ACPI_CAST_PTR(acpi_handle, + &mutex_node)); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + /* Ensure that we actually have a Mutex object */ + + if (!mutex_node || (mutex_node->type != ACPI_TYPE_MUTEX)) { + return (AE_TYPE); + } + + /* Get the low-level mutex object */ + + mutex_obj = acpi_ns_get_attached_object(mutex_node); + if (!mutex_obj) { + return (AE_NULL_OBJECT); + } + + *ret_obj = mutex_obj; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_acquire_mutex + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * Timeout - Max time to wait for the lock (millisec) + * + * RETURN: Status + * + * DESCRIPTION: Acquire an AML mutex. This is a device driver interface to + * AML mutex objects, and allows for transaction locking between + * drivers and AML code. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +acpi_status +acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout) +{ + acpi_status status; + union acpi_operand_object *mutex_obj; + + /* Get the low-level mutex associated with Handle:Pathname */ + + status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Acquire the OS mutex */ + + status = acpi_os_acquire_mutex(mutex_obj->mutex.os_mutex, timeout); + return (status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_release_mutex + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * + * RETURN: Status + * + * DESCRIPTION: Release an AML mutex. This is a device driver interface to + * AML mutex objects, and allows for transaction locking between + * drivers and AML code. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname) +{ + acpi_status status; + union acpi_operand_object *mutex_obj; + + /* Get the low-level mutex associated with Handle:Pathname */ + + status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Release the OS mutex */ + + acpi_os_release_mutex(mutex_obj->mutex.os_mutex); + return (AE_OK); +} diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 61540360d5ce..e45350cb6ac8 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -34,13 +34,13 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> +#include <linux/acpi_io.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/kref.h> #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/debugfs.h> -#include <acpi/atomicio.h> #include "apei-internal.h" @@ -70,7 +70,7 @@ int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val) { int rc; - rc = acpi_atomic_read(val, &entry->register_region); + rc = apei_read(val, &entry->register_region); if (rc) return rc; *val >>= entry->register_region.bit_offset; @@ -116,13 +116,13 @@ int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val) val <<= entry->register_region.bit_offset; if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) { u64 valr = 0; - rc = acpi_atomic_read(&valr, &entry->register_region); + rc = apei_read(&valr, &entry->register_region); if (rc) return rc; valr &= ~(entry->mask << entry->register_region.bit_offset); val |= valr; } - rc = acpi_atomic_write(val, &entry->register_region); + rc = apei_write(val, &entry->register_region); return rc; } @@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) - return acpi_pre_map_gar(&entry->register_region); + return acpi_os_map_generic_address(&entry->register_region); return 0; } @@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) - acpi_post_unmap_gar(&entry->register_region); + acpi_os_unmap_generic_address(&entry->register_region); return 0; } @@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1, return 0; } +int apei_resources_add(struct apei_resources *resources, + unsigned long start, unsigned long size, + bool iomem) +{ + if (iomem) + return apei_res_add(&resources->iomem, start, size); + else + return apei_res_add(&resources->ioport, start, size); +} +EXPORT_SYMBOL_GPL(apei_resources_add); + /* * EINJ has two groups of GARs (EINJ table entry and trigger table * entry), so common resources are subtracted from the trigger table @@ -438,8 +449,19 @@ int apei_resources_sub(struct apei_resources *resources1, } EXPORT_SYMBOL_GPL(apei_resources_sub); +static int apei_get_nvs_callback(__u64 start, __u64 size, void *data) +{ + struct apei_resources *resources = data; + return apei_res_add(&resources->iomem, start, size); +} + +static int apei_get_nvs_resources(struct apei_resources *resources) +{ + return acpi_nvs_for_each_region(apei_get_nvs_callback, resources); +} + /* - * IO memory/port rersource management mechanism is used to check + * IO memory/port resource management mechanism is used to check * whether memory/port area used by GARs conflicts with normal memory * or IO memory/port of devices. */ @@ -448,21 +470,35 @@ int apei_resources_request(struct apei_resources *resources, { struct apei_res *res, *res_bak = NULL; struct resource *r; + struct apei_resources nvs_resources; int rc; rc = apei_resources_sub(resources, &apei_resources_all); if (rc) return rc; + /* + * Some firmware uses ACPI NVS region, that has been marked as + * busy, so exclude it from APEI resources to avoid false + * conflict. + */ + apei_resources_init(&nvs_resources); + rc = apei_get_nvs_resources(&nvs_resources); + if (rc) + goto res_fini; + rc = apei_resources_sub(resources, &nvs_resources); + if (rc) + goto res_fini; + rc = -EINVAL; list_for_each_entry(res, &resources->iomem, list) { r = request_mem_region(res->start, res->end - res->start, desc); if (!r) { pr_err(APEI_PFX - "Can not request iomem region <%016llx-%016llx> for GARs.\n", + "Can not request [mem %#010llx-%#010llx] for %s registers\n", (unsigned long long)res->start, - (unsigned long long)res->end); + (unsigned long long)res->end - 1, desc); res_bak = res; goto err_unmap_iomem; } @@ -472,9 +508,9 @@ int apei_resources_request(struct apei_resources *resources, r = request_region(res->start, res->end - res->start, desc); if (!r) { pr_err(APEI_PFX - "Can not request ioport region <%016llx-%016llx> for GARs.\n", + "Can not request [io %#06llx-%#06llx] for %s registers\n", (unsigned long long)res->start, - (unsigned long long)res->end); + (unsigned long long)res->end - 1, desc); res_bak = res; goto err_unmap_ioport; } @@ -500,6 +536,8 @@ err_unmap_iomem: break; release_mem_region(res->start, res->end - res->start); } +res_fini: + apei_resources_fini(&nvs_resources); return rc; } EXPORT_SYMBOL_GPL(apei_resources_request); @@ -553,6 +591,96 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr) return 0; } +/* read GAR in interrupt (including NMI) or process context */ +int apei_read(u64 *val, struct acpi_generic_address *reg) +{ + int rc; + u64 address; + u32 tmp, width = reg->bit_width; + acpi_status status; + + rc = apei_check_gar(reg, &address); + if (rc) + return rc; + + if (width == 64) + width = 32; /* Break into two 32-bit transfers */ + + *val = 0; + switch(reg->space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + status = acpi_os_read_memory((acpi_physical_address) + address, &tmp, width); + if (ACPI_FAILURE(status)) + return -EIO; + *val = tmp; + + if (reg->bit_width == 64) { + /* Read the top 32 bits */ + status = acpi_os_read_memory((acpi_physical_address) + (address + 4), &tmp, 32); + if (ACPI_FAILURE(status)) + return -EIO; + *val |= ((u64)tmp << 32); + } + break; + case ACPI_ADR_SPACE_SYSTEM_IO: + status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); + if (ACPI_FAILURE(status)) + return -EIO; + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(apei_read); + +/* write GAR in interrupt (including NMI) or process context */ +int apei_write(u64 val, struct acpi_generic_address *reg) +{ + int rc; + u64 address; + u32 width = reg->bit_width; + acpi_status status; + + rc = apei_check_gar(reg, &address); + if (rc) + return rc; + + if (width == 64) + width = 32; /* Break into two 32-bit transfers */ + + switch (reg->space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + status = acpi_os_write_memory((acpi_physical_address) + address, ACPI_LODWORD(val), + width); + if (ACPI_FAILURE(status)) + return -EIO; + + if (reg->bit_width == 64) { + status = acpi_os_write_memory((acpi_physical_address) + (address + 4), + ACPI_HIDWORD(val), 32); + if (ACPI_FAILURE(status)) + return -EIO; + } + break; + case ACPI_ADR_SPACE_SYSTEM_IO: + status = acpi_os_write_port(address, val, reg->bit_width); + if (ACPI_FAILURE(status)) + return -EIO; + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(apei_write); + static int collect_res_callback(struct apei_exec_context *ctx, struct acpi_whea_header *entry, void *data) diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index f57050e7a5e7..cca240a33038 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -68,6 +68,9 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio /* IP has been set in instruction function */ #define APEI_EXEC_SET_IP 1 +int apei_read(u64 *val, struct acpi_generic_address *reg); +int apei_write(u64 val, struct acpi_generic_address *reg); + int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val); int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val); int apei_exec_read_register(struct apei_exec_context *ctx, @@ -95,6 +98,9 @@ static inline void apei_resources_init(struct apei_resources *resources) } void apei_resources_fini(struct apei_resources *resources); +int apei_resources_add(struct apei_resources *resources, + unsigned long start, unsigned long size, + bool iomem); int apei_resources_sub(struct apei_resources *resources1, struct apei_resources *resources2); int apei_resources_request(struct apei_resources *resources, diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 589b96c38704..5b898d4dda99 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -43,6 +43,42 @@ #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) /* + * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action. + */ +static int acpi5; + +struct set_error_type_with_address { + u32 type; + u32 vendor_extension; + u32 flags; + u32 apicid; + u64 memory_address; + u64 memory_address_range; + u32 pcie_sbdf; +}; +enum { + SETWA_FLAGS_APICID = 1, + SETWA_FLAGS_MEM = 2, + SETWA_FLAGS_PCIE_SBDF = 4, +}; + +/* + * Vendor extensions for platform specific operations + */ +struct vendor_error_type_extension { + u32 length; + u32 pcie_sbdf; + u16 vendor_id; + u16 device_id; + u8 rev_id; + u8 reserved[3]; +}; + +static u32 vendor_flags; +static struct debugfs_blob_wrapper vendor_blob; +static char vendor_dev[64]; + +/* * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the * EINJ table through an unpublished extension. Use with caution as * most will ignore the parameter and make their own choice of address @@ -103,7 +139,14 @@ static struct apei_exec_ins_type einj_ins_type[] = { */ static DEFINE_MUTEX(einj_mutex); -static struct einj_parameter *einj_param; +static void *einj_param; + +#ifndef readq +static inline __u64 readq(volatile void __iomem *addr) +{ + return ((__u64)readl(addr+4) << 32) + readl(addr); +} +#endif #ifndef writeq static inline void writeq(__u64 val, volatile void __iomem *addr) @@ -158,10 +201,31 @@ static int einj_timedout(u64 *t) return 0; } -static u64 einj_get_parameter_address(void) +static void check_vendor_extension(u64 paddr, + struct set_error_type_with_address *v5param) +{ + int offset = readl(&v5param->vendor_extension); + struct vendor_error_type_extension *v; + u32 sbdf; + + if (!offset) + return; + v = ioremap(paddr + offset, sizeof(*v)); + if (!v) + return; + sbdf = readl(&v->pcie_sbdf); + sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n", + sbdf >> 24, (sbdf >> 16) & 0xff, + (sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7, + readw(&v->vendor_id), readw(&v->device_id), + readb(&v->rev_id)); + iounmap(v); +} + +static void *einj_get_parameter_address(void) { int i; - u64 paddr = 0; + u64 paddrv4 = 0, paddrv5 = 0; struct acpi_whea_header *entry; entry = EINJ_TAB_ENTRY(einj_tab); @@ -170,12 +234,40 @@ static u64 einj_get_parameter_address(void) entry->instruction == ACPI_EINJ_WRITE_REGISTER && entry->register_region.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - memcpy(&paddr, &entry->register_region.address, - sizeof(paddr)); + memcpy(&paddrv4, &entry->register_region.address, + sizeof(paddrv4)); + if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS && + entry->instruction == ACPI_EINJ_WRITE_REGISTER && + entry->register_region.space_id == + ACPI_ADR_SPACE_SYSTEM_MEMORY) + memcpy(&paddrv5, &entry->register_region.address, + sizeof(paddrv5)); entry++; } + if (paddrv5) { + struct set_error_type_with_address *v5param; + + v5param = ioremap(paddrv5, sizeof(*v5param)); + if (v5param) { + acpi5 = 1; + check_vendor_extension(paddrv5, v5param); + return v5param; + } + } + if (paddrv4) { + struct einj_parameter *v4param; + + v4param = ioremap(paddrv4, sizeof(*v4param)); + if (!v4param) + return 0; + if (readq(&v4param->reserved1) || readq(&v4param->reserved2)) { + iounmap(v4param); + return 0; + } + return v4param; + } - return paddr; + return 0; } /* do sanity check to trigger table */ @@ -194,8 +286,29 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab) return 0; } +static struct acpi_generic_address *einj_get_trigger_parameter_region( + struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2) +{ + int i; + struct acpi_whea_header *entry; + + entry = (struct acpi_whea_header *) + ((char *)trigger_tab + sizeof(struct acpi_einj_trigger)); + for (i = 0; i < trigger_tab->entry_count; i++) { + if (entry->action == ACPI_EINJ_TRIGGER_ERROR && + entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE && + entry->register_region.space_id == + ACPI_ADR_SPACE_SYSTEM_MEMORY && + (entry->register_region.address & param2) == (param1 & param2)) + return &entry->register_region; + entry++; + } + + return NULL; +} /* Execute instructions in trigger error action table */ -static int __einj_error_trigger(u64 trigger_paddr) +static int __einj_error_trigger(u64 trigger_paddr, u32 type, + u64 param1, u64 param2) { struct acpi_einj_trigger *trigger_tab = NULL; struct apei_exec_context trigger_ctx; @@ -204,14 +317,16 @@ static int __einj_error_trigger(u64 trigger_paddr) struct resource *r; u32 table_size; int rc = -EIO; + struct acpi_generic_address *trigger_param_region = NULL; r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), "APEI EINJ Trigger Table"); if (!r) { pr_err(EINJ_PFX - "Can not request iomem region <%016llx-%016llx> for Trigger table.\n", + "Can not request [mem %#010llx-%#010llx] for Trigger table\n", (unsigned long long)trigger_paddr, - (unsigned long long)trigger_paddr+sizeof(*trigger_tab)); + (unsigned long long)trigger_paddr + + sizeof(*trigger_tab) - 1); goto out; } trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab)); @@ -232,9 +347,9 @@ static int __einj_error_trigger(u64 trigger_paddr) "APEI EINJ Trigger Table"); if (!r) { pr_err(EINJ_PFX -"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n", - (unsigned long long)trigger_paddr+sizeof(*trigger_tab), - (unsigned long long)trigger_paddr + table_size); +"Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n", + (unsigned long long)trigger_paddr + sizeof(*trigger_tab), + (unsigned long long)trigger_paddr + table_size - 1); goto out_rel_header; } iounmap(trigger_tab); @@ -255,6 +370,30 @@ static int __einj_error_trigger(u64 trigger_paddr) rc = apei_resources_sub(&trigger_resources, &einj_resources); if (rc) goto out_fini; + /* + * Some firmware will access target address specified in + * param1 to trigger the error when injecting memory error. + * This will cause resource conflict with regular memory. So + * remove it from trigger table resources. + */ + if (param_extension && (type & 0x0038) && param2) { + struct apei_resources addr_resources; + apei_resources_init(&addr_resources); + trigger_param_region = einj_get_trigger_parameter_region( + trigger_tab, param1, param2); + if (trigger_param_region) { + rc = apei_resources_add(&addr_resources, + trigger_param_region->address, + trigger_param_region->bit_width/8, true); + if (rc) + goto out_fini; + rc = apei_resources_sub(&trigger_resources, + &addr_resources); + } + apei_resources_fini(&addr_resources); + if (rc) + goto out_fini; + } rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger"); if (rc) goto out_fini; @@ -293,12 +432,56 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) if (rc) return rc; apei_exec_ctx_set_input(&ctx, type); - rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE); - if (rc) - return rc; - if (einj_param) { - writeq(param1, &einj_param->param1); - writeq(param2, &einj_param->param2); + if (acpi5) { + struct set_error_type_with_address *v5param = einj_param; + + writel(type, &v5param->type); + if (type & 0x80000000) { + switch (vendor_flags) { + case SETWA_FLAGS_APICID: + writel(param1, &v5param->apicid); + break; + case SETWA_FLAGS_MEM: + writeq(param1, &v5param->memory_address); + writeq(param2, &v5param->memory_address_range); + break; + case SETWA_FLAGS_PCIE_SBDF: + writel(param1, &v5param->pcie_sbdf); + break; + } + writel(vendor_flags, &v5param->flags); + } else { + switch (type) { + case ACPI_EINJ_PROCESSOR_CORRECTABLE: + case ACPI_EINJ_PROCESSOR_UNCORRECTABLE: + case ACPI_EINJ_PROCESSOR_FATAL: + writel(param1, &v5param->apicid); + writel(SETWA_FLAGS_APICID, &v5param->flags); + break; + case ACPI_EINJ_MEMORY_CORRECTABLE: + case ACPI_EINJ_MEMORY_UNCORRECTABLE: + case ACPI_EINJ_MEMORY_FATAL: + writeq(param1, &v5param->memory_address); + writeq(param2, &v5param->memory_address_range); + writel(SETWA_FLAGS_MEM, &v5param->flags); + break; + case ACPI_EINJ_PCIX_CORRECTABLE: + case ACPI_EINJ_PCIX_UNCORRECTABLE: + case ACPI_EINJ_PCIX_FATAL: + writel(param1, &v5param->pcie_sbdf); + writel(SETWA_FLAGS_PCIE_SBDF, &v5param->flags); + break; + } + } + } else { + rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE); + if (rc) + return rc; + if (einj_param) { + struct einj_parameter *v4param = einj_param; + writeq(param1, &v4param->param1); + writeq(param2, &v4param->param2); + } } rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION); if (rc) @@ -324,7 +507,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) if (rc) return rc; trigger_paddr = apei_exec_ctx_get_output(&ctx); - rc = __einj_error_trigger(trigger_paddr); + rc = __einj_error_trigger(trigger_paddr, type, param1, param2); if (rc) return rc; rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION); @@ -408,15 +591,25 @@ static int error_type_set(void *data, u64 val) { int rc; u32 available_error_type = 0; + u32 tval, vendor; + + /* + * Vendor defined types have 0x80000000 bit set, and + * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE + */ + vendor = val & 0x80000000; + tval = val & 0x7fffffff; /* Only one error type can be specified */ - if (val & (val - 1)) - return -EINVAL; - rc = einj_get_available_error_type(&available_error_type); - if (rc) - return rc; - if (!(val & available_error_type)) + if (tval & (tval - 1)) return -EINVAL; + if (!vendor) { + rc = einj_get_available_error_type(&available_error_type); + if (rc) + return rc; + if (!(val & available_error_type)) + return -EINVAL; + } error_type = val; return 0; @@ -455,7 +648,6 @@ static int einj_check_table(struct acpi_table_einj *einj_tab) static int __init einj_init(void) { int rc; - u64 param_paddr; acpi_status status; struct dentry *fentry; struct apei_exec_context ctx; @@ -465,10 +657,9 @@ static int __init einj_init(void) status = acpi_get_table(ACPI_SIG_EINJ, 0, (struct acpi_table_header **)&einj_tab); - if (status == AE_NOT_FOUND) { - pr_info(EINJ_PFX "Table is not found!\n"); + if (status == AE_NOT_FOUND) return -ENODEV; - } else if (ACPI_FAILURE(status)) { + else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err(EINJ_PFX "Failed to get table, %s\n", msg); return -EINVAL; @@ -509,23 +700,30 @@ static int __init einj_init(void) rc = apei_exec_pre_map_gars(&ctx); if (rc) goto err_release; - if (param_extension) { - param_paddr = einj_get_parameter_address(); - if (param_paddr) { - einj_param = ioremap(param_paddr, sizeof(*einj_param)); - rc = -ENOMEM; - if (!einj_param) - goto err_unmap; - fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param1); - if (!fentry) - goto err_unmap; - fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param2); - if (!fentry) - goto err_unmap; - } else - pr_warn(EINJ_PFX "Parameter extension is not supported.\n"); + + einj_param = einj_get_parameter_address(); + if ((param_extension || acpi5) && einj_param) { + fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param1); + if (!fentry) + goto err_unmap; + fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param2); + if (!fentry) + goto err_unmap; + } + + if (vendor_dev[0]) { + vendor_blob.data = vendor_dev; + vendor_blob.size = strlen(vendor_dev); + fentry = debugfs_create_blob("vendor", S_IRUSR, + einj_debug_dir, &vendor_blob); + if (!fentry) + goto err_unmap; + fentry = debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR, + einj_debug_dir, &vendor_flags); + if (!fentry) + goto err_unmap; } pr_info(EINJ_PFX "Error INJection is initialized.\n"); diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 6a9e3bad13f4..eb9fab5b96e4 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -1127,10 +1127,9 @@ static int __init erst_init(void) status = acpi_get_table(ACPI_SIG_ERST, 0, (struct acpi_table_header **)&erst_tab); - if (status == AE_NOT_FOUND) { - pr_info(ERST_PFX "Table is not found!\n"); + if (status == AE_NOT_FOUND) goto err; - } else if (ACPI_FAILURE(status)) { + else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err(ERST_PFX "Failed to get table, %s\n", msg); rc = -EINVAL; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index b8e08cb67a18..9b3cac0abecc 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -33,6 +33,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> +#include <linux/acpi_io.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/timer.h> @@ -45,8 +46,9 @@ #include <linux/irq_work.h> #include <linux/llist.h> #include <linux/genalloc.h> +#include <linux/pci.h> +#include <linux/aer.h> #include <acpi/apei.h> -#include <acpi/atomicio.h> #include <acpi/hed.h> #include <asm/mce.h> #include <asm/tlbflush.h> @@ -118,7 +120,7 @@ struct ghes_estatus_cache { struct rcu_head rcu; }; -int ghes_disable; +bool ghes_disable; module_param_named(disable, ghes_disable, bool, 0); static int ghes_panic_timeout __read_mostly = 30; @@ -299,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) if (!ghes) return ERR_PTR(-ENOMEM); ghes->generic = generic; - rc = acpi_pre_map_gar(&generic->error_status_address); + rc = acpi_os_map_generic_address(&generic->error_status_address); if (rc) goto err_free; error_block_length = generic->error_block_length; @@ -319,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) return ghes; err_unmap: - acpi_post_unmap_gar(&generic->error_status_address); + acpi_os_unmap_generic_address(&generic->error_status_address); err_free: kfree(ghes); return ERR_PTR(rc); @@ -328,7 +330,7 @@ err_free: static void ghes_fini(struct ghes *ghes) { kfree(ghes->estatus); - acpi_post_unmap_gar(&ghes->generic->error_status_address); + acpi_os_unmap_generic_address(&ghes->generic->error_status_address); } enum { @@ -399,7 +401,7 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) u32 len; int rc; - rc = acpi_atomic_read(&buf_paddr, &g->error_status_address); + rc = apei_read(&buf_paddr, &g->error_status_address); if (rc) { if (!silent && printk_ratelimit()) pr_warning(FW_WARN GHES_PFX @@ -476,6 +478,27 @@ static void ghes_do_proc(const struct acpi_hest_generic_status *estatus) } #endif } +#ifdef CONFIG_ACPI_APEI_PCIEAER + else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, + CPER_SEC_PCIE)) { + struct cper_sec_pcie *pcie_err; + pcie_err = (struct cper_sec_pcie *)(gdata+1); + if (sev == GHES_SEV_RECOVERABLE && + sec_sev == GHES_SEV_RECOVERABLE && + pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && + pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { + unsigned int devfn; + int aer_severity; + devfn = PCI_DEVFN(pcie_err->device_id.device, + pcie_err->device_id.function); + aer_severity = cper_severity_to_aer(sev); + aer_recover_queue(pcie_err->device_id.segment, + pcie_err->device_id.bus, + devfn, aer_severity); + } + + } +#endif } } @@ -483,16 +506,22 @@ static void __ghes_print_estatus(const char *pfx, const struct acpi_hest_generic *generic, const struct acpi_hest_generic_status *estatus) { + static atomic_t seqno; + unsigned int curr_seqno; + char pfx_seq[64]; + if (pfx == NULL) { if (ghes_severity(estatus->error_severity) <= GHES_SEV_CORRECTED) - pfx = KERN_WARNING HW_ERR; + pfx = KERN_WARNING; else - pfx = KERN_ERR HW_ERR; + pfx = KERN_ERR; } + curr_seqno = atomic_inc_return(&seqno); + snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno); printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", - pfx, generic->header.source_id); - apei_estatus_print(pfx, estatus); + pfx_seq, generic->header.source_id); + apei_estatus_print(pfx_seq, estatus); } static int ghes_print_estatus(const char *pfx, @@ -711,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this, return ret; } +static struct llist_node *llist_nodes_reverse(struct llist_node *llnode) +{ + struct llist_node *next, *tail = NULL; + + while (llnode) { + next = llnode->next; + llnode->next = tail; + tail = llnode; + llnode = next; + } + + return tail; +} + static void ghes_proc_in_irq(struct irq_work *irq_work) { - struct llist_node *llnode, *next, *tail = NULL; + struct llist_node *llnode, *next; struct ghes_estatus_node *estatus_node; struct acpi_hest_generic *generic; struct acpi_hest_generic_status *estatus; u32 len, node_len; + llnode = llist_del_all(&ghes_estatus_llist); /* * Because the time order of estatus in list is reversed, * revert it back to proper order. */ - llnode = llist_del_all(&ghes_estatus_llist); - while (llnode) { - next = llnode->next; - llnode->next = tail; - tail = llnode; - llnode = next; - } - llnode = tail; + llnode = llist_nodes_reverse(llnode); while (llnode) { next = llnode->next; estatus_node = llist_entry(llnode, struct ghes_estatus_node, @@ -750,6 +787,32 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) } } +static void ghes_print_queued_estatus(void) +{ + struct llist_node *llnode; + struct ghes_estatus_node *estatus_node; + struct acpi_hest_generic *generic; + struct acpi_hest_generic_status *estatus; + u32 len, node_len; + + llnode = llist_del_all(&ghes_estatus_llist); + /* + * Because the time order of estatus in list is reversed, + * revert it back to proper order. + */ + llnode = llist_nodes_reverse(llnode); + while (llnode) { + estatus_node = llist_entry(llnode, struct ghes_estatus_node, + llnode); + estatus = GHES_ESTATUS_FROM_NODE(estatus_node); + len = apei_estatus_len(estatus); + node_len = GHES_ESTATUS_NODE_LEN(len); + generic = estatus_node->generic; + ghes_print_estatus(NULL, generic, estatus); + llnode = llnode->next; + } +} + static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) { struct ghes *ghes, *ghes_global = NULL; @@ -775,7 +838,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) if (sev_global >= GHES_SEV_PANIC) { oops_begin(); - __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global->generic, + ghes_print_queued_estatus(); + __ghes_print_estatus(KERN_EMERG, ghes_global->generic, ghes_global->estatus); /* reboot to log the error! */ if (panic_timeout == 0) diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 05fee06f4d6e..7f00cf38098f 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -41,7 +41,7 @@ #define HEST_PFX "HEST: " -int hest_disable; +bool hest_disable; EXPORT_SYMBOL_GPL(hest_disable); /* HEST table parsing */ @@ -221,10 +221,9 @@ void __init acpi_hest_init(void) status = acpi_get_table(ACPI_SIG_HEST, 0, (struct acpi_table_header **)&hest_tab); - if (status == AE_NOT_FOUND) { - pr_info(HEST_PFX "Table not found.\n"); + if (status == AE_NOT_FOUND) goto err; - } else if (ACPI_FAILURE(status)) { + else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err(HEST_PFX "Failed to get table, %s\n", msg); rc = -EINVAL; diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c index cfc0cc10af39..d4a5b3d3657b 100644 --- a/drivers/acpi/atomicio.c +++ b/drivers/acpi/atomicio.c @@ -32,6 +32,8 @@ #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/slab.h> +#include <linux/mm.h> +#include <linux/highmem.h> #include <acpi/atomicio.h> #define ACPI_PFX "ACPI: " @@ -97,6 +99,37 @@ static void __iomem *__acpi_try_ioremap(phys_addr_t paddr, return NULL; } +#ifndef CONFIG_IA64 +#define should_use_kmap(pfn) page_is_ram(pfn) +#else +/* ioremap will take care of cache attributes */ +#define should_use_kmap(pfn) 0 +#endif + +static void __iomem *acpi_map(phys_addr_t pg_off, unsigned long pg_sz) +{ + unsigned long pfn; + + pfn = pg_off >> PAGE_SHIFT; + if (should_use_kmap(pfn)) { + if (pg_sz > PAGE_SIZE) + return NULL; + return (void __iomem __force *)kmap(pfn_to_page(pfn)); + } else + return ioremap(pg_off, pg_sz); +} + +static void acpi_unmap(phys_addr_t pg_off, void __iomem *vaddr) +{ + unsigned long pfn; + + pfn = pg_off >> PAGE_SHIFT; + if (page_is_ram(pfn)) + kunmap(pfn_to_page(pfn)); + else + iounmap(vaddr); +} + /* * Used to pre-map the specified IO memory area. First try to find * whether the area is already pre-mapped, if it is, increase the @@ -119,7 +152,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, pg_off = paddr & PAGE_MASK; pg_sz = ((paddr + size + PAGE_SIZE - 1) & PAGE_MASK) - pg_off; - vaddr = ioremap(pg_off, pg_sz); + vaddr = acpi_map(pg_off, pg_sz); if (!vaddr) return NULL; map = kmalloc(sizeof(*map), GFP_KERNEL); @@ -135,7 +168,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, vaddr = __acpi_try_ioremap(paddr, size); if (vaddr) { spin_unlock_irqrestore(&acpi_iomaps_lock, flags); - iounmap(map->vaddr); + acpi_unmap(pg_off, map->vaddr); kfree(map); return vaddr; } @@ -144,7 +177,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, return map->vaddr + (paddr - map->paddr); err_unmap: - iounmap(vaddr); + acpi_unmap(pg_off, vaddr); return NULL; } @@ -177,7 +210,7 @@ static void acpi_post_unmap(phys_addr_t paddr, unsigned long size) return; synchronize_rcu(); - iounmap(map->vaddr); + acpi_unmap(map->paddr, map->vaddr); kfree(map); } @@ -260,6 +293,21 @@ int acpi_post_unmap_gar(struct acpi_generic_address *reg) } EXPORT_SYMBOL_GPL(acpi_post_unmap_gar); +#ifdef readq +static inline u64 read64(const volatile void __iomem *addr) +{ + return readq(addr); +} +#else +static inline u64 read64(const volatile void __iomem *addr) +{ + u64 l, h; + l = readl(addr); + h = readl(addr+4); + return l | (h << 32); +} +#endif + /* * Can be used in atomic (including NMI) or process context. RCU read * lock can only be released after the IO memory area accessing. @@ -280,11 +328,9 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width) case 32: *val = readl(addr); break; -#ifdef readq case 64: - *val = readq(addr); + *val = read64(addr); break; -#endif default: return -EINVAL; } @@ -293,6 +339,19 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width) return 0; } +#ifdef writeq +static inline void write64(u64 val, volatile void __iomem *addr) +{ + writeq(val, addr); +} +#else +static inline void write64(u64 val, volatile void __iomem *addr) +{ + writel(val, addr); + writel(val>>32, addr+4); +} +#endif + static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width) { void __iomem *addr; @@ -309,11 +368,9 @@ static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width) case 32: writel(val, addr); break; -#ifdef writeq case 64: - writeq(val, addr); + write64(val, addr); break; -#endif default: return -EINVAL; } diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 19a61136d848..88eb14304667 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -43,7 +43,7 @@ MODULE_AUTHOR("Kristen Carlson Accardi"); MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); MODULE_LICENSE("GPL"); -static int immediate_undock = 1; +static bool immediate_undock = 1; module_param(immediate_undock, bool, 0644); MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " "undock immediately when the undock button is pressed, 0 will cause" diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 3b5c3189fd99..e56f3be7b07d 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -45,6 +45,8 @@ static int pxm_to_node_map[MAX_PXM_DOMAINS] static int node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; +unsigned char acpi_srat_revision __initdata; + int pxm_to_node(int pxm) { if (pxm < 0) @@ -255,9 +257,13 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header, static int __init acpi_parse_srat(struct acpi_table_header *table) { + struct acpi_table_srat *srat; if (!table) return -EINVAL; + srat = (struct acpi_table_srat *)table; + acpi_srat_revision = srat->header.revision; + /* Real work done in acpi_table_parse_srat below. */ return 0; diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 096787b43c96..7a2035fa8c71 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -15,6 +15,56 @@ #include <linux/acpi_io.h> #include <acpi/acpiosxf.h> +/* ACPI NVS regions, APEI may use it */ + +struct nvs_region { + __u64 phys_start; + __u64 size; + struct list_head node; +}; + +static LIST_HEAD(nvs_region_list); + +#ifdef CONFIG_ACPI_SLEEP +static int suspend_nvs_register(unsigned long start, unsigned long size); +#else +static inline int suspend_nvs_register(unsigned long a, unsigned long b) +{ + return 0; +} +#endif + +int acpi_nvs_register(__u64 start, __u64 size) +{ + struct nvs_region *region; + + region = kmalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return -ENOMEM; + region->phys_start = start; + region->size = size; + list_add_tail(®ion->node, &nvs_region_list); + + return suspend_nvs_register(start, size); +} + +int acpi_nvs_for_each_region(int (*func)(__u64 start, __u64 size, void *data), + void *data) +{ + int rc; + struct nvs_region *region; + + list_for_each_entry(region, &nvs_region_list, node) { + rc = func(region->phys_start, region->size, data); + if (rc) + return rc; + } + + return 0; +} + + +#ifdef CONFIG_ACPI_SLEEP /* * Platforms, like ACPI, may want us to save some memory used by them during * suspend and to restore the contents of this memory during the subsequent @@ -41,7 +91,7 @@ static LIST_HEAD(nvs_list); * things so that the data from page-aligned addresses in this region will * be copied into separate RAM pages. */ -int suspend_nvs_register(unsigned long start, unsigned long size) +static int suspend_nvs_register(unsigned long start, unsigned long size) { struct nvs_page *entry, *next; @@ -159,3 +209,4 @@ void suspend_nvs_restore(void) if (entry->data) memcpy(entry->kaddr, entry->data, entry->size); } +#endif diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index f31c5c5f1b7e..fcc12d842bcc 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -83,19 +83,6 @@ static struct workqueue_struct *kacpi_notify_wq; struct workqueue_struct *kacpi_hotplug_wq; EXPORT_SYMBOL(kacpi_hotplug_wq); -struct acpi_res_list { - resource_size_t start; - resource_size_t end; - acpi_adr_space_type resource_type; /* IO port, System memory, ...*/ - char name[5]; /* only can have a length of 4 chars, make use of this - one instead of res->name, no need to kalloc then */ - struct list_head resource_list; - int count; -}; - -static LIST_HEAD(resource_list_head); -static DEFINE_SPINLOCK(acpi_res_lock); - /* * This list of permanent mappings is for memory that may be accessed from * interrupt context, where we can't do the ioremap(). @@ -166,17 +153,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) return supported; } -static void __init acpi_request_region (struct acpi_generic_address *addr, +static void __init acpi_request_region (struct acpi_generic_address *gas, unsigned int length, char *desc) { - if (!addr->address || !length) + u64 addr; + + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !length) return; /* Resources are never freed */ - if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) - request_region(addr->address, length, desc); - else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - request_mem_region(addr->address, length, desc); + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) + request_region(addr, length, desc); + else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + request_mem_region(addr, length, desc); } static int __init acpi_reserve_resources(void) @@ -427,35 +418,42 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) __acpi_unmap_table(virt, size); } -static int acpi_os_map_generic_address(struct acpi_generic_address *addr) +int acpi_os_map_generic_address(struct acpi_generic_address *gas) { + u64 addr; void __iomem *virt; - if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return 0; - if (!addr->address || !addr->bit_width) + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !gas->bit_width) return -EINVAL; - virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); + virt = acpi_os_map_memory(addr, gas->bit_width / 8); if (!virt) return -EIO; return 0; } +EXPORT_SYMBOL(acpi_os_map_generic_address); -static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) +void acpi_os_unmap_generic_address(struct acpi_generic_address *gas) { + u64 addr; struct acpi_ioremap *map; - if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return; - if (!addr->address || !addr->bit_width) + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !gas->bit_width) return; mutex_lock(&acpi_ioremap_lock); - map = acpi_map_lookup(addr->address, addr->bit_width / 8); + map = acpi_map_lookup(addr, gas->bit_width / 8); if (!map) { mutex_unlock(&acpi_ioremap_lock); return; @@ -465,6 +463,7 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) acpi_os_map_cleanup(map); } +EXPORT_SYMBOL(acpi_os_unmap_generic_address); #ifdef ACPI_FUTURE_USAGE acpi_status @@ -1278,44 +1277,28 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); * drivers */ int acpi_check_resource_conflict(const struct resource *res) { - struct acpi_res_list *res_list_elem; - int ioport = 0, clash = 0; + acpi_adr_space_type space_id; + acpi_size length; + u8 warn = 0; + int clash = 0; if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) return 0; if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM)) return 0; - ioport = res->flags & IORESOURCE_IO; - - spin_lock(&acpi_res_lock); - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - if (ioport && (res_list_elem->resource_type - != ACPI_ADR_SPACE_SYSTEM_IO)) - continue; - if (!ioport && (res_list_elem->resource_type - != ACPI_ADR_SPACE_SYSTEM_MEMORY)) - continue; + if (res->flags & IORESOURCE_IO) + space_id = ACPI_ADR_SPACE_SYSTEM_IO; + else + space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY; - if (res->end < res_list_elem->start - || res_list_elem->end < res->start) - continue; - clash = 1; - break; - } - spin_unlock(&acpi_res_lock); + length = res->end - res->start + 1; + if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) + warn = 1; + clash = acpi_check_address_range(space_id, res->start, length, warn); if (clash) { if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { - printk(KERN_WARNING "ACPI: resource %s %pR" - " conflicts with ACPI region %s " - "[%s 0x%zx-0x%zx]\n", - res->name, res, res_list_elem->name, - (res_list_elem->resource_type == - ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem", - (size_t) res_list_elem->start, - (size_t) res_list_elem->end); if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) printk(KERN_NOTICE "ACPI: This conflict may" " cause random problems and system" @@ -1467,155 +1450,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) kmem_cache_free(cache, object); return (AE_OK); } - -static inline int acpi_res_list_add(struct acpi_res_list *res) -{ - struct acpi_res_list *res_list_elem; - - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - - if (res->resource_type == res_list_elem->resource_type && - res->start == res_list_elem->start && - res->end == res_list_elem->end) { - - /* - * The Region(addr,len) already exist in the list, - * just increase the count - */ - - res_list_elem->count++; - return 0; - } - } - - res->count = 1; - list_add(&res->resource_list, &resource_list_head); - return 1; -} - -static inline void acpi_res_list_del(struct acpi_res_list *res) -{ - struct acpi_res_list *res_list_elem; - - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - - if (res->resource_type == res_list_elem->resource_type && - res->start == res_list_elem->start && - res->end == res_list_elem->end) { - - /* - * If the res count is decreased to 0, - * remove and free it - */ - - if (--res_list_elem->count == 0) { - list_del(&res_list_elem->resource_list); - kfree(res_list_elem); - } - return; - } - } -} - -acpi_status -acpi_os_invalidate_address( - u8 space_id, - acpi_physical_address address, - acpi_size length) -{ - struct acpi_res_list res; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_IO: - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - /* Only interference checks against SystemIO and SystemMemory - are needed */ - res.start = address; - res.end = address + length - 1; - res.resource_type = space_id; - spin_lock(&acpi_res_lock); - acpi_res_list_del(&res); - spin_unlock(&acpi_res_lock); - break; - case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_EC: - case ACPI_ADR_SPACE_SMBUS: - case ACPI_ADR_SPACE_CMOS: - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - case ACPI_ADR_SPACE_DATA_TABLE: - case ACPI_ADR_SPACE_FIXED_HARDWARE: - break; - } - return AE_OK; -} - -/****************************************************************************** - * - * FUNCTION: acpi_os_validate_address - * - * PARAMETERS: space_id - ACPI space ID - * address - Physical address - * length - Address length - * - * RETURN: AE_OK if address/length is valid for the space_id. Otherwise, - * should return AE_AML_ILLEGAL_ADDRESS. - * - * DESCRIPTION: Validate a system address via the host OS. Used to validate - * the addresses accessed by AML operation regions. - * - *****************************************************************************/ - -acpi_status -acpi_os_validate_address ( - u8 space_id, - acpi_physical_address address, - acpi_size length, - char *name) -{ - struct acpi_res_list *res; - int added; - if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) - return AE_OK; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_IO: - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - /* Only interference checks against SystemIO and SystemMemory - are needed */ - res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL); - if (!res) - return AE_OK; - /* ACPI names are fixed to 4 bytes, still better use strlcpy */ - strlcpy(res->name, name, 5); - res->start = address; - res->end = address + length - 1; - res->resource_type = space_id; - spin_lock(&acpi_res_lock); - added = acpi_res_list_add(res); - spin_unlock(&acpi_res_lock); - pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " - "name: %s\n", added ? "Added" : "Already exist", - (space_id == ACPI_ADR_SPACE_SYSTEM_IO) - ? "SystemIO" : "System Memory", - (unsigned long long)res->start, - (unsigned long long)res->end, - res->name); - if (!added) - kfree(res); - break; - case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_EC: - case ACPI_ADR_SPACE_SMBUS: - case ACPI_ADR_SPACE_CMOS: - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - case ACPI_ADR_SPACE_DATA_TABLE: - case ACPI_ADR_SPACE_FIXED_HARDWARE: - break; - } - return AE_OK; -} #endif acpi_status __init acpi_os_initialize(void) diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 07f7fea8a4e2..e50e31a518af 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -34,7 +34,7 @@ #include <acpi/acpi_drivers.h> #include <linux/dmi.h> -static int debug; +static bool debug; static int check_sta_before_sun; #define DRIVER_VERSION "0.1" diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 3a0428e8435c..c850de4c9a14 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -173,8 +173,30 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) apic_id = map_mat_entry(handle, type, acpi_id); if (apic_id == -1) apic_id = map_madt_entry(type, acpi_id); - if (apic_id == -1) - return apic_id; + if (apic_id == -1) { + /* + * On UP processor, there is no _MAT or MADT table. + * So above apic_id is always set to -1. + * + * BIOS may define multiple CPU handles even for UP processor. + * For example, + * + * Scope (_PR) + * { + * Processor (CPU0, 0x00, 0x00000410, 0x06) {} + * Processor (CPU1, 0x01, 0x00000410, 0x06) {} + * Processor (CPU2, 0x02, 0x00000410, 0x06) {} + * Processor (CPU3, 0x03, 0x00000410, 0x06) {} + * } + * + * Ignores apic_id and always return 0 for CPU0's handle. + * Return -1 for other CPU's handle. + */ + if (acpi_id == 0) + return acpi_id; + else + return apic_id; + } #ifdef CONFIG_SMP for_each_possible_cpu(i) { diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 20a68ca386de..0034ede38710 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -82,7 +82,7 @@ MODULE_LICENSE("GPL"); static int acpi_processor_add(struct acpi_device *device); static int acpi_processor_remove(struct acpi_device *device, int type); static void acpi_processor_notify(struct acpi_device *device, u32 event); -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); +static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr); static int acpi_processor_handle_eject(struct acpi_processor *pr); @@ -324,10 +324,8 @@ static int acpi_processor_get_info(struct acpi_device *device) * they are physically not present. */ if (pr->id == -1) { - if (ACPI_FAILURE - (acpi_processor_hotadd_init(pr->handle, &pr->id))) { + if (ACPI_FAILURE(acpi_processor_hotadd_init(pr))) return -ENODEV; - } } /* * On some boxes several processors use the same processor bus id. @@ -539,6 +537,7 @@ err_thermal_unregister: thermal_cooling_device_unregister(pr->cdev); err_power_exit: acpi_processor_power_exit(pr, device); + sysfs_remove_link(&device->dev.kobj, "sysdev"); err_free_cpumask: free_cpumask_var(pr->throttling.shared_cpu_map); @@ -720,18 +719,19 @@ processor_walk_namespace_cb(acpi_handle handle, return (AE_OK); } -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu) +static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) { + acpi_handle handle = pr->handle; if (!is_processor_present(handle)) { return AE_ERROR; } - if (acpi_map_lsapic(handle, p_cpu)) + if (acpi_map_lsapic(handle, &pr->id)) return AE_ERROR; - if (arch_register_cpu(*p_cpu)) { - acpi_unmap_lsapic(*p_cpu); + if (arch_register_cpu(pr->id)) { + acpi_unmap_lsapic(pr->id); return AE_ERROR; } @@ -748,7 +748,7 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr) return (0); } #else -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu) +static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) { return AE_ERROR; } @@ -827,8 +827,6 @@ static void __exit acpi_processor_exit(void) acpi_bus_unregister_driver(&acpi_processor_driver); - cpuidle_unregister_driver(&acpi_idle_driver); - return; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 08a44b532f7c..eaef02afc7cf 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -69,21 +69,21 @@ MODULE_AUTHOR("Bruno Ducrot"); MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); -static int brightness_switch_enabled = 1; +static bool brightness_switch_enabled = 1; module_param(brightness_switch_enabled, bool, 0644); /* * By default, we don't allow duplicate ACPI video bus devices * under the same VGA controller */ -static int allow_duplicates; +static bool allow_duplicates; module_param(allow_duplicates, bool, 0644); /* * Some BIOSes claim they use minimum backlight at boot, * and this may bring dimming screen after boot */ -static int use_bios_initial_backlight = 1; +static bool use_bios_initial_backlight = 1; module_param(use_bios_initial_backlight, bool, 0644); static int register_count = 0; diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 69ac373c72ab..fdf27b9fce43 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -1117,6 +1117,13 @@ static int piix_broken_suspend(void) }, }, { + .ident = "Satellite Pro A120", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite Pro A120"), + }, + }, + { .ident = "Portege M500", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 11c9aea4f4f7..c06e0ec11556 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4125,6 +4125,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { * device and controller are SATA. */ { "PIONEER DVD-RW DVRTD08", NULL, ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVRTD08A", NULL, ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-215", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index 9a7f0ea565df..74aaee30e264 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -291,6 +291,7 @@ int ata_tport_add(struct device *parent, goto tport_err; } + device_enable_async_suspend(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index d6a4677fdf71..1e65842e2ca7 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -251,6 +251,8 @@ static const u32 udma_tenvmin = 20; static const u32 udma_tackmin = 20; static const u32 udma_tssmin = 50; +#define BFIN_MAX_SG_SEGMENTS 4 + /** * * Function: num_clocks_min @@ -829,79 +831,61 @@ static void bfin_set_devctl(struct ata_port *ap, u8 ctl) static void bfin_bmdma_setup(struct ata_queued_cmd *qc) { - unsigned short config = WDSIZE_16; + struct ata_port *ap = qc->ap; + struct dma_desc_array *dma_desc_cpu = (struct dma_desc_array *)ap->bmdma_prd; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned short config = DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_16 | DMAEN; struct scatterlist *sg; unsigned int si; + unsigned int channel; + unsigned int dir; + unsigned int size = 0; dev_dbg(qc->ap->dev, "in atapi dma setup\n"); /* Program the ATA_CTRL register with dir */ if (qc->tf.flags & ATA_TFLAG_WRITE) { - /* fill the ATAPI DMA controller */ - set_dma_config(CH_ATAPI_TX, config); - set_dma_x_modify(CH_ATAPI_TX, 2); - for_each_sg(qc->sg, sg, qc->n_elem, si) { - set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg)); - set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1); - } + channel = CH_ATAPI_TX; + dir = DMA_TO_DEVICE; } else { + channel = CH_ATAPI_RX; + dir = DMA_FROM_DEVICE; config |= WNR; - /* fill the ATAPI DMA controller */ - set_dma_config(CH_ATAPI_RX, config); - set_dma_x_modify(CH_ATAPI_RX, 2); - for_each_sg(qc->sg, sg, qc->n_elem, si) { - set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg)); - set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1); - } } -} -/** - * bfin_bmdma_start - Start an IDE DMA transaction - * @qc: Info associated with this ATA transaction. - * - * Note: Original code is ata_bmdma_start(). - */ + dma_map_sg(ap->dev, qc->sg, qc->n_elem, dir); -static void bfin_bmdma_start(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; - struct scatterlist *sg; - unsigned int si; + /* fill the ATAPI DMA controller */ + for_each_sg(qc->sg, sg, qc->n_elem, si) { + dma_desc_cpu[si].start_addr = sg_dma_address(sg); + dma_desc_cpu[si].cfg = config; + dma_desc_cpu[si].x_count = sg_dma_len(sg) >> 1; + dma_desc_cpu[si].x_modify = 2; + size += sg_dma_len(sg); + } - dev_dbg(qc->ap->dev, "in atapi dma start\n"); - if (!(ap->udma_mask || ap->mwdma_mask)) - return; + /* Set the last descriptor to stop mode */ + dma_desc_cpu[qc->n_elem - 1].cfg &= ~(DMAFLOW | NDSIZE); - /* start ATAPI DMA controller*/ - if (qc->tf.flags & ATA_TFLAG_WRITE) { - /* - * On blackfin arch, uncacheable memory is not - * allocated with flag GFP_DMA. DMA buffer from - * common kenel code should be flushed if WB - * data cache is enabled. Otherwise, this loop - * is an empty loop and optimized out. - */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { - flush_dcache_range(sg_dma_address(sg), - sg_dma_address(sg) + sg_dma_len(sg)); - } - enable_dma(CH_ATAPI_TX); - dev_dbg(qc->ap->dev, "enable udma write\n"); + flush_dcache_range((unsigned int)dma_desc_cpu, + (unsigned int)dma_desc_cpu + + qc->n_elem * sizeof(struct dma_desc_array)); - /* Send ATA DMA write command */ - bfin_exec_command(ap, &qc->tf); + /* Enable ATA DMA operation*/ + set_dma_curr_desc_addr(channel, (unsigned long *)ap->bmdma_prd_dma); + set_dma_x_count(channel, 0); + set_dma_x_modify(channel, 0); + set_dma_config(channel, config); + + SSYNC(); + + /* Send ATA DMA command */ + bfin_exec_command(ap, &qc->tf); + if (qc->tf.flags & ATA_TFLAG_WRITE) { /* set ATA DMA write direction */ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); } else { - enable_dma(CH_ATAPI_RX); - dev_dbg(qc->ap->dev, "enable udma read\n"); - - /* Send ATA DMA read command */ - bfin_exec_command(ap, &qc->tf); - /* set ATA DMA read direction */ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR)); @@ -913,12 +897,28 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) /* Set ATAPI state machine contorl in terminate sequence */ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM); - /* Set transfer length to buffer len */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { - ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1)); - } + /* Set transfer length to the total size of sg buffers */ + ATAPI_SET_XFER_LEN(base, size >> 1); +} - /* Enable ATA DMA operation*/ +/** + * bfin_bmdma_start - Start an IDE DMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_start(). + */ + +static void bfin_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + + dev_dbg(qc->ap->dev, "in atapi dma start\n"); + + if (!(ap->udma_mask || ap->mwdma_mask)) + return; + + /* start ATAPI transfer*/ if (ap->udma_mask) ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | ULTRA_START); @@ -935,34 +935,23 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) static void bfin_bmdma_stop(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scatterlist *sg; - unsigned int si; + unsigned int dir; dev_dbg(qc->ap->dev, "in atapi dma stop\n"); + if (!(ap->udma_mask || ap->mwdma_mask)) return; /* stop ATAPI DMA controller*/ - if (qc->tf.flags & ATA_TFLAG_WRITE) + if (qc->tf.flags & ATA_TFLAG_WRITE) { + dir = DMA_TO_DEVICE; disable_dma(CH_ATAPI_TX); - else { + } else { + dir = DMA_FROM_DEVICE; disable_dma(CH_ATAPI_RX); - if (ap->hsm_task_state & HSM_ST_LAST) { - /* - * On blackfin arch, uncacheable memory is not - * allocated with flag GFP_DMA. DMA buffer from - * common kenel code should be invalidated if - * data cache is enabled. Otherwise, this loop - * is an empty loop and optimized out. - */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { - invalidate_dcache_range( - sg_dma_address(sg), - sg_dma_address(sg) - + sg_dma_len(sg)); - } - } } + + dma_unmap_sg(ap->dev, qc->sg, qc->n_elem, dir); } /** @@ -1260,6 +1249,11 @@ static void bfin_port_stop(struct ata_port *ap) { dev_dbg(ap->dev, "in atapi port stop\n"); if (ap->udma_mask != 0 || ap->mwdma_mask != 0) { + dma_free_coherent(ap->dev, + BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array), + ap->bmdma_prd, + ap->bmdma_prd_dma); + free_dma(CH_ATAPI_RX); free_dma(CH_ATAPI_TX); } @@ -1271,14 +1265,29 @@ static int bfin_port_start(struct ata_port *ap) if (!(ap->udma_mask || ap->mwdma_mask)) return 0; + ap->bmdma_prd = dma_alloc_coherent(ap->dev, + BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array), + &ap->bmdma_prd_dma, + GFP_KERNEL); + + if (ap->bmdma_prd == NULL) { + dev_info(ap->dev, "Unable to allocate DMA descriptor array.\n"); + goto out; + } + if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) { if (request_dma(CH_ATAPI_TX, "BFIN ATAPI TX DMA") >= 0) return 0; free_dma(CH_ATAPI_RX); + dma_free_coherent(ap->dev, + BFIN_MAX_SG_SEGMENTS * sizeof(struct dma_desc_array), + ap->bmdma_prd, + ap->bmdma_prd_dma); } +out: ap->udma_mask = 0; ap->mwdma_mask = 0; dev_err(ap->dev, "Unable to request ATAPI DMA!" @@ -1400,7 +1409,7 @@ static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance) static struct scsi_host_template bfin_sht = { ATA_BASE_SHT(DRV_NAME), - .sg_tablesize = SG_NONE, + .sg_tablesize = BFIN_MAX_SG_SEGMENTS, .dma_boundary = ATA_DMA_BOUNDARY, }; diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 5a2c95ba050a..0120b0d1e9a5 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -140,6 +140,7 @@ enum { */ HCONTROL_ONLINE_PHY_RST = (1 << 31), HCONTROL_FORCE_OFFLINE = (1 << 30), + HCONTROL_LEGACY = (1 << 28), HCONTROL_PARITY_PROT_MOD = (1 << 14), HCONTROL_DPATH_PARITY = (1 << 12), HCONTROL_SNOOP_ENABLE = (1 << 10), @@ -1223,6 +1224,10 @@ static int sata_fsl_init_controller(struct ata_host *host) * part of the port_start() callback */ + /* sata controller to operate in enterprise mode */ + temp = ioread32(hcr_base + HCONTROL); + iowrite32(temp & ~HCONTROL_LEGACY, hcr_base + HCONTROL); + /* ack. any pending IRQs for this controller/port */ temp = ioread32(hcr_base + HSTATUS); if (temp & 0x3F) @@ -1421,6 +1426,12 @@ static int sata_fsl_resume(struct platform_device *op) /* Recovery the CHBA register in host controller cmd register set */ iowrite32(pp->cmdslot_paddr & 0xffffffff, hcr_base + CHBA); + iowrite32((ioread32(hcr_base + HCONTROL) + | HCONTROL_ONLINE_PHY_RST + | HCONTROL_SNOOP_ENABLE + | HCONTROL_PMP_ATTACHED), + hcr_base + HCONTROL); + ata_host_resume(host); return 0; } diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index e0bc9646a38e..55d6179dde58 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -599,9 +599,9 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, nv_pci_tbl); MODULE_VERSION(DRV_VERSION); -static int adma_enabled; -static int swncq_enabled = 1; -static int msi_enabled; +static bool adma_enabled; +static bool swncq_enabled = 1; +static bool msi_enabled; static void nv_adma_register_mode(struct ata_port *ap) { diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 1e9140626a83..e7e610aa9a7a 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -417,7 +417,7 @@ static struct ata_port_operations sil24_ops = { #endif }; -static int sata_sil24_msi; /* Disable MSI */ +static bool sata_sil24_msi; /* Disable MSI */ module_param_named(msi, sata_sil24_msi, bool, S_IRUGO); MODULE_PARM_DESC(msi, "Enable MSI (Default: false)"); diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 9a51df4f5b74..b182c2f7d777 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -112,12 +112,12 @@ static u8 read_prom_byte(struct he_dev *he_dev, int addr); /* globals */ static struct he_dev *he_devs; -static int disable64; +static bool disable64; static short nvpibits = -1; static short nvcibits = -1; static short rx_skb_reserve = 16; -static int irq_coalesce = 1; -static int sdh = 0; +static bool irq_coalesce = 1; +static bool sdh = 0; /* Read from EEPROM = 0000 0011b */ static unsigned int readtab[] = { diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index fcbec8ac134d..7be9f79018e9 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -179,7 +179,7 @@ config GENERIC_CPU_DEVICES source "drivers/base/regmap/Kconfig" config DMA_SHARED_BUFFER - bool "Buffer framework to be shared between drivers" + bool default n select ANON_INODES depends on EXPERIMENTAL diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 99dc5921e1dd..40fb12288ce2 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -915,9 +915,10 @@ static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); /** * __bus_register - register a driver-core subsystem - * @bus: bus. + * @bus: bus to register + * @key: lockdep class key * - * Once we have that, we registered the bus with the kobject + * Once we have that, we register the bus with the kobject * infrastructure, then register the children subsystems it has: * the devices and drivers that belong to the subsystem. */ @@ -1220,8 +1221,8 @@ static void system_root_device_release(struct device *dev) } /** * subsys_system_register - register a subsystem at /sys/devices/system/ - * @subsys - system subsystem - * @groups - default attributes for the root device + * @subsys: system subsystem + * @groups: default attributes for the root device * * All 'system' subsystems have a /sys/devices/system/<name> root device * with the name of the subsystem. The root device can carry subsystem- diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 26ab358dac62..6c9387d646ec 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -525,8 +525,7 @@ static int _request_firmware(const struct firmware **firmware_p, if (!firmware) { dev_err(device, "%s: kmalloc(struct firmware) failed\n", __func__); - retval = -ENOMEM; - goto out; + return -ENOMEM; } if (fw_get_builtin_firmware(firmware, name)) { diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 92e6a9048065..978bbf7ac6af 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1429,6 +1429,8 @@ static int pm_genpd_default_restore_state(struct device *dev) return 0; } +#ifdef CONFIG_PM_SLEEP + /** * pm_genpd_default_suspend - Default "device suspend" for PM domians. * @dev: Device to handle. @@ -1517,6 +1519,19 @@ static int pm_genpd_default_thaw(struct device *dev) return cb ? cb(dev) : pm_generic_thaw(dev); } +#else /* !CONFIG_PM_SLEEP */ + +#define pm_genpd_default_suspend NULL +#define pm_genpd_default_suspend_late NULL +#define pm_genpd_default_resume_early NULL +#define pm_genpd_default_resume NULL +#define pm_genpd_default_freeze NULL +#define pm_genpd_default_freeze_late NULL +#define pm_genpd_default_thaw_early NULL +#define pm_genpd_default_thaw NULL + +#endif /* !CONFIG_PM_SLEEP */ + /** * pm_genpd_init - Initialize a generic I/O PM domain object. * @genpd: PM domain object to initialize. diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index 51527ee92d10..66a265bf5867 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -12,6 +12,8 @@ #include <linux/pm_qos.h> #include <linux/hrtimer.h> +#ifdef CONFIG_PM_RUNTIME + /** * default_stop_ok - Default PM domain governor routine for stopping devices. * @dev: Device to check. @@ -137,16 +139,28 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) return true; } -struct dev_power_governor simple_qos_governor = { - .stop_ok = default_stop_ok, - .power_down_ok = default_power_down_ok, -}; - static bool always_on_power_down_ok(struct dev_pm_domain *domain) { return false; } +#else /* !CONFIG_PM_RUNTIME */ + +bool default_stop_ok(struct device *dev) +{ + return false; +} + +#define default_power_down_ok NULL +#define always_on_power_down_ok NULL + +#endif /* !CONFIG_PM_RUNTIME */ + +struct dev_power_governor simple_qos_governor = { + .stop_ok = default_stop_ok, + .power_down_ok = default_power_down_ok, +}; + /** * pm_genpd_gov_always_on - A governor implementing an always-on policy */ diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index bcd1c01cde9e..b8379b90d045 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -179,10 +179,8 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) err = bcma_sprom_get(bus); if (err == -ENOENT) { pr_err("No SPROM available\n"); - } else if (err) { + } else if (err) pr_err("Failed to get SPROM: %d\n", err); - return -ENOENT; - } /* Register found cores */ bcma_register_cores(bus); diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 6621b2221b40..f94cccccfa56 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -415,15 +415,18 @@ int bcma_bus_scan(struct bcma_bus *bus) core->bus = bus; err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core); - if (err == -ENODEV) { - core_num++; - continue; - } else if (err == -ENXIO) - continue; - else if (err == -ESPIPE) - break; - else if (err < 0) + if (err < 0) { + kfree(core); + if (err == -ENODEV) { + core_num++; + continue; + } else if (err == -ENXIO) { + continue; + } else if (err == -ESPIPE) { + break; + } return err; + } core->core_index = core_num++; bus->nr_cores++; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 6f07ec1c2f58..4e4c8a4a5fd3 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -116,6 +116,8 @@ config PARIDE source "drivers/block/paride/Kconfig" +source "drivers/block/mtip32xx/Kconfig" + config BLK_CPQ_DA tristate "Compaq SMART2 support" depends on PCI && VIRT_TO_BUS @@ -315,6 +317,17 @@ config BLK_DEV_NBD If unsure, say N. +config BLK_DEV_NVME + tristate "NVM Express block device" + depends on PCI + ---help--- + The NVM Express driver is for solid state drives directly + connected to the PCI or PCI Express bus. If you know you + don't have one of these, it is safe to answer N. + + To compile this driver as a module, choose M here: the + module will be called nvme. + config BLK_DEV_OSD tristate "OSD object-as-blkdev support" depends on SCSI_OSD_ULD diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 76646e9a1c91..5b795059f8fb 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_XILINX_SYSACE) += xsysace.o obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o obj-$(CONFIG_MG_DISK) += mg_disk.o obj-$(CONFIG_SUNVDC) += sunvdc.o +obj-$(CONFIG_BLK_DEV_NVME) += nvme.o obj-$(CONFIG_BLK_DEV_OSD) += osdblk.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o @@ -39,5 +40,6 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o obj-$(CONFIG_XEN_BLKDEV_BACKEND) += xen-blkback/ obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ obj-$(CONFIG_BLK_DEV_RBD) += rbd.o +obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/ swim_mod-y := swim.o swim_asm.o diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 587cce57adae..b0f553b26d0f 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1735,7 +1735,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, case CCISS_BIG_PASSTHRU: return cciss_bigpassthru(h, argp); - /* scsi_cmd_ioctl handles these, below, though some are not */ + /* scsi_cmd_blk_ioctl handles these, below, though some are not */ /* very meaningful for cciss. SG_IO is the main one people want. */ case SG_GET_VERSION_NUM: @@ -1746,9 +1746,9 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, case SG_EMULATED_HOST: case SG_IO: case SCSI_IOCTL_SEND_COMMAND: - return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); + return scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); - /* scsi_cmd_ioctl would normally handle these, below, but */ + /* scsi_cmd_blk_ioctl would normally handle these, below, but */ /* they aren't a good fit for cciss, as CD-ROMs are */ /* not supported, and we don't have any bus/target/lun */ /* which we present to the kernel. */ diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 9cf20355ceec..8d680562ba73 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -59,8 +59,8 @@ /* module parameter, defined in drbd_main.c */ extern unsigned int minor_count; -extern int disable_sendpage; -extern int allow_oos; +extern bool disable_sendpage; +extern bool allow_oos; extern unsigned int cn_idx; #ifdef CONFIG_DRBD_FAULT_INJECTION diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 0358e55356c8..211fc44f84be 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -117,8 +117,8 @@ module_param(fault_devs, int, 0644); /* module parameter, defined */ unsigned int minor_count = DRBD_MINOR_COUNT_DEF; -int disable_sendpage; -int allow_oos; +bool disable_sendpage; +bool allow_oos; unsigned int cn_idx = CN_IDX_DRBD; int proc_details; /* Detail level in proc drbd*/ diff --git a/drivers/block/mtip32xx/Kconfig b/drivers/block/mtip32xx/Kconfig new file mode 100644 index 000000000000..b5dd14e072f2 --- /dev/null +++ b/drivers/block/mtip32xx/Kconfig @@ -0,0 +1,9 @@ +# +# mtip32xx device driver configuration +# + +config BLK_DEV_PCIESSD_MTIP32XX + tristate "Block Device Driver for Micron PCIe SSDs" + depends on HOTPLUG_PCI_PCIE + help + This enables the block driver for Micron PCIe SSDs. diff --git a/drivers/block/mtip32xx/Makefile b/drivers/block/mtip32xx/Makefile new file mode 100644 index 000000000000..4fbef8c8329b --- /dev/null +++ b/drivers/block/mtip32xx/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for Block device driver for Micron PCIe SSD +# + +obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx.o diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c new file mode 100644 index 000000000000..b74eab70c3d0 --- /dev/null +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -0,0 +1,3651 @@ +/* + * Driver for the Micron P320 SSD + * Copyright (C) 2011 Micron Technology, Inc. + * + * Portions of this code were derived from works subjected to the + * following copyright: + * Copyright (C) 2009 Integrated Device Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/ata.h> +#include <linux/delay.h> +#include <linux/hdreg.h> +#include <linux/uaccess.h> +#include <linux/random.h> +#include <linux/smp.h> +#include <linux/compat.h> +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/genhd.h> +#include <linux/blkdev.h> +#include <linux/bio.h> +#include <linux/dma-mapping.h> +#include <linux/idr.h> +#include <linux/kthread.h> +#include <../drivers/ata/ahci.h> +#include "mtip32xx.h" + +#define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32) +#define HW_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (MTIP_MAX_SG * 16)) +#define HW_CMD_TBL_AR_SZ (HW_CMD_TBL_SZ * MTIP_MAX_COMMAND_SLOTS) +#define HW_PORT_PRIV_DMA_SZ \ + (HW_CMD_SLOT_SZ + HW_CMD_TBL_AR_SZ + AHCI_RX_FIS_SZ) + +#define HOST_HSORG 0xFC +#define HSORG_DISABLE_SLOTGRP_INTR (1<<24) +#define HSORG_DISABLE_SLOTGRP_PXIS (1<<16) +#define HSORG_HWREV 0xFF00 +#define HSORG_STYLE 0x8 +#define HSORG_SLOTGROUPS 0x7 + +#define PORT_COMMAND_ISSUE 0x38 +#define PORT_SDBV 0x7C + +#define PORT_OFFSET 0x100 +#define PORT_MEM_SIZE 0x80 + +#define PORT_IRQ_ERR \ + (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | PORT_IRQ_CONNECT | \ + PORT_IRQ_PHYRDY | PORT_IRQ_UNK_FIS | PORT_IRQ_BAD_PMP | \ + PORT_IRQ_TF_ERR | PORT_IRQ_HBUS_DATA_ERR | PORT_IRQ_IF_NONFATAL | \ + PORT_IRQ_OVERFLOW) +#define PORT_IRQ_LEGACY \ + (PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS) +#define PORT_IRQ_HANDLED \ + (PORT_IRQ_SDB_FIS | PORT_IRQ_LEGACY | \ + PORT_IRQ_TF_ERR | PORT_IRQ_IF_ERR | \ + PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY) +#define DEF_PORT_IRQ \ + (PORT_IRQ_ERR | PORT_IRQ_LEGACY | PORT_IRQ_SDB_FIS) + +/* product numbers */ +#define MTIP_PRODUCT_UNKNOWN 0x00 +#define MTIP_PRODUCT_ASICFPGA 0x11 + +/* Device instance number, incremented each time a device is probed. */ +static int instance; + +/* + * Global variable used to hold the major block device number + * allocated in mtip_init(). + */ +static int mtip_major; + +static DEFINE_SPINLOCK(rssd_index_lock); +static DEFINE_IDA(rssd_index_ida); + +static int mtip_block_initialize(struct driver_data *dd); + +#ifdef CONFIG_COMPAT +struct mtip_compat_ide_task_request_s { + __u8 io_ports[8]; + __u8 hob_ports[8]; + ide_reg_valid_t out_flags; + ide_reg_valid_t in_flags; + int data_phase; + int req_cmd; + compat_ulong_t out_size; + compat_ulong_t in_size; +}; +#endif + +/* + * This function check_for_surprise_removal is called + * while card is removed from the system and it will + * read the vendor id from the configration space + * + * @pdev Pointer to the pci_dev structure. + * + * return value + * true if device removed, else false + */ +static bool mtip_check_surprise_removal(struct pci_dev *pdev) +{ + u16 vendor_id = 0; + + /* Read the vendorID from the configuration space */ + pci_read_config_word(pdev, 0x00, &vendor_id); + if (vendor_id == 0xFFFF) + return true; /* device removed */ + + return false; /* device present */ +} + +/* + * This function is called for clean the pending command in the + * command slot during the surprise removal of device and return + * error to the upper layer. + * + * @dd Pointer to the DRIVER_DATA structure. + * + * return value + * None + */ +static void mtip_command_cleanup(struct driver_data *dd) +{ + int group = 0, commandslot = 0, commandindex = 0; + struct mtip_cmd *command; + struct mtip_port *port = dd->port; + + for (group = 0; group < 4; group++) { + for (commandslot = 0; commandslot < 32; commandslot++) { + if (!(port->allocated[group] & (1 << commandslot))) + continue; + + commandindex = group << 5 | commandslot; + command = &port->commands[commandindex]; + + if (atomic_read(&command->active) + && (command->async_callback)) { + command->async_callback(command->async_data, + -ENODEV); + command->async_callback = NULL; + command->async_data = NULL; + } + + dma_unmap_sg(&port->dd->pdev->dev, + command->sg, + command->scatter_ents, + command->direction); + } + } + + up(&port->cmd_slot); + + atomic_set(&dd->drv_cleanup_done, true); +} + +/* + * Obtain an empty command slot. + * + * This function needs to be reentrant since it could be called + * at the same time on multiple CPUs. The allocation of the + * command slot must be atomic. + * + * @port Pointer to the port data structure. + * + * return value + * >= 0 Index of command slot obtained. + * -1 No command slots available. + */ +static int get_slot(struct mtip_port *port) +{ + int slot, i; + unsigned int num_command_slots = port->dd->slot_groups * 32; + + /* + * Try 10 times, because there is a small race here. + * that's ok, because it's still cheaper than a lock. + * + * Race: Since this section is not protected by lock, same bit + * could be chosen by different process contexts running in + * different processor. So instead of costly lock, we are going + * with loop. + */ + for (i = 0; i < 10; i++) { + slot = find_next_zero_bit(port->allocated, + num_command_slots, 1); + if ((slot < num_command_slots) && + (!test_and_set_bit(slot, port->allocated))) + return slot; + } + dev_warn(&port->dd->pdev->dev, "Failed to get a tag.\n"); + + if (mtip_check_surprise_removal(port->dd->pdev)) { + /* Device not present, clean outstanding commands */ + mtip_command_cleanup(port->dd); + } + return -1; +} + +/* + * Release a command slot. + * + * @port Pointer to the port data structure. + * @tag Tag of command to release + * + * return value + * None + */ +static inline void release_slot(struct mtip_port *port, int tag) +{ + smp_mb__before_clear_bit(); + clear_bit(tag, port->allocated); + smp_mb__after_clear_bit(); +} + +/* + * Reset the HBA (without sleeping) + * + * Just like hba_reset, except does not call sleep, so can be + * run from interrupt/tasklet context. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 The reset was successful. + * -1 The HBA Reset bit did not clear. + */ +static int hba_reset_nosleep(struct driver_data *dd) +{ + unsigned long timeout; + + /* Chip quirk: quiesce any chip function */ + mdelay(10); + + /* Set the reset bit */ + writel(HOST_RESET, dd->mmio + HOST_CTL); + + /* Flush */ + readl(dd->mmio + HOST_CTL); + + /* + * Wait 10ms then spin for up to 1 second + * waiting for reset acknowledgement + */ + timeout = jiffies + msecs_to_jiffies(1000); + mdelay(10); + while ((readl(dd->mmio + HOST_CTL) & HOST_RESET) + && time_before(jiffies, timeout)) + mdelay(1); + + if (readl(dd->mmio + HOST_CTL) & HOST_RESET) + return -1; + + return 0; +} + +/* + * Issue a command to the hardware. + * + * Set the appropriate bit in the s_active and Command Issue hardware + * registers, causing hardware command processing to begin. + * + * @port Pointer to the port structure. + * @tag The tag of the command to be issued. + * + * return value + * None + */ +static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag) +{ + unsigned long flags = 0; + + atomic_set(&port->commands[tag].active, 1); + + spin_lock_irqsave(&port->cmd_issue_lock, flags); + + writel((1 << MTIP_TAG_BIT(tag)), + port->s_active[MTIP_TAG_INDEX(tag)]); + writel((1 << MTIP_TAG_BIT(tag)), + port->cmd_issue[MTIP_TAG_INDEX(tag)]); + + spin_unlock_irqrestore(&port->cmd_issue_lock, flags); +} + +/* + * Enable/disable the reception of FIS + * + * @port Pointer to the port data structure + * @enable 1 to enable, 0 to disable + * + * return value + * Previous state: 1 enabled, 0 disabled + */ +static int mtip_enable_fis(struct mtip_port *port, int enable) +{ + u32 tmp; + + /* enable FIS reception */ + tmp = readl(port->mmio + PORT_CMD); + if (enable) + writel(tmp | PORT_CMD_FIS_RX, port->mmio + PORT_CMD); + else + writel(tmp & ~PORT_CMD_FIS_RX, port->mmio + PORT_CMD); + + /* Flush */ + readl(port->mmio + PORT_CMD); + + return (((tmp & PORT_CMD_FIS_RX) == PORT_CMD_FIS_RX)); +} + +/* + * Enable/disable the DMA engine + * + * @port Pointer to the port data structure + * @enable 1 to enable, 0 to disable + * + * return value + * Previous state: 1 enabled, 0 disabled. + */ +static int mtip_enable_engine(struct mtip_port *port, int enable) +{ + u32 tmp; + + /* enable FIS reception */ + tmp = readl(port->mmio + PORT_CMD); + if (enable) + writel(tmp | PORT_CMD_START, port->mmio + PORT_CMD); + else + writel(tmp & ~PORT_CMD_START, port->mmio + PORT_CMD); + + readl(port->mmio + PORT_CMD); + return (((tmp & PORT_CMD_START) == PORT_CMD_START)); +} + +/* + * Enables the port DMA engine and FIS reception. + * + * return value + * None + */ +static inline void mtip_start_port(struct mtip_port *port) +{ + /* Enable FIS reception */ + mtip_enable_fis(port, 1); + + /* Enable the DMA engine */ + mtip_enable_engine(port, 1); +} + +/* + * Deinitialize a port by disabling port interrupts, the DMA engine, + * and FIS reception. + * + * @port Pointer to the port structure + * + * return value + * None + */ +static inline void mtip_deinit_port(struct mtip_port *port) +{ + /* Disable interrupts on this port */ + writel(0, port->mmio + PORT_IRQ_MASK); + + /* Disable the DMA engine */ + mtip_enable_engine(port, 0); + + /* Disable FIS reception */ + mtip_enable_fis(port, 0); +} + +/* + * Initialize a port. + * + * This function deinitializes the port by calling mtip_deinit_port() and + * then initializes it by setting the command header and RX FIS addresses, + * clearing the SError register and any pending port interrupts before + * re-enabling the default set of port interrupts. + * + * @port Pointer to the port structure. + * + * return value + * None + */ +static void mtip_init_port(struct mtip_port *port) +{ + int i; + mtip_deinit_port(port); + + /* Program the command list base and FIS base addresses */ + if (readl(port->dd->mmio + HOST_CAP) & HOST_CAP_64) { + writel((port->command_list_dma >> 16) >> 16, + port->mmio + PORT_LST_ADDR_HI); + writel((port->rxfis_dma >> 16) >> 16, + port->mmio + PORT_FIS_ADDR_HI); + } + + writel(port->command_list_dma & 0xFFFFFFFF, + port->mmio + PORT_LST_ADDR); + writel(port->rxfis_dma & 0xFFFFFFFF, port->mmio + PORT_FIS_ADDR); + + /* Clear SError */ + writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR); + + /* reset the completed registers.*/ + for (i = 0; i < port->dd->slot_groups; i++) + writel(0xFFFFFFFF, port->completed[i]); + + /* Clear any pending interrupts for this port */ + writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT); + + /* Enable port interrupts */ + writel(DEF_PORT_IRQ, port->mmio + PORT_IRQ_MASK); +} + +/* + * Restart a port + * + * @port Pointer to the port data structure. + * + * return value + * None + */ +static void mtip_restart_port(struct mtip_port *port) +{ + unsigned long timeout; + + /* Disable the DMA engine */ + mtip_enable_engine(port, 0); + + /* Chip quirk: wait up to 500ms for PxCMD.CR == 0 */ + timeout = jiffies + msecs_to_jiffies(500); + while ((readl(port->mmio + PORT_CMD) & PORT_CMD_LIST_ON) + && time_before(jiffies, timeout)) + ; + + /* + * Chip quirk: escalate to hba reset if + * PxCMD.CR not clear after 500 ms + */ + if (readl(port->mmio + PORT_CMD) & PORT_CMD_LIST_ON) { + dev_warn(&port->dd->pdev->dev, + "PxCMD.CR not clear, escalating reset\n"); + + if (hba_reset_nosleep(port->dd)) + dev_err(&port->dd->pdev->dev, + "HBA reset escalation failed.\n"); + + /* 30 ms delay before com reset to quiesce chip */ + mdelay(30); + } + + dev_warn(&port->dd->pdev->dev, "Issuing COM reset\n"); + + /* Set PxSCTL.DET */ + writel(readl(port->mmio + PORT_SCR_CTL) | + 1, port->mmio + PORT_SCR_CTL); + readl(port->mmio + PORT_SCR_CTL); + + /* Wait 1 ms to quiesce chip function */ + timeout = jiffies + msecs_to_jiffies(1); + while (time_before(jiffies, timeout)) + ; + + /* Clear PxSCTL.DET */ + writel(readl(port->mmio + PORT_SCR_CTL) & ~1, + port->mmio + PORT_SCR_CTL); + readl(port->mmio + PORT_SCR_CTL); + + /* Wait 500 ms for bit 0 of PORT_SCR_STS to be set */ + timeout = jiffies + msecs_to_jiffies(500); + while (((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0) + && time_before(jiffies, timeout)) + ; + + if ((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0) + dev_warn(&port->dd->pdev->dev, + "COM reset failed\n"); + + /* Clear SError, the PxSERR.DIAG.x should be set so clear it */ + writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR); + + /* Enable the DMA engine */ + mtip_enable_engine(port, 1); +} + +/* + * Called periodically to see if any read/write commands are + * taking too long to complete. + * + * @data Pointer to the PORT data structure. + * + * return value + * None + */ +static void mtip_timeout_function(unsigned long int data) +{ + struct mtip_port *port = (struct mtip_port *) data; + struct host_to_dev_fis *fis; + struct mtip_cmd *command; + int tag, cmdto_cnt = 0; + unsigned int bit, group; + unsigned int num_command_slots = port->dd->slot_groups * 32; + + if (unlikely(!port)) + return; + + if (atomic_read(&port->dd->resumeflag) == true) { + mod_timer(&port->cmd_timer, + jiffies + msecs_to_jiffies(30000)); + return; + } + + for (tag = 0; tag < num_command_slots; tag++) { + /* + * Skip internal command slot as it has + * its own timeout mechanism + */ + if (tag == MTIP_TAG_INTERNAL) + continue; + + if (atomic_read(&port->commands[tag].active) && + (time_after(jiffies, port->commands[tag].comp_time))) { + group = tag >> 5; + bit = tag & 0x1F; + + command = &port->commands[tag]; + fis = (struct host_to_dev_fis *) command->command; + + dev_warn(&port->dd->pdev->dev, + "Timeout for command tag %d\n", tag); + + cmdto_cnt++; + if (cmdto_cnt == 1) + set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + + /* + * Clear the completed bit. This should prevent + * any interrupt handlers from trying to retire + * the command. + */ + writel(1 << bit, port->completed[group]); + + /* Call the async completion callback. */ + if (likely(command->async_callback)) + command->async_callback(command->async_data, + -EIO); + command->async_callback = NULL; + command->comp_func = NULL; + + /* Unmap the DMA scatter list entries */ + dma_unmap_sg(&port->dd->pdev->dev, + command->sg, + command->scatter_ents, + command->direction); + + /* + * Clear the allocated bit and active tag for the + * command. + */ + atomic_set(&port->commands[tag].active, 0); + release_slot(port, tag); + + up(&port->cmd_slot); + } + } + + if (cmdto_cnt) { + dev_warn(&port->dd->pdev->dev, + "%d commands timed out: restarting port", + cmdto_cnt); + mtip_restart_port(port); + clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + } + + /* Restart the timer */ + mod_timer(&port->cmd_timer, + jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); +} + +/* + * IO completion function. + * + * This completion function is called by the driver ISR when a + * command that was issued by the kernel completes. It first calls the + * asynchronous completion function which normally calls back into the block + * layer passing the asynchronous callback data, then unmaps the + * scatter list associated with the completed command, and finally + * clears the allocated bit associated with the completed command. + * + * @port Pointer to the port data structure. + * @tag Tag of the command. + * @data Pointer to driver_data. + * @status Completion status. + * + * return value + * None + */ +static void mtip_async_complete(struct mtip_port *port, + int tag, + void *data, + int status) +{ + struct mtip_cmd *command; + struct driver_data *dd = data; + int cb_status = status ? -EIO : 0; + + if (unlikely(!dd) || unlikely(!port)) + return; + + command = &port->commands[tag]; + + if (unlikely(status == PORT_IRQ_TF_ERR)) { + dev_warn(&port->dd->pdev->dev, + "Command tag %d failed due to TFE\n", tag); + } + + /* Upper layer callback */ + if (likely(command->async_callback)) + command->async_callback(command->async_data, cb_status); + + command->async_callback = NULL; + command->comp_func = NULL; + + /* Unmap the DMA scatter list entries */ + dma_unmap_sg(&dd->pdev->dev, + command->sg, + command->scatter_ents, + command->direction); + + /* Clear the allocated and active bits for the command */ + atomic_set(&port->commands[tag].active, 0); + release_slot(port, tag); + + up(&port->cmd_slot); +} + +/* + * Internal command completion callback function. + * + * This function is normally called by the driver ISR when an internal + * command completed. This function signals the command completion by + * calling complete(). + * + * @port Pointer to the port data structure. + * @tag Tag of the command that has completed. + * @data Pointer to a completion structure. + * @status Completion status. + * + * return value + * None + */ +static void mtip_completion(struct mtip_port *port, + int tag, + void *data, + int status) +{ + struct mtip_cmd *command = &port->commands[tag]; + struct completion *waiting = data; + if (unlikely(status == PORT_IRQ_TF_ERR)) + dev_warn(&port->dd->pdev->dev, + "Internal command %d completed with TFE\n", tag); + + command->async_callback = NULL; + command->comp_func = NULL; + + complete(waiting); +} + +/* + * Helper function for tag logging + */ +static void print_tags(struct driver_data *dd, + char *msg, + unsigned long *tagbits) +{ + unsigned int tag, count = 0; + + for (tag = 0; tag < (dd->slot_groups) * 32; tag++) { + if (test_bit(tag, tagbits)) + count++; + } + if (count) + dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count); +} + +/* + * Handle an error. + * + * @dd Pointer to the DRIVER_DATA structure. + * + * return value + * None + */ +static void mtip_handle_tfe(struct driver_data *dd) +{ + int group, tag, bit, reissue; + struct mtip_port *port; + struct mtip_cmd *command; + u32 completed; + struct host_to_dev_fis *fis; + unsigned long tagaccum[SLOTBITS_IN_LONGS]; + + dev_warn(&dd->pdev->dev, "Taskfile error\n"); + + port = dd->port; + + /* Stop the timer to prevent command timeouts. */ + del_timer(&port->cmd_timer); + + /* Set eh_active */ + set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + + /* Loop through all the groups */ + for (group = 0; group < dd->slot_groups; group++) { + completed = readl(port->completed[group]); + + /* clear completed status register in the hardware.*/ + writel(completed, port->completed[group]); + + /* clear the tag accumulator */ + memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + + /* Process successfully completed commands */ + for (bit = 0; bit < 32 && completed; bit++) { + if (!(completed & (1<<bit))) + continue; + tag = (group << 5) + bit; + + /* Skip the internal command slot */ + if (tag == MTIP_TAG_INTERNAL) + continue; + + command = &port->commands[tag]; + if (likely(command->comp_func)) { + set_bit(tag, tagaccum); + atomic_set(&port->commands[tag].active, 0); + command->comp_func(port, + tag, + command->comp_data, + 0); + } else { + dev_err(&port->dd->pdev->dev, + "Missing completion func for tag %d", + tag); + if (mtip_check_surprise_removal(dd->pdev)) { + mtip_command_cleanup(dd); + /* don't proceed further */ + return; + } + } + } + } + print_tags(dd, "TFE tags completed:", tagaccum); + + /* Restart the port */ + mdelay(20); + mtip_restart_port(port); + + /* clear the tag accumulator */ + memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + + /* Loop through all the groups */ + for (group = 0; group < dd->slot_groups; group++) { + for (bit = 0; bit < 32; bit++) { + reissue = 1; + tag = (group << 5) + bit; + + /* If the active bit is set re-issue the command */ + if (atomic_read(&port->commands[tag].active) == 0) + continue; + + fis = (struct host_to_dev_fis *) + port->commands[tag].command; + + /* Should re-issue? */ + if (tag == MTIP_TAG_INTERNAL || + fis->command == ATA_CMD_SET_FEATURES) + reissue = 0; + + /* + * First check if this command has + * exceeded its retries. + */ + if (reissue && + (port->commands[tag].retries-- > 0)) { + + set_bit(tag, tagaccum); + + /* Update the timeout value. */ + port->commands[tag].comp_time = + jiffies + msecs_to_jiffies( + MTIP_NCQ_COMMAND_TIMEOUT_MS); + /* Re-issue the command. */ + mtip_issue_ncq_command(port, tag); + + continue; + } + + /* Retire a command that will not be reissued */ + dev_warn(&port->dd->pdev->dev, + "retiring tag %d\n", tag); + atomic_set(&port->commands[tag].active, 0); + + if (port->commands[tag].comp_func) + port->commands[tag].comp_func( + port, + tag, + port->commands[tag].comp_data, + PORT_IRQ_TF_ERR); + else + dev_warn(&port->dd->pdev->dev, + "Bad completion for tag %d\n", + tag); + } + } + print_tags(dd, "TFE tags reissued:", tagaccum); + + /* clear eh_active */ + clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + + mod_timer(&port->cmd_timer, + jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); +} + +/* + * Handle a set device bits interrupt + */ +static inline void mtip_process_sdbf(struct driver_data *dd) +{ + struct mtip_port *port = dd->port; + int group, tag, bit; + u32 completed; + struct mtip_cmd *command; + + /* walk all bits in all slot groups */ + for (group = 0; group < dd->slot_groups; group++) { + completed = readl(port->completed[group]); + + /* clear completed status register in the hardware.*/ + writel(completed, port->completed[group]); + + /* Process completed commands. */ + for (bit = 0; + (bit < 32) && completed; + bit++, completed >>= 1) { + if (completed & 0x01) { + tag = (group << 5) | bit; + + /* skip internal command slot. */ + if (unlikely(tag == MTIP_TAG_INTERNAL)) + continue; + + command = &port->commands[tag]; + /* make internal callback */ + if (likely(command->comp_func)) { + command->comp_func( + port, + tag, + command->comp_data, + 0); + } else { + dev_warn(&dd->pdev->dev, + "Null completion " + "for tag %d", + tag); + + if (mtip_check_surprise_removal( + dd->pdev)) { + mtip_command_cleanup(dd); + return; + } + } + } + } + } +} + +/* + * Process legacy pio and d2h interrupts + */ +static inline void mtip_process_legacy(struct driver_data *dd, u32 port_stat) +{ + struct mtip_port *port = dd->port; + struct mtip_cmd *cmd = &port->commands[MTIP_TAG_INTERNAL]; + + if (test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) && + (cmd != NULL) && !(readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL))) { + if (cmd->comp_func) { + cmd->comp_func(port, + MTIP_TAG_INTERNAL, + cmd->comp_data, + 0); + return; + } + } + + dev_warn(&dd->pdev->dev, "IRQ status 0x%x ignored.\n", port_stat); + + return; +} + +/* + * Demux and handle errors + */ +static inline void mtip_process_errors(struct driver_data *dd, u32 port_stat) +{ + if (likely(port_stat & (PORT_IRQ_TF_ERR | PORT_IRQ_IF_ERR))) + mtip_handle_tfe(dd); + + if (unlikely(port_stat & PORT_IRQ_CONNECT)) { + dev_warn(&dd->pdev->dev, + "Clearing PxSERR.DIAG.x\n"); + writel((1 << 26), dd->port->mmio + PORT_SCR_ERR); + } + + if (unlikely(port_stat & PORT_IRQ_PHYRDY)) { + dev_warn(&dd->pdev->dev, + "Clearing PxSERR.DIAG.n\n"); + writel((1 << 16), dd->port->mmio + PORT_SCR_ERR); + } + + if (unlikely(port_stat & ~PORT_IRQ_HANDLED)) { + dev_warn(&dd->pdev->dev, + "Port stat errors %x unhandled\n", + (port_stat & ~PORT_IRQ_HANDLED)); + } +} + +static inline irqreturn_t mtip_handle_irq(struct driver_data *data) +{ + struct driver_data *dd = (struct driver_data *) data; + struct mtip_port *port = dd->port; + u32 hba_stat, port_stat; + int rv = IRQ_NONE; + + hba_stat = readl(dd->mmio + HOST_IRQ_STAT); + if (hba_stat) { + rv = IRQ_HANDLED; + + /* Acknowledge the interrupt status on the port.*/ + port_stat = readl(port->mmio + PORT_IRQ_STAT); + writel(port_stat, port->mmio + PORT_IRQ_STAT); + + /* Demux port status */ + if (likely(port_stat & PORT_IRQ_SDB_FIS)) + mtip_process_sdbf(dd); + + if (unlikely(port_stat & PORT_IRQ_ERR)) { + if (unlikely(mtip_check_surprise_removal(dd->pdev))) { + mtip_command_cleanup(dd); + /* don't proceed further */ + return IRQ_HANDLED; + } + + mtip_process_errors(dd, port_stat & PORT_IRQ_ERR); + } + + if (unlikely(port_stat & PORT_IRQ_LEGACY)) + mtip_process_legacy(dd, port_stat & PORT_IRQ_LEGACY); + } + + /* acknowledge interrupt */ + writel(hba_stat, dd->mmio + HOST_IRQ_STAT); + + return rv; +} + +/* + * Wrapper for mtip_handle_irq + * (ignores return code) + */ +static void mtip_tasklet(unsigned long data) +{ + mtip_handle_irq((struct driver_data *) data); +} + +/* + * HBA interrupt subroutine. + * + * @irq IRQ number. + * @instance Pointer to the driver data structure. + * + * return value + * IRQ_HANDLED A HBA interrupt was pending and handled. + * IRQ_NONE This interrupt was not for the HBA. + */ +static irqreturn_t mtip_irq_handler(int irq, void *instance) +{ + struct driver_data *dd = instance; + tasklet_schedule(&dd->tasklet); + return IRQ_HANDLED; +} + +static void mtip_issue_non_ncq_command(struct mtip_port *port, int tag) +{ + atomic_set(&port->commands[tag].active, 1); + writel(1 << MTIP_TAG_BIT(tag), + port->cmd_issue[MTIP_TAG_INDEX(tag)]); +} + +/* + * Wait for port to quiesce + * + * @port Pointer to port data structure + * @timeout Max duration to wait (ms) + * + * return value + * 0 Success + * -EBUSY Commands still active + */ +static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) +{ + unsigned long to; + unsigned int n; + unsigned int active = 1; + + to = jiffies + msecs_to_jiffies(timeout); + do { + if (test_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags) && + test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { + msleep(20); + continue; /* svc thd is actively issuing commands */ + } + /* + * Ignore s_active bit 0 of array element 0. + * This bit will always be set + */ + active = readl(port->s_active[0]) & 0xFFFFFFFE; + for (n = 1; n < port->dd->slot_groups; n++) + active |= readl(port->s_active[n]); + + if (!active) + break; + + msleep(20); + } while (time_before(jiffies, to)); + + return active ? -EBUSY : 0; +} + +/* + * Execute an internal command and wait for the completion. + * + * @port Pointer to the port data structure. + * @fis Pointer to the FIS that describes the command. + * @fis_len Length in WORDS of the FIS. + * @buffer DMA accessible for command data. + * @buf_len Length, in bytes, of the data buffer. + * @opts Command header options, excluding the FIS length + * and the number of PRD entries. + * @timeout Time in ms to wait for the command to complete. + * + * return value + * 0 Command completed successfully. + * -EFAULT The buffer address is not correctly aligned. + * -EBUSY Internal command or other IO in progress. + * -EAGAIN Time out waiting for command to complete. + */ +static int mtip_exec_internal_command(struct mtip_port *port, + void *fis, + int fis_len, + dma_addr_t buffer, + int buf_len, + u32 opts, + gfp_t atomic, + unsigned long timeout) +{ + struct mtip_cmd_sg *command_sg; + DECLARE_COMPLETION_ONSTACK(wait); + int rv = 0; + struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL]; + + /* Make sure the buffer is 8 byte aligned. This is asic specific. */ + if (buffer & 0x00000007) { + dev_err(&port->dd->pdev->dev, + "SG buffer is not 8 byte aligned\n"); + return -EFAULT; + } + + /* Only one internal command should be running at a time */ + if (test_and_set_bit(MTIP_TAG_INTERNAL, port->allocated)) { + dev_warn(&port->dd->pdev->dev, + "Internal command already active\n"); + return -EBUSY; + } + set_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + + if (atomic == GFP_KERNEL) { + /* wait for io to complete if non atomic */ + if (mtip_quiesce_io(port, 5000) < 0) { + dev_warn(&port->dd->pdev->dev, + "Failed to quiesce IO\n"); + release_slot(port, MTIP_TAG_INTERNAL); + clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + return -EBUSY; + } + + /* Set the completion function and data for the command. */ + int_cmd->comp_data = &wait; + int_cmd->comp_func = mtip_completion; + + } else { + /* Clear completion - we're going to poll */ + int_cmd->comp_data = NULL; + int_cmd->comp_func = NULL; + } + + /* Copy the command to the command table */ + memcpy(int_cmd->command, fis, fis_len*4); + + /* Populate the SG list */ + int_cmd->command_header->opts = + __force_bit2int cpu_to_le32(opts | fis_len); + if (buf_len) { + command_sg = int_cmd->command + AHCI_CMD_TBL_HDR_SZ; + + command_sg->info = + __force_bit2int cpu_to_le32((buf_len-1) & 0x3FFFFF); + command_sg->dba = + __force_bit2int cpu_to_le32(buffer & 0xFFFFFFFF); + command_sg->dba_upper = + __force_bit2int cpu_to_le32((buffer >> 16) >> 16); + + int_cmd->command_header->opts |= + __force_bit2int cpu_to_le32((1 << 16)); + } + + /* Populate the command header */ + int_cmd->command_header->byte_count = 0; + + /* Issue the command to the hardware */ + mtip_issue_non_ncq_command(port, MTIP_TAG_INTERNAL); + + /* Poll if atomic, wait_for_completion otherwise */ + if (atomic == GFP_KERNEL) { + /* Wait for the command to complete or timeout. */ + if (wait_for_completion_timeout( + &wait, + msecs_to_jiffies(timeout)) == 0) { + dev_err(&port->dd->pdev->dev, + "Internal command did not complete [%d] " + "within timeout of %lu ms\n", + atomic, timeout); + rv = -EAGAIN; + } + + if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) { + dev_warn(&port->dd->pdev->dev, + "Retiring internal command but CI is 1.\n"); + } + + } else { + /* Spin for <timeout> checking if command still outstanding */ + timeout = jiffies + msecs_to_jiffies(timeout); + + while ((readl( + port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) + && time_before(jiffies, timeout)) + ; + + if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) { + dev_err(&port->dd->pdev->dev, + "Internal command did not complete [%d]\n", + atomic); + rv = -EAGAIN; + } + } + + /* Clear the allocated and active bits for the internal command. */ + atomic_set(&int_cmd->active, 0); + release_slot(port, MTIP_TAG_INTERNAL); + clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + + return rv; +} + +/* + * Byte-swap ATA ID strings. + * + * ATA identify data contains strings in byte-swapped 16-bit words. + * They must be swapped (on all architectures) to be usable as C strings. + * This function swaps bytes in-place. + * + * @buf The buffer location of the string + * @len The number of bytes to swap + * + * return value + * None + */ +static inline void ata_swap_string(u16 *buf, unsigned int len) +{ + int i; + for (i = 0; i < (len/2); i++) + be16_to_cpus(&buf[i]); +} + +/* + * Request the device identity information. + * + * If a user space buffer is not specified, i.e. is NULL, the + * identify information is still read from the drive and placed + * into the identify data buffer (@e port->identify) in the + * port data structure. + * When the identify buffer contains valid identify information @e + * port->identify_valid is non-zero. + * + * @port Pointer to the port structure. + * @user_buffer A user space buffer where the identify data should be + * copied. + * + * return value + * 0 Command completed successfully. + * -EFAULT An error occurred while coping data to the user buffer. + * -1 Command failed. + */ +static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer) +{ + int rv = 0; + struct host_to_dev_fis fis; + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = ATA_CMD_ID_ATA; + + /* Set the identify information as invalid. */ + port->identify_valid = 0; + + /* Clear the identify information. */ + memset(port->identify, 0, sizeof(u16) * ATA_ID_WORDS); + + /* Execute the command. */ + if (mtip_exec_internal_command(port, + &fis, + 5, + port->identify_dma, + sizeof(u16) * ATA_ID_WORDS, + 0, + GFP_KERNEL, + MTIP_INTERNAL_COMMAND_TIMEOUT_MS) + < 0) { + rv = -1; + goto out; + } + + /* + * Perform any necessary byte-swapping. Yes, the kernel does in fact + * perform field-sensitive swapping on the string fields. + * See the kernel use of ata_id_string() for proof of this. + */ +#ifdef __LITTLE_ENDIAN + ata_swap_string(port->identify + 27, 40); /* model string*/ + ata_swap_string(port->identify + 23, 8); /* firmware string*/ + ata_swap_string(port->identify + 10, 20); /* serial# string*/ +#else + { + int i; + for (i = 0; i < ATA_ID_WORDS; i++) + port->identify[i] = le16_to_cpu(port->identify[i]); + } +#endif + + /* Set the identify buffer as valid. */ + port->identify_valid = 1; + + if (user_buffer) { + if (copy_to_user( + user_buffer, + port->identify, + ATA_ID_WORDS * sizeof(u16))) { + rv = -EFAULT; + goto out; + } + } + +out: + return rv; +} + +/* + * Issue a standby immediate command to the device. + * + * @port Pointer to the port structure. + * + * return value + * 0 Command was executed successfully. + * -1 An error occurred while executing the command. + */ +static int mtip_standby_immediate(struct mtip_port *port) +{ + int rv; + struct host_to_dev_fis fis; + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = ATA_CMD_STANDBYNOW1; + + /* Execute the command. Use a 15-second timeout for large drives. */ + rv = mtip_exec_internal_command(port, + &fis, + 5, + 0, + 0, + 0, + GFP_KERNEL, + 15000); + + return rv; +} + +/* + * Get the drive capacity. + * + * @dd Pointer to the device data structure. + * @sectors Pointer to the variable that will receive the sector count. + * + * return value + * 1 Capacity was returned successfully. + * 0 The identify information is invalid. + */ +static bool mtip_hw_get_capacity(struct driver_data *dd, sector_t *sectors) +{ + struct mtip_port *port = dd->port; + u64 total, raw0, raw1, raw2, raw3; + raw0 = port->identify[100]; + raw1 = port->identify[101]; + raw2 = port->identify[102]; + raw3 = port->identify[103]; + total = raw0 | raw1<<16 | raw2<<32 | raw3<<48; + *sectors = total; + return (bool) !!port->identify_valid; +} + +/* + * Reset the HBA. + * + * Resets the HBA by setting the HBA Reset bit in the Global + * HBA Control register. After setting the HBA Reset bit the + * function waits for 1 second before reading the HBA Reset + * bit to make sure it has cleared. If HBA Reset is not clear + * an error is returned. Cannot be used in non-blockable + * context. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 The reset was successful. + * -1 The HBA Reset bit did not clear. + */ +static int mtip_hba_reset(struct driver_data *dd) +{ + mtip_deinit_port(dd->port); + + /* Set the reset bit */ + writel(HOST_RESET, dd->mmio + HOST_CTL); + + /* Flush */ + readl(dd->mmio + HOST_CTL); + + /* Wait for reset to clear */ + ssleep(1); + + /* Check the bit has cleared */ + if (readl(dd->mmio + HOST_CTL) & HOST_RESET) { + dev_err(&dd->pdev->dev, + "Reset bit did not clear.\n"); + return -1; + } + + return 0; +} + +/* + * Display the identify command data. + * + * @port Pointer to the port data structure. + * + * return value + * None + */ +static void mtip_dump_identify(struct mtip_port *port) +{ + sector_t sectors; + unsigned short revid; + char cbuf[42]; + + if (!port->identify_valid) + return; + + strlcpy(cbuf, (char *)(port->identify+10), 21); + dev_info(&port->dd->pdev->dev, + "Serial No.: %s\n", cbuf); + + strlcpy(cbuf, (char *)(port->identify+23), 9); + dev_info(&port->dd->pdev->dev, + "Firmware Ver.: %s\n", cbuf); + + strlcpy(cbuf, (char *)(port->identify+27), 41); + dev_info(&port->dd->pdev->dev, "Model: %s\n", cbuf); + + if (mtip_hw_get_capacity(port->dd, §ors)) + dev_info(&port->dd->pdev->dev, + "Capacity: %llu sectors (%llu MB)\n", + (u64)sectors, + ((u64)sectors) * ATA_SECT_SIZE >> 20); + + pci_read_config_word(port->dd->pdev, PCI_REVISION_ID, &revid); + switch (revid & 0xFF) { + case 0x1: + strlcpy(cbuf, "A0", 3); + break; + case 0x3: + strlcpy(cbuf, "A2", 3); + break; + default: + strlcpy(cbuf, "?", 2); + break; + } + dev_info(&port->dd->pdev->dev, + "Card Type: %s\n", cbuf); +} + +/* + * Map the commands scatter list into the command table. + * + * @command Pointer to the command. + * @nents Number of scatter list entries. + * + * return value + * None + */ +static inline void fill_command_sg(struct driver_data *dd, + struct mtip_cmd *command, + int nents) +{ + int n; + unsigned int dma_len; + struct mtip_cmd_sg *command_sg; + struct scatterlist *sg = command->sg; + + command_sg = command->command + AHCI_CMD_TBL_HDR_SZ; + + for (n = 0; n < nents; n++) { + dma_len = sg_dma_len(sg); + if (dma_len > 0x400000) + dev_err(&dd->pdev->dev, + "DMA segment length truncated\n"); + command_sg->info = __force_bit2int + cpu_to_le32((dma_len-1) & 0x3FFFFF); + command_sg->dba = __force_bit2int + cpu_to_le32(sg_dma_address(sg)); + command_sg->dba_upper = __force_bit2int + cpu_to_le32((sg_dma_address(sg) >> 16) >> 16); + command_sg++; + sg++; + } +} + +/* + * @brief Execute a drive command. + * + * return value 0 The command completed successfully. + * return value -1 An error occurred while executing the command. + */ +static int exec_drive_task(struct mtip_port *port, u8 *command) +{ + struct host_to_dev_fis fis; + struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG); + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = command[0]; + fis.features = command[1]; + fis.sect_count = command[2]; + fis.sector = command[3]; + fis.cyl_low = command[4]; + fis.cyl_hi = command[5]; + fis.device = command[6] & ~0x10; /* Clear the dev bit*/ + + + dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, " + "nsect %x, sect %x, lcyl %x, " + "hcyl %x, sel %x\n", + __func__, + command[0], + command[1], + command[2], + command[3], + command[4], + command[5], + command[6]); + + /* Execute the command. */ + if (mtip_exec_internal_command(port, + &fis, + 5, + 0, + 0, + 0, + GFP_KERNEL, + MTIP_IOCTL_COMMAND_TIMEOUT_MS) < 0) { + return -1; + } + + command[0] = reply->command; /* Status*/ + command[1] = reply->features; /* Error*/ + command[4] = reply->cyl_low; + command[5] = reply->cyl_hi; + + dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, " + "err %x , cyl_lo %x cyl_hi %x\n", + __func__, + command[0], + command[1], + command[4], + command[5]); + + return 0; +} + +/* + * @brief Execute a drive command. + * + * @param port Pointer to the port data structure. + * @param command Pointer to the user specified command parameters. + * @param user_buffer Pointer to the user space buffer where read sector + * data should be copied. + * + * return value 0 The command completed successfully. + * return value -EFAULT An error occurred while copying the completion + * data to the user space buffer. + * return value -1 An error occurred while executing the command. + */ +static int exec_drive_command(struct mtip_port *port, u8 *command, + void __user *user_buffer) +{ + struct host_to_dev_fis fis; + struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG); + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = command[0]; + fis.features = command[2]; + fis.sect_count = command[3]; + if (fis.command == ATA_CMD_SMART) { + fis.sector = command[1]; + fis.cyl_low = 0x4F; + fis.cyl_hi = 0xC2; + } + + dbg_printk(MTIP_DRV_NAME + "%s: User Command: cmd %x, sect %x, " + "feat %x, sectcnt %x\n", + __func__, + command[0], + command[1], + command[2], + command[3]); + + memset(port->sector_buffer, 0x00, ATA_SECT_SIZE); + + /* Execute the command. */ + if (mtip_exec_internal_command(port, + &fis, + 5, + port->sector_buffer_dma, + (command[3] != 0) ? ATA_SECT_SIZE : 0, + 0, + GFP_KERNEL, + MTIP_IOCTL_COMMAND_TIMEOUT_MS) + < 0) { + return -1; + } + + /* Collect the completion status. */ + command[0] = reply->command; /* Status*/ + command[1] = reply->features; /* Error*/ + command[2] = command[3]; + + dbg_printk(MTIP_DRV_NAME + "%s: Completion Status: stat %x, " + "err %x, cmd %x\n", + __func__, + command[0], + command[1], + command[2]); + + if (user_buffer && command[3]) { + if (copy_to_user(user_buffer, + port->sector_buffer, + ATA_SECT_SIZE * command[3])) { + return -EFAULT; + } + } + + return 0; +} + +/* + * Indicates whether a command has a single sector payload. + * + * @command passed to the device to perform the certain event. + * @features passed to the device to perform the certain event. + * + * return value + * 1 command is one that always has a single sector payload, + * regardless of the value in the Sector Count field. + * 0 otherwise + * + */ +static unsigned int implicit_sector(unsigned char command, + unsigned char features) +{ + unsigned int rv = 0; + + /* list of commands that have an implicit sector count of 1 */ + switch (command) { + case ATA_CMD_SEC_SET_PASS: + case ATA_CMD_SEC_UNLOCK: + case ATA_CMD_SEC_ERASE_PREP: + case ATA_CMD_SEC_ERASE_UNIT: + case ATA_CMD_SEC_FREEZE_LOCK: + case ATA_CMD_SEC_DISABLE_PASS: + case ATA_CMD_PMP_READ: + case ATA_CMD_PMP_WRITE: + rv = 1; + break; + case ATA_CMD_SET_MAX: + if (features == ATA_SET_MAX_UNLOCK) + rv = 1; + break; + case ATA_CMD_SMART: + if ((features == ATA_SMART_READ_VALUES) || + (features == ATA_SMART_READ_THRESHOLDS)) + rv = 1; + break; + case ATA_CMD_CONF_OVERLAY: + if ((features == ATA_DCO_IDENTIFY) || + (features == ATA_DCO_SET)) + rv = 1; + break; + } + return rv; +} + +/* + * Executes a taskfile + * See ide_taskfile_ioctl() for derivation + */ +static int exec_drive_taskfile(struct driver_data *dd, + void __user *buf, + ide_task_request_t *req_task, + int outtotal) +{ + struct host_to_dev_fis fis; + struct host_to_dev_fis *reply; + u8 *outbuf = NULL; + u8 *inbuf = NULL; + dma_addr_t outbuf_dma = 0; + dma_addr_t inbuf_dma = 0; + dma_addr_t dma_buffer = 0; + int err = 0; + unsigned int taskin = 0; + unsigned int taskout = 0; + u8 nsect = 0; + unsigned int timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; + unsigned int force_single_sector; + unsigned int transfer_size; + unsigned long task_file_data; + int intotal = outtotal + req_task->out_size; + + taskout = req_task->out_size; + taskin = req_task->in_size; + /* 130560 = 512 * 0xFF*/ + if (taskin > 130560 || taskout > 130560) { + err = -EINVAL; + goto abort; + } + + if (taskout) { + outbuf = kzalloc(taskout, GFP_KERNEL); + if (outbuf == NULL) { + err = -ENOMEM; + goto abort; + } + if (copy_from_user(outbuf, buf + outtotal, taskout)) { + err = -EFAULT; + goto abort; + } + outbuf_dma = pci_map_single(dd->pdev, + outbuf, + taskout, + DMA_TO_DEVICE); + if (outbuf_dma == 0) { + err = -ENOMEM; + goto abort; + } + dma_buffer = outbuf_dma; + } + + if (taskin) { + inbuf = kzalloc(taskin, GFP_KERNEL); + if (inbuf == NULL) { + err = -ENOMEM; + goto abort; + } + + if (copy_from_user(inbuf, buf + intotal, taskin)) { + err = -EFAULT; + goto abort; + } + inbuf_dma = pci_map_single(dd->pdev, + inbuf, + taskin, DMA_FROM_DEVICE); + if (inbuf_dma == 0) { + err = -ENOMEM; + goto abort; + } + dma_buffer = inbuf_dma; + } + + /* only supports PIO and non-data commands from this ioctl. */ + switch (req_task->data_phase) { + case TASKFILE_OUT: + nsect = taskout / ATA_SECT_SIZE; + reply = (dd->port->rxfis + RX_FIS_PIO_SETUP); + break; + case TASKFILE_IN: + reply = (dd->port->rxfis + RX_FIS_PIO_SETUP); + break; + case TASKFILE_NO_DATA: + reply = (dd->port->rxfis + RX_FIS_D2H_REG); + break; + default: + err = -EINVAL; + goto abort; + } + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = req_task->io_ports[7]; + fis.features = req_task->io_ports[1]; + fis.sect_count = req_task->io_ports[2]; + fis.lba_low = req_task->io_ports[3]; + fis.lba_mid = req_task->io_ports[4]; + fis.lba_hi = req_task->io_ports[5]; + /* Clear the dev bit*/ + fis.device = req_task->io_ports[6] & ~0x10; + + if ((req_task->in_flags.all == 0) && (req_task->out_flags.all & 1)) { + req_task->in_flags.all = + IDE_TASKFILE_STD_IN_FLAGS | + (IDE_HOB_STD_IN_FLAGS << 8); + fis.lba_low_ex = req_task->hob_ports[3]; + fis.lba_mid_ex = req_task->hob_ports[4]; + fis.lba_hi_ex = req_task->hob_ports[5]; + fis.features_ex = req_task->hob_ports[1]; + fis.sect_cnt_ex = req_task->hob_ports[2]; + + } else { + req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; + } + + force_single_sector = implicit_sector(fis.command, fis.features); + + if ((taskin || taskout) && (!fis.sect_count)) { + if (nsect) + fis.sect_count = nsect; + else { + if (!force_single_sector) { + dev_warn(&dd->pdev->dev, + "data movement but " + "sect_count is 0\n"); + err = -EINVAL; + goto abort; + } + } + } + + dbg_printk(MTIP_DRV_NAME + "taskfile: cmd %x, feat %x, nsect %x," + " sect/lbal %x, lcyl/lbam %x, hcyl/lbah %x," + " head/dev %x\n", + fis.command, + fis.features, + fis.sect_count, + fis.lba_low, + fis.lba_mid, + fis.lba_hi, + fis.device); + + switch (fis.command) { + case ATA_CMD_DOWNLOAD_MICRO: + /* Change timeout for Download Microcode to 60 seconds.*/ + timeout = 60000; + break; + case ATA_CMD_SEC_ERASE_UNIT: + /* Change timeout for Security Erase Unit to 4 minutes.*/ + timeout = 240000; + break; + case ATA_CMD_STANDBYNOW1: + /* Change timeout for standby immediate to 10 seconds.*/ + timeout = 10000; + break; + case 0xF7: + case 0xFA: + /* Change timeout for vendor unique command to 10 secs */ + timeout = 10000; + break; + case ATA_CMD_SMART: + /* Change timeout for vendor unique command to 10 secs */ + timeout = 10000; + break; + default: + timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; + break; + } + + /* Determine the correct transfer size.*/ + if (force_single_sector) + transfer_size = ATA_SECT_SIZE; + else + transfer_size = ATA_SECT_SIZE * fis.sect_count; + + /* Execute the command.*/ + if (mtip_exec_internal_command(dd->port, + &fis, + 5, + dma_buffer, + transfer_size, + 0, + GFP_KERNEL, + timeout) < 0) { + err = -EIO; + goto abort; + } + + task_file_data = readl(dd->port->mmio+PORT_TFDATA); + + if ((req_task->data_phase == TASKFILE_IN) && !(task_file_data & 1)) { + reply = dd->port->rxfis + RX_FIS_PIO_SETUP; + req_task->io_ports[7] = reply->control; + } else { + reply = dd->port->rxfis + RX_FIS_D2H_REG; + req_task->io_ports[7] = reply->command; + } + + /* reclaim the DMA buffers.*/ + if (inbuf_dma) + pci_unmap_single(dd->pdev, inbuf_dma, + taskin, DMA_FROM_DEVICE); + if (outbuf_dma) + pci_unmap_single(dd->pdev, outbuf_dma, + taskout, DMA_TO_DEVICE); + inbuf_dma = 0; + outbuf_dma = 0; + + /* return the ATA registers to the caller.*/ + req_task->io_ports[1] = reply->features; + req_task->io_ports[2] = reply->sect_count; + req_task->io_ports[3] = reply->lba_low; + req_task->io_ports[4] = reply->lba_mid; + req_task->io_ports[5] = reply->lba_hi; + req_task->io_ports[6] = reply->device; + + if (req_task->out_flags.all & 1) { + + req_task->hob_ports[3] = reply->lba_low_ex; + req_task->hob_ports[4] = reply->lba_mid_ex; + req_task->hob_ports[5] = reply->lba_hi_ex; + req_task->hob_ports[1] = reply->features_ex; + req_task->hob_ports[2] = reply->sect_cnt_ex; + } + + /* Com rest after secure erase or lowlevel format */ + if (((fis.command == ATA_CMD_SEC_ERASE_UNIT) || + ((fis.command == 0xFC) && + (fis.features == 0x27 || fis.features == 0x72 || + fis.features == 0x62 || fis.features == 0x26))) && + !(reply->command & 1)) { + mtip_restart_port(dd->port); + } + + dbg_printk(MTIP_DRV_NAME + "%s: Completion: stat %x," + "err %x, sect_cnt %x, lbalo %x," + "lbamid %x, lbahi %x, dev %x\n", + __func__, + req_task->io_ports[7], + req_task->io_ports[1], + req_task->io_ports[2], + req_task->io_ports[3], + req_task->io_ports[4], + req_task->io_ports[5], + req_task->io_ports[6]); + + if (taskout) { + if (copy_to_user(buf + outtotal, outbuf, taskout)) { + err = -EFAULT; + goto abort; + } + } + if (taskin) { + if (copy_to_user(buf + intotal, inbuf, taskin)) { + err = -EFAULT; + goto abort; + } + } +abort: + if (inbuf_dma) + pci_unmap_single(dd->pdev, inbuf_dma, + taskin, DMA_FROM_DEVICE); + if (outbuf_dma) + pci_unmap_single(dd->pdev, outbuf_dma, + taskout, DMA_TO_DEVICE); + kfree(outbuf); + kfree(inbuf); + + return err; +} + +/* + * Handle IOCTL calls from the Block Layer. + * + * This function is called by the Block Layer when it receives an IOCTL + * command that it does not understand. If the IOCTL command is not supported + * this function returns -ENOTTY. + * + * @dd Pointer to the driver data structure. + * @cmd IOCTL command passed from the Block Layer. + * @arg IOCTL argument passed from the Block Layer. + * + * return value + * 0 The IOCTL completed successfully. + * -ENOTTY The specified command is not supported. + * -EFAULT An error occurred copying data to a user space buffer. + * -EIO An error occurred while executing the command. + */ +static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case HDIO_GET_IDENTITY: + if (mtip_get_identify(dd->port, (void __user *) arg) < 0) { + dev_warn(&dd->pdev->dev, + "Unable to read identity\n"); + return -EIO; + } + + break; + case HDIO_DRIVE_CMD: + { + u8 drive_command[4]; + + /* Copy the user command info to our buffer. */ + if (copy_from_user(drive_command, + (void __user *) arg, + sizeof(drive_command))) + return -EFAULT; + + /* Execute the drive command. */ + if (exec_drive_command(dd->port, + drive_command, + (void __user *) (arg+4))) + return -EIO; + + /* Copy the status back to the users buffer. */ + if (copy_to_user((void __user *) arg, + drive_command, + sizeof(drive_command))) + return -EFAULT; + + break; + } + case HDIO_DRIVE_TASK: + { + u8 drive_command[7]; + + /* Copy the user command info to our buffer. */ + if (copy_from_user(drive_command, + (void __user *) arg, + sizeof(drive_command))) + return -EFAULT; + + /* Execute the drive command. */ + if (exec_drive_task(dd->port, drive_command)) + return -EIO; + + /* Copy the status back to the users buffer. */ + if (copy_to_user((void __user *) arg, + drive_command, + sizeof(drive_command))) + return -EFAULT; + + break; + } + case HDIO_DRIVE_TASKFILE: { + ide_task_request_t req_task; + int ret, outtotal; + + if (copy_from_user(&req_task, (void __user *) arg, + sizeof(req_task))) + return -EFAULT; + + outtotal = sizeof(req_task); + + ret = exec_drive_taskfile(dd, (void __user *) arg, + &req_task, outtotal); + + if (copy_to_user((void __user *) arg, &req_task, + sizeof(req_task))) + return -EFAULT; + + return ret; + } + + default: + return -EINVAL; + } + return 0; +} + +/* + * Submit an IO to the hw + * + * This function is called by the block layer to issue an io + * to the device. Upon completion, the callback function will + * be called with the data parameter passed as the callback data. + * + * @dd Pointer to the driver data structure. + * @start First sector to read. + * @nsect Number of sectors to read. + * @nents Number of entries in scatter list for the read command. + * @tag The tag of this read command. + * @callback Pointer to the function that should be called + * when the read completes. + * @data Callback data passed to the callback function + * when the read completes. + * @barrier If non-zero, this command must be completed before + * issuing any other commands. + * @dir Direction (read or write) + * + * return value + * None + */ +static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, + int nsect, int nents, int tag, void *callback, + void *data, int barrier, int dir) +{ + struct host_to_dev_fis *fis; + struct mtip_port *port = dd->port; + struct mtip_cmd *command = &port->commands[tag]; + + /* Map the scatter list for DMA access */ + if (dir == READ) + nents = dma_map_sg(&dd->pdev->dev, command->sg, + nents, DMA_FROM_DEVICE); + else + nents = dma_map_sg(&dd->pdev->dev, command->sg, + nents, DMA_TO_DEVICE); + + command->scatter_ents = nents; + + /* + * The number of retries for this command before it is + * reported as a failure to the upper layers. + */ + command->retries = MTIP_MAX_RETRIES; + + /* Fill out fis */ + fis = command->command; + fis->type = 0x27; + fis->opts = 1 << 7; + fis->command = + (dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE); + *((unsigned int *) &fis->lba_low) = (start & 0xFFFFFF); + *((unsigned int *) &fis->lba_low_ex) = ((start >> 24) & 0xFFFFFF); + fis->device = 1 << 6; + if (barrier) + fis->device |= FUA_BIT; + fis->features = nsect & 0xFF; + fis->features_ex = (nsect >> 8) & 0xFF; + fis->sect_count = ((tag << 3) | (tag >> 5)); + fis->sect_cnt_ex = 0; + fis->control = 0; + fis->res2 = 0; + fis->res3 = 0; + fill_command_sg(dd, command, nents); + + /* Populate the command header */ + command->command_header->opts = + __force_bit2int cpu_to_le32( + (nents << 16) | 5 | AHCI_CMD_PREFETCH); + command->command_header->byte_count = 0; + + /* + * Set the completion function and data for the command + * within this layer. + */ + command->comp_data = dd; + command->comp_func = mtip_async_complete; + command->direction = (dir == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + + /* + * Set the completion function and data for the command passed + * from the upper layer. + */ + command->async_data = data; + command->async_callback = callback; + + /* + * To prevent this command from being issued + * if an internal command is in progress or error handling is active. + */ + if (unlikely(test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) || + test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags))) { + set_bit(tag, port->cmds_to_issue); + set_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); + return; + } + + /* Issue the command to the hardware */ + mtip_issue_ncq_command(port, tag); + + /* Set the command's timeout value.*/ + port->commands[tag].comp_time = jiffies + msecs_to_jiffies( + MTIP_NCQ_COMMAND_TIMEOUT_MS); +} + +/* + * Release a command slot. + * + * @dd Pointer to the driver data structure. + * @tag Slot tag + * + * return value + * None + */ +static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag) +{ + release_slot(dd->port, tag); +} + +/* + * Obtain a command slot and return its associated scatter list. + * + * @dd Pointer to the driver data structure. + * @tag Pointer to an int that will receive the allocated command + * slot tag. + * + * return value + * Pointer to the scatter list for the allocated command slot + * or NULL if no command slots are available. + */ +static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, + int *tag) +{ + /* + * It is possible that, even with this semaphore, a thread + * may think that no command slots are available. Therefore, we + * need to make an attempt to get_slot(). + */ + down(&dd->port->cmd_slot); + *tag = get_slot(dd->port); + + if (unlikely(*tag < 0)) + return NULL; + + return dd->port->commands[*tag].sg; +} + +/* + * Sysfs register/status dump. + * + * @dev Pointer to the device structure, passed by the kernrel. + * @attr Pointer to the device_attribute structure passed by the kernel. + * @buf Pointer to the char buffer that will receive the stats info. + * + * return value + * The size, in bytes, of the data copied into buf. + */ +static ssize_t hw_show_registers(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u32 group_allocated; + struct driver_data *dd = dev_to_disk(dev)->private_data; + int size = 0; + int n; + + size += sprintf(&buf[size], "%s:\ns_active:\n", __func__); + + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", + readl(dd->port->s_active[n])); + + size += sprintf(&buf[size], "Command Issue:\n"); + + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", + readl(dd->port->cmd_issue[n])); + + size += sprintf(&buf[size], "Allocated:\n"); + + for (n = 0; n < dd->slot_groups; n++) { + if (sizeof(long) > sizeof(u32)) + group_allocated = + dd->port->allocated[n/2] >> (32*(n&1)); + else + group_allocated = dd->port->allocated[n]; + size += sprintf(&buf[size], "0x%08x\n", + group_allocated); + } + + size += sprintf(&buf[size], "completed:\n"); + + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", + readl(dd->port->completed[n])); + + size += sprintf(&buf[size], "PORT_IRQ_STAT 0x%08x\n", + readl(dd->port->mmio + PORT_IRQ_STAT)); + size += sprintf(&buf[size], "HOST_IRQ_STAT 0x%08x\n", + readl(dd->mmio + HOST_IRQ_STAT)); + + return size; +} +static DEVICE_ATTR(registers, S_IRUGO, hw_show_registers, NULL); + +/* + * Create the sysfs related attributes. + * + * @dd Pointer to the driver data structure. + * @kobj Pointer to the kobj for the block device. + * + * return value + * 0 Operation completed successfully. + * -EINVAL Invalid parameter. + */ +static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj) +{ + if (!kobj || !dd) + return -EINVAL; + + if (sysfs_create_file(kobj, &dev_attr_registers.attr)) + dev_warn(&dd->pdev->dev, + "Error creating registers sysfs entry\n"); + return 0; +} + +/* + * Remove the sysfs related attributes. + * + * @dd Pointer to the driver data structure. + * @kobj Pointer to the kobj for the block device. + * + * return value + * 0 Operation completed successfully. + * -EINVAL Invalid parameter. + */ +static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj) +{ + if (!kobj || !dd) + return -EINVAL; + + sysfs_remove_file(kobj, &dev_attr_registers.attr); + + return 0; +} + +/* + * Perform any init/resume time hardware setup + * + * @dd Pointer to the driver data structure. + * + * return value + * None + */ +static inline void hba_setup(struct driver_data *dd) +{ + u32 hwdata; + hwdata = readl(dd->mmio + HOST_HSORG); + + /* interrupt bug workaround: use only 1 IS bit.*/ + writel(hwdata | + HSORG_DISABLE_SLOTGRP_INTR | + HSORG_DISABLE_SLOTGRP_PXIS, + dd->mmio + HOST_HSORG); +} + +/* + * Detect the details of the product, and store anything needed + * into the driver data structure. This includes product type and + * version and number of slot groups. + * + * @dd Pointer to the driver data structure. + * + * return value + * None + */ +static void mtip_detect_product(struct driver_data *dd) +{ + u32 hwdata; + unsigned int rev, slotgroups; + + /* + * HBA base + 0xFC [15:0] - vendor-specific hardware interface + * info register: + * [15:8] hardware/software interface rev# + * [ 3] asic-style interface + * [ 2:0] number of slot groups, minus 1 (only valid for asic-style). + */ + hwdata = readl(dd->mmio + HOST_HSORG); + + dd->product_type = MTIP_PRODUCT_UNKNOWN; + dd->slot_groups = 1; + + if (hwdata & 0x8) { + dd->product_type = MTIP_PRODUCT_ASICFPGA; + rev = (hwdata & HSORG_HWREV) >> 8; + slotgroups = (hwdata & HSORG_SLOTGROUPS) + 1; + dev_info(&dd->pdev->dev, + "ASIC-FPGA design, HS rev 0x%x, " + "%i slot groups [%i slots]\n", + rev, + slotgroups, + slotgroups * 32); + + if (slotgroups > MTIP_MAX_SLOT_GROUPS) { + dev_warn(&dd->pdev->dev, + "Warning: driver only supports " + "%i slot groups.\n", MTIP_MAX_SLOT_GROUPS); + slotgroups = MTIP_MAX_SLOT_GROUPS; + } + dd->slot_groups = slotgroups; + return; + } + + dev_warn(&dd->pdev->dev, "Unrecognized product id\n"); +} + +/* + * Blocking wait for FTL rebuild to complete + * + * @dd Pointer to the DRIVER_DATA structure. + * + * return value + * 0 FTL rebuild completed successfully + * -EFAULT FTL rebuild error/timeout/interruption + */ +static int mtip_ftl_rebuild_poll(struct driver_data *dd) +{ + unsigned long timeout, cnt = 0, start; + + dev_warn(&dd->pdev->dev, + "FTL rebuild in progress. Polling for completion.\n"); + + start = jiffies; + dd->ftlrebuildflag = 1; + timeout = jiffies + msecs_to_jiffies(MTIP_FTL_REBUILD_TIMEOUT_MS); + + do { + if (mtip_check_surprise_removal(dd->pdev)) + return -EFAULT; + + if (mtip_get_identify(dd->port, NULL) < 0) + return -EFAULT; + + if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == + MTIP_FTL_REBUILD_MAGIC) { + ssleep(1); + /* Print message every 3 minutes */ + if (cnt++ >= 180) { + dev_warn(&dd->pdev->dev, + "FTL rebuild in progress (%d secs).\n", + jiffies_to_msecs(jiffies - start) / 1000); + cnt = 0; + } + } else { + dev_warn(&dd->pdev->dev, + "FTL rebuild complete (%d secs).\n", + jiffies_to_msecs(jiffies - start) / 1000); + dd->ftlrebuildflag = 0; + mtip_block_initialize(dd); + break; + } + ssleep(10); + } while (time_before(jiffies, timeout)); + + /* Check for timeout */ + if (dd->ftlrebuildflag) { + dev_err(&dd->pdev->dev, + "Timed out waiting for FTL rebuild to complete (%d secs).\n", + jiffies_to_msecs(jiffies - start) / 1000); + return -EFAULT; + } + + return 0; +} + +/* + * service thread to issue queued commands + * + * @data Pointer to the driver data structure. + * + * return value + * 0 + */ + +static int mtip_service_thread(void *data) +{ + struct driver_data *dd = (struct driver_data *)data; + unsigned long slot, slot_start, slot_wrap; + unsigned int num_cmd_slots = dd->slot_groups * 32; + struct mtip_port *port = dd->port; + + while (1) { + /* + * the condition is to check neither an internal command is + * is in progress nor error handling is active + */ + wait_event_interruptible(port->svc_wait, (port->flags) && + !test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) && + !test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags)); + + if (kthread_should_stop()) + break; + + set_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); + if (test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { + slot = 1; + /* used to restrict the loop to one iteration */ + slot_start = num_cmd_slots; + slot_wrap = 0; + while (1) { + slot = find_next_bit(port->cmds_to_issue, + num_cmd_slots, slot); + if (slot_wrap == 1) { + if ((slot_start >= slot) || + (slot >= num_cmd_slots)) + break; + } + if (unlikely(slot_start == num_cmd_slots)) + slot_start = slot; + + if (unlikely(slot == num_cmd_slots)) { + slot = 1; + slot_wrap = 1; + continue; + } + + /* Issue the command to the hardware */ + mtip_issue_ncq_command(port, slot); + + /* Set the command's timeout value.*/ + port->commands[slot].comp_time = jiffies + + msecs_to_jiffies(MTIP_NCQ_COMMAND_TIMEOUT_MS); + + clear_bit(slot, port->cmds_to_issue); + } + + clear_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); + } else if (test_bit(MTIP_FLAG_REBUILD_BIT, &port->flags)) { + mtip_ftl_rebuild_poll(dd); + clear_bit(MTIP_FLAG_REBUILD_BIT, &port->flags); + } + clear_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); + + if (test_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &port->flags)) + break; + } + return 0; +} + +/* + * Called once for each card. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 on success, else an error code. + */ +static int mtip_hw_init(struct driver_data *dd) +{ + int i; + int rv; + unsigned int num_command_slots; + + dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; + + mtip_detect_product(dd); + if (dd->product_type == MTIP_PRODUCT_UNKNOWN) { + rv = -EIO; + goto out1; + } + num_command_slots = dd->slot_groups * 32; + + hba_setup(dd); + + tasklet_init(&dd->tasklet, mtip_tasklet, (unsigned long)dd); + + dd->port = kzalloc(sizeof(struct mtip_port), GFP_KERNEL); + if (!dd->port) { + dev_err(&dd->pdev->dev, + "Memory allocation: port structure\n"); + return -ENOMEM; + } + + /* Counting semaphore to track command slot usage */ + sema_init(&dd->port->cmd_slot, num_command_slots - 1); + + /* Spinlock to prevent concurrent issue */ + spin_lock_init(&dd->port->cmd_issue_lock); + + /* Set the port mmio base address. */ + dd->port->mmio = dd->mmio + PORT_OFFSET; + dd->port->dd = dd; + + /* Allocate memory for the command list. */ + dd->port->command_list = + dmam_alloc_coherent(&dd->pdev->dev, + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + &dd->port->command_list_dma, + GFP_KERNEL); + if (!dd->port->command_list) { + dev_err(&dd->pdev->dev, + "Memory allocation: command list\n"); + rv = -ENOMEM; + goto out1; + } + + /* Clear the memory we have allocated. */ + memset(dd->port->command_list, + 0, + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2)); + + /* Setup the addresse of the RX FIS. */ + dd->port->rxfis = dd->port->command_list + HW_CMD_SLOT_SZ; + dd->port->rxfis_dma = dd->port->command_list_dma + HW_CMD_SLOT_SZ; + + /* Setup the address of the command tables. */ + dd->port->command_table = dd->port->rxfis + AHCI_RX_FIS_SZ; + dd->port->command_tbl_dma = dd->port->rxfis_dma + AHCI_RX_FIS_SZ; + + /* Setup the address of the identify data. */ + dd->port->identify = dd->port->command_table + + HW_CMD_TBL_AR_SZ; + dd->port->identify_dma = dd->port->command_tbl_dma + + HW_CMD_TBL_AR_SZ; + + /* Setup the address of the sector buffer. */ + dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE; + dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE; + + /* Point the command headers at the command tables. */ + for (i = 0; i < num_command_slots; i++) { + dd->port->commands[i].command_header = + dd->port->command_list + + (sizeof(struct mtip_cmd_hdr) * i); + dd->port->commands[i].command_header_dma = + dd->port->command_list_dma + + (sizeof(struct mtip_cmd_hdr) * i); + + dd->port->commands[i].command = + dd->port->command_table + (HW_CMD_TBL_SZ * i); + dd->port->commands[i].command_dma = + dd->port->command_tbl_dma + (HW_CMD_TBL_SZ * i); + + if (readl(dd->mmio + HOST_CAP) & HOST_CAP_64) + dd->port->commands[i].command_header->ctbau = + __force_bit2int cpu_to_le32( + (dd->port->commands[i].command_dma >> 16) >> 16); + dd->port->commands[i].command_header->ctba = + __force_bit2int cpu_to_le32( + dd->port->commands[i].command_dma & 0xFFFFFFFF); + + /* + * If this is not done, a bug is reported by the stock + * FC11 i386. Due to the fact that it has lots of kernel + * debugging enabled. + */ + sg_init_table(dd->port->commands[i].sg, MTIP_MAX_SG); + + /* Mark all commands as currently inactive.*/ + atomic_set(&dd->port->commands[i].active, 0); + } + + /* Setup the pointers to the extended s_active and CI registers. */ + for (i = 0; i < dd->slot_groups; i++) { + dd->port->s_active[i] = + dd->port->mmio + i*0x80 + PORT_SCR_ACT; + dd->port->cmd_issue[i] = + dd->port->mmio + i*0x80 + PORT_COMMAND_ISSUE; + dd->port->completed[i] = + dd->port->mmio + i*0x80 + PORT_SDBV; + } + + /* Reset the HBA. */ + if (mtip_hba_reset(dd) < 0) { + dev_err(&dd->pdev->dev, + "Card did not reset within timeout\n"); + rv = -EIO; + goto out2; + } + + mtip_init_port(dd->port); + mtip_start_port(dd->port); + + /* Setup the ISR and enable interrupts. */ + rv = devm_request_irq(&dd->pdev->dev, + dd->pdev->irq, + mtip_irq_handler, + IRQF_SHARED, + dev_driver_string(&dd->pdev->dev), + dd); + + if (rv) { + dev_err(&dd->pdev->dev, + "Unable to allocate IRQ %d\n", dd->pdev->irq); + goto out2; + } + + /* Enable interrupts on the HBA. */ + writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN, + dd->mmio + HOST_CTL); + + init_timer(&dd->port->cmd_timer); + init_waitqueue_head(&dd->port->svc_wait); + + dd->port->cmd_timer.data = (unsigned long int) dd->port; + dd->port->cmd_timer.function = mtip_timeout_function; + mod_timer(&dd->port->cmd_timer, + jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); + + if (mtip_get_identify(dd->port, NULL) < 0) { + rv = -EFAULT; + goto out3; + } + + if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == + MTIP_FTL_REBUILD_MAGIC) { + set_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags); + return MTIP_FTL_REBUILD_MAGIC; + } + mtip_dump_identify(dd->port); + return rv; + +out3: + del_timer_sync(&dd->port->cmd_timer); + + /* Disable interrupts on the HBA. */ + writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN, + dd->mmio + HOST_CTL); + + /*Release the IRQ. */ + devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd); + +out2: + mtip_deinit_port(dd->port); + + /* Free the command/command header memory. */ + dmam_free_coherent(&dd->pdev->dev, + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + dd->port->command_list, + dd->port->command_list_dma); +out1: + /* Free the memory allocated for the for structure. */ + kfree(dd->port); + + return rv; +} + +/* + * Called to deinitialize an interface. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 + */ +static int mtip_hw_exit(struct driver_data *dd) +{ + /* + * Send standby immediate (E0h) to the drive so that it + * saves its state. + */ + if (atomic_read(&dd->drv_cleanup_done) != true) { + + mtip_standby_immediate(dd->port); + + /* de-initialize the port. */ + mtip_deinit_port(dd->port); + + /* Disable interrupts on the HBA. */ + writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN, + dd->mmio + HOST_CTL); + } + + del_timer_sync(&dd->port->cmd_timer); + + /* Release the IRQ. */ + devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd); + + /* Stop the bottom half tasklet. */ + tasklet_kill(&dd->tasklet); + + /* Free the command/command header memory. */ + dmam_free_coherent(&dd->pdev->dev, + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + dd->port->command_list, + dd->port->command_list_dma); + /* Free the memory allocated for the for structure. */ + kfree(dd->port); + + return 0; +} + +/* + * Issue a Standby Immediate command to the device. + * + * This function is called by the Block Layer just before the + * system powers off during a shutdown. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 + */ +static int mtip_hw_shutdown(struct driver_data *dd) +{ + /* + * Send standby immediate (E0h) to the drive so that it + * saves its state. + */ + mtip_standby_immediate(dd->port); + + return 0; +} + +/* + * Suspend function + * + * This function is called by the Block Layer just before the + * system hibernates. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 Suspend was successful + * -EFAULT Suspend was not successful + */ +static int mtip_hw_suspend(struct driver_data *dd) +{ + /* + * Send standby immediate (E0h) to the drive + * so that it saves its state. + */ + if (mtip_standby_immediate(dd->port) != 0) { + dev_err(&dd->pdev->dev, + "Failed standby-immediate command\n"); + return -EFAULT; + } + + /* Disable interrupts on the HBA.*/ + writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN, + dd->mmio + HOST_CTL); + mtip_deinit_port(dd->port); + + return 0; +} + +/* + * Resume function + * + * This function is called by the Block Layer as the + * system resumes. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 Resume was successful + * -EFAULT Resume was not successful + */ +static int mtip_hw_resume(struct driver_data *dd) +{ + /* Perform any needed hardware setup steps */ + hba_setup(dd); + + /* Reset the HBA */ + if (mtip_hba_reset(dd) != 0) { + dev_err(&dd->pdev->dev, + "Unable to reset the HBA\n"); + return -EFAULT; + } + + /* + * Enable the port, DMA engine, and FIS reception specific + * h/w in controller. + */ + mtip_init_port(dd->port); + mtip_start_port(dd->port); + + /* Enable interrupts on the HBA.*/ + writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN, + dd->mmio + HOST_CTL); + + return 0; +} + +/* + * Helper function for reusing disk name + * upon hot insertion. + */ +static int rssd_disk_name_format(char *prefix, + int index, + char *buf, + int buflen) +{ + const int base = 'z' - 'a' + 1; + char *begin = buf + strlen(prefix); + char *end = buf + buflen; + char *p; + int unit; + + p = end - 1; + *p = '\0'; + unit = base; + do { + if (p == begin) + return -EINVAL; + *--p = 'a' + (index % unit); + index = (index / unit) - 1; + } while (index >= 0); + + memmove(begin, p, end - p); + memcpy(buf, prefix, strlen(prefix)); + + return 0; +} + +/* + * Block layer IOCTL handler. + * + * @dev Pointer to the block_device structure. + * @mode ignored + * @cmd IOCTL command passed from the user application. + * @arg Argument passed from the user application. + * + * return value + * 0 IOCTL completed successfully. + * -ENOTTY IOCTL not supported or invalid driver data + * structure pointer. + */ +static int mtip_block_ioctl(struct block_device *dev, + fmode_t mode, + unsigned cmd, + unsigned long arg) +{ + struct driver_data *dd = dev->bd_disk->private_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (!dd) + return -ENOTTY; + + switch (cmd) { + case BLKFLSBUF: + return -ENOTTY; + default: + return mtip_hw_ioctl(dd, cmd, arg); + } +} + +#ifdef CONFIG_COMPAT +/* + * Block layer compat IOCTL handler. + * + * @dev Pointer to the block_device structure. + * @mode ignored + * @cmd IOCTL command passed from the user application. + * @arg Argument passed from the user application. + * + * return value + * 0 IOCTL completed successfully. + * -ENOTTY IOCTL not supported or invalid driver data + * structure pointer. + */ +static int mtip_block_compat_ioctl(struct block_device *dev, + fmode_t mode, + unsigned cmd, + unsigned long arg) +{ + struct driver_data *dd = dev->bd_disk->private_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (!dd) + return -ENOTTY; + + switch (cmd) { + case BLKFLSBUF: + return -ENOTTY; + case HDIO_DRIVE_TASKFILE: { + struct mtip_compat_ide_task_request_s __user *compat_req_task; + ide_task_request_t req_task; + int compat_tasksize, outtotal, ret; + + compat_tasksize = + sizeof(struct mtip_compat_ide_task_request_s); + + compat_req_task = + (struct mtip_compat_ide_task_request_s __user *) arg; + + if (copy_from_user(&req_task, (void __user *) arg, + compat_tasksize - (2 * sizeof(compat_long_t)))) + return -EFAULT; + + if (get_user(req_task.out_size, &compat_req_task->out_size)) + return -EFAULT; + + if (get_user(req_task.in_size, &compat_req_task->in_size)) + return -EFAULT; + + outtotal = sizeof(struct mtip_compat_ide_task_request_s); + + ret = exec_drive_taskfile(dd, (void __user *) arg, + &req_task, outtotal); + + if (copy_to_user((void __user *) arg, &req_task, + compat_tasksize - + (2 * sizeof(compat_long_t)))) + return -EFAULT; + + if (put_user(req_task.out_size, &compat_req_task->out_size)) + return -EFAULT; + + if (put_user(req_task.in_size, &compat_req_task->in_size)) + return -EFAULT; + + return ret; + } + default: + return mtip_hw_ioctl(dd, cmd, arg); + } +} +#endif + +/* + * Obtain the geometry of the device. + * + * You may think that this function is obsolete, but some applications, + * fdisk for example still used CHS values. This function describes the + * device as having 224 heads and 56 sectors per cylinder. These values are + * chosen so that each cylinder is aligned on a 4KB boundary. Since a + * partition is described in terms of a start and end cylinder this means + * that each partition is also 4KB aligned. Non-aligned partitions adversely + * affects performance. + * + * @dev Pointer to the block_device strucutre. + * @geo Pointer to a hd_geometry structure. + * + * return value + * 0 Operation completed successfully. + * -ENOTTY An error occurred while reading the drive capacity. + */ +static int mtip_block_getgeo(struct block_device *dev, + struct hd_geometry *geo) +{ + struct driver_data *dd = dev->bd_disk->private_data; + sector_t capacity; + + if (!dd) + return -ENOTTY; + + if (!(mtip_hw_get_capacity(dd, &capacity))) { + dev_warn(&dd->pdev->dev, + "Could not get drive capacity.\n"); + return -ENOTTY; + } + + geo->heads = 224; + geo->sectors = 56; + sector_div(capacity, (geo->heads * geo->sectors)); + geo->cylinders = capacity; + return 0; +} + +/* + * Block device operation function. + * + * This structure contains pointers to the functions required by the block + * layer. + */ +static const struct block_device_operations mtip_block_ops = { + .ioctl = mtip_block_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = mtip_block_compat_ioctl, +#endif + .getgeo = mtip_block_getgeo, + .owner = THIS_MODULE +}; + +/* + * Block layer make request function. + * + * This function is called by the kernel to process a BIO for + * the P320 device. + * + * @queue Pointer to the request queue. Unused other than to obtain + * the driver data structure. + * @bio Pointer to the BIO. + * + */ +static void mtip_make_request(struct request_queue *queue, struct bio *bio) +{ + struct driver_data *dd = queue->queuedata; + struct scatterlist *sg; + struct bio_vec *bvec; + int nents = 0; + int tag = 0; + + if (unlikely(!bio_has_data(bio))) { + blk_queue_flush(queue, 0); + bio_endio(bio, 0); + return; + } + + sg = mtip_hw_get_scatterlist(dd, &tag); + if (likely(sg != NULL)) { + blk_queue_bounce(queue, &bio); + + if (unlikely((bio)->bi_vcnt > MTIP_MAX_SG)) { + dev_warn(&dd->pdev->dev, + "Maximum number of SGL entries exceeded"); + bio_io_error(bio); + mtip_hw_release_scatterlist(dd, tag); + return; + } + + /* Create the scatter list for this bio. */ + bio_for_each_segment(bvec, bio, nents) { + sg_set_page(&sg[nents], + bvec->bv_page, + bvec->bv_len, + bvec->bv_offset); + } + + /* Issue the read/write. */ + mtip_hw_submit_io(dd, + bio->bi_sector, + bio_sectors(bio), + nents, + tag, + bio_endio, + bio, + bio->bi_rw & REQ_FUA, + bio_data_dir(bio)); + } else + bio_io_error(bio); +} + +/* + * Block layer initialization function. + * + * This function is called once by the PCI layer for each P320 + * device that is connected to the system. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 on success else an error code. + */ +static int mtip_block_initialize(struct driver_data *dd) +{ + int rv = 0, wait_for_rebuild = 0; + sector_t capacity; + unsigned int index = 0; + struct kobject *kobj; + unsigned char thd_name[16]; + + if (dd->disk) + goto skip_create_disk; /* hw init done, before rebuild */ + + /* Initialize the protocol layer. */ + wait_for_rebuild = mtip_hw_init(dd); + if (wait_for_rebuild < 0) { + dev_err(&dd->pdev->dev, + "Protocol layer initialization failed\n"); + rv = -EINVAL; + goto protocol_init_error; + } + + dd->disk = alloc_disk(MTIP_MAX_MINORS); + if (dd->disk == NULL) { + dev_err(&dd->pdev->dev, + "Unable to allocate gendisk structure\n"); + rv = -EINVAL; + goto alloc_disk_error; + } + + /* Generate the disk name, implemented same as in sd.c */ + do { + if (!ida_pre_get(&rssd_index_ida, GFP_KERNEL)) + goto ida_get_error; + + spin_lock(&rssd_index_lock); + rv = ida_get_new(&rssd_index_ida, &index); + spin_unlock(&rssd_index_lock); + } while (rv == -EAGAIN); + + if (rv) + goto ida_get_error; + + rv = rssd_disk_name_format("rssd", + index, + dd->disk->disk_name, + DISK_NAME_LEN); + if (rv) + goto disk_index_error; + + dd->disk->driverfs_dev = &dd->pdev->dev; + dd->disk->major = dd->major; + dd->disk->first_minor = dd->instance * MTIP_MAX_MINORS; + dd->disk->fops = &mtip_block_ops; + dd->disk->private_data = dd; + dd->index = index; + + /* + * if rebuild pending, start the service thread, and delay the block + * queue creation and add_disk() + */ + if (wait_for_rebuild == MTIP_FTL_REBUILD_MAGIC) + goto start_service_thread; + +skip_create_disk: + /* Allocate the request queue. */ + dd->queue = blk_alloc_queue(GFP_KERNEL); + if (dd->queue == NULL) { + dev_err(&dd->pdev->dev, + "Unable to allocate request queue\n"); + rv = -ENOMEM; + goto block_queue_alloc_init_error; + } + + /* Attach our request function to the request queue. */ + blk_queue_make_request(dd->queue, mtip_make_request); + + dd->disk->queue = dd->queue; + dd->queue->queuedata = dd; + + /* Set device limits. */ + set_bit(QUEUE_FLAG_NONROT, &dd->queue->queue_flags); + blk_queue_max_segments(dd->queue, MTIP_MAX_SG); + blk_queue_physical_block_size(dd->queue, 4096); + blk_queue_io_min(dd->queue, 4096); + blk_queue_flush(dd->queue, 0); + + /* Set the capacity of the device in 512 byte sectors. */ + if (!(mtip_hw_get_capacity(dd, &capacity))) { + dev_warn(&dd->pdev->dev, + "Could not read drive capacity\n"); + rv = -EIO; + goto read_capacity_error; + } + set_capacity(dd->disk, capacity); + + /* Enable the block device and add it to /dev */ + add_disk(dd->disk); + + /* + * Now that the disk is active, initialize any sysfs attributes + * managed by the protocol layer. + */ + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); + if (kobj) { + mtip_hw_sysfs_init(dd, kobj); + kobject_put(kobj); + } + + if (dd->mtip_svc_handler) + return rv; /* service thread created for handling rebuild */ + +start_service_thread: + sprintf(thd_name, "mtip_svc_thd_%02d", index); + + dd->mtip_svc_handler = kthread_run(mtip_service_thread, + dd, thd_name); + + if (IS_ERR(dd->mtip_svc_handler)) { + printk(KERN_ERR "mtip32xx: service thread failed to start\n"); + dd->mtip_svc_handler = NULL; + rv = -EFAULT; + goto kthread_run_error; + } + + return rv; + +kthread_run_error: + /* Delete our gendisk. This also removes the device from /dev */ + del_gendisk(dd->disk); + +read_capacity_error: + blk_cleanup_queue(dd->queue); + +block_queue_alloc_init_error: +disk_index_error: + spin_lock(&rssd_index_lock); + ida_remove(&rssd_index_ida, index); + spin_unlock(&rssd_index_lock); + +ida_get_error: + put_disk(dd->disk); + +alloc_disk_error: + mtip_hw_exit(dd); /* De-initialize the protocol layer. */ + +protocol_init_error: + return rv; +} + +/* + * Block layer deinitialization function. + * + * Called by the PCI layer as each P320 device is removed. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 + */ +static int mtip_block_remove(struct driver_data *dd) +{ + struct kobject *kobj; + + if (dd->mtip_svc_handler) { + set_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags); + wake_up_interruptible(&dd->port->svc_wait); + kthread_stop(dd->mtip_svc_handler); + } + + /* Clean up the sysfs attributes managed by the protocol layer. */ + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); + if (kobj) { + mtip_hw_sysfs_exit(dd, kobj); + kobject_put(kobj); + } + + /* + * Delete our gendisk structure. This also removes the device + * from /dev + */ + del_gendisk(dd->disk); + blk_cleanup_queue(dd->queue); + dd->disk = NULL; + dd->queue = NULL; + + /* De-initialize the protocol layer. */ + mtip_hw_exit(dd); + + return 0; +} + +/* + * Function called by the PCI layer when just before the + * machine shuts down. + * + * If a protocol layer shutdown function is present it will be called + * by this function. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 + */ +static int mtip_block_shutdown(struct driver_data *dd) +{ + dev_info(&dd->pdev->dev, + "Shutting down %s ...\n", dd->disk->disk_name); + + /* Delete our gendisk structure, and cleanup the blk queue. */ + del_gendisk(dd->disk); + blk_cleanup_queue(dd->queue); + dd->disk = NULL; + dd->queue = NULL; + + mtip_hw_shutdown(dd); + return 0; +} + +static int mtip_block_suspend(struct driver_data *dd) +{ + dev_info(&dd->pdev->dev, + "Suspending %s ...\n", dd->disk->disk_name); + mtip_hw_suspend(dd); + return 0; +} + +static int mtip_block_resume(struct driver_data *dd) +{ + dev_info(&dd->pdev->dev, "Resuming %s ...\n", + dd->disk->disk_name); + mtip_hw_resume(dd); + return 0; +} + +/* + * Called for each supported PCI device detected. + * + * This function allocates the private data structure, enables the + * PCI device and then calls the block layer initialization function. + * + * return value + * 0 on success else an error code. + */ +static int mtip_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rv = 0; + struct driver_data *dd = NULL; + + /* Allocate memory for this devices private data. */ + dd = kzalloc(sizeof(struct driver_data), GFP_KERNEL); + if (dd == NULL) { + dev_err(&pdev->dev, + "Unable to allocate memory for driver data\n"); + return -ENOMEM; + } + + /* Set the atomic variable as 1 in case of SRSI */ + atomic_set(&dd->drv_cleanup_done, true); + + atomic_set(&dd->resumeflag, false); + + /* Attach the private data to this PCI device. */ + pci_set_drvdata(pdev, dd); + + rv = pcim_enable_device(pdev); + if (rv < 0) { + dev_err(&pdev->dev, "Unable to enable device\n"); + goto iomap_err; + } + + /* Map BAR5 to memory. */ + rv = pcim_iomap_regions(pdev, 1 << MTIP_ABAR, MTIP_DRV_NAME); + if (rv < 0) { + dev_err(&pdev->dev, "Unable to map regions\n"); + goto iomap_err; + } + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + rv = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + + if (rv) { + rv = pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32)); + if (rv) { + dev_warn(&pdev->dev, + "64-bit DMA enable failed\n"); + goto setmask_err; + } + } + } + + pci_set_master(pdev); + + if (pci_enable_msi(pdev)) { + dev_warn(&pdev->dev, + "Unable to enable MSI interrupt.\n"); + goto block_initialize_err; + } + + /* Copy the info we may need later into the private data structure. */ + dd->major = mtip_major; + dd->instance = instance; + dd->pdev = pdev; + + /* Initialize the block layer. */ + rv = mtip_block_initialize(dd); + if (rv < 0) { + dev_err(&pdev->dev, + "Unable to initialize block layer\n"); + goto block_initialize_err; + } + + /* + * Increment the instance count so that each device has a unique + * instance number. + */ + instance++; + + goto done; + +block_initialize_err: + pci_disable_msi(pdev); + +setmask_err: + pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); + +iomap_err: + kfree(dd); + pci_set_drvdata(pdev, NULL); + return rv; +done: + /* Set the atomic variable as 0 in case of SRSI */ + atomic_set(&dd->drv_cleanup_done, true); + + return rv; +} + +/* + * Called for each probed device when the device is removed or the + * driver is unloaded. + * + * return value + * None + */ +static void mtip_pci_remove(struct pci_dev *pdev) +{ + struct driver_data *dd = pci_get_drvdata(pdev); + int counter = 0; + + if (mtip_check_surprise_removal(pdev)) { + while (atomic_read(&dd->drv_cleanup_done) == false) { + counter++; + msleep(20); + if (counter == 10) { + /* Cleanup the outstanding commands */ + mtip_command_cleanup(dd); + break; + } + } + } + /* Set the atomic variable as 1 in case of SRSI */ + atomic_set(&dd->drv_cleanup_done, true); + + /* Clean up the block layer. */ + mtip_block_remove(dd); + + pci_disable_msi(pdev); + + kfree(dd); + pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); +} + +/* + * Called for each probed device when the device is suspended. + * + * return value + * 0 Success + * <0 Error + */ +static int mtip_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + int rv = 0; + struct driver_data *dd = pci_get_drvdata(pdev); + + if (!dd) { + dev_err(&pdev->dev, + "Driver private datastructure is NULL\n"); + return -EFAULT; + } + + atomic_set(&dd->resumeflag, true); + + /* Disable ports & interrupts then send standby immediate */ + rv = mtip_block_suspend(dd); + if (rv < 0) { + dev_err(&pdev->dev, + "Failed to suspend controller\n"); + return rv; + } + + /* + * Save the pci config space to pdev structure & + * disable the device + */ + pci_save_state(pdev); + pci_disable_device(pdev); + + /* Move to Low power state*/ + pci_set_power_state(pdev, PCI_D3hot); + + return rv; +} + +/* + * Called for each probed device when the device is resumed. + * + * return value + * 0 Success + * <0 Error + */ +static int mtip_pci_resume(struct pci_dev *pdev) +{ + int rv = 0; + struct driver_data *dd; + + dd = pci_get_drvdata(pdev); + if (!dd) { + dev_err(&pdev->dev, + "Driver private datastructure is NULL\n"); + return -EFAULT; + } + + /* Move the device to active State */ + pci_set_power_state(pdev, PCI_D0); + + /* Restore PCI configuration space */ + pci_restore_state(pdev); + + /* Enable the PCI device*/ + rv = pcim_enable_device(pdev); + if (rv < 0) { + dev_err(&pdev->dev, + "Failed to enable card during resume\n"); + goto err; + } + pci_set_master(pdev); + + /* + * Calls hbaReset, initPort, & startPort function + * then enables interrupts + */ + rv = mtip_block_resume(dd); + if (rv < 0) + dev_err(&pdev->dev, "Unable to resume\n"); + +err: + atomic_set(&dd->resumeflag, false); + + return rv; +} + +/* + * Shutdown routine + * + * return value + * None + */ +static void mtip_pci_shutdown(struct pci_dev *pdev) +{ + struct driver_data *dd = pci_get_drvdata(pdev); + if (dd) + mtip_block_shutdown(dd); +} + +/* Table of device ids supported by this driver. */ +static DEFINE_PCI_DEVICE_TABLE(mtip_pci_tbl) = { + { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320_DEVICE_ID) }, + { 0 } +}; + +/* Structure that describes the PCI driver functions. */ +static struct pci_driver mtip_pci_driver = { + .name = MTIP_DRV_NAME, + .id_table = mtip_pci_tbl, + .probe = mtip_pci_probe, + .remove = mtip_pci_remove, + .suspend = mtip_pci_suspend, + .resume = mtip_pci_resume, + .shutdown = mtip_pci_shutdown, +}; + +MODULE_DEVICE_TABLE(pci, mtip_pci_tbl); + +/* + * Module initialization function. + * + * Called once when the module is loaded. This function allocates a major + * block device number to the Cyclone devices and registers the PCI layer + * of the driver. + * + * Return value + * 0 on success else error code. + */ +static int __init mtip_init(void) +{ + printk(KERN_INFO MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n"); + + /* Allocate a major block device number to use with this driver. */ + mtip_major = register_blkdev(0, MTIP_DRV_NAME); + if (mtip_major < 0) { + printk(KERN_ERR "Unable to register block device (%d)\n", + mtip_major); + return -EBUSY; + } + + /* Register our PCI operations. */ + return pci_register_driver(&mtip_pci_driver); +} + +/* + * Module de-initialization function. + * + * Called once when the module is unloaded. This function deallocates + * the major block device number allocated by mtip_init() and + * unregisters the PCI layer of the driver. + * + * Return value + * none + */ +static void __exit mtip_exit(void) +{ + /* Release the allocated major block device number. */ + unregister_blkdev(mtip_major, MTIP_DRV_NAME); + + /* Unregister the PCI driver. */ + pci_unregister_driver(&mtip_pci_driver); +} + +MODULE_AUTHOR("Micron Technology, Inc"); +MODULE_DESCRIPTION("Micron RealSSD PCIe Block Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MTIP_DRV_VERSION); + +module_init(mtip_init); +module_exit(mtip_exit); diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h new file mode 100644 index 000000000000..723d7c4946dc --- /dev/null +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -0,0 +1,423 @@ +/* + * mtip32xx.h - Header file for the P320 SSD Block Driver + * Copyright (C) 2011 Micron Technology, Inc. + * + * Portions of this code were derived from works subjected to the + * following copyright: + * Copyright (C) 2009 Integrated Device Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MTIP32XX_H__ +#define __MTIP32XX_H__ + +#include <linux/spinlock.h> +#include <linux/rwsem.h> +#include <linux/ata.h> +#include <linux/interrupt.h> +#include <linux/genhd.h> +#include <linux/version.h> + +/* Offset of Subsystem Device ID in pci confoguration space */ +#define PCI_SUBSYSTEM_DEVICEID 0x2E + +/* offset of Device Control register in PCIe extended capabilites space */ +#define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48 + +/* # of times to retry timed out IOs */ +#define MTIP_MAX_RETRIES 5 + +/* Various timeout values in ms */ +#define MTIP_NCQ_COMMAND_TIMEOUT_MS 5000 +#define MTIP_IOCTL_COMMAND_TIMEOUT_MS 5000 +#define MTIP_INTERNAL_COMMAND_TIMEOUT_MS 5000 + +/* check for timeouts every 500ms */ +#define MTIP_TIMEOUT_CHECK_PERIOD 500 + +/* ftl rebuild */ +#define MTIP_FTL_REBUILD_OFFSET 142 +#define MTIP_FTL_REBUILD_MAGIC 0xED51 +#define MTIP_FTL_REBUILD_TIMEOUT_MS 2400000 + +/* Macro to extract the tag bit number from a tag value. */ +#define MTIP_TAG_BIT(tag) (tag & 0x1F) + +/* + * Macro to extract the tag index from a tag value. The index + * is used to access the correct s_active/Command Issue register based + * on the tag value. + */ +#define MTIP_TAG_INDEX(tag) (tag >> 5) + +/* + * Maximum number of scatter gather entries + * a single command may have. + */ +#define MTIP_MAX_SG 128 + +/* + * Maximum number of slot groups (Command Issue & s_active registers) + * NOTE: This is the driver maximum; check dd->slot_groups for actual value. + */ +#define MTIP_MAX_SLOT_GROUPS 8 + +/* Internal command tag. */ +#define MTIP_TAG_INTERNAL 0 + +/* Micron Vendor ID & P320x SSD Device ID */ +#define PCI_VENDOR_ID_MICRON 0x1344 +#define P320_DEVICE_ID 0x5150 + +/* Driver name and version strings */ +#define MTIP_DRV_NAME "mtip32xx" +#define MTIP_DRV_VERSION "1.2.6os3" + +/* Maximum number of minor device numbers per device. */ +#define MTIP_MAX_MINORS 16 + +/* Maximum number of supported command slots. */ +#define MTIP_MAX_COMMAND_SLOTS (MTIP_MAX_SLOT_GROUPS * 32) + +/* + * Per-tag bitfield size in longs. + * Linux bit manipulation functions + * (i.e. test_and_set_bit, find_next_zero_bit) + * manipulate memory in longs, so we try to make the math work. + * take the slot groups and find the number of longs, rounding up. + * Careful! i386 and x86_64 use different size longs! + */ +#define U32_PER_LONG (sizeof(long) / sizeof(u32)) +#define SLOTBITS_IN_LONGS ((MTIP_MAX_SLOT_GROUPS + \ + (U32_PER_LONG-1))/U32_PER_LONG) + +/* BAR number used to access the HBA registers. */ +#define MTIP_ABAR 5 + +/* Forced Unit Access Bit */ +#define FUA_BIT 0x80 + +#ifdef DEBUG + #define dbg_printk(format, arg...) \ + printk(pr_fmt(format), ##arg); +#else + #define dbg_printk(format, arg...) +#endif + +#define __force_bit2int (unsigned int __force) + +/* below are bit numbers in 'flags' defined in mtip_port */ +#define MTIP_FLAG_IC_ACTIVE_BIT 0 +#define MTIP_FLAG_EH_ACTIVE_BIT 1 +#define MTIP_FLAG_SVC_THD_ACTIVE_BIT 2 +#define MTIP_FLAG_ISSUE_CMDS_BIT 4 +#define MTIP_FLAG_REBUILD_BIT 5 +#define MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT 8 + +/* Register Frame Information Structure (FIS), host to device. */ +struct host_to_dev_fis { + /* + * FIS type. + * - 27h Register FIS, host to device. + * - 34h Register FIS, device to host. + * - 39h DMA Activate FIS, device to host. + * - 41h DMA Setup FIS, bi-directional. + * - 46h Data FIS, bi-directional. + * - 58h BIST Activate FIS, bi-directional. + * - 5Fh PIO Setup FIS, device to host. + * - A1h Set Device Bits FIS, device to host. + */ + unsigned char type; + unsigned char opts; + unsigned char command; + unsigned char features; + + union { + unsigned char lba_low; + unsigned char sector; + }; + union { + unsigned char lba_mid; + unsigned char cyl_low; + }; + union { + unsigned char lba_hi; + unsigned char cyl_hi; + }; + union { + unsigned char device; + unsigned char head; + }; + + union { + unsigned char lba_low_ex; + unsigned char sector_ex; + }; + union { + unsigned char lba_mid_ex; + unsigned char cyl_low_ex; + }; + union { + unsigned char lba_hi_ex; + unsigned char cyl_hi_ex; + }; + unsigned char features_ex; + + unsigned char sect_count; + unsigned char sect_cnt_ex; + unsigned char res2; + unsigned char control; + + unsigned int res3; +}; + +/* Command header structure. */ +struct mtip_cmd_hdr { + /* + * Command options. + * - Bits 31:16 Number of PRD entries. + * - Bits 15:8 Unused in this implementation. + * - Bit 7 Prefetch bit, informs the drive to prefetch PRD entries. + * - Bit 6 Write bit, should be set when writing data to the device. + * - Bit 5 Unused in this implementation. + * - Bits 4:0 Length of the command FIS in DWords (DWord = 4 bytes). + */ + unsigned int opts; + /* This field is unsed when using NCQ. */ + union { + unsigned int byte_count; + unsigned int status; + }; + /* + * Lower 32 bits of the command table address associated with this + * header. The command table addresses must be 128 byte aligned. + */ + unsigned int ctba; + /* + * If 64 bit addressing is used this field is the upper 32 bits + * of the command table address associated with this command. + */ + unsigned int ctbau; + /* Reserved and unused. */ + unsigned int res[4]; +}; + +/* Command scatter gather structure (PRD). */ +struct mtip_cmd_sg { + /* + * Low 32 bits of the data buffer address. For P320 this + * address must be 8 byte aligned signified by bits 2:0 being + * set to 0. + */ + unsigned int dba; + /* + * When 64 bit addressing is used this field is the upper + * 32 bits of the data buffer address. + */ + unsigned int dba_upper; + /* Unused. */ + unsigned int reserved; + /* + * Bit 31: interrupt when this data block has been transferred. + * Bits 30..22: reserved + * Bits 21..0: byte count (minus 1). For P320 the byte count must be + * 8 byte aligned signified by bits 2:0 being set to 1. + */ + unsigned int info; +}; +struct mtip_port; + +/* Structure used to describe a command. */ +struct mtip_cmd { + + struct mtip_cmd_hdr *command_header; /* ptr to command header entry */ + + dma_addr_t command_header_dma; /* corresponding physical address */ + + void *command; /* ptr to command table entry */ + + dma_addr_t command_dma; /* corresponding physical address */ + + void *comp_data; /* data passed to completion function comp_func() */ + /* + * Completion function called by the ISR upon completion of + * a command. + */ + void (*comp_func)(struct mtip_port *port, + int tag, + void *data, + int status); + /* Additional callback function that may be called by comp_func() */ + void (*async_callback)(void *data, int status); + + void *async_data; /* Addl. data passed to async_callback() */ + + int scatter_ents; /* Number of scatter list entries used */ + + struct scatterlist sg[MTIP_MAX_SG]; /* Scatter list entries */ + + int retries; /* The number of retries left for this command. */ + + int direction; /* Data transfer direction */ + + unsigned long comp_time; /* command completion time, in jiffies */ + + atomic_t active; /* declares if this command sent to the drive. */ +}; + +/* Structure used to describe a port. */ +struct mtip_port { + /* Pointer back to the driver data for this port. */ + struct driver_data *dd; + /* + * Used to determine if the data pointed to by the + * identify field is valid. + */ + unsigned long identify_valid; + /* Base address of the memory mapped IO for the port. */ + void __iomem *mmio; + /* Array of pointers to the memory mapped s_active registers. */ + void __iomem *s_active[MTIP_MAX_SLOT_GROUPS]; + /* Array of pointers to the memory mapped completed registers. */ + void __iomem *completed[MTIP_MAX_SLOT_GROUPS]; + /* Array of pointers to the memory mapped Command Issue registers. */ + void __iomem *cmd_issue[MTIP_MAX_SLOT_GROUPS]; + /* + * Pointer to the beginning of the command header memory as used + * by the driver. + */ + void *command_list; + /* + * Pointer to the beginning of the command header memory as used + * by the DMA. + */ + dma_addr_t command_list_dma; + /* + * Pointer to the beginning of the RX FIS memory as used + * by the driver. + */ + void *rxfis; + /* + * Pointer to the beginning of the RX FIS memory as used + * by the DMA. + */ + dma_addr_t rxfis_dma; + /* + * Pointer to the beginning of the command table memory as used + * by the driver. + */ + void *command_table; + /* + * Pointer to the beginning of the command table memory as used + * by the DMA. + */ + dma_addr_t command_tbl_dma; + /* + * Pointer to the beginning of the identify data memory as used + * by the driver. + */ + u16 *identify; + /* + * Pointer to the beginning of the identify data memory as used + * by the DMA. + */ + dma_addr_t identify_dma; + /* + * Pointer to the beginning of a sector buffer that is used + * by the driver when issuing internal commands. + */ + u16 *sector_buffer; + /* + * Pointer to the beginning of a sector buffer that is used + * by the DMA when the driver issues internal commands. + */ + dma_addr_t sector_buffer_dma; + /* + * Bit significant, used to determine if a command slot has + * been allocated. i.e. the slot is in use. Bits are cleared + * when the command slot and all associated data structures + * are no longer needed. + */ + unsigned long allocated[SLOTBITS_IN_LONGS]; + /* + * used to queue commands when an internal command is in progress + * or error handling is active + */ + unsigned long cmds_to_issue[SLOTBITS_IN_LONGS]; + /* + * Array of command slots. Structure includes pointers to the + * command header and command table, and completion function and data + * pointers. + */ + struct mtip_cmd commands[MTIP_MAX_COMMAND_SLOTS]; + /* Used by mtip_service_thread to wait for an event */ + wait_queue_head_t svc_wait; + /* + * indicates the state of the port. Also, helps the service thread + * to determine its action on wake up. + */ + unsigned long flags; + /* + * Timer used to complete commands that have been active for too long. + */ + struct timer_list cmd_timer; + /* + * Semaphore used to block threads if there are no + * command slots available. + */ + struct semaphore cmd_slot; + /* Spinlock for working around command-issue bug. */ + spinlock_t cmd_issue_lock; +}; + +/* + * Driver private data structure. + * + * One structure is allocated per probed device. + */ +struct driver_data { + void __iomem *mmio; /* Base address of the HBA registers. */ + + int major; /* Major device number. */ + + int instance; /* Instance number. First device probed is 0, ... */ + + struct gendisk *disk; /* Pointer to our gendisk structure. */ + + struct pci_dev *pdev; /* Pointer to the PCI device structure. */ + + struct request_queue *queue; /* Our request queue. */ + + struct mtip_port *port; /* Pointer to the port data structure. */ + + /* Tasklet used to process the bottom half of the ISR. */ + struct tasklet_struct tasklet; + + unsigned product_type; /* magic value declaring the product type */ + + unsigned slot_groups; /* number of slot groups the product supports */ + + atomic_t drv_cleanup_done; /* Atomic variable for SRSI */ + + unsigned long index; /* Index to determine the disk name */ + + unsigned int ftlrebuildflag; /* FTL rebuild flag */ + + atomic_t resumeflag; /* Atomic variable to track suspend/resume */ + + atomic_t eh_active; /* Flag for error handling tracking */ + + struct task_struct *mtip_svc_handler; /* task_struct of svc thd */ +}; + +#endif diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c new file mode 100644 index 000000000000..c1dc4d86c221 --- /dev/null +++ b/drivers/block/nvme.c @@ -0,0 +1,1739 @@ +/* + * NVM Express device driver + * Copyright (c) 2011, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/nvme.h> +#include <linux/bio.h> +#include <linux/bitops.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/genhd.h> +#include <linux/idr.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kdev_t.h> +#include <linux/kthread.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/pci.h> +#include <linux/poison.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/version.h> + +#define NVME_Q_DEPTH 1024 +#define SQ_SIZE(depth) (depth * sizeof(struct nvme_command)) +#define CQ_SIZE(depth) (depth * sizeof(struct nvme_completion)) +#define NVME_MINORS 64 +#define NVME_IO_TIMEOUT (5 * HZ) +#define ADMIN_TIMEOUT (60 * HZ) + +static int nvme_major; +module_param(nvme_major, int, 0); + +static int use_threaded_interrupts; +module_param(use_threaded_interrupts, int, 0); + +static DEFINE_SPINLOCK(dev_list_lock); +static LIST_HEAD(dev_list); +static struct task_struct *nvme_thread; + +/* + * Represents an NVM Express device. Each nvme_dev is a PCI function. + */ +struct nvme_dev { + struct list_head node; + struct nvme_queue **queues; + u32 __iomem *dbs; + struct pci_dev *pci_dev; + struct dma_pool *prp_page_pool; + struct dma_pool *prp_small_pool; + int instance; + int queue_count; + int db_stride; + u32 ctrl_config; + struct msix_entry *entry; + struct nvme_bar __iomem *bar; + struct list_head namespaces; + char serial[20]; + char model[40]; + char firmware_rev[8]; +}; + +/* + * An NVM Express namespace is equivalent to a SCSI LUN + */ +struct nvme_ns { + struct list_head list; + + struct nvme_dev *dev; + struct request_queue *queue; + struct gendisk *disk; + + int ns_id; + int lba_shift; +}; + +/* + * An NVM Express queue. Each device has at least two (one for admin + * commands and one for I/O commands). + */ +struct nvme_queue { + struct device *q_dmadev; + struct nvme_dev *dev; + spinlock_t q_lock; + struct nvme_command *sq_cmds; + volatile struct nvme_completion *cqes; + dma_addr_t sq_dma_addr; + dma_addr_t cq_dma_addr; + wait_queue_head_t sq_full; + wait_queue_t sq_cong_wait; + struct bio_list sq_cong; + u32 __iomem *q_db; + u16 q_depth; + u16 cq_vector; + u16 sq_head; + u16 sq_tail; + u16 cq_head; + u16 cq_phase; + unsigned long cmdid_data[]; +}; + +/* + * Check we didin't inadvertently grow the command struct + */ +static inline void _nvme_check_size(void) +{ + BUILD_BUG_ON(sizeof(struct nvme_rw_command) != 64); + BUILD_BUG_ON(sizeof(struct nvme_create_cq) != 64); + BUILD_BUG_ON(sizeof(struct nvme_create_sq) != 64); + BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64); + BUILD_BUG_ON(sizeof(struct nvme_features) != 64); + BUILD_BUG_ON(sizeof(struct nvme_command) != 64); + BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != 4096); + BUILD_BUG_ON(sizeof(struct nvme_id_ns) != 4096); + BUILD_BUG_ON(sizeof(struct nvme_lba_range_type) != 64); +} + +typedef void (*nvme_completion_fn)(struct nvme_dev *, void *, + struct nvme_completion *); + +struct nvme_cmd_info { + nvme_completion_fn fn; + void *ctx; + unsigned long timeout; +}; + +static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq) +{ + return (void *)&nvmeq->cmdid_data[BITS_TO_LONGS(nvmeq->q_depth)]; +} + +/** + * alloc_cmdid() - Allocate a Command ID + * @nvmeq: The queue that will be used for this command + * @ctx: A pointer that will be passed to the handler + * @handler: The function to call on completion + * + * Allocate a Command ID for a queue. The data passed in will + * be passed to the completion handler. This is implemented by using + * the bottom two bits of the ctx pointer to store the handler ID. + * Passing in a pointer that's not 4-byte aligned will cause a BUG. + * We can change this if it becomes a problem. + * + * May be called with local interrupts disabled and the q_lock held, + * or with interrupts enabled and no locks held. + */ +static int alloc_cmdid(struct nvme_queue *nvmeq, void *ctx, + nvme_completion_fn handler, unsigned timeout) +{ + int depth = nvmeq->q_depth - 1; + struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); + int cmdid; + + do { + cmdid = find_first_zero_bit(nvmeq->cmdid_data, depth); + if (cmdid >= depth) + return -EBUSY; + } while (test_and_set_bit(cmdid, nvmeq->cmdid_data)); + + info[cmdid].fn = handler; + info[cmdid].ctx = ctx; + info[cmdid].timeout = jiffies + timeout; + return cmdid; +} + +static int alloc_cmdid_killable(struct nvme_queue *nvmeq, void *ctx, + nvme_completion_fn handler, unsigned timeout) +{ + int cmdid; + wait_event_killable(nvmeq->sq_full, + (cmdid = alloc_cmdid(nvmeq, ctx, handler, timeout)) >= 0); + return (cmdid < 0) ? -EINTR : cmdid; +} + +/* Special values must be less than 0x1000 */ +#define CMD_CTX_BASE ((void *)POISON_POINTER_DELTA) +#define CMD_CTX_CANCELLED (0x30C + CMD_CTX_BASE) +#define CMD_CTX_COMPLETED (0x310 + CMD_CTX_BASE) +#define CMD_CTX_INVALID (0x314 + CMD_CTX_BASE) +#define CMD_CTX_FLUSH (0x318 + CMD_CTX_BASE) + +static void special_completion(struct nvme_dev *dev, void *ctx, + struct nvme_completion *cqe) +{ + if (ctx == CMD_CTX_CANCELLED) + return; + if (ctx == CMD_CTX_FLUSH) + return; + if (ctx == CMD_CTX_COMPLETED) { + dev_warn(&dev->pci_dev->dev, + "completed id %d twice on queue %d\n", + cqe->command_id, le16_to_cpup(&cqe->sq_id)); + return; + } + if (ctx == CMD_CTX_INVALID) { + dev_warn(&dev->pci_dev->dev, + "invalid id %d completed on queue %d\n", + cqe->command_id, le16_to_cpup(&cqe->sq_id)); + return; + } + + dev_warn(&dev->pci_dev->dev, "Unknown special completion %p\n", ctx); +} + +/* + * Called with local interrupts disabled and the q_lock held. May not sleep. + */ +static void *free_cmdid(struct nvme_queue *nvmeq, int cmdid, + nvme_completion_fn *fn) +{ + void *ctx; + struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); + + if (cmdid >= nvmeq->q_depth) { + *fn = special_completion; + return CMD_CTX_INVALID; + } + *fn = info[cmdid].fn; + ctx = info[cmdid].ctx; + info[cmdid].fn = special_completion; + info[cmdid].ctx = CMD_CTX_COMPLETED; + clear_bit(cmdid, nvmeq->cmdid_data); + wake_up(&nvmeq->sq_full); + return ctx; +} + +static void *cancel_cmdid(struct nvme_queue *nvmeq, int cmdid, + nvme_completion_fn *fn) +{ + void *ctx; + struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); + if (fn) + *fn = info[cmdid].fn; + ctx = info[cmdid].ctx; + info[cmdid].fn = special_completion; + info[cmdid].ctx = CMD_CTX_CANCELLED; + return ctx; +} + +static struct nvme_queue *get_nvmeq(struct nvme_dev *dev) +{ + return dev->queues[get_cpu() + 1]; +} + +static void put_nvmeq(struct nvme_queue *nvmeq) +{ + put_cpu(); +} + +/** + * nvme_submit_cmd() - Copy a command into a queue and ring the doorbell + * @nvmeq: The queue to use + * @cmd: The command to send + * + * Safe to use from interrupt context + */ +static int nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd) +{ + unsigned long flags; + u16 tail; + spin_lock_irqsave(&nvmeq->q_lock, flags); + tail = nvmeq->sq_tail; + memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd)); + if (++tail == nvmeq->q_depth) + tail = 0; + writel(tail, nvmeq->q_db); + nvmeq->sq_tail = tail; + spin_unlock_irqrestore(&nvmeq->q_lock, flags); + + return 0; +} + +/* + * The nvme_iod describes the data in an I/O, including the list of PRP + * entries. You can't see it in this data structure because C doesn't let + * me express that. Use nvme_alloc_iod to ensure there's enough space + * allocated to store the PRP list. + */ +struct nvme_iod { + void *private; /* For the use of the submitter of the I/O */ + int npages; /* In the PRP list. 0 means small pool in use */ + int offset; /* Of PRP list */ + int nents; /* Used in scatterlist */ + int length; /* Of data, in bytes */ + dma_addr_t first_dma; + struct scatterlist sg[0]; +}; + +static __le64 **iod_list(struct nvme_iod *iod) +{ + return ((void *)iod) + iod->offset; +} + +/* + * Will slightly overestimate the number of pages needed. This is OK + * as it only leads to a small amount of wasted memory for the lifetime of + * the I/O. + */ +static int nvme_npages(unsigned size) +{ + unsigned nprps = DIV_ROUND_UP(size + PAGE_SIZE, PAGE_SIZE); + return DIV_ROUND_UP(8 * nprps, PAGE_SIZE - 8); +} + +static struct nvme_iod * +nvme_alloc_iod(unsigned nseg, unsigned nbytes, gfp_t gfp) +{ + struct nvme_iod *iod = kmalloc(sizeof(struct nvme_iod) + + sizeof(__le64 *) * nvme_npages(nbytes) + + sizeof(struct scatterlist) * nseg, gfp); + + if (iod) { + iod->offset = offsetof(struct nvme_iod, sg[nseg]); + iod->npages = -1; + iod->length = nbytes; + } + + return iod; +} + +static void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod) +{ + const int last_prp = PAGE_SIZE / 8 - 1; + int i; + __le64 **list = iod_list(iod); + dma_addr_t prp_dma = iod->first_dma; + + if (iod->npages == 0) + dma_pool_free(dev->prp_small_pool, list[0], prp_dma); + for (i = 0; i < iod->npages; i++) { + __le64 *prp_list = list[i]; + dma_addr_t next_prp_dma = le64_to_cpu(prp_list[last_prp]); + dma_pool_free(dev->prp_page_pool, prp_list, prp_dma); + prp_dma = next_prp_dma; + } + kfree(iod); +} + +static void requeue_bio(struct nvme_dev *dev, struct bio *bio) +{ + struct nvme_queue *nvmeq = get_nvmeq(dev); + if (bio_list_empty(&nvmeq->sq_cong)) + add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait); + bio_list_add(&nvmeq->sq_cong, bio); + put_nvmeq(nvmeq); + wake_up_process(nvme_thread); +} + +static void bio_completion(struct nvme_dev *dev, void *ctx, + struct nvme_completion *cqe) +{ + struct nvme_iod *iod = ctx; + struct bio *bio = iod->private; + u16 status = le16_to_cpup(&cqe->status) >> 1; + + dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents, + bio_data_dir(bio) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + nvme_free_iod(dev, iod); + if (status) { + bio_endio(bio, -EIO); + } else if (bio->bi_vcnt > bio->bi_idx) { + requeue_bio(dev, bio); + } else { + bio_endio(bio, 0); + } +} + +/* length is in bytes. gfp flags indicates whether we may sleep. */ +static int nvme_setup_prps(struct nvme_dev *dev, + struct nvme_common_command *cmd, struct nvme_iod *iod, + int total_len, gfp_t gfp) +{ + struct dma_pool *pool; + int length = total_len; + struct scatterlist *sg = iod->sg; + int dma_len = sg_dma_len(sg); + u64 dma_addr = sg_dma_address(sg); + int offset = offset_in_page(dma_addr); + __le64 *prp_list; + __le64 **list = iod_list(iod); + dma_addr_t prp_dma; + int nprps, i; + + cmd->prp1 = cpu_to_le64(dma_addr); + length -= (PAGE_SIZE - offset); + if (length <= 0) + return total_len; + + dma_len -= (PAGE_SIZE - offset); + if (dma_len) { + dma_addr += (PAGE_SIZE - offset); + } else { + sg = sg_next(sg); + dma_addr = sg_dma_address(sg); + dma_len = sg_dma_len(sg); + } + + if (length <= PAGE_SIZE) { + cmd->prp2 = cpu_to_le64(dma_addr); + return total_len; + } + + nprps = DIV_ROUND_UP(length, PAGE_SIZE); + if (nprps <= (256 / 8)) { + pool = dev->prp_small_pool; + iod->npages = 0; + } else { + pool = dev->prp_page_pool; + iod->npages = 1; + } + + prp_list = dma_pool_alloc(pool, gfp, &prp_dma); + if (!prp_list) { + cmd->prp2 = cpu_to_le64(dma_addr); + iod->npages = -1; + return (total_len - length) + PAGE_SIZE; + } + list[0] = prp_list; + iod->first_dma = prp_dma; + cmd->prp2 = cpu_to_le64(prp_dma); + i = 0; + for (;;) { + if (i == PAGE_SIZE / 8) { + __le64 *old_prp_list = prp_list; + prp_list = dma_pool_alloc(pool, gfp, &prp_dma); + if (!prp_list) + return total_len - length; + list[iod->npages++] = prp_list; + prp_list[0] = old_prp_list[i - 1]; + old_prp_list[i - 1] = cpu_to_le64(prp_dma); + i = 1; + } + prp_list[i++] = cpu_to_le64(dma_addr); + dma_len -= PAGE_SIZE; + dma_addr += PAGE_SIZE; + length -= PAGE_SIZE; + if (length <= 0) + break; + if (dma_len > 0) + continue; + BUG_ON(dma_len < 0); + sg = sg_next(sg); + dma_addr = sg_dma_address(sg); + dma_len = sg_dma_len(sg); + } + + return total_len; +} + +/* NVMe scatterlists require no holes in the virtual address */ +#define BIOVEC_NOT_VIRT_MERGEABLE(vec1, vec2) ((vec2)->bv_offset || \ + (((vec1)->bv_offset + (vec1)->bv_len) % PAGE_SIZE)) + +static int nvme_map_bio(struct device *dev, struct nvme_iod *iod, + struct bio *bio, enum dma_data_direction dma_dir, int psegs) +{ + struct bio_vec *bvec, *bvprv = NULL; + struct scatterlist *sg = NULL; + int i, old_idx, length = 0, nsegs = 0; + + sg_init_table(iod->sg, psegs); + old_idx = bio->bi_idx; + bio_for_each_segment(bvec, bio, i) { + if (bvprv && BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) { + sg->length += bvec->bv_len; + } else { + if (bvprv && BIOVEC_NOT_VIRT_MERGEABLE(bvprv, bvec)) + break; + sg = sg ? sg + 1 : iod->sg; + sg_set_page(sg, bvec->bv_page, bvec->bv_len, + bvec->bv_offset); + nsegs++; + } + length += bvec->bv_len; + bvprv = bvec; + } + bio->bi_idx = i; + iod->nents = nsegs; + sg_mark_end(sg); + if (dma_map_sg(dev, iod->sg, iod->nents, dma_dir) == 0) { + bio->bi_idx = old_idx; + return -ENOMEM; + } + return length; +} + +static int nvme_submit_flush(struct nvme_queue *nvmeq, struct nvme_ns *ns, + int cmdid) +{ + struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; + + memset(cmnd, 0, sizeof(*cmnd)); + cmnd->common.opcode = nvme_cmd_flush; + cmnd->common.command_id = cmdid; + cmnd->common.nsid = cpu_to_le32(ns->ns_id); + + if (++nvmeq->sq_tail == nvmeq->q_depth) + nvmeq->sq_tail = 0; + writel(nvmeq->sq_tail, nvmeq->q_db); + + return 0; +} + +static int nvme_submit_flush_data(struct nvme_queue *nvmeq, struct nvme_ns *ns) +{ + int cmdid = alloc_cmdid(nvmeq, (void *)CMD_CTX_FLUSH, + special_completion, NVME_IO_TIMEOUT); + if (unlikely(cmdid < 0)) + return cmdid; + + return nvme_submit_flush(nvmeq, ns, cmdid); +} + +/* + * Called with local interrupts disabled and the q_lock held. May not sleep. + */ +static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, + struct bio *bio) +{ + struct nvme_command *cmnd; + struct nvme_iod *iod; + enum dma_data_direction dma_dir; + int cmdid, length, result = -ENOMEM; + u16 control; + u32 dsmgmt; + int psegs = bio_phys_segments(ns->queue, bio); + + if ((bio->bi_rw & REQ_FLUSH) && psegs) { + result = nvme_submit_flush_data(nvmeq, ns); + if (result) + return result; + } + + iod = nvme_alloc_iod(psegs, bio->bi_size, GFP_ATOMIC); + if (!iod) + goto nomem; + iod->private = bio; + + result = -EBUSY; + cmdid = alloc_cmdid(nvmeq, iod, bio_completion, NVME_IO_TIMEOUT); + if (unlikely(cmdid < 0)) + goto free_iod; + + if ((bio->bi_rw & REQ_FLUSH) && !psegs) + return nvme_submit_flush(nvmeq, ns, cmdid); + + control = 0; + if (bio->bi_rw & REQ_FUA) + control |= NVME_RW_FUA; + if (bio->bi_rw & (REQ_FAILFAST_DEV | REQ_RAHEAD)) + control |= NVME_RW_LR; + + dsmgmt = 0; + if (bio->bi_rw & REQ_RAHEAD) + dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH; + + cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; + + memset(cmnd, 0, sizeof(*cmnd)); + if (bio_data_dir(bio)) { + cmnd->rw.opcode = nvme_cmd_write; + dma_dir = DMA_TO_DEVICE; + } else { + cmnd->rw.opcode = nvme_cmd_read; + dma_dir = DMA_FROM_DEVICE; + } + + result = nvme_map_bio(nvmeq->q_dmadev, iod, bio, dma_dir, psegs); + if (result < 0) + goto free_iod; + length = result; + + cmnd->rw.command_id = cmdid; + cmnd->rw.nsid = cpu_to_le32(ns->ns_id); + length = nvme_setup_prps(nvmeq->dev, &cmnd->common, iod, length, + GFP_ATOMIC); + cmnd->rw.slba = cpu_to_le64(bio->bi_sector >> (ns->lba_shift - 9)); + cmnd->rw.length = cpu_to_le16((length >> ns->lba_shift) - 1); + cmnd->rw.control = cpu_to_le16(control); + cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt); + + bio->bi_sector += length >> 9; + + if (++nvmeq->sq_tail == nvmeq->q_depth) + nvmeq->sq_tail = 0; + writel(nvmeq->sq_tail, nvmeq->q_db); + + return 0; + + free_iod: + nvme_free_iod(nvmeq->dev, iod); + nomem: + return result; +} + +static void nvme_make_request(struct request_queue *q, struct bio *bio) +{ + struct nvme_ns *ns = q->queuedata; + struct nvme_queue *nvmeq = get_nvmeq(ns->dev); + int result = -EBUSY; + + spin_lock_irq(&nvmeq->q_lock); + if (bio_list_empty(&nvmeq->sq_cong)) + result = nvme_submit_bio_queue(nvmeq, ns, bio); + if (unlikely(result)) { + if (bio_list_empty(&nvmeq->sq_cong)) + add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait); + bio_list_add(&nvmeq->sq_cong, bio); + } + + spin_unlock_irq(&nvmeq->q_lock); + put_nvmeq(nvmeq); +} + +static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq) +{ + u16 head, phase; + + head = nvmeq->cq_head; + phase = nvmeq->cq_phase; + + for (;;) { + void *ctx; + nvme_completion_fn fn; + struct nvme_completion cqe = nvmeq->cqes[head]; + if ((le16_to_cpu(cqe.status) & 1) != phase) + break; + nvmeq->sq_head = le16_to_cpu(cqe.sq_head); + if (++head == nvmeq->q_depth) { + head = 0; + phase = !phase; + } + + ctx = free_cmdid(nvmeq, cqe.command_id, &fn); + fn(nvmeq->dev, ctx, &cqe); + } + + /* If the controller ignores the cq head doorbell and continuously + * writes to the queue, it is theoretically possible to wrap around + * the queue twice and mistakenly return IRQ_NONE. Linux only + * requires that 0.1% of your interrupts are handled, so this isn't + * a big problem. + */ + if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) + return IRQ_NONE; + + writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride)); + nvmeq->cq_head = head; + nvmeq->cq_phase = phase; + + return IRQ_HANDLED; +} + +static irqreturn_t nvme_irq(int irq, void *data) +{ + irqreturn_t result; + struct nvme_queue *nvmeq = data; + spin_lock(&nvmeq->q_lock); + result = nvme_process_cq(nvmeq); + spin_unlock(&nvmeq->q_lock); + return result; +} + +static irqreturn_t nvme_irq_check(int irq, void *data) +{ + struct nvme_queue *nvmeq = data; + struct nvme_completion cqe = nvmeq->cqes[nvmeq->cq_head]; + if ((le16_to_cpu(cqe.status) & 1) != nvmeq->cq_phase) + return IRQ_NONE; + return IRQ_WAKE_THREAD; +} + +static void nvme_abort_command(struct nvme_queue *nvmeq, int cmdid) +{ + spin_lock_irq(&nvmeq->q_lock); + cancel_cmdid(nvmeq, cmdid, NULL); + spin_unlock_irq(&nvmeq->q_lock); +} + +struct sync_cmd_info { + struct task_struct *task; + u32 result; + int status; +}; + +static void sync_completion(struct nvme_dev *dev, void *ctx, + struct nvme_completion *cqe) +{ + struct sync_cmd_info *cmdinfo = ctx; + cmdinfo->result = le32_to_cpup(&cqe->result); + cmdinfo->status = le16_to_cpup(&cqe->status) >> 1; + wake_up_process(cmdinfo->task); +} + +/* + * Returns 0 on success. If the result is negative, it's a Linux error code; + * if the result is positive, it's an NVM Express status code + */ +static int nvme_submit_sync_cmd(struct nvme_queue *nvmeq, + struct nvme_command *cmd, u32 *result, unsigned timeout) +{ + int cmdid; + struct sync_cmd_info cmdinfo; + + cmdinfo.task = current; + cmdinfo.status = -EINTR; + + cmdid = alloc_cmdid_killable(nvmeq, &cmdinfo, sync_completion, + timeout); + if (cmdid < 0) + return cmdid; + cmd->common.command_id = cmdid; + + set_current_state(TASK_KILLABLE); + nvme_submit_cmd(nvmeq, cmd); + schedule(); + + if (cmdinfo.status == -EINTR) { + nvme_abort_command(nvmeq, cmdid); + return -EINTR; + } + + if (result) + *result = cmdinfo.result; + + return cmdinfo.status; +} + +static int nvme_submit_admin_cmd(struct nvme_dev *dev, struct nvme_command *cmd, + u32 *result) +{ + return nvme_submit_sync_cmd(dev->queues[0], cmd, result, ADMIN_TIMEOUT); +} + +static int adapter_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id) +{ + int status; + struct nvme_command c; + + memset(&c, 0, sizeof(c)); + c.delete_queue.opcode = opcode; + c.delete_queue.qid = cpu_to_le16(id); + + status = nvme_submit_admin_cmd(dev, &c, NULL); + if (status) + return -EIO; + return 0; +} + +static int adapter_alloc_cq(struct nvme_dev *dev, u16 qid, + struct nvme_queue *nvmeq) +{ + int status; + struct nvme_command c; + int flags = NVME_QUEUE_PHYS_CONTIG | NVME_CQ_IRQ_ENABLED; + + memset(&c, 0, sizeof(c)); + c.create_cq.opcode = nvme_admin_create_cq; + c.create_cq.prp1 = cpu_to_le64(nvmeq->cq_dma_addr); + c.create_cq.cqid = cpu_to_le16(qid); + c.create_cq.qsize = cpu_to_le16(nvmeq->q_depth - 1); + c.create_cq.cq_flags = cpu_to_le16(flags); + c.create_cq.irq_vector = cpu_to_le16(nvmeq->cq_vector); + + status = nvme_submit_admin_cmd(dev, &c, NULL); + if (status) + return -EIO; + return 0; +} + +static int adapter_alloc_sq(struct nvme_dev *dev, u16 qid, + struct nvme_queue *nvmeq) +{ + int status; + struct nvme_command c; + int flags = NVME_QUEUE_PHYS_CONTIG | NVME_SQ_PRIO_MEDIUM; + + memset(&c, 0, sizeof(c)); + c.create_sq.opcode = nvme_admin_create_sq; + c.create_sq.prp1 = cpu_to_le64(nvmeq->sq_dma_addr); + c.create_sq.sqid = cpu_to_le16(qid); + c.create_sq.qsize = cpu_to_le16(nvmeq->q_depth - 1); + c.create_sq.sq_flags = cpu_to_le16(flags); + c.create_sq.cqid = cpu_to_le16(qid); + + status = nvme_submit_admin_cmd(dev, &c, NULL); + if (status) + return -EIO; + return 0; +} + +static int adapter_delete_cq(struct nvme_dev *dev, u16 cqid) +{ + return adapter_delete_queue(dev, nvme_admin_delete_cq, cqid); +} + +static int adapter_delete_sq(struct nvme_dev *dev, u16 sqid) +{ + return adapter_delete_queue(dev, nvme_admin_delete_sq, sqid); +} + +static int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns, + dma_addr_t dma_addr) +{ + struct nvme_command c; + + memset(&c, 0, sizeof(c)); + c.identify.opcode = nvme_admin_identify; + c.identify.nsid = cpu_to_le32(nsid); + c.identify.prp1 = cpu_to_le64(dma_addr); + c.identify.cns = cpu_to_le32(cns); + + return nvme_submit_admin_cmd(dev, &c, NULL); +} + +static int nvme_get_features(struct nvme_dev *dev, unsigned fid, + unsigned dword11, dma_addr_t dma_addr) +{ + struct nvme_command c; + + memset(&c, 0, sizeof(c)); + c.features.opcode = nvme_admin_get_features; + c.features.prp1 = cpu_to_le64(dma_addr); + c.features.fid = cpu_to_le32(fid); + c.features.dword11 = cpu_to_le32(dword11); + + return nvme_submit_admin_cmd(dev, &c, NULL); +} + +static int nvme_set_features(struct nvme_dev *dev, unsigned fid, + unsigned dword11, dma_addr_t dma_addr, u32 *result) +{ + struct nvme_command c; + + memset(&c, 0, sizeof(c)); + c.features.opcode = nvme_admin_set_features; + c.features.prp1 = cpu_to_le64(dma_addr); + c.features.fid = cpu_to_le32(fid); + c.features.dword11 = cpu_to_le32(dword11); + + return nvme_submit_admin_cmd(dev, &c, result); +} + +static void nvme_free_queue(struct nvme_dev *dev, int qid) +{ + struct nvme_queue *nvmeq = dev->queues[qid]; + int vector = dev->entry[nvmeq->cq_vector].vector; + + irq_set_affinity_hint(vector, NULL); + free_irq(vector, nvmeq); + + /* Don't tell the adapter to delete the admin queue */ + if (qid) { + adapter_delete_sq(dev, qid); + adapter_delete_cq(dev, qid); + } + + dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), + (void *)nvmeq->cqes, nvmeq->cq_dma_addr); + dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), + nvmeq->sq_cmds, nvmeq->sq_dma_addr); + kfree(nvmeq); +} + +static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, + int depth, int vector) +{ + struct device *dmadev = &dev->pci_dev->dev; + unsigned extra = (depth / 8) + (depth * sizeof(struct nvme_cmd_info)); + struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL); + if (!nvmeq) + return NULL; + + nvmeq->cqes = dma_alloc_coherent(dmadev, CQ_SIZE(depth), + &nvmeq->cq_dma_addr, GFP_KERNEL); + if (!nvmeq->cqes) + goto free_nvmeq; + memset((void *)nvmeq->cqes, 0, CQ_SIZE(depth)); + + nvmeq->sq_cmds = dma_alloc_coherent(dmadev, SQ_SIZE(depth), + &nvmeq->sq_dma_addr, GFP_KERNEL); + if (!nvmeq->sq_cmds) + goto free_cqdma; + + nvmeq->q_dmadev = dmadev; + nvmeq->dev = dev; + spin_lock_init(&nvmeq->q_lock); + nvmeq->cq_head = 0; + nvmeq->cq_phase = 1; + init_waitqueue_head(&nvmeq->sq_full); + init_waitqueue_entry(&nvmeq->sq_cong_wait, nvme_thread); + bio_list_init(&nvmeq->sq_cong); + nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; + nvmeq->q_depth = depth; + nvmeq->cq_vector = vector; + + return nvmeq; + + free_cqdma: + dma_free_coherent(dmadev, CQ_SIZE(nvmeq->q_depth), (void *)nvmeq->cqes, + nvmeq->cq_dma_addr); + free_nvmeq: + kfree(nvmeq); + return NULL; +} + +static int queue_request_irq(struct nvme_dev *dev, struct nvme_queue *nvmeq, + const char *name) +{ + if (use_threaded_interrupts) + return request_threaded_irq(dev->entry[nvmeq->cq_vector].vector, + nvme_irq_check, nvme_irq, + IRQF_DISABLED | IRQF_SHARED, + name, nvmeq); + return request_irq(dev->entry[nvmeq->cq_vector].vector, nvme_irq, + IRQF_DISABLED | IRQF_SHARED, name, nvmeq); +} + +static __devinit struct nvme_queue *nvme_create_queue(struct nvme_dev *dev, + int qid, int cq_size, int vector) +{ + int result; + struct nvme_queue *nvmeq = nvme_alloc_queue(dev, qid, cq_size, vector); + + if (!nvmeq) + return ERR_PTR(-ENOMEM); + + result = adapter_alloc_cq(dev, qid, nvmeq); + if (result < 0) + goto free_nvmeq; + + result = adapter_alloc_sq(dev, qid, nvmeq); + if (result < 0) + goto release_cq; + + result = queue_request_irq(dev, nvmeq, "nvme"); + if (result < 0) + goto release_sq; + + return nvmeq; + + release_sq: + adapter_delete_sq(dev, qid); + release_cq: + adapter_delete_cq(dev, qid); + free_nvmeq: + dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), + (void *)nvmeq->cqes, nvmeq->cq_dma_addr); + dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), + nvmeq->sq_cmds, nvmeq->sq_dma_addr); + kfree(nvmeq); + return ERR_PTR(result); +} + +static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev) +{ + int result; + u32 aqa; + u64 cap; + unsigned long timeout; + struct nvme_queue *nvmeq; + + dev->dbs = ((void __iomem *)dev->bar) + 4096; + + nvmeq = nvme_alloc_queue(dev, 0, 64, 0); + if (!nvmeq) + return -ENOMEM; + + aqa = nvmeq->q_depth - 1; + aqa |= aqa << 16; + + dev->ctrl_config = NVME_CC_ENABLE | NVME_CC_CSS_NVM; + dev->ctrl_config |= (PAGE_SHIFT - 12) << NVME_CC_MPS_SHIFT; + dev->ctrl_config |= NVME_CC_ARB_RR | NVME_CC_SHN_NONE; + dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES; + + writel(0, &dev->bar->cc); + writel(aqa, &dev->bar->aqa); + writeq(nvmeq->sq_dma_addr, &dev->bar->asq); + writeq(nvmeq->cq_dma_addr, &dev->bar->acq); + writel(dev->ctrl_config, &dev->bar->cc); + + cap = readq(&dev->bar->cap); + timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies; + dev->db_stride = NVME_CAP_STRIDE(cap); + + while (!(readl(&dev->bar->csts) & NVME_CSTS_RDY)) { + msleep(100); + if (fatal_signal_pending(current)) + return -EINTR; + if (time_after(jiffies, timeout)) { + dev_err(&dev->pci_dev->dev, + "Device not ready; aborting initialisation\n"); + return -ENODEV; + } + } + + result = queue_request_irq(dev, nvmeq, "nvme admin"); + dev->queues[0] = nvmeq; + return result; +} + +static struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, + unsigned long addr, unsigned length) +{ + int i, err, count, nents, offset; + struct scatterlist *sg; + struct page **pages; + struct nvme_iod *iod; + + if (addr & 3) + return ERR_PTR(-EINVAL); + if (!length) + return ERR_PTR(-EINVAL); + + offset = offset_in_page(addr); + count = DIV_ROUND_UP(offset + length, PAGE_SIZE); + pages = kcalloc(count, sizeof(*pages), GFP_KERNEL); + + err = get_user_pages_fast(addr, count, 1, pages); + if (err < count) { + count = err; + err = -EFAULT; + goto put_pages; + } + + iod = nvme_alloc_iod(count, length, GFP_KERNEL); + sg = iod->sg; + sg_init_table(sg, count); + for (i = 0; i < count; i++) { + sg_set_page(&sg[i], pages[i], + min_t(int, length, PAGE_SIZE - offset), offset); + length -= (PAGE_SIZE - offset); + offset = 0; + } + sg_mark_end(&sg[i - 1]); + iod->nents = count; + + err = -ENOMEM; + nents = dma_map_sg(&dev->pci_dev->dev, sg, count, + write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (!nents) + goto free_iod; + + kfree(pages); + return iod; + + free_iod: + kfree(iod); + put_pages: + for (i = 0; i < count; i++) + put_page(pages[i]); + kfree(pages); + return ERR_PTR(err); +} + +static void nvme_unmap_user_pages(struct nvme_dev *dev, int write, + struct nvme_iod *iod) +{ + int i; + + dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents, + write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + + for (i = 0; i < iod->nents; i++) + put_page(sg_page(&iod->sg[i])); +} + +static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) +{ + struct nvme_dev *dev = ns->dev; + struct nvme_queue *nvmeq; + struct nvme_user_io io; + struct nvme_command c; + unsigned length; + int status; + struct nvme_iod *iod; + + if (copy_from_user(&io, uio, sizeof(io))) + return -EFAULT; + length = (io.nblocks + 1) << ns->lba_shift; + + switch (io.opcode) { + case nvme_cmd_write: + case nvme_cmd_read: + case nvme_cmd_compare: + iod = nvme_map_user_pages(dev, io.opcode & 1, io.addr, length); + break; + default: + return -EINVAL; + } + + if (IS_ERR(iod)) + return PTR_ERR(iod); + + memset(&c, 0, sizeof(c)); + c.rw.opcode = io.opcode; + c.rw.flags = io.flags; + c.rw.nsid = cpu_to_le32(ns->ns_id); + c.rw.slba = cpu_to_le64(io.slba); + c.rw.length = cpu_to_le16(io.nblocks); + c.rw.control = cpu_to_le16(io.control); + c.rw.dsmgmt = cpu_to_le16(io.dsmgmt); + c.rw.reftag = io.reftag; + c.rw.apptag = io.apptag; + c.rw.appmask = io.appmask; + /* XXX: metadata */ + length = nvme_setup_prps(dev, &c.common, iod, length, GFP_KERNEL); + + nvmeq = get_nvmeq(dev); + /* + * Since nvme_submit_sync_cmd sleeps, we can't keep preemption + * disabled. We may be preempted at any point, and be rescheduled + * to a different CPU. That will cause cacheline bouncing, but no + * additional races since q_lock already protects against other CPUs. + */ + put_nvmeq(nvmeq); + if (length != (io.nblocks + 1) << ns->lba_shift) + status = -ENOMEM; + else + status = nvme_submit_sync_cmd(nvmeq, &c, NULL, NVME_IO_TIMEOUT); + + nvme_unmap_user_pages(dev, io.opcode & 1, iod); + nvme_free_iod(dev, iod); + return status; +} + +static int nvme_user_admin_cmd(struct nvme_ns *ns, + struct nvme_admin_cmd __user *ucmd) +{ + struct nvme_dev *dev = ns->dev; + struct nvme_admin_cmd cmd; + struct nvme_command c; + int status, length; + struct nvme_iod *iod; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (copy_from_user(&cmd, ucmd, sizeof(cmd))) + return -EFAULT; + + memset(&c, 0, sizeof(c)); + c.common.opcode = cmd.opcode; + c.common.flags = cmd.flags; + c.common.nsid = cpu_to_le32(cmd.nsid); + c.common.cdw2[0] = cpu_to_le32(cmd.cdw2); + c.common.cdw2[1] = cpu_to_le32(cmd.cdw3); + c.common.cdw10[0] = cpu_to_le32(cmd.cdw10); + c.common.cdw10[1] = cpu_to_le32(cmd.cdw11); + c.common.cdw10[2] = cpu_to_le32(cmd.cdw12); + c.common.cdw10[3] = cpu_to_le32(cmd.cdw13); + c.common.cdw10[4] = cpu_to_le32(cmd.cdw14); + c.common.cdw10[5] = cpu_to_le32(cmd.cdw15); + + length = cmd.data_len; + if (cmd.data_len) { + iod = nvme_map_user_pages(dev, cmd.opcode & 1, cmd.addr, + length); + if (IS_ERR(iod)) + return PTR_ERR(iod); + length = nvme_setup_prps(dev, &c.common, iod, length, + GFP_KERNEL); + } + + if (length != cmd.data_len) + status = -ENOMEM; + else + status = nvme_submit_admin_cmd(dev, &c, NULL); + + if (cmd.data_len) { + nvme_unmap_user_pages(dev, cmd.opcode & 1, iod); + nvme_free_iod(dev, iod); + } + return status; +} + +static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, + unsigned long arg) +{ + struct nvme_ns *ns = bdev->bd_disk->private_data; + + switch (cmd) { + case NVME_IOCTL_ID: + return ns->ns_id; + case NVME_IOCTL_ADMIN_CMD: + return nvme_user_admin_cmd(ns, (void __user *)arg); + case NVME_IOCTL_SUBMIT_IO: + return nvme_submit_io(ns, (void __user *)arg); + default: + return -ENOTTY; + } +} + +static const struct block_device_operations nvme_fops = { + .owner = THIS_MODULE, + .ioctl = nvme_ioctl, + .compat_ioctl = nvme_ioctl, +}; + +static void nvme_timeout_ios(struct nvme_queue *nvmeq) +{ + int depth = nvmeq->q_depth - 1; + struct nvme_cmd_info *info = nvme_cmd_info(nvmeq); + unsigned long now = jiffies; + int cmdid; + + for_each_set_bit(cmdid, nvmeq->cmdid_data, depth) { + void *ctx; + nvme_completion_fn fn; + static struct nvme_completion cqe = { .status = cpu_to_le16(NVME_SC_ABORT_REQ) << 1, }; + + if (!time_after(now, info[cmdid].timeout)) + continue; + dev_warn(nvmeq->q_dmadev, "Timing out I/O %d\n", cmdid); + ctx = cancel_cmdid(nvmeq, cmdid, &fn); + fn(nvmeq->dev, ctx, &cqe); + } +} + +static void nvme_resubmit_bios(struct nvme_queue *nvmeq) +{ + while (bio_list_peek(&nvmeq->sq_cong)) { + struct bio *bio = bio_list_pop(&nvmeq->sq_cong); + struct nvme_ns *ns = bio->bi_bdev->bd_disk->private_data; + if (nvme_submit_bio_queue(nvmeq, ns, bio)) { + bio_list_add_head(&nvmeq->sq_cong, bio); + break; + } + if (bio_list_empty(&nvmeq->sq_cong)) + remove_wait_queue(&nvmeq->sq_full, + &nvmeq->sq_cong_wait); + } +} + +static int nvme_kthread(void *data) +{ + struct nvme_dev *dev; + + while (!kthread_should_stop()) { + __set_current_state(TASK_RUNNING); + spin_lock(&dev_list_lock); + list_for_each_entry(dev, &dev_list, node) { + int i; + for (i = 0; i < dev->queue_count; i++) { + struct nvme_queue *nvmeq = dev->queues[i]; + if (!nvmeq) + continue; + spin_lock_irq(&nvmeq->q_lock); + if (nvme_process_cq(nvmeq)) + printk("process_cq did something\n"); + nvme_timeout_ios(nvmeq); + nvme_resubmit_bios(nvmeq); + spin_unlock_irq(&nvmeq->q_lock); + } + } + spin_unlock(&dev_list_lock); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + } + return 0; +} + +static DEFINE_IDA(nvme_index_ida); + +static int nvme_get_ns_idx(void) +{ + int index, error; + + do { + if (!ida_pre_get(&nvme_index_ida, GFP_KERNEL)) + return -1; + + spin_lock(&dev_list_lock); + error = ida_get_new(&nvme_index_ida, &index); + spin_unlock(&dev_list_lock); + } while (error == -EAGAIN); + + if (error) + index = -1; + return index; +} + +static void nvme_put_ns_idx(int index) +{ + spin_lock(&dev_list_lock); + ida_remove(&nvme_index_ida, index); + spin_unlock(&dev_list_lock); +} + +static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int nsid, + struct nvme_id_ns *id, struct nvme_lba_range_type *rt) +{ + struct nvme_ns *ns; + struct gendisk *disk; + int lbaf; + + if (rt->attributes & NVME_LBART_ATTRIB_HIDE) + return NULL; + + ns = kzalloc(sizeof(*ns), GFP_KERNEL); + if (!ns) + return NULL; + ns->queue = blk_alloc_queue(GFP_KERNEL); + if (!ns->queue) + goto out_free_ns; + ns->queue->queue_flags = QUEUE_FLAG_DEFAULT; + queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, ns->queue); + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, ns->queue); +/* queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue); */ + blk_queue_make_request(ns->queue, nvme_make_request); + ns->dev = dev; + ns->queue->queuedata = ns; + + disk = alloc_disk(NVME_MINORS); + if (!disk) + goto out_free_queue; + ns->ns_id = nsid; + ns->disk = disk; + lbaf = id->flbas & 0xf; + ns->lba_shift = id->lbaf[lbaf].ds; + + disk->major = nvme_major; + disk->minors = NVME_MINORS; + disk->first_minor = NVME_MINORS * nvme_get_ns_idx(); + disk->fops = &nvme_fops; + disk->private_data = ns; + disk->queue = ns->queue; + disk->driverfs_dev = &dev->pci_dev->dev; + sprintf(disk->disk_name, "nvme%dn%d", dev->instance, nsid); + set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9)); + + return ns; + + out_free_queue: + blk_cleanup_queue(ns->queue); + out_free_ns: + kfree(ns); + return NULL; +} + +static void nvme_ns_free(struct nvme_ns *ns) +{ + int index = ns->disk->first_minor / NVME_MINORS; + put_disk(ns->disk); + nvme_put_ns_idx(index); + blk_cleanup_queue(ns->queue); + kfree(ns); +} + +static int set_queue_count(struct nvme_dev *dev, int count) +{ + int status; + u32 result; + u32 q_count = (count - 1) | ((count - 1) << 16); + + status = nvme_set_features(dev, NVME_FEAT_NUM_QUEUES, q_count, 0, + &result); + if (status) + return -EIO; + return min(result & 0xffff, result >> 16) + 1; +} + +static int __devinit nvme_setup_io_queues(struct nvme_dev *dev) +{ + int result, cpu, i, nr_io_queues, db_bar_size; + + nr_io_queues = num_online_cpus(); + result = set_queue_count(dev, nr_io_queues); + if (result < 0) + return result; + if (result < nr_io_queues) + nr_io_queues = result; + + /* Deregister the admin queue's interrupt */ + free_irq(dev->entry[0].vector, dev->queues[0]); + + db_bar_size = 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); + if (db_bar_size > 8192) { + iounmap(dev->bar); + dev->bar = ioremap(pci_resource_start(dev->pci_dev, 0), + db_bar_size); + dev->dbs = ((void __iomem *)dev->bar) + 4096; + dev->queues[0]->q_db = dev->dbs; + } + + for (i = 0; i < nr_io_queues; i++) + dev->entry[i].entry = i; + for (;;) { + result = pci_enable_msix(dev->pci_dev, dev->entry, + nr_io_queues); + if (result == 0) { + break; + } else if (result > 0) { + nr_io_queues = result; + continue; + } else { + nr_io_queues = 1; + break; + } + } + + result = queue_request_irq(dev, dev->queues[0], "nvme admin"); + /* XXX: handle failure here */ + + cpu = cpumask_first(cpu_online_mask); + for (i = 0; i < nr_io_queues; i++) { + irq_set_affinity_hint(dev->entry[i].vector, get_cpu_mask(cpu)); + cpu = cpumask_next(cpu, cpu_online_mask); + } + + for (i = 0; i < nr_io_queues; i++) { + dev->queues[i + 1] = nvme_create_queue(dev, i + 1, + NVME_Q_DEPTH, i); + if (IS_ERR(dev->queues[i + 1])) + return PTR_ERR(dev->queues[i + 1]); + dev->queue_count++; + } + + for (; i < num_possible_cpus(); i++) { + int target = i % rounddown_pow_of_two(dev->queue_count - 1); + dev->queues[i + 1] = dev->queues[target + 1]; + } + + return 0; +} + +static void nvme_free_queues(struct nvme_dev *dev) +{ + int i; + + for (i = dev->queue_count - 1; i >= 0; i--) + nvme_free_queue(dev, i); +} + +static int __devinit nvme_dev_add(struct nvme_dev *dev) +{ + int res, nn, i; + struct nvme_ns *ns, *next; + struct nvme_id_ctrl *ctrl; + struct nvme_id_ns *id_ns; + void *mem; + dma_addr_t dma_addr; + + res = nvme_setup_io_queues(dev); + if (res) + return res; + + mem = dma_alloc_coherent(&dev->pci_dev->dev, 8192, &dma_addr, + GFP_KERNEL); + + res = nvme_identify(dev, 0, 1, dma_addr); + if (res) { + res = -EIO; + goto out_free; + } + + ctrl = mem; + nn = le32_to_cpup(&ctrl->nn); + memcpy(dev->serial, ctrl->sn, sizeof(ctrl->sn)); + memcpy(dev->model, ctrl->mn, sizeof(ctrl->mn)); + memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr)); + + id_ns = mem; + for (i = 1; i <= nn; i++) { + res = nvme_identify(dev, i, 0, dma_addr); + if (res) + continue; + + if (id_ns->ncap == 0) + continue; + + res = nvme_get_features(dev, NVME_FEAT_LBA_RANGE, i, + dma_addr + 4096); + if (res) + continue; + + ns = nvme_alloc_ns(dev, i, mem, mem + 4096); + if (ns) + list_add_tail(&ns->list, &dev->namespaces); + } + list_for_each_entry(ns, &dev->namespaces, list) + add_disk(ns->disk); + + goto out; + + out_free: + list_for_each_entry_safe(ns, next, &dev->namespaces, list) { + list_del(&ns->list); + nvme_ns_free(ns); + } + + out: + dma_free_coherent(&dev->pci_dev->dev, 8192, mem, dma_addr); + return res; +} + +static int nvme_dev_remove(struct nvme_dev *dev) +{ + struct nvme_ns *ns, *next; + + spin_lock(&dev_list_lock); + list_del(&dev->node); + spin_unlock(&dev_list_lock); + + /* TODO: wait all I/O finished or cancel them */ + + list_for_each_entry_safe(ns, next, &dev->namespaces, list) { + list_del(&ns->list); + del_gendisk(ns->disk); + nvme_ns_free(ns); + } + + nvme_free_queues(dev); + + return 0; +} + +static int nvme_setup_prp_pools(struct nvme_dev *dev) +{ + struct device *dmadev = &dev->pci_dev->dev; + dev->prp_page_pool = dma_pool_create("prp list page", dmadev, + PAGE_SIZE, PAGE_SIZE, 0); + if (!dev->prp_page_pool) + return -ENOMEM; + + /* Optimisation for I/Os between 4k and 128k */ + dev->prp_small_pool = dma_pool_create("prp list 256", dmadev, + 256, 256, 0); + if (!dev->prp_small_pool) { + dma_pool_destroy(dev->prp_page_pool); + return -ENOMEM; + } + return 0; +} + +static void nvme_release_prp_pools(struct nvme_dev *dev) +{ + dma_pool_destroy(dev->prp_page_pool); + dma_pool_destroy(dev->prp_small_pool); +} + +/* XXX: Use an ida or something to let remove / add work correctly */ +static void nvme_set_instance(struct nvme_dev *dev) +{ + static int instance; + dev->instance = instance++; +} + +static void nvme_release_instance(struct nvme_dev *dev) +{ +} + +static int __devinit nvme_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int bars, result = -ENOMEM; + struct nvme_dev *dev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + dev->entry = kcalloc(num_possible_cpus(), sizeof(*dev->entry), + GFP_KERNEL); + if (!dev->entry) + goto free; + dev->queues = kcalloc(num_possible_cpus() + 1, sizeof(void *), + GFP_KERNEL); + if (!dev->queues) + goto free; + + if (pci_enable_device_mem(pdev)) + goto free; + pci_set_master(pdev); + bars = pci_select_bars(pdev, IORESOURCE_MEM); + if (pci_request_selected_regions(pdev, bars, "nvme")) + goto disable; + + INIT_LIST_HEAD(&dev->namespaces); + dev->pci_dev = pdev; + pci_set_drvdata(pdev, dev); + dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); + nvme_set_instance(dev); + dev->entry[0].vector = pdev->irq; + + result = nvme_setup_prp_pools(dev); + if (result) + goto disable_msix; + + dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); + if (!dev->bar) { + result = -ENOMEM; + goto disable_msix; + } + + result = nvme_configure_admin_queue(dev); + if (result) + goto unmap; + dev->queue_count++; + + spin_lock(&dev_list_lock); + list_add(&dev->node, &dev_list); + spin_unlock(&dev_list_lock); + + result = nvme_dev_add(dev); + if (result) + goto delete; + + return 0; + + delete: + spin_lock(&dev_list_lock); + list_del(&dev->node); + spin_unlock(&dev_list_lock); + + nvme_free_queues(dev); + unmap: + iounmap(dev->bar); + disable_msix: + pci_disable_msix(pdev); + nvme_release_instance(dev); + nvme_release_prp_pools(dev); + disable: + pci_disable_device(pdev); + pci_release_regions(pdev); + free: + kfree(dev->queues); + kfree(dev->entry); + kfree(dev); + return result; +} + +static void __devexit nvme_remove(struct pci_dev *pdev) +{ + struct nvme_dev *dev = pci_get_drvdata(pdev); + nvme_dev_remove(dev); + pci_disable_msix(pdev); + iounmap(dev->bar); + nvme_release_instance(dev); + nvme_release_prp_pools(dev); + pci_disable_device(pdev); + pci_release_regions(pdev); + kfree(dev->queues); + kfree(dev->entry); + kfree(dev); +} + +/* These functions are yet to be implemented */ +#define nvme_error_detected NULL +#define nvme_dump_registers NULL +#define nvme_link_reset NULL +#define nvme_slot_reset NULL +#define nvme_error_resume NULL +#define nvme_suspend NULL +#define nvme_resume NULL + +static struct pci_error_handlers nvme_err_handler = { + .error_detected = nvme_error_detected, + .mmio_enabled = nvme_dump_registers, + .link_reset = nvme_link_reset, + .slot_reset = nvme_slot_reset, + .resume = nvme_error_resume, +}; + +/* Move to pci_ids.h later */ +#define PCI_CLASS_STORAGE_EXPRESS 0x010802 + +static DEFINE_PCI_DEVICE_TABLE(nvme_id_table) = { + { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, nvme_id_table); + +static struct pci_driver nvme_driver = { + .name = "nvme", + .id_table = nvme_id_table, + .probe = nvme_probe, + .remove = __devexit_p(nvme_remove), + .suspend = nvme_suspend, + .resume = nvme_resume, + .err_handler = &nvme_err_handler, +}; + +static int __init nvme_init(void) +{ + int result = -EBUSY; + + nvme_thread = kthread_run(nvme_kthread, NULL, "nvme"); + if (IS_ERR(nvme_thread)) + return PTR_ERR(nvme_thread); + + nvme_major = register_blkdev(nvme_major, "nvme"); + if (nvme_major <= 0) + goto kill_kthread; + + result = pci_register_driver(&nvme_driver); + if (result) + goto unregister_blkdev; + return 0; + + unregister_blkdev: + unregister_blkdev(nvme_major, "nvme"); + kill_kthread: + kthread_stop(nvme_thread); + return result; +} + +static void __exit nvme_exit(void) +{ + pci_unregister_driver(&nvme_driver); + unregister_blkdev(nvme_major, "nvme"); + kthread_stop(nvme_thread); +} + +MODULE_AUTHOR("Matthew Wilcox <willy@linux.intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.8"); +module_init(nvme_init); +module_exit(nvme_exit); diff --git a/drivers/block/paride/bpck6.c b/drivers/block/paride/bpck6.c index ad124525ac23..ec64e7f5d1ce 100644 --- a/drivers/block/paride/bpck6.c +++ b/drivers/block/paride/bpck6.c @@ -20,9 +20,6 @@ */ -/* PARAMETERS */ -static int verbose; /* set this to 1 to see debugging messages and whatnot */ - #define BACKPACK_VERSION "2.0.2" #include <linux/module.h> @@ -36,6 +33,8 @@ static int verbose; /* set this to 1 to see debugging messages and whatnot */ #include "ppc6lnx.c" #include "paride.h" +/* PARAMETERS */ +static bool verbose; /* set this to 1 to see debugging messages and whatnot */ #define PPCSTRUCT(pi) ((Interface *)(pi->private)) diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 46b8136c31bb..ba2b6b5e5910 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -144,7 +144,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; static DEFINE_MUTEX(pcd_mutex); static DEFINE_SPINLOCK(pcd_lock); -module_param(verbose, bool, 0644); +module_param(verbose, int, 0644); module_param(major, int, 0); module_param(name, charp, 0); module_param(nice, int, 0); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 869e7676d46f..831e3ac156e6 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -124,8 +124,9 @@ by default. */ +#include <linux/types.h> -static int verbose = 0; +static bool verbose = 0; static int major = PD_MAJOR; static char *name = PD_NAME; static int cluster = 64; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index f21b520ef419..ec8f9ed6326e 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -118,13 +118,15 @@ #define PF_NAME "pf" #define PF_UNITS 4 +#include <linux/types.h> + /* Here are things one can override from the insmod command. Most are autoprobed by paride unless set here. Verbose is off by default. */ -static int verbose = 0; +static bool verbose = 0; static int major = PF_MAJOR; static char *name = PF_NAME; static int cluster = 64; diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index a79fb4f7ff62..4a27b1de5fcb 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -130,13 +130,14 @@ #define PI_PG 4 #endif +#include <linux/types.h> /* Here are things one can override from the insmod command. Most are autoprobed by paride unless set here. Verbose is 0 by default. */ -static int verbose = 0; +static bool verbose = 0; static int major = PG_MAJOR; static char *name = PG_NAME; static int disable = 0; diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 7179f79d7468..2596042eb987 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -109,13 +109,15 @@ #define PT_NAME "pt" #define PT_UNITS 4 +#include <linux/types.h> + /* Here are things one can override from the insmod command. Most are autoprobed by paride unless set here. Verbose is on by default. */ -static int verbose = 0; +static bool verbose = 0; static int major = PT_MAJOR; static char *name = PT_NAME; static int disable = 0; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 148ab944378d..3fd31dec8c9c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2184,6 +2184,8 @@ static ssize_t rbd_add(struct bus_type *bus, INIT_LIST_HEAD(&rbd_dev->node); INIT_LIST_HEAD(&rbd_dev->snaps); + init_rwsem(&rbd_dev->header.snap_rwsem); + /* generate unique id: find highest unique id, add one */ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index b70f0fca9a42..e7472f567c9d 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -619,8 +619,10 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx) host->state == HST_DEV_SCAN); spin_unlock_irq(&host->lock); - DPRINTK("blk_insert_request, tag == %u\n", idx); - blk_insert_request(host->oob_q, crq->rq, 1, crq); + DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx); + crq->rq->cmd_type = REQ_TYPE_SPECIAL; + crq->rq->special = crq; + blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL); return 0; @@ -658,8 +660,10 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func) BUG_ON(rc < 0); crq->msg_bucket = (u32) rc; - DPRINTK("blk_insert_request, tag == %u\n", idx); - blk_insert_request(host->oob_q, crq->rq, 1, crq); + DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx); + crq->rq->cmd_type = REQ_TYPE_SPECIAL; + crq->rq->special = crq; + blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL); return 0; } diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 0e376d46bdd1..7333b9e44411 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1744,12 +1744,11 @@ static int ub_bd_release(struct gendisk *disk, fmode_t mode) static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct gendisk *disk = bdev->bd_disk; void __user *usermem = (void __user *) arg; int ret; mutex_lock(&ub_mutex); - ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem); + ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem); mutex_unlock(&ub_mutex); return ret; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index ffd5ca919295..c4a60badf252 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -250,8 +250,8 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) return -ENOTTY; - return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, - (void __user *)data); + return scsi_cmd_blk_ioctl(bdev, mode, cmd, + (void __user *)data); } /* We provide getgeo only to please some old bootloader/partitioning tools */ diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 4abd2bcd20fb..51a972704db5 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -148,7 +148,7 @@ static volatile int xdc_busy; static struct timer_list xd_watchdog_int; static volatile u_char xd_error; -static int nodma = XD_DONT_USE_DMA; +static bool nodma = XD_DONT_USE_DMA; static struct request_queue *xd_queue; diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 15ec4db194d1..0088bf60f368 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -39,9 +39,6 @@ #include <linux/list.h> #include <linux/delay.h> #include <linux/freezer.h> -#include <linux/loop.h> -#include <linux/falloc.h> -#include <linux/fs.h> #include <xen/events.h> #include <xen/page.h> @@ -362,7 +359,7 @@ static int xen_blkbk_map(struct blkif_request *req, { struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST]; int i; - int nseg = req->nr_segments; + int nseg = req->u.rw.nr_segments; int ret = 0; /* @@ -416,30 +413,25 @@ static int xen_blkbk_map(struct blkif_request *req, return ret; } -static void xen_blk_discard(struct xen_blkif *blkif, struct blkif_request *req) +static int dispatch_discard_io(struct xen_blkif *blkif, + struct blkif_request *req) { int err = 0; int status = BLKIF_RSP_OKAY; struct block_device *bdev = blkif->vbd.bdev; - if (blkif->blk_backend_type == BLKIF_BACKEND_PHY) - /* just forward the discard request */ + blkif->st_ds_req++; + + xen_blkif_get(blkif); + if (blkif->blk_backend_type == BLKIF_BACKEND_PHY || + blkif->blk_backend_type == BLKIF_BACKEND_FILE) { + unsigned long secure = (blkif->vbd.discard_secure && + (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? + BLKDEV_DISCARD_SECURE : 0; err = blkdev_issue_discard(bdev, req->u.discard.sector_number, req->u.discard.nr_sectors, - GFP_KERNEL, 0); - else if (blkif->blk_backend_type == BLKIF_BACKEND_FILE) { - /* punch a hole in the backing file */ - struct loop_device *lo = bdev->bd_disk->private_data; - struct file *file = lo->lo_backing_file; - - if (file->f_op->fallocate) - err = file->f_op->fallocate(file, - FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, - req->u.discard.sector_number << 9, - req->u.discard.nr_sectors << 9); - else - err = -EOPNOTSUPP; + GFP_KERNEL, secure); } else err = -EOPNOTSUPP; @@ -449,7 +441,9 @@ static void xen_blk_discard(struct xen_blkif *blkif, struct blkif_request *req) } else if (err) status = BLKIF_RSP_ERROR; - make_response(blkif, req->id, req->operation, status); + make_response(blkif, req->u.discard.id, req->operation, status); + xen_blkif_put(blkif); + return err; } static void xen_blk_drain_io(struct xen_blkif *blkif) @@ -573,8 +567,11 @@ __do_block_io_op(struct xen_blkif *blkif) /* Apply all sanity checks to /private copy/ of request. */ barrier(); - - if (dispatch_rw_block_io(blkif, &req, pending_req)) + if (unlikely(req.operation == BLKIF_OP_DISCARD)) { + free_req(pending_req); + if (dispatch_discard_io(blkif, &req)) + break; + } else if (dispatch_rw_block_io(blkif, &req, pending_req)) break; /* Yield point for this unbounded loop. */ @@ -633,10 +630,6 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, blkif->st_f_req++; operation = WRITE_FLUSH; break; - case BLKIF_OP_DISCARD: - blkif->st_ds_req++; - operation = REQ_DISCARD; - break; default: operation = 0; /* make gcc happy */ goto fail_response; @@ -644,9 +637,9 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, } /* Check that the number of segments is sane. */ - nseg = req->nr_segments; - if (unlikely(nseg == 0 && operation != WRITE_FLUSH && - operation != REQ_DISCARD) || + nseg = req->u.rw.nr_segments; + + if (unlikely(nseg == 0 && operation != WRITE_FLUSH) || unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) { pr_debug(DRV_PFX "Bad number of segments in request (%d)\n", nseg); @@ -654,12 +647,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, goto fail_response; } - preq.dev = req->handle; + preq.dev = req->u.rw.handle; preq.sector_number = req->u.rw.sector_number; preq.nr_sects = 0; pending_req->blkif = blkif; - pending_req->id = req->id; + pending_req->id = req->u.rw.id; pending_req->operation = req->operation; pending_req->status = BLKIF_RSP_OKAY; pending_req->nr_pages = nseg; @@ -707,7 +700,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, * the hypercall to unmap the grants - that is all done in * xen_blkbk_unmap. */ - if (operation != REQ_DISCARD && xen_blkbk_map(req, pending_req, seg)) + if (xen_blkbk_map(req, pending_req, seg)) goto fail_flush; /* @@ -739,23 +732,16 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, /* This will be hit if the operation was a flush or discard. */ if (!bio) { - BUG_ON(operation != WRITE_FLUSH && operation != REQ_DISCARD); + BUG_ON(operation != WRITE_FLUSH); - if (operation == WRITE_FLUSH) { - bio = bio_alloc(GFP_KERNEL, 0); - if (unlikely(bio == NULL)) - goto fail_put_bio; + bio = bio_alloc(GFP_KERNEL, 0); + if (unlikely(bio == NULL)) + goto fail_put_bio; - biolist[nbio++] = bio; - bio->bi_bdev = preq.bdev; - bio->bi_private = pending_req; - bio->bi_end_io = end_block_io_op; - } else if (operation == REQ_DISCARD) { - xen_blk_discard(blkif, req); - xen_blkif_put(blkif); - free_req(pending_req); - return 0; - } + biolist[nbio++] = bio; + bio->bi_bdev = preq.bdev; + bio->bi_private = pending_req; + bio->bi_end_io = end_block_io_op; } /* @@ -784,7 +770,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, xen_blkbk_unmap(pending_req); fail_response: /* Haven't submitted any bio's yet. */ - make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); + make_response(blkif, req->u.rw.id, req->operation, BLKIF_RSP_ERROR); free_req(pending_req); msleep(1); /* back off a bit */ return -EIO; diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index dfb1b3a43a5d..d0ee7edc9be8 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -60,58 +60,66 @@ struct blkif_common_response { char dummy; }; -/* i386 protocol version */ -#pragma pack(push, 4) - struct blkif_x86_32_request_rw { + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ + uint64_t id; /* private guest value, echoed in resp */ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; -}; +} __attribute__((__packed__)); struct blkif_x86_32_request_discard { + uint8_t flag; /* BLKIF_DISCARD_SECURE or zero */ + blkif_vdev_t _pad1; /* was "handle" for read/write requests */ + uint64_t id; /* private guest value, echoed in resp */ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ - uint64_t nr_sectors; -}; + uint64_t nr_sectors; +} __attribute__((__packed__)); struct blkif_x86_32_request { uint8_t operation; /* BLKIF_OP_??? */ - uint8_t nr_segments; /* number of segments */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t id; /* private guest value, echoed in resp */ union { struct blkif_x86_32_request_rw rw; struct blkif_x86_32_request_discard discard; } u; -}; +} __attribute__((__packed__)); + +/* i386 protocol version */ +#pragma pack(push, 4) struct blkif_x86_32_response { uint64_t id; /* copied from request */ uint8_t operation; /* copied from request */ int16_t status; /* BLKIF_RSP_??? */ }; #pragma pack(pop) - /* x86_64 protocol version */ struct blkif_x86_64_request_rw { + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ + uint32_t _pad1; /* offsetof(blkif_reqest..,u.rw.id)==8 */ + uint64_t id; blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; -}; +} __attribute__((__packed__)); struct blkif_x86_64_request_discard { + uint8_t flag; /* BLKIF_DISCARD_SECURE or zero */ + blkif_vdev_t _pad1; /* was "handle" for read/write requests */ + uint32_t _pad2; /* offsetof(blkif_..,u.discard.id)==8 */ + uint64_t id; blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ - uint64_t nr_sectors; -}; + uint64_t nr_sectors; +} __attribute__((__packed__)); struct blkif_x86_64_request { uint8_t operation; /* BLKIF_OP_??? */ - uint8_t nr_segments; /* number of segments */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t __attribute__((__aligned__(8))) id; union { struct blkif_x86_64_request_rw rw; struct blkif_x86_64_request_discard discard; } u; -}; +} __attribute__((__packed__)); + struct blkif_x86_64_response { uint64_t __attribute__((__aligned__(8))) id; uint8_t operation; /* copied from request */ @@ -156,6 +164,7 @@ struct xen_vbd { /* Cached size parameter. */ sector_t size; bool flush_support; + bool discard_secure; }; struct backend_info; @@ -237,22 +246,23 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst, { int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; dst->operation = src->operation; - dst->nr_segments = src->nr_segments; - dst->handle = src->handle; - dst->id = src->id; switch (src->operation) { case BLKIF_OP_READ: case BLKIF_OP_WRITE: case BLKIF_OP_WRITE_BARRIER: case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.nr_segments = src->u.rw.nr_segments; + dst->u.rw.handle = src->u.rw.handle; + dst->u.rw.id = src->u.rw.id; dst->u.rw.sector_number = src->u.rw.sector_number; barrier(); - if (n > dst->nr_segments) - n = dst->nr_segments; + if (n > dst->u.rw.nr_segments) + n = dst->u.rw.nr_segments; for (i = 0; i < n; i++) dst->u.rw.seg[i] = src->u.rw.seg[i]; break; case BLKIF_OP_DISCARD: + dst->u.discard.flag = src->u.discard.flag; dst->u.discard.sector_number = src->u.discard.sector_number; dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; @@ -266,22 +276,23 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst, { int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; dst->operation = src->operation; - dst->nr_segments = src->nr_segments; - dst->handle = src->handle; - dst->id = src->id; switch (src->operation) { case BLKIF_OP_READ: case BLKIF_OP_WRITE: case BLKIF_OP_WRITE_BARRIER: case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.nr_segments = src->u.rw.nr_segments; + dst->u.rw.handle = src->u.rw.handle; + dst->u.rw.id = src->u.rw.id; dst->u.rw.sector_number = src->u.rw.sector_number; barrier(); - if (n > dst->nr_segments) - n = dst->nr_segments; + if (n > dst->u.rw.nr_segments) + n = dst->u.rw.nr_segments; for (i = 0; i < n; i++) dst->u.rw.seg[i] = src->u.rw.seg[i]; break; case BLKIF_OP_DISCARD: + dst->u.discard.flag = src->u.discard.flag; dst->u.discard.sector_number = src->u.discard.sector_number; dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 37c794d31264..24a2fb57e5d0 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -338,6 +338,9 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle, if (q && q->flush_flags) vbd->flush_support = true; + if (q && blk_queue_secdiscard(q)) + vbd->discard_secure = true; + DPRINTK("Successful creation of handle=%04x (dom=%u)\n", handle, blkif->domid); return 0; @@ -420,6 +423,15 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) state = 1; blkif->blk_backend_type = BLKIF_BACKEND_PHY; } + /* Optional. */ + err = xenbus_printf(xbt, dev->nodename, + "discard-secure", "%d", + blkif->vbd.discard_secure); + if (err) { + xenbus_dev_fatal(dev, err, + "writting discard-secure"); + goto kfree; + } } } else { err = PTR_ERR(type); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 9fd3ee203b1e..2f22874c0a37 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -98,7 +98,8 @@ struct blkfront_info unsigned long shadow_free; unsigned int feature_flush; unsigned int flush_op; - unsigned int feature_discard; + unsigned int feature_discard:1; + unsigned int feature_secdiscard:1; unsigned int discard_granularity; unsigned int discard_alignment; int is_ready; @@ -135,15 +136,15 @@ static int get_id_from_freelist(struct blkfront_info *info) { unsigned long free = info->shadow_free; BUG_ON(free >= BLK_RING_SIZE); - info->shadow_free = info->shadow[free].req.id; - info->shadow[free].req.id = 0x0fffffee; /* debug */ + info->shadow_free = info->shadow[free].req.u.rw.id; + info->shadow[free].req.u.rw.id = 0x0fffffee; /* debug */ return free; } static void add_id_to_freelist(struct blkfront_info *info, unsigned long id) { - info->shadow[id].req.id = info->shadow_free; + info->shadow[id].req.u.rw.id = info->shadow_free; info->shadow[id].request = NULL; info->shadow_free = id; } @@ -156,7 +157,7 @@ static int xlbd_reserve_minors(unsigned int minor, unsigned int nr) if (end > nr_minors) { unsigned long *bitmap, *old; - bitmap = kzalloc(BITS_TO_LONGS(end) * sizeof(*bitmap), + bitmap = kcalloc(BITS_TO_LONGS(end), sizeof(*bitmap), GFP_KERNEL); if (bitmap == NULL) return -ENOMEM; @@ -287,9 +288,9 @@ static int blkif_queue_request(struct request *req) id = get_id_from_freelist(info); info->shadow[id].request = req; - ring_req->id = id; + ring_req->u.rw.id = id; ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req); - ring_req->handle = info->handle; + ring_req->u.rw.handle = info->handle; ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE : BLKIF_OP_READ; @@ -305,16 +306,21 @@ static int blkif_queue_request(struct request *req) ring_req->operation = info->flush_op; } - if (unlikely(req->cmd_flags & REQ_DISCARD)) { + if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) { /* id, sector_number and handle are set above. */ ring_req->operation = BLKIF_OP_DISCARD; - ring_req->nr_segments = 0; ring_req->u.discard.nr_sectors = blk_rq_sectors(req); + if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard) + ring_req->u.discard.flag = BLKIF_DISCARD_SECURE; + else + ring_req->u.discard.flag = 0; } else { - ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); - BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); + ring_req->u.rw.nr_segments = blk_rq_map_sg(req->q, req, + info->sg); + BUG_ON(ring_req->u.rw.nr_segments > + BLKIF_MAX_SEGMENTS_PER_REQUEST); - for_each_sg(info->sg, sg, ring_req->nr_segments, i) { + for_each_sg(info->sg, sg, ring_req->u.rw.nr_segments, i) { buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg))); fsect = sg->offset >> 9; lsect = fsect + (sg->length >> 9) - 1; @@ -424,6 +430,8 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) blk_queue_max_discard_sectors(rq, get_capacity(gd)); rq->limits.discard_granularity = info->discard_granularity; rq->limits.discard_alignment = info->discard_alignment; + if (info->feature_secdiscard) + queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, rq); } /* Hard sector size and max sectors impersonate the equiv. hardware. */ @@ -705,7 +713,9 @@ static void blkif_free(struct blkfront_info *info, int suspend) static void blkif_completion(struct blk_shadow *s) { int i; - for (i = 0; i < s->req.nr_segments; i++) + /* Do not let BLKIF_OP_DISCARD as nr_segment is in the same place + * flag. */ + for (i = 0; i < s->req.u.rw.nr_segments; i++) gnttab_end_foreign_access(s->req.u.rw.seg[i].gref, 0, 0UL); } @@ -736,7 +746,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) id = bret->id; req = info->shadow[id].request; - blkif_completion(&info->shadow[id]); + if (bret->operation != BLKIF_OP_DISCARD) + blkif_completion(&info->shadow[id]); add_id_to_freelist(info, id); @@ -749,7 +760,9 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) info->gd->disk_name); error = -EOPNOTSUPP; info->feature_discard = 0; + info->feature_secdiscard = 0; queue_flag_clear(QUEUE_FLAG_DISCARD, rq); + queue_flag_clear(QUEUE_FLAG_SECDISCARD, rq); } __blk_end_request_all(req, error); break; @@ -763,7 +776,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) error = -EOPNOTSUPP; } if (unlikely(bret->status == BLKIF_RSP_ERROR && - info->shadow[id].req.nr_segments == 0)) { + info->shadow[id].req.u.rw.nr_segments == 0)) { printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n", info->flush_op == BLKIF_OP_WRITE_BARRIER ? "barrier" : "flush disk cache", @@ -984,8 +997,8 @@ static int blkfront_probe(struct xenbus_device *dev, INIT_WORK(&info->work, blkif_restart_queue); for (i = 0; i < BLK_RING_SIZE; i++) - info->shadow[i].req.id = i+1; - info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + info->shadow[i].req.u.rw.id = i+1; + info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff; /* Front end dir is a number, which is used as the id. */ info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0); @@ -1019,9 +1032,9 @@ static int blkif_recover(struct blkfront_info *info) /* Stage 2: Set up free list. */ memset(&info->shadow, 0, sizeof(info->shadow)); for (i = 0; i < BLK_RING_SIZE; i++) - info->shadow[i].req.id = i+1; + info->shadow[i].req.u.rw.id = i+1; info->shadow_free = info->ring.req_prod_pvt; - info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff; /* Stage 3: Find pending requests and requeue them. */ for (i = 0; i < BLK_RING_SIZE; i++) { @@ -1034,17 +1047,19 @@ static int blkif_recover(struct blkfront_info *info) *req = copy[i].req; /* We get a new request id, and must reset the shadow state. */ - req->id = get_id_from_freelist(info); - memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); + req->u.rw.id = get_id_from_freelist(info); + memcpy(&info->shadow[req->u.rw.id], ©[i], sizeof(copy[i])); + if (req->operation != BLKIF_OP_DISCARD) { /* Rewrite any grant references invalidated by susp/resume. */ - for (j = 0; j < req->nr_segments; j++) - gnttab_grant_foreign_access_ref( - req->u.rw.seg[j].gref, - info->xbdev->otherend_id, - pfn_to_mfn(info->shadow[req->id].frame[j]), - rq_data_dir(info->shadow[req->id].request)); - info->shadow[req->id].req = *req; + for (j = 0; j < req->u.rw.nr_segments; j++) + gnttab_grant_foreign_access_ref( + req->u.rw.seg[j].gref, + info->xbdev->otherend_id, + pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]), + rq_data_dir(info->shadow[req->u.rw.id].request)); + } + info->shadow[req->u.rw.id].req = *req; info->ring.req_prod_pvt++; } @@ -1135,11 +1150,13 @@ static void blkfront_setup_discard(struct blkfront_info *info) char *type; unsigned int discard_granularity; unsigned int discard_alignment; + unsigned int discard_secure; type = xenbus_read(XBT_NIL, info->xbdev->otherend, "type", NULL); if (IS_ERR(type)) return; + info->feature_secdiscard = 0; if (strncmp(type, "phy", 3) == 0) { err = xenbus_gather(XBT_NIL, info->xbdev->otherend, "discard-granularity", "%u", &discard_granularity, @@ -1150,6 +1167,12 @@ static void blkfront_setup_discard(struct blkfront_info *info) info->discard_granularity = discard_granularity; info->discard_alignment = discard_alignment; } + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "discard-secure", "%d", &discard_secure, + NULL); + if (!err) + info->feature_secdiscard = discard_secure; + } else if (strncmp(type, "file", 4) == 0) info->feature_discard = 1; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 55ac349695c4..789c9b579aea 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -37,13 +37,13 @@ #define VERSION "0.6" -static int ignore_dga; -static int ignore_csr; -static int ignore_sniffer; -static int disable_scofix; -static int force_scofix; +static bool ignore_dga; +static bool ignore_csr; +static bool ignore_sniffer; +static bool disable_scofix; +static bool force_scofix; -static int reset = 1; +static bool reset = 1; static struct usb_driver btusb_driver; @@ -102,6 +102,7 @@ static struct usb_device_id btusb_table[] = { /* Broadcom BCM20702A0 */ { USB_DEVICE(0x0a5c, 0x21e3) }, + { USB_DEVICE(0x0a5c, 0x21f3) }, { USB_DEVICE(0x413c, 0x8197) }, { } /* Terminating entry */ @@ -726,9 +727,6 @@ static int btusb_send_frame(struct sk_buff *skb) usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len, btusb_tx_complete, skb); - if (skb->priority >= HCI_PRIO_MAX - 1) - urb->transfer_flags = URB_ISO_ASAP; - hdev->stat.acl_tx++; break; diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 9c5b2dc38e29..a767d4de45a4 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -49,8 +49,8 @@ #define VERSION "0.3" -static int txcrc = 1; -static int hciextn = 1; +static bool txcrc = 1; +static bool hciextn = 1; #define BCSP_TXWINSIZE 4 diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 48ad2a7ab080..07114489994f 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -48,7 +48,7 @@ #define VERSION "2.2" -static int reset = 0; +static bool reset = 0; static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 2118211aff99..55eaf474d32c 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -285,17 +285,17 @@ #include <asm/uaccess.h> /* used to tell the module to turn on full debugging messages */ -static int debug; +static bool debug; /* used to keep tray locked at all times */ static int keeplocked; /* default compatibility mode */ -static int autoclose=1; -static int autoeject; -static int lockdoor = 1; +static bool autoclose=1; +static bool autoeject; +static bool lockdoor = 1; /* will we ever get to use this... sigh. */ -static int check_media_type; +static bool check_media_type; /* automatically restart mrw format */ -static int mrw_format_restart = 1; +static bool mrw_format_restart = 1; module_param(debug, bool, 0); module_param(autoclose, bool, 0); module_param(autoeject, bool, 0); @@ -2746,12 +2746,11 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, { void __user *argp = (void __user *)arg; int ret; - struct gendisk *disk = bdev->bd_disk; /* * Try the generic SCSI command ioctl's first. */ - ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); + ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); if (ret != -ENOTTY) return ret; diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 780498d76581..444f8b6ab411 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -33,7 +33,7 @@ #define ULI_X86_64_ENU_SCR_REG 0x54 static struct resource *aperture_resource; -static int __initdata agp_try_unsupported = 1; +static bool __initdata agp_try_unsupported = 1; static int agp_bridges_found; static void amd64_tlbflush(struct agp_memory *temp) diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 29aacd81de78..08704ae53956 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -17,7 +17,7 @@ #define PCI_DEVICE_ID_SI_662 0x0662 #define PCI_DEVICE_ID_SI_671 0x0671 -static int __devinitdata agp_sis_force_delay = 0; +static bool __devinitdata agp_sis_force_delay = 0; static int __devinitdata agp_sis_agp_spec = -1; static int sis_fetch_size(void) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 6e40072fbf67..40cc0cf2ded6 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -69,19 +69,19 @@ MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); MODULE_LICENSE("GPL"); -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force loading without checking for supported models"); -static int ignore_dmi; +static bool ignore_dmi; module_param(ignore_dmi, bool, 0); MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match"); -static int restricted; +static bool restricted; module_param(restricted, bool, 0); MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); -static int power_status; +static bool power_status; module_param(power_status, bool, 0600); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 9397ab49b72e..50fcf9c04569 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1227,7 +1227,7 @@ static int smi_num; /* Used to sequence the SMIs */ #define DEFAULT_REGSPACING 1 #define DEFAULT_REGSIZE 1 -static int si_trydefaults = 1; +static bool si_trydefaults = 1; static char *si_type[SI_MAX_PARMS]; #define MAX_SI_TYPE_STR 30 static char si_type_str[MAX_SI_TYPE_STR]; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 97c3edb95ae7..f43485607063 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -829,7 +829,7 @@ static struct console lpcons = { static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; static char *parport[LP_NO]; -static int reset; +static bool reset; module_param_array(parport, charp, NULL, 0); module_param(reset, bool, 0); diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index a12f52400dbc..bf586ae1ee83 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -51,7 +51,7 @@ static int write_block(unsigned long p, const char __user *buf, int count); #define KFLASH_ID 0x89A6 //Intel flash #define KFLASH_ID4 0xB0D4 //Intel flash 4Meg -static int flashdebug; //if set - we will display progress msgs +static bool flashdebug; //if set - we will display progress msgs static int gbWriteEnable; static int gbWriteBase64Enable; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 15781396af25..07f6a5abe372 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -439,7 +439,7 @@ static int mgslpc_device_count = 0; * .text section address and breakpoint on module load. * This is useful for use with gdb and add-symbol-file command. */ -static int break_on_load=0; +static bool break_on_load=0; /* * Driver major number, defaults to zero to get auto diff --git a/drivers/char/random.c b/drivers/char/random.c index 85da8740586b..54ca8b23cde3 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -387,7 +387,7 @@ static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static struct fasync_struct *fasync; #if 0 -static int debug; +static bool debug; module_param(debug, bool, 0644); #define DEBUG_ENT(fmt, arg...) do { \ if (debug) \ @@ -965,6 +965,7 @@ EXPORT_SYMBOL(get_random_bytes); */ static void init_std_data(struct entropy_store *r) { + int i; ktime_t now; unsigned long flags; @@ -974,6 +975,11 @@ static void init_std_data(struct entropy_store *r) now = ktime_get_real(); mix_pool_bytes(r, &now, sizeof(now)); + for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof flags) { + if (!arch_get_random_long(&flags)) + break; + mix_pool_bytes(r, &flags, sizeof(flags)); + } mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); } diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 6a8771f47a55..32362cf35b8d 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -846,6 +846,15 @@ int tpm_do_selftest(struct tpm_chip *chip) do { rc = __tpm_pcr_read(chip, 0, digest); + if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { + dev_info(chip->dev, + "TPM is disabled/deactivated (0x%X)\n", rc); + /* TPM is disabled and/or deactivated; driver can + * proceed and TPM does handle commands for + * suspend/resume correctly + */ + return 0; + } if (rc != TPM_WARN_DOING_SELFTEST) return rc; msleep(delay_msec); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 8c1df302fbb6..010547138281 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -39,6 +39,9 @@ enum tpm_addr { }; #define TPM_WARN_DOING_SELFTEST 0x802 +#define TPM_ERR_DEACTIVATED 0x6 +#define TPM_ERR_DISABLED 0x7 + #define TPM_HEADER_SIZE 10 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, char *); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 10cc44ceb5d1..a1748621111b 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -255,7 +255,7 @@ out: return size; } -static int itpm; +static bool itpm; module_param(itpm, bool, 0444); MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)"); @@ -500,7 +500,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) return IRQ_HANDLED; } -static int interrupts = 1; +static bool interrupts = 1; module_param(interrupts, bool, 0444); MODULE_PARM_DESC(interrupts, "Enable interrupts"); @@ -828,7 +828,7 @@ static struct platform_driver tis_drv = { static struct platform_device *pdev; -static int force; +static bool force; module_param(force, bool, 0444); MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry"); static int __init init_tis(void) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 5a99bb3f255a..f1a274994bb1 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -124,7 +124,7 @@ config MV_XOR config MX3_IPU bool "MX3x Image Processing Unit support" - depends on SOC_IMX31 || SOC_IMX35 + depends on ARCH_MXC select DMA_ENGINE default y help @@ -187,6 +187,13 @@ config TIMB_DMA help Enable support for the Timberdale FPGA DMA engine. +config SIRF_DMA + tristate "CSR SiRFprimaII DMA support" + depends on ARCH_PRIMA2 + select DMA_ENGINE + help + Enable support for the CSR SiRFprimaII DMA engine. + config ARCH_HAS_ASYNC_TX_FIND_CHANNEL bool @@ -201,26 +208,26 @@ config PL330_DMA platform_data for a dma-pl330 device. config PCH_DMA - tristate "Intel EG20T PCH / OKI Semi IOH(ML7213/ML7223) DMA support" + tristate "Intel EG20T PCH / LAPIS Semicon IOH(ML7213/ML7223/ML7831) DMA" depends on PCI && X86 select DMA_ENGINE help Enable support for Intel EG20T PCH DMA engine. - This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7213 and ML7223. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is - for MP(Media Phone) use. - ML7213/ML7223 is companion chip for Intel Atom E6xx series. - ML7213/ML7223 is completely compatible for Intel EG20T PCH. + This driver also can be used for LAPIS Semiconductor IOH(Input/ + Output Hub), ML7213, ML7223 and ML7831. + ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is + for MP(Media Phone) use and ML7831 IOH is for general purpose use. + ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. config IMX_SDMA tristate "i.MX SDMA support" - depends on ARCH_MX25 || SOC_IMX31 || SOC_IMX35 || ARCH_MX5 + depends on ARCH_MXC select DMA_ENGINE help Support the i.MX SDMA engine. This engine is integrated into - Freescale i.MX25/31/35/51 chips. + Freescale i.MX25/31/35/51/53 chips. config IMX_DMA tristate "i.MX DMA support" diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 30cf3b1f0c5c..009a222e8283 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_IMX_SDMA) += imx-sdma.o obj-$(CONFIG_IMX_DMA) += imx-dma.o obj-$(CONFIG_MXS_DMA) += mxs-dma.o obj-$(CONFIG_TIMB_DMA) += timb_dma.o +obj-$(CONFIG_SIRF_DMA) += sirf-dma.o obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o obj-$(CONFIG_PL330_DMA) += pl330.o obj-$(CONFIG_PCH_DMA) += pch_dma.o diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 0698695e8bf9..8a281584458b 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -854,8 +854,10 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, int ret; /* Check if we already have a channel */ - if (plchan->phychan) - return 0; + if (plchan->phychan) { + ch = plchan->phychan; + goto got_channel; + } ch = pl08x_get_phy_channel(pl08x, plchan); if (!ch) { @@ -880,21 +882,22 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, return -EBUSY; } ch->signal = ret; - - /* Assign the flow control signal to this channel */ - if (txd->direction == DMA_TO_DEVICE) - txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT; - else if (txd->direction == DMA_FROM_DEVICE) - txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT; } + plchan->phychan = ch; dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n", ch->id, ch->signal, plchan->name); +got_channel: + /* Assign the flow control signal to this channel */ + if (txd->direction == DMA_MEM_TO_DEV) + txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT; + else if (txd->direction == DMA_DEV_TO_MEM) + txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT; + plchan->phychan_hold++; - plchan->phychan = ch; return 0; } @@ -1102,10 +1105,10 @@ static int dma_set_runtime_config(struct dma_chan *chan, /* Transfer direction */ plchan->runtime_direction = config->direction; - if (config->direction == DMA_TO_DEVICE) { + if (config->direction == DMA_MEM_TO_DEV) { addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; - } else if (config->direction == DMA_FROM_DEVICE) { + } else if (config->direction == DMA_DEV_TO_MEM) { addr_width = config->src_addr_width; maxburst = config->src_maxburst; } else { @@ -1136,7 +1139,7 @@ static int dma_set_runtime_config(struct dma_chan *chan, cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT; cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT; - if (plchan->runtime_direction == DMA_FROM_DEVICE) { + if (plchan->runtime_direction == DMA_DEV_TO_MEM) { plchan->src_addr = config->src_addr; plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR | pl08x_select_bus(plchan->cd->periph_buses, @@ -1152,7 +1155,7 @@ static int dma_set_runtime_config(struct dma_chan *chan, "configured channel %s (%s) for %s, data width %d, " "maxburst %d words, LE, CCTL=0x%08x\n", dma_chan_name(chan), plchan->name, - (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", + (config->direction == DMA_DEV_TO_MEM) ? "RX" : "TX", addr_width, maxburst, cctl); @@ -1322,7 +1325,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); @@ -1354,10 +1357,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( */ txd->direction = direction; - if (direction == DMA_TO_DEVICE) { + if (direction == DMA_MEM_TO_DEV) { txd->cctl = plchan->dst_cctl; slave_addr = plchan->dst_addr; - } else if (direction == DMA_FROM_DEVICE) { + } else if (direction == DMA_DEV_TO_MEM) { txd->cctl = plchan->src_cctl; slave_addr = plchan->src_addr; } else { @@ -1368,10 +1371,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( } if (plchan->cd->device_fc) - tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER_PER : + tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER : PL080_FLOW_PER2MEM_PER; else - tmp = (direction == DMA_TO_DEVICE) ? PL080_FLOW_MEM2PER : + tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER : PL080_FLOW_PER2MEM; txd->ccfg |= tmp << PL080_CONFIG_FLOW_CONTROL_SHIFT; @@ -1387,7 +1390,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( list_add_tail(&dsg->node, &txd->dsg_list); dsg->len = sg_dma_len(sg); - if (direction == DMA_TO_DEVICE) { + if (direction == DMA_MEM_TO_DEV) { dsg->src_addr = sg_phys(sg); dsg->dst_addr = slave_addr; } else { diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index fcfa0a8b5c59..97f87b29b9f3 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -23,6 +23,8 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_device.h> #include "at_hdmac_regs.h" @@ -660,7 +662,7 @@ err_desc_get: */ static struct dma_async_tx_descriptor * atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct at_dma_chan *atchan = to_at_dma_chan(chan); @@ -678,7 +680,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, dev_vdbg(chan2dev(chan), "prep_slave_sg (%d): %s f0x%lx\n", sg_len, - direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE", + direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE", flags); if (unlikely(!atslave || !sg_len)) { @@ -692,7 +694,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctrlb = ATC_IEN; switch (direction) { - case DMA_TO_DEVICE: + case DMA_MEM_TO_DEV: ctrla |= ATC_DST_WIDTH(reg_width); ctrlb |= ATC_DST_ADDR_MODE_FIXED | ATC_SRC_ADDR_MODE_INCR @@ -725,7 +727,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, total_len += len; } break; - case DMA_FROM_DEVICE: + case DMA_DEV_TO_MEM: ctrla |= ATC_SRC_WIDTH(reg_width); ctrlb |= ATC_DST_ADDR_MODE_INCR | ATC_SRC_ADDR_MODE_FIXED @@ -787,7 +789,7 @@ err_desc_get: */ static int atc_dma_cyclic_check_values(unsigned int reg_width, dma_addr_t buf_addr, - size_t period_len, enum dma_data_direction direction) + size_t period_len, enum dma_transfer_direction direction) { if (period_len > (ATC_BTSIZE_MAX << reg_width)) goto err_out; @@ -795,7 +797,7 @@ atc_dma_cyclic_check_values(unsigned int reg_width, dma_addr_t buf_addr, goto err_out; if (unlikely(buf_addr & ((1 << reg_width) - 1))) goto err_out; - if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE)))) + if (unlikely(!(direction & (DMA_DEV_TO_MEM | DMA_MEM_TO_DEV)))) goto err_out; return 0; @@ -810,7 +812,7 @@ err_out: static int atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc, unsigned int period_index, dma_addr_t buf_addr, - size_t period_len, enum dma_data_direction direction) + size_t period_len, enum dma_transfer_direction direction) { u32 ctrla; unsigned int reg_width = atslave->reg_width; @@ -822,7 +824,7 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc, | period_len >> reg_width; switch (direction) { - case DMA_TO_DEVICE: + case DMA_MEM_TO_DEV: desc->lli.saddr = buf_addr + (period_len * period_index); desc->lli.daddr = atslave->tx_reg; desc->lli.ctrla = ctrla; @@ -833,7 +835,7 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc, | ATC_DIF(AT_DMA_PER_IF); break; - case DMA_FROM_DEVICE: + case DMA_DEV_TO_MEM: desc->lli.saddr = atslave->rx_reg; desc->lli.daddr = buf_addr + (period_len * period_index); desc->lli.ctrla = ctrla; @@ -861,7 +863,7 @@ atc_dma_cyclic_fill_desc(struct at_dma_slave *atslave, struct at_desc *desc, */ static struct dma_async_tx_descriptor * atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_data_direction direction) + size_t period_len, enum dma_transfer_direction direction) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma_slave *atslave = chan->private; @@ -872,7 +874,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, unsigned int i; dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n", - direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE", + direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE", buf_addr, periods, buf_len, period_len); @@ -1175,6 +1177,56 @@ static void atc_free_chan_resources(struct dma_chan *chan) /*-- Module Management -----------------------------------------------*/ +/* cap_mask is a multi-u32 bitfield, fill it with proper C code. */ +static struct at_dma_platform_data at91sam9rl_config = { + .nr_channels = 2, +}; +static struct at_dma_platform_data at91sam9g45_config = { + .nr_channels = 8, +}; + +#if defined(CONFIG_OF) +static const struct of_device_id atmel_dma_dt_ids[] = { + { + .compatible = "atmel,at91sam9rl-dma", + .data = &at91sam9rl_config, + }, { + .compatible = "atmel,at91sam9g45-dma", + .data = &at91sam9g45_config, + }, { + /* sentinel */ + } +}; + +MODULE_DEVICE_TABLE(of, atmel_dma_dt_ids); +#endif + +static const struct platform_device_id atdma_devtypes[] = { + { + .name = "at91sam9rl_dma", + .driver_data = (unsigned long) &at91sam9rl_config, + }, { + .name = "at91sam9g45_dma", + .driver_data = (unsigned long) &at91sam9g45_config, + }, { + /* sentinel */ + } +}; + +static inline struct at_dma_platform_data * __init at_dma_get_driver_data( + struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(atmel_dma_dt_ids, pdev->dev.of_node); + if (match == NULL) + return NULL; + return match->data; + } + return (struct at_dma_platform_data *) + platform_get_device_id(pdev)->driver_data; +} + /** * at_dma_off - disable DMA controller * @atdma: the Atmel HDAMC device @@ -1193,18 +1245,23 @@ static void at_dma_off(struct at_dma *atdma) static int __init at_dma_probe(struct platform_device *pdev) { - struct at_dma_platform_data *pdata; struct resource *io; struct at_dma *atdma; size_t size; int irq; int err; int i; + struct at_dma_platform_data *plat_dat; - /* get DMA Controller parameters from platform */ - pdata = pdev->dev.platform_data; - if (!pdata || pdata->nr_channels > AT_DMA_MAX_NR_CHANNELS) - return -EINVAL; + /* setup platform data for each SoC */ + dma_cap_set(DMA_MEMCPY, at91sam9rl_config.cap_mask); + dma_cap_set(DMA_MEMCPY, at91sam9g45_config.cap_mask); + dma_cap_set(DMA_SLAVE, at91sam9g45_config.cap_mask); + + /* get DMA parameters from controller type */ + plat_dat = at_dma_get_driver_data(pdev); + if (!plat_dat) + return -ENODEV; io = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!io) @@ -1215,14 +1272,14 @@ static int __init at_dma_probe(struct platform_device *pdev) return irq; size = sizeof(struct at_dma); - size += pdata->nr_channels * sizeof(struct at_dma_chan); + size += plat_dat->nr_channels * sizeof(struct at_dma_chan); atdma = kzalloc(size, GFP_KERNEL); if (!atdma) return -ENOMEM; - /* discover transaction capabilites from the platform data */ - atdma->dma_common.cap_mask = pdata->cap_mask; - atdma->all_chan_mask = (1 << pdata->nr_channels) - 1; + /* discover transaction capabilities */ + atdma->dma_common.cap_mask = plat_dat->cap_mask; + atdma->all_chan_mask = (1 << plat_dat->nr_channels) - 1; size = resource_size(io); if (!request_mem_region(io->start, size, pdev->dev.driver->name)) { @@ -1268,7 +1325,7 @@ static int __init at_dma_probe(struct platform_device *pdev) /* initialize channels related values */ INIT_LIST_HEAD(&atdma->dma_common.channels); - for (i = 0; i < pdata->nr_channels; i++) { + for (i = 0; i < plat_dat->nr_channels; i++) { struct at_dma_chan *atchan = &atdma->chan[i]; atchan->chan_common.device = &atdma->dma_common; @@ -1313,7 +1370,7 @@ static int __init at_dma_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s), %d channels\n", dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "", dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ? "slave " : "", - pdata->nr_channels); + plat_dat->nr_channels); dma_async_device_register(&atdma->dma_common); @@ -1495,9 +1552,11 @@ static const struct dev_pm_ops at_dma_dev_pm_ops = { static struct platform_driver at_dma_driver = { .remove = __exit_p(at_dma_remove), .shutdown = at_dma_shutdown, + .id_table = atdma_devtypes, .driver = { .name = "at_hdmac", .pm = &at_dma_dev_pm_ops, + .of_match_table = of_match_ptr(atmel_dma_dt_ids), }, }; diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index aa4c9aebab7c..dcaedfc181cf 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -251,6 +251,7 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan) /** * struct at_dma - internal representation of an Atmel HDMA Controller * @chan_common: common dmaengine dma_device object members + * @atdma_devtype: identifier of DMA controller compatibility * @ch_regs: memory mapped register base * @clk: dma controller clock * @save_imr: interrupt mask register that is saved on suspend/resume cycle diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 4234f416ef11..d65a718c0f9b 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -39,7 +39,7 @@ struct coh901318_desc { struct scatterlist *sg; unsigned int sg_len; struct coh901318_lli *lli; - enum dma_data_direction dir; + enum dma_transfer_direction dir; unsigned long flags; u32 head_config; u32 head_ctrl; @@ -1034,7 +1034,7 @@ coh901318_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, static struct dma_async_tx_descriptor * coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct coh901318_chan *cohc = to_coh901318_chan(chan); @@ -1077,7 +1077,7 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctrl_last |= cohc->runtime_ctrl; ctrl |= cohc->runtime_ctrl; - if (direction == DMA_TO_DEVICE) { + if (direction == DMA_MEM_TO_DEV) { u32 tx_flags = COH901318_CX_CTRL_PRDD_SOURCE | COH901318_CX_CTRL_SRC_ADDR_INC_ENABLE; @@ -1085,7 +1085,7 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctrl_chained |= tx_flags; ctrl_last |= tx_flags; ctrl |= tx_flags; - } else if (direction == DMA_FROM_DEVICE) { + } else if (direction == DMA_DEV_TO_MEM) { u32 rx_flags = COH901318_CX_CTRL_PRDD_DEST | COH901318_CX_CTRL_DST_ADDR_INC_ENABLE; @@ -1274,11 +1274,11 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan, int i = 0; /* We only support mem to per or per to mem transfers */ - if (config->direction == DMA_FROM_DEVICE) { + if (config->direction == DMA_DEV_TO_MEM) { addr = config->src_addr; addr_width = config->src_addr_width; maxburst = config->src_maxburst; - } else if (config->direction == DMA_TO_DEVICE) { + } else if (config->direction == DMA_MEM_TO_DEV) { addr = config->dst_addr; addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; diff --git a/drivers/dma/coh901318_lli.c b/drivers/dma/coh901318_lli.c index 9f7e0e6a7eea..6c0e2d4c6682 100644 --- a/drivers/dma/coh901318_lli.c +++ b/drivers/dma/coh901318_lli.c @@ -7,11 +7,10 @@ * Author: Per Friden <per.friden@stericsson.com> */ -#include <linux/dma-mapping.h> #include <linux/spinlock.h> -#include <linux/dmapool.h> #include <linux/memory.h> #include <linux/gfp.h> +#include <linux/dmapool.h> #include <mach/coh901318.h> #include "coh901318_lli.h" @@ -177,18 +176,18 @@ coh901318_lli_fill_single(struct coh901318_pool *pool, struct coh901318_lli *lli, dma_addr_t buf, unsigned int size, dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl_eom, - enum dma_data_direction dir) + enum dma_transfer_direction dir) { int s = size; dma_addr_t src; dma_addr_t dst; - if (dir == DMA_TO_DEVICE) { + if (dir == DMA_MEM_TO_DEV) { src = buf; dst = dev_addr; - } else if (dir == DMA_FROM_DEVICE) { + } else if (dir == DMA_DEV_TO_MEM) { src = dev_addr; dst = buf; @@ -215,9 +214,9 @@ coh901318_lli_fill_single(struct coh901318_pool *pool, lli = coh901318_lli_next(lli); - if (dir == DMA_TO_DEVICE) + if (dir == DMA_MEM_TO_DEV) src += block_size; - else if (dir == DMA_FROM_DEVICE) + else if (dir == DMA_DEV_TO_MEM) dst += block_size; } @@ -234,7 +233,7 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool, struct scatterlist *sgl, unsigned int nents, dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl, u32 ctrl_last, - enum dma_data_direction dir, u32 ctrl_irq_mask) + enum dma_transfer_direction dir, u32 ctrl_irq_mask) { int i; struct scatterlist *sg; @@ -249,9 +248,9 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool, spin_lock(&pool->lock); - if (dir == DMA_TO_DEVICE) + if (dir == DMA_MEM_TO_DEV) dst = dev_addr; - else if (dir == DMA_FROM_DEVICE) + else if (dir == DMA_DEV_TO_MEM) src = dev_addr; else goto err; @@ -269,7 +268,7 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool, ctrl_sg = ctrl ? ctrl : ctrl_last; - if (dir == DMA_TO_DEVICE) + if (dir == DMA_MEM_TO_DEV) /* increment source address */ src = sg_phys(sg); else @@ -293,7 +292,7 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool, lli->src_addr = src; lli->dst_addr = dst; - if (dir == DMA_FROM_DEVICE) + if (dir == DMA_DEV_TO_MEM) dst += elem_size; else src += elem_size; diff --git a/drivers/dma/coh901318_lli.h b/drivers/dma/coh901318_lli.h index 7a5c80990e9e..abff3714fdda 100644 --- a/drivers/dma/coh901318_lli.h +++ b/drivers/dma/coh901318_lli.h @@ -97,7 +97,7 @@ coh901318_lli_fill_single(struct coh901318_pool *pool, struct coh901318_lli *lli, dma_addr_t buf, unsigned int size, dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl_last, - enum dma_data_direction dir); + enum dma_transfer_direction dir); /** * coh901318_lli_fill_single() - Prepares the lli:s for dma scatter list transfer @@ -119,6 +119,6 @@ coh901318_lli_fill_sg(struct coh901318_pool *pool, struct scatterlist *sg, unsigned int nents, dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl, u32 ctrl_last, - enum dma_data_direction dir, u32 ctrl_irq_mask); + enum dma_transfer_direction dir, u32 ctrl_irq_mask); #endif /* COH901318_LLI_H */ diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index b48967b499da..a6c6051ec858 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -693,12 +693,12 @@ int dma_async_device_register(struct dma_device *device) !device->device_prep_dma_interrupt); BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) && !device->device_prep_dma_sg); - BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) && - !device->device_prep_slave_sg); BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) && !device->device_prep_dma_cyclic); BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) && !device->device_control); + BUG_ON(dma_has_cap(DMA_INTERLEAVE, device->cap_mask) && + !device->device_prep_interleaved_dma); BUG_ON(!device->device_alloc_chan_resources); BUG_ON(!device->device_free_chan_resources); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 9bfd6d360718..9b592b02b5f4 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -166,6 +166,38 @@ dwc_assign_cookie(struct dw_dma_chan *dwc, struct dw_desc *desc) return cookie; } +static void dwc_initialize(struct dw_dma_chan *dwc) +{ + struct dw_dma *dw = to_dw_dma(dwc->chan.device); + struct dw_dma_slave *dws = dwc->chan.private; + u32 cfghi = DWC_CFGH_FIFO_MODE; + u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); + + if (dwc->initialized == true) + return; + + if (dws) { + /* + * We need controller-specific data to set up slave + * transfers. + */ + BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev); + + cfghi = dws->cfg_hi; + cfglo |= dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK; + } + + channel_writel(dwc, CFG_LO, cfglo); + channel_writel(dwc, CFG_HI, cfghi); + + /* Enable interrupts */ + channel_set_bit(dw, MASK.XFER, dwc->mask); + channel_set_bit(dw, MASK.BLOCK, dwc->mask); + channel_set_bit(dw, MASK.ERROR, dwc->mask); + + dwc->initialized = true; +} + /*----------------------------------------------------------------------*/ /* Called with dwc->lock held and bh disabled */ @@ -189,6 +221,8 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) return; } + dwc_initialize(dwc); + channel_writel(dwc, LLP, first->txd.phys); channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN); @@ -696,7 +730,7 @@ err_desc_get: static struct dma_async_tx_descriptor * dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); @@ -720,7 +754,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, prev = first = NULL; switch (direction) { - case DMA_TO_DEVICE: + case DMA_MEM_TO_DEV: ctllo = (DWC_DEFAULT_CTLLO(chan->private) | DWC_CTLL_DST_WIDTH(reg_width) | DWC_CTLL_DST_FIX @@ -777,7 +811,7 @@ slave_sg_todev_fill_desc: goto slave_sg_todev_fill_desc; } break; - case DMA_FROM_DEVICE: + case DMA_DEV_TO_MEM: ctllo = (DWC_DEFAULT_CTLLO(chan->private) | DWC_CTLL_SRC_WIDTH(reg_width) | DWC_CTLL_DST_INC @@ -959,10 +993,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_dma *dw = to_dw_dma(chan->device); struct dw_desc *desc; - struct dw_dma_slave *dws; int i; - u32 cfghi; - u32 cfglo; unsigned long flags; dev_vdbg(chan2dev(chan), "alloc_chan_resources\n"); @@ -975,26 +1006,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) dwc->completed = chan->cookie = 1; - cfghi = DWC_CFGH_FIFO_MODE; - cfglo = 0; - - dws = chan->private; - if (dws) { - /* - * We need controller-specific data to set up slave - * transfers. - */ - BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev); - - cfghi = dws->cfg_hi; - cfglo = dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK; - } - - cfglo |= DWC_CFGL_CH_PRIOR(dwc->priority); - - channel_writel(dwc, CFG_LO, cfglo); - channel_writel(dwc, CFG_HI, cfghi); - /* * NOTE: some controllers may have additional features that we * need to initialize here, like "scatter-gather" (which @@ -1026,11 +1037,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) i = ++dwc->descs_allocated; } - /* Enable interrupts */ - channel_set_bit(dw, MASK.XFER, dwc->mask); - channel_set_bit(dw, MASK.BLOCK, dwc->mask); - channel_set_bit(dw, MASK.ERROR, dwc->mask); - spin_unlock_irqrestore(&dwc->lock, flags); dev_dbg(chan2dev(chan), @@ -1058,6 +1064,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) spin_lock_irqsave(&dwc->lock, flags); list_splice_init(&dwc->free_list, &list); dwc->descs_allocated = 0; + dwc->initialized = false; /* Disable interrupts */ channel_clear_bit(dw, MASK.XFER, dwc->mask); @@ -1165,7 +1172,7 @@ EXPORT_SYMBOL(dw_dma_cyclic_stop); */ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, - enum dma_data_direction direction) + enum dma_transfer_direction direction) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_cyclic_desc *cdesc; @@ -1206,7 +1213,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, goto out_err; if (unlikely(buf_addr & ((1 << reg_width) - 1))) goto out_err; - if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE)))) + if (unlikely(!(direction & (DMA_MEM_TO_DEV | DMA_DEV_TO_MEM)))) goto out_err; retval = ERR_PTR(-ENOMEM); @@ -1228,7 +1235,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, goto out_err_desc_get; switch (direction) { - case DMA_TO_DEVICE: + case DMA_MEM_TO_DEV: desc->lli.dar = dws->tx_reg; desc->lli.sar = buf_addr + (period_len * i); desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private) @@ -1239,7 +1246,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, | DWC_CTLL_FC(dws->fc) | DWC_CTLL_INT_EN); break; - case DMA_FROM_DEVICE: + case DMA_DEV_TO_MEM: desc->lli.dar = buf_addr + (period_len * i); desc->lli.sar = dws->rx_reg; desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private) @@ -1335,6 +1342,8 @@ EXPORT_SYMBOL(dw_dma_cyclic_free); static void dw_dma_off(struct dw_dma *dw) { + int i; + dma_writel(dw, CFG, 0); channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); @@ -1345,6 +1354,9 @@ static void dw_dma_off(struct dw_dma *dw) while (dma_readl(dw, CFG) & DW_CFG_DMA_EN) cpu_relax(); + + for (i = 0; i < dw->dma.chancnt; i++) + dw->chan[i].initialized = false; } static int __init dw_probe(struct platform_device *pdev) @@ -1533,6 +1545,7 @@ static int dw_suspend_noirq(struct device *dev) dw_dma_off(platform_get_drvdata(pdev)); clk_disable(dw->clk); + return 0; } diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index c3419518d701..5eef6946a367 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -140,6 +140,7 @@ struct dw_dma_chan { u8 mask; u8 priority; bool paused; + bool initialized; spinlock_t lock; diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index b47e2b803faf..59e7a965772b 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -246,6 +246,9 @@ static void ep93xx_dma_set_active(struct ep93xx_dma_chan *edmac, static struct ep93xx_dma_desc * ep93xx_dma_get_active(struct ep93xx_dma_chan *edmac) { + if (list_empty(&edmac->active)) + return NULL; + return list_first_entry(&edmac->active, struct ep93xx_dma_desc, node); } @@ -263,16 +266,22 @@ ep93xx_dma_get_active(struct ep93xx_dma_chan *edmac) */ static bool ep93xx_dma_advance_active(struct ep93xx_dma_chan *edmac) { + struct ep93xx_dma_desc *desc; + list_rotate_left(&edmac->active); if (test_bit(EP93XX_DMA_IS_CYCLIC, &edmac->flags)) return true; + desc = ep93xx_dma_get_active(edmac); + if (!desc) + return false; + /* * If txd.cookie is set it means that we are back in the first * descriptor in the chain and hence done with it. */ - return !ep93xx_dma_get_active(edmac)->txd.cookie; + return !desc->txd.cookie; } /* @@ -327,10 +336,16 @@ static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac) static void m2p_fill_desc(struct ep93xx_dma_chan *edmac) { - struct ep93xx_dma_desc *desc = ep93xx_dma_get_active(edmac); + struct ep93xx_dma_desc *desc; u32 bus_addr; - if (ep93xx_dma_chan_direction(&edmac->chan) == DMA_TO_DEVICE) + desc = ep93xx_dma_get_active(edmac); + if (!desc) { + dev_warn(chan2dev(edmac), "M2P: empty descriptor list\n"); + return; + } + + if (ep93xx_dma_chan_direction(&edmac->chan) == DMA_MEM_TO_DEV) bus_addr = desc->src_addr; else bus_addr = desc->dst_addr; @@ -443,7 +458,7 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) control = (5 << M2M_CONTROL_PWSC_SHIFT); control |= M2M_CONTROL_NO_HDSK; - if (data->direction == DMA_TO_DEVICE) { + if (data->direction == DMA_MEM_TO_DEV) { control |= M2M_CONTROL_DAH; control |= M2M_CONTROL_TM_TX; control |= M2M_CONTROL_RSS_SSPTX; @@ -459,11 +474,7 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) * This IDE part is totally untested. Values below are taken * from the EP93xx Users's Guide and might not be correct. */ - control |= M2M_CONTROL_NO_HDSK; - control |= M2M_CONTROL_RSS_IDE; - control |= M2M_CONTROL_PW_16; - - if (data->direction == DMA_TO_DEVICE) { + if (data->direction == DMA_MEM_TO_DEV) { /* Worst case from the UG */ control = (3 << M2M_CONTROL_PWSC_SHIFT); control |= M2M_CONTROL_DAH; @@ -473,6 +484,10 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) control |= M2M_CONTROL_SAH; control |= M2M_CONTROL_TM_RX; } + + control |= M2M_CONTROL_NO_HDSK; + control |= M2M_CONTROL_RSS_IDE; + control |= M2M_CONTROL_PW_16; break; default: @@ -491,7 +506,13 @@ static void m2m_hw_shutdown(struct ep93xx_dma_chan *edmac) static void m2m_fill_desc(struct ep93xx_dma_chan *edmac) { - struct ep93xx_dma_desc *desc = ep93xx_dma_get_active(edmac); + struct ep93xx_dma_desc *desc; + + desc = ep93xx_dma_get_active(edmac); + if (!desc) { + dev_warn(chan2dev(edmac), "M2M: empty descriptor list\n"); + return; + } if (edmac->buffer == 0) { writel(desc->src_addr, edmac->regs + M2M_SAR_BASE0); @@ -669,24 +690,30 @@ static void ep93xx_dma_tasklet(unsigned long data) { struct ep93xx_dma_chan *edmac = (struct ep93xx_dma_chan *)data; struct ep93xx_dma_desc *desc, *d; - dma_async_tx_callback callback; - void *callback_param; + dma_async_tx_callback callback = NULL; + void *callback_param = NULL; LIST_HEAD(list); spin_lock_irq(&edmac->lock); + /* + * If dma_terminate_all() was called before we get to run, the active + * list has become empty. If that happens we aren't supposed to do + * anything more than call ep93xx_dma_advance_work(). + */ desc = ep93xx_dma_get_active(edmac); - if (desc->complete) { - edmac->last_completed = desc->txd.cookie; - list_splice_init(&edmac->active, &list); + if (desc) { + if (desc->complete) { + edmac->last_completed = desc->txd.cookie; + list_splice_init(&edmac->active, &list); + } + callback = desc->txd.callback; + callback_param = desc->txd.callback_param; } spin_unlock_irq(&edmac->lock); /* Pick up the next descriptor from the queue */ ep93xx_dma_advance_work(edmac); - callback = desc->txd.callback; - callback_param = desc->txd.callback_param; - /* Now we can release all the chained descriptors */ list_for_each_entry_safe(desc, d, &list, node) { /* @@ -706,13 +733,22 @@ static void ep93xx_dma_tasklet(unsigned long data) static irqreturn_t ep93xx_dma_interrupt(int irq, void *dev_id) { struct ep93xx_dma_chan *edmac = dev_id; + struct ep93xx_dma_desc *desc; irqreturn_t ret = IRQ_HANDLED; spin_lock(&edmac->lock); + desc = ep93xx_dma_get_active(edmac); + if (!desc) { + dev_warn(chan2dev(edmac), + "got interrupt while active list is empty\n"); + spin_unlock(&edmac->lock); + return IRQ_NONE; + } + switch (edmac->edma->hw_interrupt(edmac)) { case INTERRUPT_DONE: - ep93xx_dma_get_active(edmac)->complete = true; + desc->complete = true; tasklet_schedule(&edmac->tasklet); break; @@ -803,8 +839,8 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan) switch (data->port) { case EP93XX_DMA_SSP: case EP93XX_DMA_IDE: - if (data->direction != DMA_TO_DEVICE && - data->direction != DMA_FROM_DEVICE) + if (data->direction != DMA_MEM_TO_DEV && + data->direction != DMA_DEV_TO_MEM) return -EINVAL; break; default: @@ -952,7 +988,7 @@ fail: */ static struct dma_async_tx_descriptor * ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction dir, + unsigned int sg_len, enum dma_transfer_direction dir, unsigned long flags) { struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan); @@ -988,7 +1024,7 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, goto fail; } - if (dir == DMA_TO_DEVICE) { + if (dir == DMA_MEM_TO_DEV) { desc->src_addr = sg_dma_address(sg); desc->dst_addr = edmac->runtime_addr; } else { @@ -1032,7 +1068,7 @@ fail: static struct dma_async_tx_descriptor * ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, - enum dma_data_direction dir) + enum dma_transfer_direction dir) { struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan); struct ep93xx_dma_desc *desc, *first; @@ -1065,7 +1101,7 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, goto fail; } - if (dir == DMA_TO_DEVICE) { + if (dir == DMA_MEM_TO_DEV) { desc->src_addr = dma_addr + offset; desc->dst_addr = edmac->runtime_addr; } else { @@ -1133,12 +1169,12 @@ static int ep93xx_dma_slave_config(struct ep93xx_dma_chan *edmac, return -EINVAL; switch (config->direction) { - case DMA_FROM_DEVICE: + case DMA_DEV_TO_MEM: width = config->src_addr_width; addr = config->src_addr; break; - case DMA_TO_DEVICE: + case DMA_MEM_TO_DEV: width = config->dst_addr_width; addr = config->dst_addr; break; diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 8a781540590c..b98070c33ca9 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -772,7 +772,7 @@ fail: */ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg( struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len, - enum dma_data_direction direction, unsigned long flags) + enum dma_transfer_direction direction, unsigned long flags) { /* * This operation is not supported on the Freescale DMA controller @@ -819,7 +819,7 @@ static int fsl_dma_device_control(struct dma_chan *dchan, return -ENXIO; /* we set the controller burst size depending on direction */ - if (config->direction == DMA_TO_DEVICE) + if (config->direction == DMA_MEM_TO_DEV) size = config->dst_addr_width * config->dst_maxburst; else size = config->src_addr_width * config->src_maxburst; diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 4be55f9bb6c1..e4383ee2c9ac 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -107,7 +107,7 @@ static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, imx_dma_disable(imxdmac->imxdma_channel); return 0; case DMA_SLAVE_CONFIG: - if (dmaengine_cfg->direction == DMA_FROM_DEVICE) { + if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { imxdmac->per_address = dmaengine_cfg->src_addr; imxdmac->watermark_level = dmaengine_cfg->src_maxburst; imxdmac->word_size = dmaengine_cfg->src_addr_width; @@ -224,7 +224,7 @@ static void imxdma_free_chan_resources(struct dma_chan *chan) static struct dma_async_tx_descriptor *imxdma_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct imxdma_channel *imxdmac = to_imxdma_chan(chan); @@ -241,7 +241,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg( dma_length += sg->length; } - if (direction == DMA_FROM_DEVICE) + if (direction == DMA_DEV_TO_MEM) dmamode = DMA_MODE_READ; else dmamode = DMA_MODE_WRITE; @@ -271,7 +271,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg( static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, - size_t period_len, enum dma_data_direction direction) + size_t period_len, enum dma_transfer_direction direction) { struct imxdma_channel *imxdmac = to_imxdma_chan(chan); struct imxdma_engine *imxdma = imxdmac->imxdma; @@ -317,7 +317,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic( imxdmac->sg_list[periods].page_link = ((unsigned long)imxdmac->sg_list | 0x01) & ~0x02; - if (direction == DMA_FROM_DEVICE) + if (direction == DMA_DEV_TO_MEM) dmamode = DMA_MODE_READ; else dmamode = DMA_MODE_WRITE; diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f993955a640c..a8af379680c1 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -247,7 +247,7 @@ struct sdma_engine; struct sdma_channel { struct sdma_engine *sdma; unsigned int channel; - enum dma_data_direction direction; + enum dma_transfer_direction direction; enum sdma_peripheral_type peripheral_type; unsigned int event_id0; unsigned int event_id1; @@ -268,6 +268,8 @@ struct sdma_channel { struct dma_async_tx_descriptor desc; dma_cookie_t last_completed; enum dma_status status; + unsigned int chn_count; + unsigned int chn_real_count; }; #define IMX_DMA_SG_LOOP (1 << 0) @@ -503,6 +505,7 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) struct sdma_buffer_descriptor *bd; int i, error = 0; + sdmac->chn_real_count = 0; /* * non loop mode. Iterate over all descriptors, collect * errors and call callback function @@ -512,6 +515,7 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) if (bd->mode.status & (BD_DONE | BD_RROR)) error = -EIO; + sdmac->chn_real_count += bd->mode.count; } if (error) @@ -519,9 +523,9 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) else sdmac->status = DMA_SUCCESS; + sdmac->last_completed = sdmac->desc.cookie; if (sdmac->desc.callback) sdmac->desc.callback(sdmac->desc.callback_param); - sdmac->last_completed = sdmac->desc.cookie; } static void mxc_sdma_handle_channel(struct sdma_channel *sdmac) @@ -650,7 +654,7 @@ static int sdma_load_context(struct sdma_channel *sdmac) struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd; int ret; - if (sdmac->direction == DMA_FROM_DEVICE) { + if (sdmac->direction == DMA_DEV_TO_MEM) { load_address = sdmac->pc_from_device; } else { load_address = sdmac->pc_to_device; @@ -832,17 +836,18 @@ static struct sdma_channel *to_sdma_chan(struct dma_chan *chan) static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx) { + unsigned long flags; struct sdma_channel *sdmac = to_sdma_chan(tx->chan); struct sdma_engine *sdma = sdmac->sdma; dma_cookie_t cookie; - spin_lock_irq(&sdmac->lock); + spin_lock_irqsave(&sdmac->lock, flags); cookie = sdma_assign_cookie(sdmac); sdma_enable_channel(sdma, sdmac->channel); - spin_unlock_irq(&sdmac->lock); + spin_unlock_irqrestore(&sdmac->lock, flags); return cookie; } @@ -911,7 +916,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan) static struct dma_async_tx_descriptor *sdma_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct sdma_channel *sdmac = to_sdma_chan(chan); @@ -941,6 +946,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( goto err_out; } + sdmac->chn_count = 0; for_each_sg(sgl, sg, sg_len, i) { struct sdma_buffer_descriptor *bd = &sdmac->bd[i]; int param; @@ -957,6 +963,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( } bd->mode.count = count; + sdmac->chn_count += count; if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) { ret = -EINVAL; @@ -1008,7 +1015,7 @@ err_out: static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, - size_t period_len, enum dma_data_direction direction) + size_t period_len, enum dma_transfer_direction direction) { struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; @@ -1093,7 +1100,7 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, sdma_disable_channel(sdmac); return 0; case DMA_SLAVE_CONFIG: - if (dmaengine_cfg->direction == DMA_FROM_DEVICE) { + if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { sdmac->per_address = dmaengine_cfg->src_addr; sdmac->watermark_level = dmaengine_cfg->src_maxburst; sdmac->word_size = dmaengine_cfg->src_addr_width; @@ -1102,6 +1109,7 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, sdmac->watermark_level = dmaengine_cfg->dst_maxburst; sdmac->word_size = dmaengine_cfg->dst_addr_width; } + sdmac->direction = dmaengine_cfg->direction; return sdma_config_channel(sdmac); default: return -ENOSYS; @@ -1119,7 +1127,8 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan, last_used = chan->cookie; - dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0); + dma_set_tx_state(txstate, sdmac->last_completed, last_used, + sdmac->chn_count - sdmac->chn_real_count); return sdmac->status; } diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 19a0c64d45d3..74f70aadf9e4 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -280,7 +280,8 @@ static void midc_dostart(struct intel_mid_dma_chan *midc, * callbacks but must be called with the lock held. */ static void midc_descriptor_complete(struct intel_mid_dma_chan *midc, - struct intel_mid_dma_desc *desc) + struct intel_mid_dma_desc *desc) + __releases(&midc->lock) __acquires(&midc->lock) { struct dma_async_tx_descriptor *txd = &desc->txd; dma_async_tx_callback callback_txd = NULL; @@ -311,6 +312,7 @@ static void midc_descriptor_complete(struct intel_mid_dma_chan *midc, pci_pool_free(desc->lli_pool, desc->lli, desc->lli_phys); pci_pool_destroy(desc->lli_pool); + desc->lli = NULL; } list_move(&desc->desc_node, &midc->free_list); midc->busy = false; @@ -395,10 +397,10 @@ static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc, midc->dma->block_size); /*Populate SAR and DAR values*/ sg_phy_addr = sg_phys(sg); - if (desc->dirn == DMA_TO_DEVICE) { + if (desc->dirn == DMA_MEM_TO_DEV) { lli_bloc_desc->sar = sg_phy_addr; lli_bloc_desc->dar = mids->dma_slave.dst_addr; - } else if (desc->dirn == DMA_FROM_DEVICE) { + } else if (desc->dirn == DMA_DEV_TO_MEM) { lli_bloc_desc->sar = mids->dma_slave.src_addr; lli_bloc_desc->dar = sg_phy_addr; } @@ -490,7 +492,9 @@ static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan, ret = dma_async_is_complete(cookie, last_complete, last_used); if (ret != DMA_SUCCESS) { + spin_lock_bh(&midc->lock); midc_scan_descriptors(to_middma_device(chan->device), midc); + spin_unlock_bh(&midc->lock); last_complete = midc->completed; last_used = chan->cookie; @@ -566,6 +570,7 @@ static int intel_mid_dma_device_control(struct dma_chan *chan, pci_pool_free(desc->lli_pool, desc->lli, desc->lli_phys); pci_pool_destroy(desc->lli_pool); + desc->lli = NULL; } list_move(&desc->desc_node, &midc->free_list); } @@ -632,13 +637,13 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy( if (midc->dma->pimr_mask) { cfg_hi.cfgx.protctl = 0x0; /*default value*/ cfg_hi.cfgx.fifo_mode = 1; - if (mids->dma_slave.direction == DMA_TO_DEVICE) { + if (mids->dma_slave.direction == DMA_MEM_TO_DEV) { cfg_hi.cfgx.src_per = 0; if (mids->device_instance == 0) cfg_hi.cfgx.dst_per = 3; if (mids->device_instance == 1) cfg_hi.cfgx.dst_per = 1; - } else if (mids->dma_slave.direction == DMA_FROM_DEVICE) { + } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) { if (mids->device_instance == 0) cfg_hi.cfgx.src_per = 2; if (mids->device_instance == 1) @@ -682,11 +687,11 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy( ctl_lo.ctlx.sinc = 0; ctl_lo.ctlx.dinc = 0; } else { - if (mids->dma_slave.direction == DMA_TO_DEVICE) { + if (mids->dma_slave.direction == DMA_MEM_TO_DEV) { ctl_lo.ctlx.sinc = 0; ctl_lo.ctlx.dinc = 2; ctl_lo.ctlx.tt_fc = 1; - } else if (mids->dma_slave.direction == DMA_FROM_DEVICE) { + } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) { ctl_lo.ctlx.sinc = 2; ctl_lo.ctlx.dinc = 0; ctl_lo.ctlx.tt_fc = 2; @@ -732,7 +737,7 @@ err_desc_get: */ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct intel_mid_dma_chan *midc = NULL; @@ -868,7 +873,7 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan) pm_runtime_get_sync(&mid->pdev->dev); if (mid->state == SUSPENDED) { - if (dma_resume(mid->pdev)) { + if (dma_resume(&mid->pdev->dev)) { pr_err("ERR_MDMA: resume failed"); return -EFAULT; } @@ -1099,7 +1104,8 @@ static int mid_setup_dma(struct pci_dev *pdev) LNW_PERIPHRAL_MASK_SIZE); if (dma->mask_reg == NULL) { pr_err("ERR_MDMA:Can't map periphral intr space !!\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_ioremap; } } else dma->mask_reg = NULL; @@ -1196,6 +1202,9 @@ static int mid_setup_dma(struct pci_dev *pdev) err_engine: free_irq(pdev->irq, dma); err_irq: + if (dma->mask_reg) + iounmap(dma->mask_reg); +err_ioremap: pci_pool_destroy(dma->dma_pool); err_dma_pool: pr_err("ERR_MDMA:setup_dma failed: %d\n", err); @@ -1337,8 +1346,9 @@ static void __devexit intel_mid_dma_remove(struct pci_dev *pdev) * * This function is called by OS when a power event occurs */ -int dma_suspend(struct pci_dev *pci, pm_message_t state) +static int dma_suspend(struct device *dev) { + struct pci_dev *pci = to_pci_dev(dev); int i; struct middma_device *device = pci_get_drvdata(pci); pr_debug("MDMA: dma_suspend called\n"); @@ -1362,8 +1372,9 @@ int dma_suspend(struct pci_dev *pci, pm_message_t state) * * This function is called by OS when a power event occurs */ -int dma_resume(struct pci_dev *pci) +int dma_resume(struct device *dev) { + struct pci_dev *pci = to_pci_dev(dev); int ret; struct middma_device *device = pci_get_drvdata(pci); @@ -1429,6 +1440,8 @@ static const struct dev_pm_ops intel_mid_dma_pm = { .runtime_suspend = dma_runtime_suspend, .runtime_resume = dma_runtime_resume, .runtime_idle = dma_runtime_idle, + .suspend = dma_suspend, + .resume = dma_resume, }; static struct pci_driver intel_mid_dma_pci_driver = { @@ -1437,8 +1450,6 @@ static struct pci_driver intel_mid_dma_pci_driver = { .probe = intel_mid_dma_probe, .remove = __devexit_p(intel_mid_dma_remove), #ifdef CONFIG_PM - .suspend = dma_suspend, - .resume = dma_resume, .driver = { .pm = &intel_mid_dma_pm, }, diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h index aea5ee88ce03..c83d35b97bd8 100644 --- a/drivers/dma/intel_mid_dma_regs.h +++ b/drivers/dma/intel_mid_dma_regs.h @@ -262,7 +262,7 @@ struct intel_mid_dma_desc { unsigned int lli_length; unsigned int current_lli; dma_addr_t next; - enum dma_data_direction dirn; + enum dma_transfer_direction dirn; enum dma_status status; enum dma_slave_buswidth width; /*width of DMA txn*/ enum intel_mid_dma_mode cfg_mode; /*mode configuration*/ @@ -296,6 +296,6 @@ static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave } -int dma_resume(struct pci_dev *pci); +int dma_resume(struct device *dev); #endif /*__INTEL_MID_DMAC_REGS_H__*/ diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index e03f811a83dd..04be90b645b8 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -1735,8 +1735,6 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan) spin_unlock_bh(&iop_chan->lock); } -MODULE_ALIAS("platform:iop-adma"); - static struct platform_driver iop_adma_driver = { .probe = iop_adma_probe, .remove = __devexit_p(iop_adma_remove), @@ -1746,19 +1744,9 @@ static struct platform_driver iop_adma_driver = { }, }; -static int __init iop_adma_init (void) -{ - return platform_driver_register(&iop_adma_driver); -} - -static void __exit iop_adma_exit (void) -{ - platform_driver_unregister(&iop_adma_driver); - return; -} -module_exit(iop_adma_exit); -module_init(iop_adma_init); +module_platform_driver(iop_adma_driver); MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("IOP ADMA Engine Driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:iop-adma"); diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index 0e5ef33f90a1..6212b16e8cf2 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -312,7 +312,7 @@ static void ipu_ch_param_set_size(union chan_param_mem *params, case IPU_PIX_FMT_RGB565: params->ip.bpp = 2; params->ip.pfs = 4; - params->ip.npb = 7; + params->ip.npb = 15; params->ip.sat = 2; /* SAT = 32-bit access */ params->ip.ofs0 = 0; /* Red bit offset */ params->ip.ofs1 = 5; /* Green bit offset */ @@ -422,12 +422,6 @@ static void ipu_ch_param_set_size(union chan_param_mem *params, params->pp.nsb = 1; } -static void ipu_ch_param_set_burst_size(union chan_param_mem *params, - uint16_t burst_pixels) -{ - params->pp.npb = burst_pixels - 1; -} - static void ipu_ch_param_set_buffer(union chan_param_mem *params, dma_addr_t buf0, dma_addr_t buf1) { @@ -690,23 +684,6 @@ static int ipu_init_channel_buffer(struct idmac_channel *ichan, ipu_ch_param_set_size(¶ms, pixel_fmt, width, height, stride_bytes); ipu_ch_param_set_buffer(¶ms, phyaddr_0, phyaddr_1); ipu_ch_param_set_rotation(¶ms, rot_mode); - /* Some channels (rotation) have restriction on burst length */ - switch (channel) { - case IDMAC_IC_7: /* Hangs with burst 8, 16, other values - invalid - Table 44-30 */ -/* - ipu_ch_param_set_burst_size(¶ms, 8); - */ - break; - case IDMAC_SDC_0: - case IDMAC_SDC_1: - /* In original code only IPU_PIX_FMT_RGB565 was setting burst */ - ipu_ch_param_set_burst_size(¶ms, 16); - break; - case IDMAC_IC_0: - default: - break; - } spin_lock_irqsave(&ipu->lock, flags); @@ -1364,7 +1341,7 @@ static void ipu_gc_tasklet(unsigned long arg) /* Allocate and initialise a transfer descriptor. */ static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, - enum dma_data_direction direction, unsigned long tx_flags) + enum dma_transfer_direction direction, unsigned long tx_flags) { struct idmac_channel *ichan = to_idmac_chan(chan); struct idmac_tx_desc *desc = NULL; @@ -1376,7 +1353,7 @@ static struct dma_async_tx_descriptor *idmac_prep_slave_sg(struct dma_chan *chan chan->chan_id != IDMAC_IC_7) return NULL; - if (direction != DMA_FROM_DEVICE && direction != DMA_TO_DEVICE) { + if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV) { dev_err(chan->device->dev, "Invalid DMA direction %d!\n", direction); return NULL; } diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 8ba4edc6185e..4d6d4cf66949 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -835,17 +835,7 @@ static struct platform_driver mpc_dma_driver = { }, }; -static int __init mpc_dma_init(void) -{ - return platform_driver_register(&mpc_dma_driver); -} -module_init(mpc_dma_init); - -static void __exit mpc_dma_exit(void) -{ - platform_driver_unregister(&mpc_dma_driver); -} -module_exit(mpc_dma_exit); +module_platform_driver(mpc_dma_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Piotr Ziecik <kosmo@semihalf.com>"); diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index fc903c0ed234..b06cd4ca626f 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -44,7 +44,6 @@ #define HW_APBHX_CTRL0 0x000 #define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29) #define BM_APBH_CTRL0_APB_BURST_EN (1 << 28) -#define BP_APBH_CTRL0_CLKGATE_CHANNEL 8 #define BP_APBH_CTRL0_RESET_CHANNEL 16 #define HW_APBHX_CTRL1 0x010 #define HW_APBHX_CTRL2 0x020 @@ -111,6 +110,7 @@ struct mxs_dma_chan { int chan_irq; struct mxs_dma_ccw *ccw; dma_addr_t ccw_phys; + int desc_count; dma_cookie_t last_completed; enum dma_status status; unsigned int flags; @@ -130,23 +130,6 @@ struct mxs_dma_engine { struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; }; -static inline void mxs_dma_clkgate(struct mxs_dma_chan *mxs_chan, int enable) -{ - struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; - int chan_id = mxs_chan->chan.chan_id; - int set_clr = enable ? MXS_CLR_ADDR : MXS_SET_ADDR; - - /* enable apbh channel clock */ - if (dma_is_apbh()) { - if (apbh_is_old()) - writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), - mxs_dma->base + HW_APBHX_CTRL0 + set_clr); - else - writel(1 << chan_id, - mxs_dma->base + HW_APBHX_CTRL0 + set_clr); - } -} - static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan) { struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; @@ -165,9 +148,6 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan) struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; int chan_id = mxs_chan->chan.chan_id; - /* clkgate needs to be enabled before writing other registers */ - mxs_dma_clkgate(mxs_chan, 1); - /* set cmd_addr up */ writel(mxs_chan->ccw_phys, mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id)); @@ -178,9 +158,6 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan) static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan) { - /* disable apbh channel clock */ - mxs_dma_clkgate(mxs_chan, 0); - mxs_chan->status = DMA_SUCCESS; } @@ -268,7 +245,7 @@ static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id) /* * When both completion and error of termination bits set at the * same time, we do not take it as an error. IOW, it only becomes - * an error we need to handler here in case of ether it's (1) an bus + * an error we need to handle here in case of either it's (1) a bus * error or (2) a termination error with no completion. */ stat2 = ((stat2 >> MXS_DMA_CHANNELS) & stat2) | /* (1) */ @@ -338,10 +315,7 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan) if (ret) goto err_clk; - /* clkgate needs to be enabled for reset to finish */ - mxs_dma_clkgate(mxs_chan, 1); mxs_dma_reset_chan(mxs_chan); - mxs_dma_clkgate(mxs_chan, 0); dma_async_tx_descriptor_init(&mxs_chan->desc, chan); mxs_chan->desc.tx_submit = mxs_dma_tx_submit; @@ -377,7 +351,7 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan) static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long append) { struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); @@ -386,7 +360,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( struct scatterlist *sg; int i, j; u32 *pio; - static int idx; + int idx = append ? mxs_chan->desc_count : 0; if (mxs_chan->status == DMA_IN_PROGRESS && !append) return NULL; @@ -417,7 +391,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( idx = 0; } - if (direction == DMA_NONE) { + if (direction == DMA_TRANS_NONE) { ccw = &mxs_chan->ccw[idx++]; pio = (u32 *) sgl; @@ -450,7 +424,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( ccw->bits |= CCW_CHAIN; ccw->bits |= CCW_HALT_ON_TERM; ccw->bits |= CCW_TERM_FLUSH; - ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ? + ccw->bits |= BF_CCW(direction == DMA_DEV_TO_MEM ? MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ, COMMAND); @@ -462,6 +436,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( } } } + mxs_chan->desc_count = idx; return &mxs_chan->desc; @@ -472,7 +447,7 @@ err_out: static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, - size_t period_len, enum dma_data_direction direction) + size_t period_len, enum dma_transfer_direction direction) { struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; @@ -515,7 +490,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic( ccw->bits |= CCW_IRQ; ccw->bits |= CCW_HALT_ON_TERM; ccw->bits |= CCW_TERM_FLUSH; - ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ? + ccw->bits |= BF_CCW(direction == DMA_DEV_TO_MEM ? MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ, COMMAND); dma_addr += period_len; @@ -523,6 +498,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic( i++; } + mxs_chan->desc_count = i; return &mxs_chan->desc; @@ -539,8 +515,8 @@ static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, switch (cmd) { case DMA_TERMINATE_ALL: - mxs_dma_disable_chan(mxs_chan); mxs_dma_reset_chan(mxs_chan); + mxs_dma_disable_chan(mxs_chan); break; case DMA_PAUSE: mxs_dma_pause_chan(mxs_chan); @@ -580,7 +556,7 @@ static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma) ret = clk_prepare_enable(mxs_dma->clk); if (ret) - goto err_out; + return ret; ret = mxs_reset_block(mxs_dma->base); if (ret) @@ -604,11 +580,8 @@ static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma) writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS, mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR); - clk_disable_unprepare(mxs_dma->clk); - - return 0; - err_out: + clk_disable_unprepare(mxs_dma->clk); return ret; } diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index a6d0e3dbed07..823f58179f9d 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -1,7 +1,7 @@ /* * Topcliff PCH DMA controller driver * Copyright (c) 2010 Intel Corporation - * Copyright (C) 2011 OKI SEMICONDUCTOR CO., LTD. + * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. * * 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 @@ -99,7 +99,7 @@ struct pch_dma_desc { struct pch_dma_chan { struct dma_chan chan; void __iomem *membase; - enum dma_data_direction dir; + enum dma_transfer_direction dir; struct tasklet_struct tasklet; unsigned long err_status; @@ -224,7 +224,7 @@ static void pdc_set_dir(struct dma_chan *chan) mask_ctl = DMA_MASK_CTL0_MODE & ~(DMA_CTL0_MODE_MASK_BITS << (DMA_CTL0_BITS_PER_CH * chan->chan_id)); val &= mask_mode; - if (pd_chan->dir == DMA_TO_DEVICE) + if (pd_chan->dir == DMA_MEM_TO_DEV) val |= 0x1 << (DMA_CTL0_BITS_PER_CH * chan->chan_id + DMA_CTL0_DIR_SHIFT_BITS); else @@ -242,7 +242,7 @@ static void pdc_set_dir(struct dma_chan *chan) mask_ctl = DMA_MASK_CTL2_MODE & ~(DMA_CTL0_MODE_MASK_BITS << (DMA_CTL0_BITS_PER_CH * ch)); val &= mask_mode; - if (pd_chan->dir == DMA_TO_DEVICE) + if (pd_chan->dir == DMA_MEM_TO_DEV) val |= 0x1 << (DMA_CTL0_BITS_PER_CH * ch + DMA_CTL0_DIR_SHIFT_BITS); else @@ -607,7 +607,7 @@ static void pd_issue_pending(struct dma_chan *chan) static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, - enum dma_data_direction direction, unsigned long flags) + enum dma_transfer_direction direction, unsigned long flags) { struct pch_dma_chan *pd_chan = to_pd_chan(chan); struct pch_dma_slave *pd_slave = chan->private; @@ -623,9 +623,9 @@ static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan, return NULL; } - if (direction == DMA_FROM_DEVICE) + if (direction == DMA_DEV_TO_MEM) reg = pd_slave->rx_reg; - else if (direction == DMA_TO_DEVICE) + else if (direction == DMA_MEM_TO_DEV) reg = pd_slave->tx_reg; else return NULL; @@ -1018,6 +1018,8 @@ static void __devexit pch_dma_remove(struct pci_dev *pdev) #define PCI_DEVICE_ID_ML7223_DMA2_4CH 0x800E #define PCI_DEVICE_ID_ML7223_DMA3_4CH 0x8017 #define PCI_DEVICE_ID_ML7223_DMA4_4CH 0x803B +#define PCI_DEVICE_ID_ML7831_DMA1_8CH 0x8810 +#define PCI_DEVICE_ID_ML7831_DMA2_4CH 0x8815 DEFINE_PCI_DEVICE_TABLE(pch_dma_id_table) = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_8CH), 8 }, @@ -1030,6 +1032,8 @@ DEFINE_PCI_DEVICE_TABLE(pch_dma_id_table) = { { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA2_4CH), 4}, /* Video SPI */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA3_4CH), 4}, /* Security */ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_DMA4_4CH), 4}, /* FPGA */ + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_DMA1_8CH), 8}, /* UART */ + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_DMA2_4CH), 4}, /* SPI */ { 0, }, }; @@ -1057,7 +1061,7 @@ static void __exit pch_dma_exit(void) module_init(pch_dma_init); module_exit(pch_dma_exit); -MODULE_DESCRIPTION("Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH " +MODULE_DESCRIPTION("Intel EG20T PCH / LAPIS Semicon ML7213/ML7223/ML7831 IOH " "DMA controller driver"); MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 09adcfcd953e..b8ec03ee8e22 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -350,14 +350,14 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned case DMA_SLAVE_CONFIG: slave_config = (struct dma_slave_config *)arg; - if (slave_config->direction == DMA_TO_DEVICE) { + if (slave_config->direction == DMA_MEM_TO_DEV) { if (slave_config->dst_addr) pch->fifo_addr = slave_config->dst_addr; if (slave_config->dst_addr_width) pch->burst_sz = __ffs(slave_config->dst_addr_width); if (slave_config->dst_maxburst) pch->burst_len = slave_config->dst_maxburst; - } else if (slave_config->direction == DMA_FROM_DEVICE) { + } else if (slave_config->direction == DMA_DEV_TO_MEM) { if (slave_config->src_addr) pch->fifo_addr = slave_config->src_addr; if (slave_config->src_addr_width) @@ -621,7 +621,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t len, - size_t period_len, enum dma_data_direction direction) + size_t period_len, enum dma_transfer_direction direction) { struct dma_pl330_desc *desc; struct dma_pl330_chan *pch = to_pchan(chan); @@ -636,14 +636,14 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( } switch (direction) { - case DMA_TO_DEVICE: + case DMA_MEM_TO_DEV: desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 0; desc->req.rqtype = MEMTODEV; src = dma_addr; dst = pch->fifo_addr; break; - case DMA_FROM_DEVICE: + case DMA_DEV_TO_MEM: desc->rqcfg.src_inc = 0; desc->rqcfg.dst_inc = 1; desc->req.rqtype = DEVTOMEM; @@ -710,7 +710,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, static struct dma_async_tx_descriptor * pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flg) { struct dma_pl330_desc *first, *desc = NULL; @@ -759,7 +759,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, else list_add_tail(&desc->node, &first->node); - if (direction == DMA_TO_DEVICE) { + if (direction == DMA_MEM_TO_DEV) { desc->rqcfg.src_inc = 1; desc->rqcfg.dst_inc = 0; desc->req.rqtype = MEMTODEV; @@ -834,17 +834,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) amba_set_drvdata(adev, pdmac); -#ifdef CONFIG_PM_RUNTIME - /* to use the runtime PM helper functions */ - pm_runtime_enable(&adev->dev); - - /* enable the power domain */ - if (pm_runtime_get_sync(&adev->dev)) { - dev_err(&adev->dev, "failed to get runtime pm\n"); - ret = -ENODEV; - goto probe_err1; - } -#else +#ifndef CONFIG_PM_RUNTIME /* enable dma clk */ clk_enable(pdmac->clk); #endif @@ -977,10 +967,7 @@ static int __devexit pl330_remove(struct amba_device *adev) res = &adev->res; release_mem_region(res->start, resource_size(res)); -#ifdef CONFIG_PM_RUNTIME - pm_runtime_put(&adev->dev); - pm_runtime_disable(&adev->dev); -#else +#ifndef CONFIG_PM_RUNTIME clk_disable(pdmac->clk); #endif diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 81809c2b46ab..54043cd831c8 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -23,7 +23,6 @@ #include <linux/interrupt.h> #include <linux/dmaengine.h> #include <linux/delay.h> -#include <linux/dma-mapping.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/sh_dma.h> @@ -57,6 +56,15 @@ static LIST_HEAD(sh_dmae_devices); static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)]; static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all); +static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan); + +static void chclr_write(struct sh_dmae_chan *sh_dc, u32 data) +{ + struct sh_dmae_device *shdev = to_sh_dev(sh_dc); + + __raw_writel(data, shdev->chan_reg + + shdev->pdata->channel[sh_dc->id].chclr_offset); +} static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg) { @@ -129,6 +137,15 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev) dmaor = dmaor_read(shdev) & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME); + if (shdev->pdata->chclr_present) { + int i; + for (i = 0; i < shdev->pdata->channel_num; i++) { + struct sh_dmae_chan *sh_chan = shdev->chan[i]; + if (sh_chan) + chclr_write(sh_chan, 0); + } + } + dmaor_write(shdev, dmaor | shdev->pdata->dmaor_init); dmaor = dmaor_read(shdev); @@ -139,6 +156,10 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev) dev_warn(shdev->common.dev, "Can't initialize DMAOR.\n"); return -EIO; } + if (shdev->pdata->dmaor_init & ~dmaor) + dev_warn(shdev->common.dev, + "DMAOR=0x%x hasn't latched the initial value 0x%x.\n", + dmaor, shdev->pdata->dmaor_init); return 0; } @@ -259,8 +280,6 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val) return 0; } -static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan); - static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) { struct sh_desc *desc = tx_to_sh_desc(tx), *chunk, *last = desc, *c; @@ -340,6 +359,8 @@ static dma_cookie_t sh_dmae_tx_submit(struct dma_async_tx_descriptor *tx) sh_chan_xfer_ld_queue(sh_chan); sh_chan->pm_state = DMAE_PM_ESTABLISHED; } + } else { + sh_chan->pm_state = DMAE_PM_PENDING; } spin_unlock_irq(&sh_chan->desc_lock); @@ -479,19 +500,19 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan) * @sh_chan: DMA channel * @flags: DMA transfer flags * @dest: destination DMA address, incremented when direction equals - * DMA_FROM_DEVICE or DMA_BIDIRECTIONAL + * DMA_DEV_TO_MEM * @src: source DMA address, incremented when direction equals - * DMA_TO_DEVICE or DMA_BIDIRECTIONAL + * DMA_MEM_TO_DEV * @len: DMA transfer length * @first: if NULL, set to the current descriptor and cookie set to -EBUSY * @direction: needed for slave DMA to decide which address to keep constant, - * equals DMA_BIDIRECTIONAL for MEMCPY + * equals DMA_MEM_TO_MEM for MEMCPY * Returns 0 or an error * Locks: called with desc_lock held */ static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan, unsigned long flags, dma_addr_t *dest, dma_addr_t *src, size_t *len, - struct sh_desc **first, enum dma_data_direction direction) + struct sh_desc **first, enum dma_transfer_direction direction) { struct sh_desc *new; size_t copy_size; @@ -531,9 +552,9 @@ static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan, new->direction = direction; *len -= copy_size; - if (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE) + if (direction == DMA_MEM_TO_MEM || direction == DMA_MEM_TO_DEV) *src += copy_size; - if (direction == DMA_BIDIRECTIONAL || direction == DMA_FROM_DEVICE) + if (direction == DMA_MEM_TO_MEM || direction == DMA_DEV_TO_MEM) *dest += copy_size; return new; @@ -546,12 +567,12 @@ static struct sh_desc *sh_dmae_add_desc(struct sh_dmae_chan *sh_chan, * converted to scatter-gather to guarantee consistent locking and a correct * list manipulation. For slave DMA direction carries the usual meaning, and, * logically, the SG list is RAM and the addr variable contains slave address, - * e.g., the FIFO I/O register. For MEMCPY direction equals DMA_BIDIRECTIONAL + * e.g., the FIFO I/O register. For MEMCPY direction equals DMA_MEM_TO_MEM * and the SG list contains only one element and points at the source buffer. */ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_chan, struct scatterlist *sgl, unsigned int sg_len, dma_addr_t *addr, - enum dma_data_direction direction, unsigned long flags) + enum dma_transfer_direction direction, unsigned long flags) { struct scatterlist *sg; struct sh_desc *first = NULL, *new = NULL /* compiler... */; @@ -592,7 +613,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_sg(struct sh_dmae_chan *sh_c dev_dbg(sh_chan->dev, "Add SG #%d@%p[%d], dma %llx\n", i, sg, len, (unsigned long long)sg_addr); - if (direction == DMA_FROM_DEVICE) + if (direction == DMA_DEV_TO_MEM) new = sh_dmae_add_desc(sh_chan, flags, &sg_addr, addr, &len, &first, direction); @@ -646,13 +667,13 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy( sg_dma_address(&sg) = dma_src; sg_dma_len(&sg) = len; - return sh_dmae_prep_sg(sh_chan, &sg, 1, &dma_dest, DMA_BIDIRECTIONAL, + return sh_dmae_prep_sg(sh_chan, &sg, 1, &dma_dest, DMA_MEM_TO_MEM, flags); } static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, - enum dma_data_direction direction, unsigned long flags) + enum dma_transfer_direction direction, unsigned long flags) { struct sh_dmae_slave *param; struct sh_dmae_chan *sh_chan; @@ -996,7 +1017,7 @@ static void dmae_do_tasklet(unsigned long data) spin_lock_irq(&sh_chan->desc_lock); list_for_each_entry(desc, &sh_chan->ld_queue, node) { if (desc->mark == DESC_SUBMITTED && - ((desc->direction == DMA_FROM_DEVICE && + ((desc->direction == DMA_DEV_TO_MEM && (desc->hw.dar + desc->hw.tcr) == dar_buf) || (desc->hw.sar + desc->hw.tcr) == sar_buf)) { dev_dbg(sh_chan->dev, "done #%d@%p dst %u\n", @@ -1225,6 +1246,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev) platform_set_drvdata(pdev, shdev); + shdev->common.dev = &pdev->dev; + pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); @@ -1254,7 +1277,6 @@ static int __init sh_dmae_probe(struct platform_device *pdev) shdev->common.device_prep_slave_sg = sh_dmae_prep_slave_sg; shdev->common.device_control = sh_dmae_control; - shdev->common.dev = &pdev->dev; /* Default transfer size of 32 bytes requires 32-byte alignment */ shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE; @@ -1435,22 +1457,17 @@ static int sh_dmae_runtime_resume(struct device *dev) #ifdef CONFIG_PM static int sh_dmae_suspend(struct device *dev) { - struct sh_dmae_device *shdev = dev_get_drvdata(dev); - int i; - - for (i = 0; i < shdev->pdata->channel_num; i++) { - struct sh_dmae_chan *sh_chan = shdev->chan[i]; - if (sh_chan->descs_allocated) - sh_chan->pm_error = pm_runtime_put_sync(dev); - } - return 0; } static int sh_dmae_resume(struct device *dev) { struct sh_dmae_device *shdev = dev_get_drvdata(dev); - int i; + int i, ret; + + ret = sh_dmae_rst(shdev); + if (ret < 0) + dev_err(dev, "Failed to reset!\n"); for (i = 0; i < shdev->pdata->channel_num; i++) { struct sh_dmae_chan *sh_chan = shdev->chan[i]; @@ -1459,9 +1476,6 @@ static int sh_dmae_resume(struct device *dev) if (!sh_chan->descs_allocated) continue; - if (!sh_chan->pm_error) - pm_runtime_get_sync(dev); - if (param) { const struct sh_dmae_slave_config *cfg = param->config; dmae_set_dmars(sh_chan, cfg->mid_rid); diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c new file mode 100644 index 000000000000..2333810d1688 --- /dev/null +++ b/drivers/dma/sirf-dma.c @@ -0,0 +1,707 @@ +/* + * DMA controller driver for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/module.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/sirfsoc_dma.h> + +#define SIRFSOC_DMA_DESCRIPTORS 16 +#define SIRFSOC_DMA_CHANNELS 16 + +#define SIRFSOC_DMA_CH_ADDR 0x00 +#define SIRFSOC_DMA_CH_XLEN 0x04 +#define SIRFSOC_DMA_CH_YLEN 0x08 +#define SIRFSOC_DMA_CH_CTRL 0x0C + +#define SIRFSOC_DMA_WIDTH_0 0x100 +#define SIRFSOC_DMA_CH_VALID 0x140 +#define SIRFSOC_DMA_CH_INT 0x144 +#define SIRFSOC_DMA_INT_EN 0x148 +#define SIRFSOC_DMA_CH_LOOP_CTRL 0x150 + +#define SIRFSOC_DMA_MODE_CTRL_BIT 4 +#define SIRFSOC_DMA_DIR_CTRL_BIT 5 + +/* xlen and dma_width register is in 4 bytes boundary */ +#define SIRFSOC_DMA_WORD_LEN 4 + +struct sirfsoc_dma_desc { + struct dma_async_tx_descriptor desc; + struct list_head node; + + /* SiRFprimaII 2D-DMA parameters */ + + int xlen; /* DMA xlen */ + int ylen; /* DMA ylen */ + int width; /* DMA width */ + int dir; + bool cyclic; /* is loop DMA? */ + u32 addr; /* DMA buffer address */ +}; + +struct sirfsoc_dma_chan { + struct dma_chan chan; + struct list_head free; + struct list_head prepared; + struct list_head queued; + struct list_head active; + struct list_head completed; + dma_cookie_t completed_cookie; + unsigned long happened_cyclic; + unsigned long completed_cyclic; + + /* Lock for this structure */ + spinlock_t lock; + + int mode; +}; + +struct sirfsoc_dma { + struct dma_device dma; + struct tasklet_struct tasklet; + struct sirfsoc_dma_chan channels[SIRFSOC_DMA_CHANNELS]; + void __iomem *base; + int irq; +}; + +#define DRV_NAME "sirfsoc_dma" + +/* Convert struct dma_chan to struct sirfsoc_dma_chan */ +static inline +struct sirfsoc_dma_chan *dma_chan_to_sirfsoc_dma_chan(struct dma_chan *c) +{ + return container_of(c, struct sirfsoc_dma_chan, chan); +} + +/* Convert struct dma_chan to struct sirfsoc_dma */ +static inline struct sirfsoc_dma *dma_chan_to_sirfsoc_dma(struct dma_chan *c) +{ + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(c); + return container_of(schan, struct sirfsoc_dma, channels[c->chan_id]); +} + +/* Execute all queued DMA descriptors */ +static void sirfsoc_dma_execute(struct sirfsoc_dma_chan *schan) +{ + struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan); + int cid = schan->chan.chan_id; + struct sirfsoc_dma_desc *sdesc = NULL; + + /* + * lock has been held by functions calling this, so we don't hold + * lock again + */ + + sdesc = list_first_entry(&schan->queued, struct sirfsoc_dma_desc, + node); + /* Move the first queued descriptor to active list */ + list_move_tail(&schan->queued, &schan->active); + + /* Start the DMA transfer */ + writel_relaxed(sdesc->width, sdma->base + SIRFSOC_DMA_WIDTH_0 + + cid * 4); + writel_relaxed(cid | (schan->mode << SIRFSOC_DMA_MODE_CTRL_BIT) | + (sdesc->dir << SIRFSOC_DMA_DIR_CTRL_BIT), + sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_CTRL); + writel_relaxed(sdesc->xlen, sdma->base + cid * 0x10 + + SIRFSOC_DMA_CH_XLEN); + writel_relaxed(sdesc->ylen, sdma->base + cid * 0x10 + + SIRFSOC_DMA_CH_YLEN); + writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN) | + (1 << cid), sdma->base + SIRFSOC_DMA_INT_EN); + + /* + * writel has an implict memory write barrier to make sure data is + * flushed into memory before starting DMA + */ + writel(sdesc->addr >> 2, sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_ADDR); + + if (sdesc->cyclic) { + writel((1 << cid) | 1 << (cid + 16) | + readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL), + sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL); + schan->happened_cyclic = schan->completed_cyclic = 0; + } +} + +/* Interrupt handler */ +static irqreturn_t sirfsoc_dma_irq(int irq, void *data) +{ + struct sirfsoc_dma *sdma = data; + struct sirfsoc_dma_chan *schan; + struct sirfsoc_dma_desc *sdesc = NULL; + u32 is; + int ch; + + is = readl(sdma->base + SIRFSOC_DMA_CH_INT); + while ((ch = fls(is) - 1) >= 0) { + is &= ~(1 << ch); + writel_relaxed(1 << ch, sdma->base + SIRFSOC_DMA_CH_INT); + schan = &sdma->channels[ch]; + + spin_lock(&schan->lock); + + sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc, + node); + if (!sdesc->cyclic) { + /* Execute queued descriptors */ + list_splice_tail_init(&schan->active, &schan->completed); + if (!list_empty(&schan->queued)) + sirfsoc_dma_execute(schan); + } else + schan->happened_cyclic++; + + spin_unlock(&schan->lock); + } + + /* Schedule tasklet */ + tasklet_schedule(&sdma->tasklet); + + return IRQ_HANDLED; +} + +/* process completed descriptors */ +static void sirfsoc_dma_process_completed(struct sirfsoc_dma *sdma) +{ + dma_cookie_t last_cookie = 0; + struct sirfsoc_dma_chan *schan; + struct sirfsoc_dma_desc *sdesc; + struct dma_async_tx_descriptor *desc; + unsigned long flags; + unsigned long happened_cyclic; + LIST_HEAD(list); + int i; + + for (i = 0; i < sdma->dma.chancnt; i++) { + schan = &sdma->channels[i]; + + /* Get all completed descriptors */ + spin_lock_irqsave(&schan->lock, flags); + if (!list_empty(&schan->completed)) { + list_splice_tail_init(&schan->completed, &list); + spin_unlock_irqrestore(&schan->lock, flags); + + /* Execute callbacks and run dependencies */ + list_for_each_entry(sdesc, &list, node) { + desc = &sdesc->desc; + + if (desc->callback) + desc->callback(desc->callback_param); + + last_cookie = desc->cookie; + dma_run_dependencies(desc); + } + + /* Free descriptors */ + spin_lock_irqsave(&schan->lock, flags); + list_splice_tail_init(&list, &schan->free); + schan->completed_cookie = last_cookie; + spin_unlock_irqrestore(&schan->lock, flags); + } else { + /* for cyclic channel, desc is always in active list */ + sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc, + node); + + if (!sdesc || (sdesc && !sdesc->cyclic)) { + /* without active cyclic DMA */ + spin_unlock_irqrestore(&schan->lock, flags); + continue; + } + + /* cyclic DMA */ + happened_cyclic = schan->happened_cyclic; + spin_unlock_irqrestore(&schan->lock, flags); + + desc = &sdesc->desc; + while (happened_cyclic != schan->completed_cyclic) { + if (desc->callback) + desc->callback(desc->callback_param); + schan->completed_cyclic++; + } + } + } +} + +/* DMA Tasklet */ +static void sirfsoc_dma_tasklet(unsigned long data) +{ + struct sirfsoc_dma *sdma = (void *)data; + + sirfsoc_dma_process_completed(sdma); +} + +/* Submit descriptor to hardware */ +static dma_cookie_t sirfsoc_dma_tx_submit(struct dma_async_tx_descriptor *txd) +{ + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(txd->chan); + struct sirfsoc_dma_desc *sdesc; + unsigned long flags; + dma_cookie_t cookie; + + sdesc = container_of(txd, struct sirfsoc_dma_desc, desc); + + spin_lock_irqsave(&schan->lock, flags); + + /* Move descriptor to queue */ + list_move_tail(&sdesc->node, &schan->queued); + + /* Update cookie */ + cookie = schan->chan.cookie + 1; + if (cookie <= 0) + cookie = 1; + + schan->chan.cookie = cookie; + sdesc->desc.cookie = cookie; + + spin_unlock_irqrestore(&schan->lock, flags); + + return cookie; +} + +static int sirfsoc_dma_slave_config(struct sirfsoc_dma_chan *schan, + struct dma_slave_config *config) +{ + unsigned long flags; + + if ((config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) || + (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)) + return -EINVAL; + + spin_lock_irqsave(&schan->lock, flags); + schan->mode = (config->src_maxburst == 4 ? 1 : 0); + spin_unlock_irqrestore(&schan->lock, flags); + + return 0; +} + +static int sirfsoc_dma_terminate_all(struct sirfsoc_dma_chan *schan) +{ + struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan); + int cid = schan->chan.chan_id; + unsigned long flags; + + writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN) & + ~(1 << cid), sdma->base + SIRFSOC_DMA_INT_EN); + writel_relaxed(1 << cid, sdma->base + SIRFSOC_DMA_CH_VALID); + + writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL) + & ~((1 << cid) | 1 << (cid + 16)), + sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL); + + spin_lock_irqsave(&schan->lock, flags); + list_splice_tail_init(&schan->active, &schan->free); + list_splice_tail_init(&schan->queued, &schan->free); + spin_unlock_irqrestore(&schan->lock, flags); + + return 0; +} + +static int sirfsoc_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + struct dma_slave_config *config; + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); + + switch (cmd) { + case DMA_TERMINATE_ALL: + return sirfsoc_dma_terminate_all(schan); + case DMA_SLAVE_CONFIG: + config = (struct dma_slave_config *)arg; + return sirfsoc_dma_slave_config(schan, config); + + default: + break; + } + + return -ENOSYS; +} + +/* Alloc channel resources */ +static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan); + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); + struct sirfsoc_dma_desc *sdesc; + unsigned long flags; + LIST_HEAD(descs); + int i; + + /* Alloc descriptors for this channel */ + for (i = 0; i < SIRFSOC_DMA_DESCRIPTORS; i++) { + sdesc = kzalloc(sizeof(*sdesc), GFP_KERNEL); + if (!sdesc) { + dev_notice(sdma->dma.dev, "Memory allocation error. " + "Allocated only %u descriptors\n", i); + break; + } + + dma_async_tx_descriptor_init(&sdesc->desc, chan); + sdesc->desc.flags = DMA_CTRL_ACK; + sdesc->desc.tx_submit = sirfsoc_dma_tx_submit; + + list_add_tail(&sdesc->node, &descs); + } + + /* Return error only if no descriptors were allocated */ + if (i == 0) + return -ENOMEM; + + spin_lock_irqsave(&schan->lock, flags); + + list_splice_tail_init(&descs, &schan->free); + spin_unlock_irqrestore(&schan->lock, flags); + + return i; +} + +/* Free channel resources */ +static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan) +{ + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); + struct sirfsoc_dma_desc *sdesc, *tmp; + unsigned long flags; + LIST_HEAD(descs); + + spin_lock_irqsave(&schan->lock, flags); + + /* Channel must be idle */ + BUG_ON(!list_empty(&schan->prepared)); + BUG_ON(!list_empty(&schan->queued)); + BUG_ON(!list_empty(&schan->active)); + BUG_ON(!list_empty(&schan->completed)); + + /* Move data */ + list_splice_tail_init(&schan->free, &descs); + + spin_unlock_irqrestore(&schan->lock, flags); + + /* Free descriptors */ + list_for_each_entry_safe(sdesc, tmp, &descs, node) + kfree(sdesc); +} + +/* Send pending descriptor to hardware */ +static void sirfsoc_dma_issue_pending(struct dma_chan *chan) +{ + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&schan->lock, flags); + + if (list_empty(&schan->active) && !list_empty(&schan->queued)) + sirfsoc_dma_execute(schan); + + spin_unlock_irqrestore(&schan->lock, flags); +} + +/* Check request completion status */ +static enum dma_status +sirfsoc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); + unsigned long flags; + dma_cookie_t last_used; + dma_cookie_t last_complete; + + spin_lock_irqsave(&schan->lock, flags); + last_used = schan->chan.cookie; + last_complete = schan->completed_cookie; + spin_unlock_irqrestore(&schan->lock, flags); + + dma_set_tx_state(txstate, last_complete, last_used, 0); + return dma_async_is_complete(cookie, last_complete, last_used); +} + +static struct dma_async_tx_descriptor *sirfsoc_dma_prep_interleaved( + struct dma_chan *chan, struct dma_interleaved_template *xt, + unsigned long flags) +{ + struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan); + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); + struct sirfsoc_dma_desc *sdesc = NULL; + unsigned long iflags; + int ret; + + if ((xt->dir != DMA_MEM_TO_DEV) || (xt->dir != DMA_DEV_TO_MEM)) { + ret = -EINVAL; + goto err_dir; + } + + /* Get free descriptor */ + spin_lock_irqsave(&schan->lock, iflags); + if (!list_empty(&schan->free)) { + sdesc = list_first_entry(&schan->free, struct sirfsoc_dma_desc, + node); + list_del(&sdesc->node); + } + spin_unlock_irqrestore(&schan->lock, iflags); + + if (!sdesc) { + /* try to free completed descriptors */ + sirfsoc_dma_process_completed(sdma); + ret = 0; + goto no_desc; + } + + /* Place descriptor in prepared list */ + spin_lock_irqsave(&schan->lock, iflags); + + /* + * Number of chunks in a frame can only be 1 for prima2 + * and ylen (number of frame - 1) must be at least 0 + */ + if ((xt->frame_size == 1) && (xt->numf > 0)) { + sdesc->cyclic = 0; + sdesc->xlen = xt->sgl[0].size / SIRFSOC_DMA_WORD_LEN; + sdesc->width = (xt->sgl[0].size + xt->sgl[0].icg) / + SIRFSOC_DMA_WORD_LEN; + sdesc->ylen = xt->numf - 1; + if (xt->dir == DMA_MEM_TO_DEV) { + sdesc->addr = xt->src_start; + sdesc->dir = 1; + } else { + sdesc->addr = xt->dst_start; + sdesc->dir = 0; + } + + list_add_tail(&sdesc->node, &schan->prepared); + } else { + pr_err("sirfsoc DMA Invalid xfer\n"); + ret = -EINVAL; + goto err_xfer; + } + spin_unlock_irqrestore(&schan->lock, iflags); + + return &sdesc->desc; +err_xfer: + spin_unlock_irqrestore(&schan->lock, iflags); +no_desc: +err_dir: + return ERR_PTR(ret); +} + +static struct dma_async_tx_descriptor * +sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr, + size_t buf_len, size_t period_len, + enum dma_transfer_direction direction) +{ + struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); + struct sirfsoc_dma_desc *sdesc = NULL; + unsigned long iflags; + + /* + * we only support cycle transfer with 2 period + * If the X-length is set to 0, it would be the loop mode. + * The DMA address keeps increasing until reaching the end of a loop + * area whose size is defined by (DMA_WIDTH x (Y_LENGTH + 1)). Then + * the DMA address goes back to the beginning of this area. + * In loop mode, the DMA data region is divided into two parts, BUFA + * and BUFB. DMA controller generates interrupts twice in each loop: + * when the DMA address reaches the end of BUFA or the end of the + * BUFB + */ + if (buf_len != 2 * period_len) + return ERR_PTR(-EINVAL); + + /* Get free descriptor */ + spin_lock_irqsave(&schan->lock, iflags); + if (!list_empty(&schan->free)) { + sdesc = list_first_entry(&schan->free, struct sirfsoc_dma_desc, + node); + list_del(&sdesc->node); + } + spin_unlock_irqrestore(&schan->lock, iflags); + + if (!sdesc) + return 0; + + /* Place descriptor in prepared list */ + spin_lock_irqsave(&schan->lock, iflags); + sdesc->addr = addr; + sdesc->cyclic = 1; + sdesc->xlen = 0; + sdesc->ylen = buf_len / SIRFSOC_DMA_WORD_LEN - 1; + sdesc->width = 1; + list_add_tail(&sdesc->node, &schan->prepared); + spin_unlock_irqrestore(&schan->lock, iflags); + + return &sdesc->desc; +} + +/* + * The DMA controller consists of 16 independent DMA channels. + * Each channel is allocated to a different function + */ +bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id) +{ + unsigned int ch_nr = (unsigned int) chan_id; + + if (ch_nr == chan->chan_id + + chan->device->dev_id * SIRFSOC_DMA_CHANNELS) + return true; + + return false; +} +EXPORT_SYMBOL(sirfsoc_dma_filter_id); + +static int __devinit sirfsoc_dma_probe(struct platform_device *op) +{ + struct device_node *dn = op->dev.of_node; + struct device *dev = &op->dev; + struct dma_device *dma; + struct sirfsoc_dma *sdma; + struct sirfsoc_dma_chan *schan; + struct resource res; + ulong regs_start, regs_size; + u32 id; + int ret, i; + + sdma = devm_kzalloc(dev, sizeof(*sdma), GFP_KERNEL); + if (!sdma) { + dev_err(dev, "Memory exhausted!\n"); + return -ENOMEM; + } + + if (of_property_read_u32(dn, "cell-index", &id)) { + dev_err(dev, "Fail to get DMAC index\n"); + ret = -ENODEV; + goto free_mem; + } + + sdma->irq = irq_of_parse_and_map(dn, 0); + if (sdma->irq == NO_IRQ) { + dev_err(dev, "Error mapping IRQ!\n"); + ret = -EINVAL; + goto free_mem; + } + + ret = of_address_to_resource(dn, 0, &res); + if (ret) { + dev_err(dev, "Error parsing memory region!\n"); + goto free_mem; + } + + regs_start = res.start; + regs_size = resource_size(&res); + + sdma->base = devm_ioremap(dev, regs_start, regs_size); + if (!sdma->base) { + dev_err(dev, "Error mapping memory region!\n"); + ret = -ENOMEM; + goto irq_dispose; + } + + ret = devm_request_irq(dev, sdma->irq, &sirfsoc_dma_irq, 0, DRV_NAME, + sdma); + if (ret) { + dev_err(dev, "Error requesting IRQ!\n"); + ret = -EINVAL; + goto unmap_mem; + } + + dma = &sdma->dma; + dma->dev = dev; + dma->chancnt = SIRFSOC_DMA_CHANNELS; + + dma->device_alloc_chan_resources = sirfsoc_dma_alloc_chan_resources; + dma->device_free_chan_resources = sirfsoc_dma_free_chan_resources; + dma->device_issue_pending = sirfsoc_dma_issue_pending; + dma->device_control = sirfsoc_dma_control; + dma->device_tx_status = sirfsoc_dma_tx_status; + dma->device_prep_interleaved_dma = sirfsoc_dma_prep_interleaved; + dma->device_prep_dma_cyclic = sirfsoc_dma_prep_cyclic; + + INIT_LIST_HEAD(&dma->channels); + dma_cap_set(DMA_SLAVE, dma->cap_mask); + dma_cap_set(DMA_CYCLIC, dma->cap_mask); + dma_cap_set(DMA_INTERLEAVE, dma->cap_mask); + dma_cap_set(DMA_PRIVATE, dma->cap_mask); + + for (i = 0; i < dma->chancnt; i++) { + schan = &sdma->channels[i]; + + schan->chan.device = dma; + schan->chan.cookie = 1; + schan->completed_cookie = schan->chan.cookie; + + INIT_LIST_HEAD(&schan->free); + INIT_LIST_HEAD(&schan->prepared); + INIT_LIST_HEAD(&schan->queued); + INIT_LIST_HEAD(&schan->active); + INIT_LIST_HEAD(&schan->completed); + + spin_lock_init(&schan->lock); + list_add_tail(&schan->chan.device_node, &dma->channels); + } + + tasklet_init(&sdma->tasklet, sirfsoc_dma_tasklet, (unsigned long)sdma); + + /* Register DMA engine */ + dev_set_drvdata(dev, sdma); + ret = dma_async_device_register(dma); + if (ret) + goto free_irq; + + dev_info(dev, "initialized SIRFSOC DMAC driver\n"); + + return 0; + +free_irq: + devm_free_irq(dev, sdma->irq, sdma); +irq_dispose: + irq_dispose_mapping(sdma->irq); +unmap_mem: + iounmap(sdma->base); +free_mem: + devm_kfree(dev, sdma); + return ret; +} + +static int __devexit sirfsoc_dma_remove(struct platform_device *op) +{ + struct device *dev = &op->dev; + struct sirfsoc_dma *sdma = dev_get_drvdata(dev); + + dma_async_device_unregister(&sdma->dma); + devm_free_irq(dev, sdma->irq, sdma); + irq_dispose_mapping(sdma->irq); + iounmap(sdma->base); + devm_kfree(dev, sdma); + return 0; +} + +static struct of_device_id sirfsoc_dma_match[] = { + { .compatible = "sirf,prima2-dmac", }, + {}, +}; + +static struct platform_driver sirfsoc_dma_driver = { + .probe = sirfsoc_dma_probe, + .remove = __devexit_p(sirfsoc_dma_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = sirfsoc_dma_match, + }, +}; + +module_platform_driver(sirfsoc_dma_driver); + +MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, " + "Barry Song <baohua.song@csr.com>"); +MODULE_DESCRIPTION("SIRFSOC DMA control driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 13259cad0ceb..cc5ecbc067a3 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -14,6 +14,8 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/err.h> #include <linux/amba/bus.h> @@ -32,6 +34,9 @@ /* Maximum iterations taken before giving up suspending a channel */ #define D40_SUSPEND_MAX_IT 500 +/* Milliseconds */ +#define DMA40_AUTOSUSPEND_DELAY 100 + /* Hardware requirement on LCLA alignment */ #define LCLA_ALIGNMENT 0x40000 @@ -62,6 +67,55 @@ enum d40_command { D40_DMA_SUSPENDED = 3 }; +/* + * These are the registers that has to be saved and later restored + * when the DMA hw is powered off. + * TODO: Add save/restore of D40_DREG_GCC on dma40 v3 or later, if that works. + */ +static u32 d40_backup_regs[] = { + D40_DREG_LCPA, + D40_DREG_LCLA, + D40_DREG_PRMSE, + D40_DREG_PRMSO, + D40_DREG_PRMOE, + D40_DREG_PRMOO, +}; + +#define BACKUP_REGS_SZ ARRAY_SIZE(d40_backup_regs) + +/* TODO: Check if all these registers have to be saved/restored on dma40 v3 */ +static u32 d40_backup_regs_v3[] = { + D40_DREG_PSEG1, + D40_DREG_PSEG2, + D40_DREG_PSEG3, + D40_DREG_PSEG4, + D40_DREG_PCEG1, + D40_DREG_PCEG2, + D40_DREG_PCEG3, + D40_DREG_PCEG4, + D40_DREG_RSEG1, + D40_DREG_RSEG2, + D40_DREG_RSEG3, + D40_DREG_RSEG4, + D40_DREG_RCEG1, + D40_DREG_RCEG2, + D40_DREG_RCEG3, + D40_DREG_RCEG4, +}; + +#define BACKUP_REGS_SZ_V3 ARRAY_SIZE(d40_backup_regs_v3) + +static u32 d40_backup_regs_chan[] = { + D40_CHAN_REG_SSCFG, + D40_CHAN_REG_SSELT, + D40_CHAN_REG_SSPTR, + D40_CHAN_REG_SSLNK, + D40_CHAN_REG_SDCFG, + D40_CHAN_REG_SDELT, + D40_CHAN_REG_SDPTR, + D40_CHAN_REG_SDLNK, +}; + /** * struct d40_lli_pool - Structure for keeping LLIs in memory * @@ -96,7 +150,7 @@ struct d40_lli_pool { * during a transfer. * @node: List entry. * @is_in_client_list: true if the client owns this descriptor. - * the previous one. + * @cyclic: true if this is a cyclic job * * This descriptor is used for both logical and physical transfers. */ @@ -143,6 +197,7 @@ struct d40_lcla_pool { * channels. * * @lock: A lock protection this entity. + * @reserved: True if used by secure world or otherwise. * @num: The physical channel number of this entity. * @allocated_src: Bit mapped to show which src event line's are mapped to * this physical channel. Can also be free or physically allocated. @@ -152,6 +207,7 @@ struct d40_lcla_pool { */ struct d40_phy_res { spinlock_t lock; + bool reserved; int num; u32 allocated_src; u32 allocated_dst; @@ -185,7 +241,6 @@ struct d40_base; * @src_def_cfg: Default cfg register setting for src. * @dst_def_cfg: Default cfg register setting for dst. * @log_def: Default logical channel settings. - * @lcla: Space for one dst src pair for logical channel transfers. * @lcpa: Pointer to dst and src lcpa settings. * @runtime_addr: runtime configured address. * @runtime_direction: runtime configured direction. @@ -217,7 +272,7 @@ struct d40_chan { struct d40_log_lli_full *lcpa; /* Runtime reconfiguration */ dma_addr_t runtime_addr; - enum dma_data_direction runtime_direction; + enum dma_transfer_direction runtime_direction; }; /** @@ -241,6 +296,7 @@ struct d40_chan { * @dma_both: dma_device channels that can do both memcpy and slave transfers. * @dma_slave: dma_device channels that can do only do slave transfers. * @dma_memcpy: dma_device channels that can do only do memcpy transfers. + * @phy_chans: Room for all possible physical channels in system. * @log_chans: Room for all possible logical channels in system. * @lookup_log_chans: Used to map interrupt number to logical channel. Points * to log_chans entries. @@ -248,12 +304,20 @@ struct d40_chan { * to phy_chans entries. * @plat_data: Pointer to provided platform_data which is the driver * configuration. + * @lcpa_regulator: Pointer to hold the regulator for the esram bank for lcla. * @phy_res: Vector containing all physical channels. * @lcla_pool: lcla pool settings and data. * @lcpa_base: The virtual mapped address of LCPA. * @phy_lcpa: The physical address of the LCPA. * @lcpa_size: The size of the LCPA area. * @desc_slab: cache for descriptors. + * @reg_val_backup: Here the values of some hardware registers are stored + * before the DMA is powered off. They are restored when the power is back on. + * @reg_val_backup_v3: Backup of registers that only exits on dma40 v3 and + * later. + * @reg_val_backup_chan: Backup data for standard channel parameter registers. + * @gcc_pwr_off_mask: Mask to maintain the channels that can be turned off. + * @initialized: true if the dma has been initialized */ struct d40_base { spinlock_t interrupt_lock; @@ -275,6 +339,7 @@ struct d40_base { struct d40_chan **lookup_log_chans; struct d40_chan **lookup_phy_chans; struct stedma40_platform_data *plat_data; + struct regulator *lcpa_regulator; /* Physical half channels */ struct d40_phy_res *phy_res; struct d40_lcla_pool lcla_pool; @@ -282,6 +347,11 @@ struct d40_base { dma_addr_t phy_lcpa; resource_size_t lcpa_size; struct kmem_cache *desc_slab; + u32 reg_val_backup[BACKUP_REGS_SZ]; + u32 reg_val_backup_v3[BACKUP_REGS_SZ_V3]; + u32 *reg_val_backup_chan; + u16 gcc_pwr_off_mask; + bool initialized; }; /** @@ -479,13 +549,14 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c) struct d40_desc *d; struct d40_desc *_d; - list_for_each_entry_safe(d, _d, &d40c->client, node) + list_for_each_entry_safe(d, _d, &d40c->client, node) { if (async_tx_test_ack(&d->txd)) { d40_desc_remove(d); desc = d; memset(desc, 0, sizeof(*desc)); break; } + } } if (!desc) @@ -536,6 +607,7 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc) bool cyclic = desc->cyclic; int curr_lcla = -EINVAL; int first_lcla = 0; + bool use_esram_lcla = chan->base->plat_data->use_esram_lcla; bool linkback; /* @@ -608,11 +680,16 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc) &lli->src[lli_current], next_lcla, flags); - dma_sync_single_range_for_device(chan->base->dev, - pool->dma_addr, lcla_offset, - 2 * sizeof(struct d40_log_lli), - DMA_TO_DEVICE); - + /* + * Cache maintenance is not needed if lcla is + * mapped in esram + */ + if (!use_esram_lcla) { + dma_sync_single_range_for_device(chan->base->dev, + pool->dma_addr, lcla_offset, + 2 * sizeof(struct d40_log_lli), + DMA_TO_DEVICE); + } curr_lcla = next_lcla; if (curr_lcla == -EINVAL || curr_lcla == first_lcla) { @@ -740,7 +817,61 @@ static int d40_sg_2_dmalen(struct scatterlist *sgl, int sg_len, return len; } -/* Support functions for logical channels */ + +#ifdef CONFIG_PM +static void dma40_backup(void __iomem *baseaddr, u32 *backup, + u32 *regaddr, int num, bool save) +{ + int i; + + for (i = 0; i < num; i++) { + void __iomem *addr = baseaddr + regaddr[i]; + + if (save) + backup[i] = readl_relaxed(addr); + else + writel_relaxed(backup[i], addr); + } +} + +static void d40_save_restore_registers(struct d40_base *base, bool save) +{ + int i; + + /* Save/Restore channel specific registers */ + for (i = 0; i < base->num_phy_chans; i++) { + void __iomem *addr; + int idx; + + if (base->phy_res[i].reserved) + continue; + + addr = base->virtbase + D40_DREG_PCBASE + i * D40_DREG_PCDELTA; + idx = i * ARRAY_SIZE(d40_backup_regs_chan); + + dma40_backup(addr, &base->reg_val_backup_chan[idx], + d40_backup_regs_chan, + ARRAY_SIZE(d40_backup_regs_chan), + save); + } + + /* Save/Restore global registers */ + dma40_backup(base->virtbase, base->reg_val_backup, + d40_backup_regs, ARRAY_SIZE(d40_backup_regs), + save); + + /* Save/Restore registers only existing on dma40 v3 and later */ + if (base->rev >= 3) + dma40_backup(base->virtbase, base->reg_val_backup_v3, + d40_backup_regs_v3, + ARRAY_SIZE(d40_backup_regs_v3), + save); +} +#else +static void d40_save_restore_registers(struct d40_base *base, bool save) +{ +} +#endif static int d40_channel_execute_command(struct d40_chan *d40c, enum d40_command command) @@ -973,6 +1104,10 @@ static void d40_config_write(struct d40_chan *d40c) /* Set LIDX for lcla */ writel(lidx, chanbase + D40_CHAN_REG_SSELT); writel(lidx, chanbase + D40_CHAN_REG_SDELT); + + /* Clear LNK which will be used by d40_chan_has_events() */ + writel(0, chanbase + D40_CHAN_REG_SSLNK); + writel(0, chanbase + D40_CHAN_REG_SDLNK); } } @@ -1013,6 +1148,7 @@ static int d40_pause(struct d40_chan *d40c) if (!d40c->busy) return 0; + pm_runtime_get_sync(d40c->base->dev); spin_lock_irqsave(&d40c->lock, flags); res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); @@ -1025,7 +1161,8 @@ static int d40_pause(struct d40_chan *d40c) D40_DMA_RUN); } } - + pm_runtime_mark_last_busy(d40c->base->dev); + pm_runtime_put_autosuspend(d40c->base->dev); spin_unlock_irqrestore(&d40c->lock, flags); return res; } @@ -1039,7 +1176,7 @@ static int d40_resume(struct d40_chan *d40c) return 0; spin_lock_irqsave(&d40c->lock, flags); - + pm_runtime_get_sync(d40c->base->dev); if (d40c->base->rev == 0) if (chan_is_logical(d40c)) { res = d40_channel_execute_command(d40c, @@ -1057,6 +1194,8 @@ static int d40_resume(struct d40_chan *d40c) } no_suspend: + pm_runtime_mark_last_busy(d40c->base->dev); + pm_runtime_put_autosuspend(d40c->base->dev); spin_unlock_irqrestore(&d40c->lock, flags); return res; } @@ -1129,7 +1268,10 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c) d40d = d40_first_queued(d40c); if (d40d != NULL) { - d40c->busy = true; + if (!d40c->busy) + d40c->busy = true; + + pm_runtime_get_sync(d40c->base->dev); /* Remove from queue */ d40_desc_remove(d40d); @@ -1190,6 +1332,8 @@ static void dma_tc_handle(struct d40_chan *d40c) if (d40_queue_start(d40c) == NULL) d40c->busy = false; + pm_runtime_mark_last_busy(d40c->base->dev); + pm_runtime_put_autosuspend(d40c->base->dev); } d40c->pending_tx++; @@ -1405,11 +1549,16 @@ static int d40_validate_conf(struct d40_chan *d40c, return res; } -static bool d40_alloc_mask_set(struct d40_phy_res *phy, bool is_src, - int log_event_line, bool is_log) +static bool d40_alloc_mask_set(struct d40_phy_res *phy, + bool is_src, int log_event_line, bool is_log, + bool *first_user) { unsigned long flags; spin_lock_irqsave(&phy->lock, flags); + + *first_user = ((phy->allocated_src | phy->allocated_dst) + == D40_ALLOC_FREE); + if (!is_log) { /* Physical interrupts are masked per physical full channel */ if (phy->allocated_src == D40_ALLOC_FREE && @@ -1490,7 +1639,7 @@ out: return is_free; } -static int d40_allocate_channel(struct d40_chan *d40c) +static int d40_allocate_channel(struct d40_chan *d40c, bool *first_phy_user) { int dev_type; int event_group; @@ -1526,7 +1675,8 @@ static int d40_allocate_channel(struct d40_chan *d40c) for (i = 0; i < d40c->base->num_phy_chans; i++) { if (d40_alloc_mask_set(&phys[i], is_src, - 0, is_log)) + 0, is_log, + first_phy_user)) goto found_phy; } } else @@ -1536,7 +1686,8 @@ static int d40_allocate_channel(struct d40_chan *d40c) if (d40_alloc_mask_set(&phys[i], is_src, 0, - is_log)) + is_log, + first_phy_user)) goto found_phy; } } @@ -1552,6 +1703,25 @@ found_phy: /* Find logical channel */ for (j = 0; j < d40c->base->num_phy_chans; j += 8) { int phy_num = j + event_group * 2; + + if (d40c->dma_cfg.use_fixed_channel) { + i = d40c->dma_cfg.phy_channel; + + if ((i != phy_num) && (i != phy_num + 1)) { + dev_err(chan2dev(d40c), + "invalid fixed phy channel %d\n", i); + return -EINVAL; + } + + if (d40_alloc_mask_set(&phys[i], is_src, event_line, + is_log, first_phy_user)) + goto found_log; + + dev_err(chan2dev(d40c), + "could not allocate fixed phy channel %d\n", i); + return -EINVAL; + } + /* * Spread logical channels across all available physical rather * than pack every logical channel at the first available phy @@ -1560,13 +1730,15 @@ found_phy: if (is_src) { for (i = phy_num; i < phy_num + 2; i++) { if (d40_alloc_mask_set(&phys[i], is_src, - event_line, is_log)) + event_line, is_log, + first_phy_user)) goto found_log; } } else { for (i = phy_num + 1; i >= phy_num; i--) { if (d40_alloc_mask_set(&phys[i], is_src, - event_line, is_log)) + event_line, is_log, + first_phy_user)) goto found_log; } } @@ -1643,10 +1815,11 @@ static int d40_free_dma(struct d40_chan *d40c) return -EINVAL; } + pm_runtime_get_sync(d40c->base->dev); res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); if (res) { chan_err(d40c, "suspend failed\n"); - return res; + goto out; } if (chan_is_logical(d40c)) { @@ -1664,13 +1837,11 @@ static int d40_free_dma(struct d40_chan *d40c) if (d40_chan_has_events(d40c)) { res = d40_channel_execute_command(d40c, D40_DMA_RUN); - if (res) { + if (res) chan_err(d40c, "Executing RUN command\n"); - return res; - } } - return 0; + goto out; } } else { (void) d40_alloc_mask_free(phy, is_src, 0); @@ -1680,13 +1851,23 @@ static int d40_free_dma(struct d40_chan *d40c) res = d40_channel_execute_command(d40c, D40_DMA_STOP); if (res) { chan_err(d40c, "Failed to stop channel\n"); - return res; + goto out; } + + if (d40c->busy) { + pm_runtime_mark_last_busy(d40c->base->dev); + pm_runtime_put_autosuspend(d40c->base->dev); + } + + d40c->busy = false; d40c->phy_chan = NULL; d40c->configured = false; d40c->base->lookup_phy_chans[phy->num] = NULL; +out: - return 0; + pm_runtime_mark_last_busy(d40c->base->dev); + pm_runtime_put_autosuspend(d40c->base->dev); + return res; } static bool d40_is_paused(struct d40_chan *d40c) @@ -1855,7 +2036,7 @@ err: } static dma_addr_t -d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction) +d40_get_dev_addr(struct d40_chan *chan, enum dma_transfer_direction direction) { struct stedma40_platform_data *plat = chan->base->plat_data; struct stedma40_chan_cfg *cfg = &chan->dma_cfg; @@ -1864,9 +2045,9 @@ d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction) if (chan->runtime_addr) return chan->runtime_addr; - if (direction == DMA_FROM_DEVICE) + if (direction == DMA_DEV_TO_MEM) addr = plat->dev_rx[cfg->src_dev_type]; - else if (direction == DMA_TO_DEVICE) + else if (direction == DMA_MEM_TO_DEV) addr = plat->dev_tx[cfg->dst_dev_type]; return addr; @@ -1875,7 +2056,7 @@ d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction) static struct dma_async_tx_descriptor * d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, struct scatterlist *sg_dst, unsigned int sg_len, - enum dma_data_direction direction, unsigned long dma_flags) + enum dma_transfer_direction direction, unsigned long dma_flags) { struct d40_chan *chan = container_of(dchan, struct d40_chan, chan); dma_addr_t src_dev_addr = 0; @@ -1902,9 +2083,9 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, if (direction != DMA_NONE) { dma_addr_t dev_addr = d40_get_dev_addr(chan, direction); - if (direction == DMA_FROM_DEVICE) + if (direction == DMA_DEV_TO_MEM) src_dev_addr = dev_addr; - else if (direction == DMA_TO_DEVICE) + else if (direction == DMA_MEM_TO_DEV) dst_dev_addr = dev_addr; } @@ -2011,14 +2192,15 @@ static int d40_alloc_chan_resources(struct dma_chan *chan) goto fail; } } - is_free_phy = (d40c->phy_chan == NULL); - err = d40_allocate_channel(d40c); + err = d40_allocate_channel(d40c, &is_free_phy); if (err) { chan_err(d40c, "Failed to allocate channel\n"); + d40c->configured = false; goto fail; } + pm_runtime_get_sync(d40c->base->dev); /* Fill in basic CFG register values */ d40_phy_cfg(&d40c->dma_cfg, &d40c->src_def_cfg, &d40c->dst_def_cfg, chan_is_logical(d40c)); @@ -2038,6 +2220,12 @@ static int d40_alloc_chan_resources(struct dma_chan *chan) D40_LCPA_CHAN_SIZE + D40_LCPA_CHAN_DST_DELTA; } + dev_dbg(chan2dev(d40c), "allocated %s channel (phy %d%s)\n", + chan_is_logical(d40c) ? "logical" : "physical", + d40c->phy_chan->num, + d40c->dma_cfg.use_fixed_channel ? ", fixed" : ""); + + /* * Only write channel configuration to the DMA if the physical * resource is free. In case of multiple logical channels @@ -2046,6 +2234,8 @@ static int d40_alloc_chan_resources(struct dma_chan *chan) if (is_free_phy) d40_config_write(d40c); fail: + pm_runtime_mark_last_busy(d40c->base->dev); + pm_runtime_put_autosuspend(d40c->base->dev); spin_unlock_irqrestore(&d40c->lock, flags); return err; } @@ -2108,10 +2298,10 @@ d40_prep_memcpy_sg(struct dma_chan *chan, static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, - enum dma_data_direction direction, + enum dma_transfer_direction direction, unsigned long dma_flags) { - if (direction != DMA_FROM_DEVICE && direction != DMA_TO_DEVICE) + if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV) return NULL; return d40_prep_sg(chan, sgl, sgl, sg_len, direction, dma_flags); @@ -2120,7 +2310,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, static struct dma_async_tx_descriptor * dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, - enum dma_data_direction direction) + enum dma_transfer_direction direction) { unsigned int periods = buf_len / period_len; struct dma_async_tx_descriptor *txd; @@ -2269,7 +2459,7 @@ static int d40_set_runtime_config(struct dma_chan *chan, dst_addr_width = config->dst_addr_width; dst_maxburst = config->dst_maxburst; - if (config->direction == DMA_FROM_DEVICE) { + if (config->direction == DMA_DEV_TO_MEM) { dma_addr_t dev_addr_rx = d40c->base->plat_data->dev_rx[cfg->src_dev_type]; @@ -2292,7 +2482,7 @@ static int d40_set_runtime_config(struct dma_chan *chan, if (dst_maxburst == 0) dst_maxburst = src_maxburst; - } else if (config->direction == DMA_TO_DEVICE) { + } else if (config->direction == DMA_MEM_TO_DEV) { dma_addr_t dev_addr_tx = d40c->base->plat_data->dev_tx[cfg->dst_dev_type]; @@ -2357,7 +2547,7 @@ static int d40_set_runtime_config(struct dma_chan *chan, "configured channel %s for %s, data width %d/%d, " "maxburst %d/%d elements, LE, no flow control\n", dma_chan_name(chan), - (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", + (config->direction == DMA_DEV_TO_MEM) ? "RX" : "TX", src_addr_width, dst_addr_width, src_maxburst, dst_maxburst); @@ -2519,6 +2709,72 @@ failure1: return err; } +/* Suspend resume functionality */ +#ifdef CONFIG_PM +static int dma40_pm_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct d40_base *base = platform_get_drvdata(pdev); + int ret = 0; + if (!pm_runtime_suspended(dev)) + return -EBUSY; + + if (base->lcpa_regulator) + ret = regulator_disable(base->lcpa_regulator); + return ret; +} + +static int dma40_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct d40_base *base = platform_get_drvdata(pdev); + + d40_save_restore_registers(base, true); + + /* Don't disable/enable clocks for v1 due to HW bugs */ + if (base->rev != 1) + writel_relaxed(base->gcc_pwr_off_mask, + base->virtbase + D40_DREG_GCC); + + return 0; +} + +static int dma40_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct d40_base *base = platform_get_drvdata(pdev); + + if (base->initialized) + d40_save_restore_registers(base, false); + + writel_relaxed(D40_DREG_GCC_ENABLE_ALL, + base->virtbase + D40_DREG_GCC); + return 0; +} + +static int dma40_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct d40_base *base = platform_get_drvdata(pdev); + int ret = 0; + + if (base->lcpa_regulator) + ret = regulator_enable(base->lcpa_regulator); + + return ret; +} + +static const struct dev_pm_ops dma40_pm_ops = { + .suspend = dma40_pm_suspend, + .runtime_suspend = dma40_runtime_suspend, + .runtime_resume = dma40_runtime_resume, + .resume = dma40_resume, +}; +#define DMA40_PM_OPS (&dma40_pm_ops) +#else +#define DMA40_PM_OPS NULL +#endif + /* Initialization functions. */ static int __init d40_phy_res_init(struct d40_base *base) @@ -2527,6 +2783,7 @@ static int __init d40_phy_res_init(struct d40_base *base) int num_phy_chans_avail = 0; u32 val[2]; int odd_even_bit = -2; + int gcc = D40_DREG_GCC_ENA; val[0] = readl(base->virtbase + D40_DREG_PRSME); val[1] = readl(base->virtbase + D40_DREG_PRSMO); @@ -2538,9 +2795,17 @@ static int __init d40_phy_res_init(struct d40_base *base) /* Mark security only channels as occupied */ base->phy_res[i].allocated_src = D40_ALLOC_PHY; base->phy_res[i].allocated_dst = D40_ALLOC_PHY; + base->phy_res[i].reserved = true; + gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(i), + D40_DREG_GCC_SRC); + gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(i), + D40_DREG_GCC_DST); + + } else { base->phy_res[i].allocated_src = D40_ALLOC_FREE; base->phy_res[i].allocated_dst = D40_ALLOC_FREE; + base->phy_res[i].reserved = false; num_phy_chans_avail++; } spin_lock_init(&base->phy_res[i].lock); @@ -2552,6 +2817,11 @@ static int __init d40_phy_res_init(struct d40_base *base) base->phy_res[chan].allocated_src = D40_ALLOC_PHY; base->phy_res[chan].allocated_dst = D40_ALLOC_PHY; + base->phy_res[chan].reserved = true; + gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(chan), + D40_DREG_GCC_SRC); + gcc |= D40_DREG_GCC_EVTGRP_ENA(D40_PHYS_TO_GROUP(chan), + D40_DREG_GCC_DST); num_phy_chans_avail--; } @@ -2572,6 +2842,15 @@ static int __init d40_phy_res_init(struct d40_base *base) val[0] = val[0] >> 2; } + /* + * To keep things simple, Enable all clocks initially. + * The clocks will get managed later post channel allocation. + * The clocks for the event lines on which reserved channels exists + * are not managed here. + */ + writel(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC); + base->gcc_pwr_off_mask = gcc; + return num_phy_chans_avail; } @@ -2699,10 +2978,15 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) goto failure; } - base->lcla_pool.alloc_map = kzalloc(num_phy_chans * - sizeof(struct d40_desc *) * - D40_LCLA_LINK_PER_EVENT_GRP, + base->reg_val_backup_chan = kmalloc(base->num_phy_chans * + sizeof(d40_backup_regs_chan), GFP_KERNEL); + if (!base->reg_val_backup_chan) + goto failure; + + base->lcla_pool.alloc_map = + kzalloc(num_phy_chans * sizeof(struct d40_desc *) + * D40_LCLA_LINK_PER_EVENT_GRP, GFP_KERNEL); if (!base->lcla_pool.alloc_map) goto failure; @@ -2741,9 +3025,9 @@ failure: static void __init d40_hw_init(struct d40_base *base) { - static const struct d40_reg_val dma_init_reg[] = { + static struct d40_reg_val dma_init_reg[] = { /* Clock every part of the DMA block from start */ - { .reg = D40_DREG_GCC, .val = 0x0000ff01}, + { .reg = D40_DREG_GCC, .val = D40_DREG_GCC_ENABLE_ALL}, /* Interrupts on all logical channels */ { .reg = D40_DREG_LCMIS0, .val = 0xFFFFFFFF}, @@ -2943,11 +3227,31 @@ static int __init d40_probe(struct platform_device *pdev) d40_err(&pdev->dev, "Failed to ioremap LCPA region\n"); goto failure; } + /* If lcla has to be located in ESRAM we don't need to allocate */ + if (base->plat_data->use_esram_lcla) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "lcla_esram"); + if (!res) { + ret = -ENOENT; + d40_err(&pdev->dev, + "No \"lcla_esram\" memory resource\n"); + goto failure; + } + base->lcla_pool.base = ioremap(res->start, + resource_size(res)); + if (!base->lcla_pool.base) { + ret = -ENOMEM; + d40_err(&pdev->dev, "Failed to ioremap LCLA region\n"); + goto failure; + } + writel(res->start, base->virtbase + D40_DREG_LCLA); - ret = d40_lcla_allocate(base); - if (ret) { - d40_err(&pdev->dev, "Failed to allocate LCLA area\n"); - goto failure; + } else { + ret = d40_lcla_allocate(base); + if (ret) { + d40_err(&pdev->dev, "Failed to allocate LCLA area\n"); + goto failure; + } } spin_lock_init(&base->lcla_pool.lock); @@ -2960,6 +3264,32 @@ static int __init d40_probe(struct platform_device *pdev) goto failure; } + pm_runtime_irq_safe(base->dev); + pm_runtime_set_autosuspend_delay(base->dev, DMA40_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(base->dev); + pm_runtime_enable(base->dev); + pm_runtime_resume(base->dev); + + if (base->plat_data->use_esram_lcla) { + + base->lcpa_regulator = regulator_get(base->dev, "lcla_esram"); + if (IS_ERR(base->lcpa_regulator)) { + d40_err(&pdev->dev, "Failed to get lcpa_regulator\n"); + base->lcpa_regulator = NULL; + goto failure; + } + + ret = regulator_enable(base->lcpa_regulator); + if (ret) { + d40_err(&pdev->dev, + "Failed to enable lcpa_regulator\n"); + regulator_put(base->lcpa_regulator); + base->lcpa_regulator = NULL; + goto failure; + } + } + + base->initialized = true; err = d40_dmaengine_init(base, num_reserved_chans); if (err) goto failure; @@ -2976,6 +3306,11 @@ failure: if (base->virtbase) iounmap(base->virtbase); + if (base->lcla_pool.base && base->plat_data->use_esram_lcla) { + iounmap(base->lcla_pool.base); + base->lcla_pool.base = NULL; + } + if (base->lcla_pool.dma_addr) dma_unmap_single(base->dev, base->lcla_pool.dma_addr, SZ_1K * base->num_phy_chans, @@ -2998,6 +3333,11 @@ failure: clk_put(base->clk); } + if (base->lcpa_regulator) { + regulator_disable(base->lcpa_regulator); + regulator_put(base->lcpa_regulator); + } + kfree(base->lcla_pool.alloc_map); kfree(base->lookup_log_chans); kfree(base->lookup_phy_chans); @@ -3013,6 +3353,7 @@ static struct platform_driver d40_driver = { .driver = { .owner = THIS_MODULE, .name = D40_NAME, + .pm = DMA40_PM_OPS, }, }; diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index b44c455158de..8d3d490968a3 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -16,6 +16,8 @@ #define D40_TYPE_TO_GROUP(type) (type / 16) #define D40_TYPE_TO_EVENT(type) (type % 16) +#define D40_GROUP_SIZE 8 +#define D40_PHYS_TO_GROUP(phys) ((phys & (D40_GROUP_SIZE - 1)) / 2) /* Most bits of the CFG register are the same in log as in phy mode */ #define D40_SREG_CFG_MST_POS 15 @@ -123,6 +125,15 @@ /* DMA Register Offsets */ #define D40_DREG_GCC 0x000 +#define D40_DREG_GCC_ENA 0x1 +/* This assumes that there are only 4 event groups */ +#define D40_DREG_GCC_ENABLE_ALL 0xff01 +#define D40_DREG_GCC_EVTGRP_POS 8 +#define D40_DREG_GCC_SRC 0 +#define D40_DREG_GCC_DST 1 +#define D40_DREG_GCC_EVTGRP_ENA(x, y) \ + (1 << (D40_DREG_GCC_EVTGRP_POS + 2 * x + y)) + #define D40_DREG_PRTYP 0x004 #define D40_DREG_PRSME 0x008 #define D40_DREG_PRSMO 0x00C diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index a4a398f2ef61..a6f9c1684a0f 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -90,7 +90,7 @@ struct timb_dma_chan { struct list_head queue; struct list_head free_list; unsigned int bytes_per_line; - enum dma_data_direction direction; + enum dma_transfer_direction direction; unsigned int descs; /* Descriptors to allocate */ unsigned int desc_elems; /* number of elems per descriptor */ }; @@ -166,10 +166,10 @@ static void __td_unmap_desc(struct timb_dma_chan *td_chan, const u8 *dma_desc, if (single) dma_unmap_single(chan2dev(&td_chan->chan), addr, len, - td_chan->direction); + DMA_TO_DEVICE); else dma_unmap_page(chan2dev(&td_chan->chan), addr, len, - td_chan->direction); + DMA_TO_DEVICE); } static void __td_unmap_descs(struct timb_dma_desc *td_desc, bool single) @@ -235,7 +235,7 @@ static void __td_start_dma(struct timb_dma_chan *td_chan) "td_chan: %p, chan: %d, membase: %p\n", td_chan, td_chan->chan.chan_id, td_chan->membase); - if (td_chan->direction == DMA_FROM_DEVICE) { + if (td_chan->direction == DMA_DEV_TO_MEM) { /* descriptor address */ iowrite32(0, td_chan->membase + TIMBDMA_OFFS_RX_DHAR); @@ -278,7 +278,7 @@ static void __td_finish(struct timb_dma_chan *td_chan) txd->cookie); /* make sure to stop the transfer */ - if (td_chan->direction == DMA_FROM_DEVICE) + if (td_chan->direction == DMA_DEV_TO_MEM) iowrite32(0, td_chan->membase + TIMBDMA_OFFS_RX_ER); /* Currently no support for stopping DMA transfers else @@ -558,7 +558,7 @@ static void td_issue_pending(struct dma_chan *chan) static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, - enum dma_data_direction direction, unsigned long flags) + enum dma_transfer_direction direction, unsigned long flags) { struct timb_dma_chan *td_chan = container_of(chan, struct timb_dma_chan, chan); @@ -606,7 +606,7 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan, } dma_sync_single_for_device(chan2dmadev(chan), td_desc->txd.phys, - td_desc->desc_list_len, DMA_TO_DEVICE); + td_desc->desc_list_len, DMA_MEM_TO_DEV); return &td_desc->txd; } @@ -775,8 +775,8 @@ static int __devinit td_probe(struct platform_device *pdev) td_chan->descs = pchan->descriptors; td_chan->desc_elems = pchan->descriptor_elements; td_chan->bytes_per_line = pchan->bytes_per_line; - td_chan->direction = pchan->rx ? DMA_FROM_DEVICE : - DMA_TO_DEVICE; + td_chan->direction = pchan->rx ? DMA_DEV_TO_MEM : + DMA_MEM_TO_DEV; td_chan->membase = td->membase + (i / 2) * TIMBDMA_INSTANCE_OFFSET + @@ -841,17 +841,7 @@ static struct platform_driver td_driver = { .remove = __exit_p(td_remove), }; -static int __init td_init(void) -{ - return platform_driver_register(&td_driver); -} -module_init(td_init); - -static void __exit td_exit(void) -{ - platform_driver_unregister(&td_driver); -} -module_exit(td_exit); +module_platform_driver(td_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Timberdale DMA controller driver"); diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c index cbd83e362b5e..6122c364cf11 100644 --- a/drivers/dma/txx9dmac.c +++ b/drivers/dma/txx9dmac.c @@ -845,7 +845,7 @@ txx9dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, static struct dma_async_tx_descriptor * txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags) { struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); @@ -860,9 +860,9 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, BUG_ON(!ds || !ds->reg_width); if (ds->tx_reg) - BUG_ON(direction != DMA_TO_DEVICE); + BUG_ON(direction != DMA_MEM_TO_DEV); else - BUG_ON(direction != DMA_FROM_DEVICE); + BUG_ON(direction != DMA_DEV_TO_MEM); if (unlikely(!sg_len)) return NULL; @@ -882,7 +882,7 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, mem = sg_dma_address(sg); if (__is_dmac64(ddev)) { - if (direction == DMA_TO_DEVICE) { + if (direction == DMA_MEM_TO_DEV) { desc->hwdesc.SAR = mem; desc->hwdesc.DAR = ds->tx_reg; } else { @@ -891,7 +891,7 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, } desc->hwdesc.CNTR = sg_dma_len(sg); } else { - if (direction == DMA_TO_DEVICE) { + if (direction == DMA_MEM_TO_DEV) { desc->hwdesc32.SAR = mem; desc->hwdesc32.DAR = ds->tx_reg; } else { @@ -900,7 +900,7 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, } desc->hwdesc32.CNTR = sg_dma_len(sg); } - if (direction == DMA_TO_DEVICE) { + if (direction == DMA_MEM_TO_DEV) { sai = ds->reg_width; dai = 0; } else { diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index b153674431f1..e294e1b3616c 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -131,7 +131,7 @@ struct r82600_error_info { u32 eapr; }; -static unsigned int disable_hardware_scrub; +static bool disable_hardware_scrub; static struct edac_pci_ctl_info *r82600_pci; diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 68375bc3aef6..80e95aa3bf14 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -66,7 +66,7 @@ * * Concurrent logins are useful together with cluster filesystems. */ -static int sbp2_param_exclusive_login = 1; +static bool sbp2_param_exclusive_login = 1; module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644); MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " "(default = Y, use N for concurrent initiators)"); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 573532f7553e..d0c41188d4e5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -87,6 +87,7 @@ config GPIO_GENERIC_PLATFORM config GPIO_IT8761E tristate "IT8761E GPIO support" + depends on X86 # unconditional access to IO space. help Say yes here to support GPIO functionality of IT8761E super I/O chip. @@ -138,6 +139,7 @@ config GPIO_MXS config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA + select GENERIC_IRQ_CHIP help Say yes here to support the PrimeCell PL061 GPIO device diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 62e641e79e8f..fa10df604c01 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -2,7 +2,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG -obj-$(CONFIG_GPIOLIB) += gpiolib.o +obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o # Device drivers. Generally keep list sorted alphabetically obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c new file mode 100644 index 000000000000..3dd29399cef5 --- /dev/null +++ b/drivers/gpio/devres.c @@ -0,0 +1,90 @@ +/* + * drivers/gpio/devres.c - managed gpio resources + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This file is based on kernel/irq/devres.c + * + * Copyright (c) 2011 John Crispin <blogic@openwrt.org> + */ + +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/gfp.h> + +static void devm_gpio_release(struct device *dev, void *res) +{ + unsigned *gpio = res; + + gpio_free(*gpio); +} + +static int devm_gpio_match(struct device *dev, void *res, void *data) +{ + unsigned *this = res, *gpio = data; + + return *this == *gpio; +} + +/** + * devm_gpio_request - request a gpio for a managed device + * @dev: device to request the gpio for + * @gpio: gpio to allocate + * @label: the name of the requested gpio + * + * Except for the extra @dev argument, this function takes the + * same arguments and performs the same function as + * gpio_request(). GPIOs requested with this function will be + * automatically freed on driver detach. + * + * If an GPIO allocated with this function needs to be freed + * separately, devm_gpio_free() must be used. + */ + +int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) +{ + unsigned *dr; + int rc; + + dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + rc = gpio_request(gpio, label); + if (rc) { + devres_free(dr); + return rc; + } + + *dr = gpio; + devres_add(dev, dr); + + return 0; +} +EXPORT_SYMBOL(devm_gpio_request); + +/** + * devm_gpio_free - free an interrupt + * @dev: device to free gpio for + * @gpio: gpio to free + * + * Except for the extra @dev argument, this function takes the + * same arguments and performs the same function as gpio_free(). + * This function instead of gpio_free() should be used to manually + * free GPIOs allocated with devm_gpio_request(). + */ +void devm_gpio_free(struct device *dev, unsigned int gpio) +{ + + WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match, + &gpio)); + gpio_free(gpio); +} +EXPORT_SYMBOL(devm_gpio_free); diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 461958fc2264..03d6dd5dcb77 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -248,7 +248,7 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) static int ioh_irq_type(struct irq_data *d, unsigned int type) { u32 im; - u32 *im_reg; + void __iomem *im_reg; u32 ien; u32 im_pos; int ch; @@ -412,7 +412,7 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev, int i, j; struct ioh_gpio *chip; void __iomem *base; - void __iomem *chip_save; + void *chip_save; int irq_base; ret = pci_enable_device(pdev); @@ -428,7 +428,7 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev, } base = pci_iomap(pdev, 1, 0); - if (base == 0) { + if (!base) { dev_err(&pdev->dev, "%s : pci_iomap failed", __func__); ret = -ENOMEM; goto err_iomap; @@ -521,7 +521,7 @@ static void __devexit ioh_gpio_remove(struct pci_dev *pdev) int err; int i; struct ioh_gpio *chip = pci_get_drvdata(pdev); - void __iomem *chip_save; + void *chip_save; chip_save = chip; diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index f0603297f829..68fa55e86eb1 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -231,7 +231,7 @@ static void pch_gpio_setup(struct pch_gpio *chip) static int pch_irq_type(struct irq_data *d, unsigned int type) { u32 im; - u32 *im_reg; + u32 __iomem *im_reg; u32 ien; u32 im_pos; int ch; @@ -376,7 +376,7 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev, } chip->base = pci_iomap(pdev, 1, 0); - if (chip->base == 0) { + if (!chip->base) { dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); ret = -ENOMEM; goto err_iomap; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 8f79c03049f3..77c9cc70fa77 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -12,7 +12,6 @@ #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/module.h> -#include <linux/list.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/irq.h> @@ -23,6 +22,8 @@ #include <linux/amba/bus.h> #include <linux/amba/pl061.h> #include <linux/slab.h> +#include <linux/pm.h> +#include <asm/mach/irq.h> #define GPIODIR 0x400 #define GPIOIS 0x404 @@ -35,25 +36,33 @@ #define PL061_GPIO_NR 8 -struct pl061_gpio { - /* We use a list of pl061_gpio structs for each trigger IRQ in the main - * interrupts controller of the system. We need this to support systems - * in which more that one PL061s are connected to the same IRQ. The ISR - * interates through this list to find the source of the interrupt. - */ - struct list_head list; +#ifdef CONFIG_PM +struct pl061_context_save_regs { + u8 gpio_data; + u8 gpio_dir; + u8 gpio_is; + u8 gpio_ibe; + u8 gpio_iev; + u8 gpio_ie; +}; +#endif +struct pl061_gpio { /* Each of the two spinlocks protects a different set of hardware * regiters and data structurs. This decouples the code of the IRQ from * the GPIO code. This also makes the case of a GPIO routine call from * the IRQ code simpler. */ spinlock_t lock; /* GPIO registers */ - spinlock_t irq_lock; /* IRQ registers */ void __iomem *base; - unsigned irq_base; + int irq_base; + struct irq_chip_generic *irq_gc; struct gpio_chip gc; + +#ifdef CONFIG_PM + struct pl061_context_save_regs csave_regs; +#endif }; static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) @@ -118,46 +127,16 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - if (chip->irq_base == NO_IRQ) + if (chip->irq_base <= 0) return -EINVAL; return chip->irq_base + offset; } -/* - * PL061 GPIO IRQ - */ -static void pl061_irq_disable(struct irq_data *d) -{ - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - int offset = d->irq - chip->irq_base; - unsigned long flags; - u8 gpioie; - - spin_lock_irqsave(&chip->irq_lock, flags); - gpioie = readb(chip->base + GPIOIE); - gpioie &= ~(1 << offset); - writeb(gpioie, chip->base + GPIOIE); - spin_unlock_irqrestore(&chip->irq_lock, flags); -} - -static void pl061_irq_enable(struct irq_data *d) -{ - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - int offset = d->irq - chip->irq_base; - unsigned long flags; - u8 gpioie; - - spin_lock_irqsave(&chip->irq_lock, flags); - gpioie = readb(chip->base + GPIOIE); - gpioie |= 1 << offset; - writeb(gpioie, chip->base + GPIOIE); - spin_unlock_irqrestore(&chip->irq_lock, flags); -} - static int pl061_irq_type(struct irq_data *d, unsigned trigger) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = gc->private; int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpiois, gpioibe, gpioiev; @@ -165,7 +144,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) if (offset < 0 || offset >= PL061_GPIO_NR) return -EINVAL; - spin_lock_irqsave(&chip->irq_lock, flags); + raw_spin_lock_irqsave(&gc->lock, flags); gpioiev = readb(chip->base + GPIOIEV); @@ -194,49 +173,54 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) writeb(gpioiev, chip->base + GPIOIEV); - spin_unlock_irqrestore(&chip->irq_lock, flags); + raw_spin_unlock_irqrestore(&gc->lock, flags); return 0; } -static struct irq_chip pl061_irqchip = { - .name = "GPIO", - .irq_enable = pl061_irq_enable, - .irq_disable = pl061_irq_disable, - .irq_set_type = pl061_irq_type, -}; - static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) { - struct list_head *chip_list = irq_get_handler_data(irq); - struct list_head *ptr; - struct pl061_gpio *chip; - - desc->irq_data.chip->irq_ack(&desc->irq_data); - list_for_each(ptr, chip_list) { - unsigned long pending; - int offset; + unsigned long pending; + int offset; + struct pl061_gpio *chip = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); - chip = list_entry(ptr, struct pl061_gpio, list); - pending = readb(chip->base + GPIOMIS); - writeb(pending, chip->base + GPIOIC); - - if (pending == 0) - continue; + chained_irq_enter(irqchip, desc); + pending = readb(chip->base + GPIOMIS); + writeb(pending, chip->base + GPIOIC); + if (pending) { for_each_set_bit(offset, &pending, PL061_GPIO_NR) generic_handle_irq(pl061_to_irq(&chip->gc, offset)); } - desc->irq_data.chip->irq_unmask(&desc->irq_data); + + chained_irq_exit(irqchip, desc); +} + +static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base) +{ + struct irq_chip_type *ct; + + chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base, + chip->base, handle_simple_irq); + chip->irq_gc->private = chip; + + ct = chip->irq_gc->chip_types; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_set_type = pl061_irq_type; + ct->chip.irq_set_wake = irq_gc_set_wake; + ct->regs.mask = GPIOIE; + + irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR), + IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); } static int pl061_probe(struct amba_device *dev, const struct amba_id *id) { struct pl061_platform_data *pdata; struct pl061_gpio *chip; - struct list_head *chip_list; int ret, irq, i; - static DECLARE_BITMAP(init_irq, NR_IRQS); chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -248,7 +232,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) chip->irq_base = pdata->irq_base; } else if (dev->dev.of_node) { chip->gc.base = -1; - chip->irq_base = NO_IRQ; + chip->irq_base = 0; } else { ret = -ENODEV; goto free_mem; @@ -267,8 +251,6 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) } spin_lock_init(&chip->lock); - spin_lock_init(&chip->irq_lock); - INIT_LIST_HEAD(&chip->list); chip->gc.direction_input = pl061_direction_input; chip->gc.direction_output = pl061_direction_output; @@ -288,9 +270,11 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) * irq_chip support */ - if (chip->irq_base == NO_IRQ) + if (chip->irq_base <= 0) return 0; + pl061_init_gc(chip, chip->irq_base); + writeb(0, chip->base + GPIOIE); /* disable irqs */ irq = dev->irq[0]; if (irq < 0) { @@ -298,18 +282,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) goto iounmap; } irq_set_chained_handler(irq, pl061_irq_handler); - if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ - chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); - if (chip_list == NULL) { - clear_bit(irq, init_irq); - ret = -ENOMEM; - goto iounmap; - } - INIT_LIST_HEAD(chip_list); - irq_set_handler_data(irq, chip_list); - } else - chip_list = irq_get_handler_data(irq); - list_add(&chip->list, chip_list); + irq_set_handler_data(irq, chip); for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { @@ -319,13 +292,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) else pl061_direction_input(&chip->gc, i); } - - irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip, - handle_simple_irq); - set_irq_flags(i+chip->irq_base, IRQF_VALID); - irq_set_chip_data(i + chip->irq_base, chip); } + amba_set_drvdata(dev, chip); + return 0; iounmap: @@ -338,6 +308,53 @@ free_mem: return ret; } +#ifdef CONFIG_PM +static int pl061_suspend(struct device *dev) +{ + struct pl061_gpio *chip = dev_get_drvdata(dev); + int offset; + + chip->csave_regs.gpio_data = 0; + chip->csave_regs.gpio_dir = readb(chip->base + GPIODIR); + chip->csave_regs.gpio_is = readb(chip->base + GPIOIS); + chip->csave_regs.gpio_ibe = readb(chip->base + GPIOIBE); + chip->csave_regs.gpio_iev = readb(chip->base + GPIOIEV); + chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE); + + for (offset = 0; offset < PL061_GPIO_NR; offset++) { + if (chip->csave_regs.gpio_dir & (1 << offset)) + chip->csave_regs.gpio_data |= + pl061_get_value(&chip->gc, offset) << offset; + } + + return 0; +} + +static int pl061_resume(struct device *dev) +{ + struct pl061_gpio *chip = dev_get_drvdata(dev); + int offset; + + for (offset = 0; offset < PL061_GPIO_NR; offset++) { + if (chip->csave_regs.gpio_dir & (1 << offset)) + pl061_direction_output(&chip->gc, offset, + chip->csave_regs.gpio_data & + (1 << offset)); + else + pl061_direction_input(&chip->gc, offset); + } + + writeb(chip->csave_regs.gpio_is, chip->base + GPIOIS); + writeb(chip->csave_regs.gpio_ibe, chip->base + GPIOIBE); + writeb(chip->csave_regs.gpio_iev, chip->base + GPIOIEV); + writeb(chip->csave_regs.gpio_ie, chip->base + GPIOIE); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume); +#endif + static struct amba_id pl061_ids[] = { { .id = 0x00041061, @@ -351,6 +368,9 @@ MODULE_DEVICE_TABLE(amba, pl061_ids); static struct amba_driver pl061_gpio_driver = { .drv = { .name = "pl061_gpio", +#ifdef CONFIG_PM + .pm = &pl061_dev_pm_ops, +#endif }, .id_table = pl061_ids, .probe = pl061_probe, diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index b6c1f6d80649..7eecf69362ee 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -47,12 +47,18 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int return 0; } +static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return offset < 11 ? (IRQ_GPIO0 + offset) : (IRQ_GPIO11 - 11 + offset); +} + static struct gpio_chip sa1100_gpio_chip = { .label = "gpio", .direction_input = sa1100_direction_input, .direction_output = sa1100_direction_output, .set = sa1100_gpio_set, .get = sa1100_gpio_get, + .to_irq = sa1100_to_irq, .base = 0, .ngpio = GPIO_MAX + 1, }; diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 4c980b573328..87a68a896abf 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -65,7 +65,14 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val) u8 reg = stmpe->regs[which] - (offset / 8); u8 mask = 1 << (offset % 8); - stmpe_reg_write(stmpe, reg, mask); + /* + * Some variants have single register for gpio set/clear functionality. + * For them we need to write 0 to clear and 1 to set. + */ + if (stmpe->regs[STMPE_IDX_GPSR_LSB] == stmpe->regs[STMPE_IDX_GPCR_LSB]) + stmpe_set_bits(stmpe, reg, mask, val ? mask : 0); + else + stmpe_reg_write(stmpe, reg, mask); } static int stmpe_gpio_direction_output(struct gpio_chip *chip, @@ -132,6 +139,10 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) return -EINVAL; + /* STMPE801 doesn't have RE and FE registers */ + if (stmpe_gpio->stmpe->partnum == STMPE801) + return 0; + if (type == IRQ_TYPE_EDGE_RISING) stmpe_gpio->regs[REG_RE][regoffset] |= mask; else @@ -165,6 +176,11 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) int i, j; for (i = 0; i < CACHE_NR_REGS; i++) { + /* STMPE801 doesn't have RE and FE registers */ + if ((stmpe->partnum == STMPE801) && + (i != REG_IE)) + continue; + for (j = 0; j < num_banks; j++) { u8 old = stmpe_gpio->oldregs[i][j]; u8 new = stmpe_gpio->regs[i][j]; @@ -241,8 +257,11 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) } stmpe_reg_write(stmpe, statmsbreg + i, status[i]); - stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + i, - status[i]); + + /* Edge detect register is not present on 801 */ + if (stmpe->partnum != STMPE801) + stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + + i, status[i]); } return IRQ_HANDLED; diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 61044c889f7f..bdc293791590 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -361,14 +361,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; } - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "Couldn't request MEM resource\n"); - return -ENODEV; - } - - regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + regs = devm_request_and_ioremap(&pdev->dev, res); if (!regs) { dev_err(&pdev->dev, "Couldn't ioremap regs\n"); return -ENODEV; diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index b9c1c297669e..91f45b965d1e 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -52,7 +52,7 @@ static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset, struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio); /* Set the initial value */ - tps65910_gpio_set(gc, 0, value); + tps65910_gpio_set(gc, offset, value); return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset, GPIO_CFG_MASK); diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 6d0f10b7569c..c100f3e9c920 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -66,6 +66,7 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) static int cdv_intel_crt_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; int max_clock = 0; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -82,6 +83,11 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector, if (mode->hdisplay > 1680 || mode->vdisplay > 1050) return MODE_PANEL; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index 50d7cfb51662..de25560e629d 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -241,6 +241,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector) static int cdv_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; if (mode->clock > 165000) return MODE_CLOCK_HIGH; @@ -255,14 +256,11 @@ static int cdv_hdmi_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_INTERLACE) return MODE_NO_INTERLACE; - /* - * FIXME: for now we limit the size to 1680x1050 on CDV, otherwise it - * will go beyond the stolen memory size allocated to the framebuffer - */ - if (mode->hdisplay > 1680) - return MODE_PANEL; - if (mode->vdisplay > 1050) - return MODE_PANEL; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index e770bd190a5c..5d5330f667f1 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -20,6 +20,7 @@ */ #include <drm/drmP.h> +#include <linux/shmem_fs.h> #include "psb_drv.h" @@ -203,9 +204,7 @@ static int psb_gtt_attach_pages(struct gtt_range *gt) gt->npage = pages; for (i = 0; i < pages; i++) { - /* FIXME: needs updating as per mail from Hugh Dickins */ - p = read_cache_page_gfp(mapping, i, - __GFP_COLD | GFP_KERNEL); + p = shmem_read_mapping_page(mapping, i); if (IS_ERR(p)) goto err; gt->pages[i] = p; diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index 36878a60080d..025d30970cc0 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -506,6 +506,7 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; if (mode->clock > 165000) return MODE_CLOCK_HIGH; if (mode->clock < 20000) @@ -514,6 +515,11 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 4882b29119e0..88b42971c0fd 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -1141,6 +1141,7 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode) static int psb_intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) @@ -1160,6 +1161,11 @@ static int psb_intel_sdvo_mode_valid(struct drm_connector *connector, return MODE_PANEL; } + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 525744d593c1..7814a760c164 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -18,12 +18,6 @@ #include <linux/vga_switcheroo.h> -#define NOUVEAU_DSM_SUPPORTED 0x00 -#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00 - -#define NOUVEAU_DSM_ACTIVE 0x01 -#define NOUVEAU_DSM_ACTIVE_QUERY 0x00 - #define NOUVEAU_DSM_LED 0x02 #define NOUVEAU_DSM_LED_STATE 0x00 #define NOUVEAU_DSM_LED_OFF 0x10 @@ -35,6 +29,9 @@ #define NOUVEAU_DSM_POWER_SPEED 0x01 #define NOUVEAU_DSM_POWER_STAMINA 0x02 +#define NOUVEAU_DSM_OPTIMUS_FN 0x1A +#define NOUVEAU_DSM_OPTIMUS_ARGS 0x03000001 + static struct nouveau_dsm_priv { bool dsm_detected; bool optimus_detected; @@ -61,7 +58,8 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t * struct acpi_object_list input; union acpi_object params[4]; union acpi_object *obj; - int err; + int i, err; + char args_buff[4]; input.count = 4; input.pointer = params; @@ -73,7 +71,11 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t * params[2].type = ACPI_TYPE_INTEGER; params[2].integer.value = func; params[3].type = ACPI_TYPE_BUFFER; - params[3].buffer.length = 0; + params[3].buffer.length = 4; + /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ + for (i = 0; i < 4; i++) + args_buff[i] = (arg >> i * 8) & 0xFF; + params[3].buffer.pointer = args_buff; err = acpi_evaluate_object(handle, "_DSM", &input, &output); if (err) { @@ -148,6 +150,23 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) return 0; } +/* Returns 1 if a DSM function is usable and 0 otherwise */ +static int nouveau_test_dsm(acpi_handle test_handle, + int (*dsm_func)(acpi_handle, int, int, uint32_t *), + int sfnc) +{ + u32 result = 0; + + /* Function 0 returns a Buffer containing available functions. The args + * parameter is ignored for function 0, so just put 0 in it */ + if (dsm_func(test_handle, 0, 0, &result)) + return 0; + + /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If + * the n-th bit is enabled, function n is supported */ + return result & 1 && result & (1 << sfnc); +} + static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) { mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); @@ -168,6 +187,10 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id) { + /* perhaps the _DSM functions are mutually exclusive, but prepare for + * the future */ + if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected) + return 0; if (id == VGA_SWITCHEROO_IGD) return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA); else @@ -180,6 +203,11 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, if (id == VGA_SWITCHEROO_IGD) return 0; + /* Optimus laptops have the card already disabled in + * nouveau_switcheroo_set_state */ + if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected) + return 0; + return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state); } @@ -212,8 +240,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) { acpi_handle dhandle, nvidia_handle; acpi_status status; - int ret, retval = 0; - uint32_t result; + int retval = 0; dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); if (!dhandle) @@ -224,13 +251,11 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) return false; } - ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED, - NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); - if (ret == 0) + if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) retval |= NOUVEAU_DSM_HAS_MUX; - ret = nouveau_optimus_dsm(dhandle, 0, 0, &result); - if (ret == 0) + if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm, + NOUVEAU_DSM_OPTIMUS_FN)) retval |= NOUVEAU_DSM_HAS_OPT; if (retval) @@ -269,15 +294,22 @@ static bool nouveau_dsm_detect(void) } if (vga_count == 2 && has_dsm && guid_valid) { - acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, + &buffer); printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", - acpi_method_name); + acpi_method_name); nouveau_dsm_priv.dsm_detected = true; ret = true; } - if (has_optimus == 1) + if (has_optimus == 1) { + acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, + &buffer); + printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n", + acpi_method_name); nouveau_dsm_priv.optimus_detected = true; + ret = true; + } return ret; } @@ -293,6 +325,17 @@ void nouveau_register_dsm_handler(void) vga_switcheroo_register_handler(&nouveau_dsm_handler); } +/* Must be called for Optimus models before the card can be turned off */ +void nouveau_switcheroo_optimus_dsm(void) +{ + u32 result = 0; + if (!nouveau_dsm_priv.optimus_detected) + return; + + nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FN, + NOUVEAU_DSM_OPTIMUS_ARGS, &result); +} + void nouveau_unregister_dsm_handler(void) { vga_switcheroo_unregister_handler(); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 38134a9c7578..b82709828931 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1055,12 +1055,14 @@ extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); #if defined(CONFIG_ACPI) void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); +void nouveau_switcheroo_optimus_dsm(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); int nouveau_acpi_edid(struct drm_device *, struct drm_connector *); #else static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} +static inline void nouveau_switcheroo_optimus_dsm(void) {} static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index f5e98910d17f..f80c5e0762ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -525,6 +525,7 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev, printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(dev); + nouveau_switcheroo_optimus_dsm(); nouveau_pci_suspend(pdev, pmm); dev->switch_power_state = DRM_SWITCH_POWER_OFF; } diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index f7442e62c03f..8e8cd85e5c00 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -1793,10 +1793,12 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) ret = -EINVAL; break; case PACKET_TYPE2: + idx += 1; break; case PACKET_TYPE3: pkt.opcode = CP_PACKET3_GET_OPCODE(ib->ptr[idx]); ret = evergreen_vm_packet3_check(rdev, ib->ptr, &pkt); + idx += pkt.count + 2; break; default: dev_err(rdev->dev, "Unknown packet type %d !\n", pkt.type); @@ -1805,7 +1807,6 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) } if (ret) break; - idx += pkt.count + 2; } while (idx < ib->length_dw); return ret; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 3ec81c3d5108..bfd36ab643a6 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2186,7 +2186,6 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) void r100_bm_disable(struct radeon_device *rdev) { u32 tmp; - u16 tmp16; /* disable bus mastering */ tmp = RREG32(R_000030_BUS_CNTL); @@ -2197,8 +2196,7 @@ void r100_bm_disable(struct radeon_device *rdev) WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); tmp = RREG32(RADEON_BUS_CNTL); mdelay(1); - pci_read_config_word(rdev->pdev, 0x4, &tmp16); - pci_write_config_word(rdev->pdev, 0x4, tmp16 & 0xFFFB); + pci_clear_master(rdev->pdev); mdelay(1); } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 31da622eef63..8032f1fedb11 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -145,7 +145,7 @@ module_param_named(vramlimit, radeon_vram_limit, int, 0600); MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); module_param_named(agpmode, radeon_agpmode, int, 0444); -MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32,64, etc)\n"); +MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32, 64, etc)"); module_param_named(gartsize, radeon_gart_size, int, 0600); MODULE_PARM_DESC(benchmark, "Run benchmark"); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 803e0d3c1773..ec46eb45e34c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -322,16 +322,6 @@ void rs600_hpd_fini(struct radeon_device *rdev) } } -void rs600_bm_disable(struct radeon_device *rdev) -{ - u16 tmp; - - /* disable bus mastering */ - pci_read_config_word(rdev->pdev, 0x4, &tmp); - pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); - mdelay(1); -} - int rs600_asic_reset(struct radeon_device *rdev) { struct rv515_mc_save save; @@ -355,7 +345,8 @@ int rs600_asic_reset(struct radeon_device *rdev) WREG32(RADEON_CP_RB_CNTL, tmp); pci_save_state(rdev->pdev); /* disable bus mastering */ - rs600_bm_disable(rdev); + pci_clear_master(rdev->pdev); + mdelay(1); /* reset GA+VAP */ WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | S_0000F0_SOFT_RESET_GA(1)); diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index 37ead6995c87..0c46d8cdc6ea 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -952,10 +952,9 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) type = ttm_to_type(ttm->page_flags, ttm->caching_state); pool = ttm_dma_find_pool(dev, type); - if (!pool) { - WARN_ON(!pool); + if (!pool) return; - } + is_cached = (ttm_dma_find_pool(pool->dev, ttm_to_type(ttm->page_flags, tt_cached)) == pool); diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index f779009104eb..b71b77ab0dc7 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -90,7 +90,7 @@ static const char longname[] = "Prodikeys PC-MIDI Keyboard"; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; module_param_array(index, int, NULL, 0444); module_param_array(id, charp, NULL, 0444); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index cb351d358387..02260406b9e4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -474,8 +474,8 @@ config SENSORS_IT87 select HWMON_VID help If you say yes here you get support for ITE IT8705F, IT8712F, - IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor - chips, and the SiS960 clone. + IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E + sensor chips, and the SiS960 clone. This driver can also be built as a module. If so, the module will be called it87. @@ -515,11 +515,11 @@ config SENSORS_LINEAGE will be called lineage-pem. config SENSORS_LM63 - tristate "National Semiconductor LM63 and LM64" + tristate "National Semiconductor LM63 and compatibles" depends on I2C help If you say yes here you get support for the National - Semiconductor LM63 and LM64 remote diode digital temperature + Semiconductor LM63, LM64, and LM96163 remote diode digital temperature sensors with integrated fan control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro) motherboard, among others. diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 65a35cf5b3c5..3b728e8f169b 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -145,7 +145,7 @@ static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 }; /* Insmod parameters */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Set to one to force detection."); static int bank1_types[ABIT_UGURU_MAX_BANK1_SENSORS] = { -1, -1, -1, -1, -1, diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index d30855a75786..34a14a77e008 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -603,11 +603,11 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { /* Insmod parameters */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Set to one to force detection."); /* Default verbose is 1, since this driver is still in the testing phase */ -static int verbose = 1; +static bool verbose = 1; module_param(verbose, bool, 0644); MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting"); diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 522860ab6ce8..554f046bcf20 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -58,7 +58,7 @@ ACPI_MODULE_NAME(ACPI_POWER_METER_NAME); #define POWER_ALARM_NAME "power1_alarm" static int cap_in_hardware; -static int force_cap_on; +static bool force_cap_on; static int can_cap_in_hardware(void) { diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 1ad0a885c5a5..0158cc35cb2e 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -103,7 +103,7 @@ static int adm1021_remove(struct i2c_client *client); static struct adm1021_data *adm1021_update_device(struct device *dev); /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only; +static bool read_only; static const struct i2c_device_id adm1021_id[] = { diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index e6291dafa4ca..97e2cfb0bc93 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -155,7 +155,8 @@ adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) #define TEMP_OFFSET_FROM_REG(val) TEMP_FROM_REG((val) < 0 ? \ (val) | 0x70 : (val)) -#define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0) +#define FAN_FROM_REG(reg, div) ((reg) ? \ + (11250 * 60) / ((reg) * (div)) : 0) static int FAN_TO_REG(int reg, int div) { @@ -174,8 +175,8 @@ static int FAN_TO_REG(int reg, int div) (((reg) & 0x1F) | (((val) << 5) & 0xe0)) #define AUTO_TEMP_MIN_TO_REG(val, reg) \ - ((((val)/500) & 0xf8)|((reg) & 0x7)) -#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7))) + ((((val) / 500) & 0xf8) | ((reg) & 0x7)) +#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1 << ((reg) & 0x7))) #define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) #define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) @@ -202,7 +203,7 @@ static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) /* FAN auto control */ #define GET_FAN_AUTO_BITFIELD(data, idx) \ - (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] + (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2] /* The tables below contains the possible values for the auto fan * control bitfields. the index in the table is the register value. @@ -230,7 +231,7 @@ static const auto_chan_table_t auto_channel_select_table_adm1030 = { */ static int get_fan_auto_nearest(struct adm1031_data *data, - int chan, u8 val, u8 reg, u8 * new_reg) + int chan, u8 val, u8 reg, u8 *new_reg) { int i; int first_match = -1, exact_match = -1; @@ -258,13 +259,13 @@ get_fan_auto_nearest(struct adm1031_data *data, } } - if (exact_match >= 0) { + if (exact_match >= 0) *new_reg = exact_match; - } else if (first_match >= 0) { + else if (first_match >= 0) *new_reg = first_match; - } else { + else return -EINVAL; - } + return 0; } @@ -283,23 +284,28 @@ set_fan_auto_channel(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; u8 reg; int ret; u8 old_fan_mode; + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; + old_fan_mode = data->conf1; mutex_lock(&data->update_lock); - if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { + ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®); + if (ret) { mutex_unlock(&data->update_lock); return ret; } data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^ (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { - if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ + if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { /* Switch to Auto Fan Mode * Save PWM registers * Set PWM registers to 33% Both */ @@ -350,7 +356,12 @@ set_auto_temp_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; mutex_lock(&data->update_lock); data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); @@ -374,10 +385,16 @@ set_auto_temp_max(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; mutex_lock(&data->update_lock); - data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); + data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], + data->pwm[nr]); adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), data->temp_max[nr]); mutex_unlock(&data->update_lock); @@ -410,8 +427,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); - int reg; + long val; + int ret, reg; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; mutex_lock(&data->update_lock); if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && @@ -449,9 +470,13 @@ static int trust_fan_readings(struct adm1031_data *data, int chan) if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { switch (data->conf1 & 0x60) { - case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */ + case 0x00: + /* + * remote temp1 controls fan1, + * remote temp2 controls fan2 + */ res = data->temp[chan+1] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); break; case 0x20: /* remote temp1 controls both fans */ res = @@ -515,7 +540,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; mutex_lock(&data->update_lock); if (val) { @@ -534,10 +564,15 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; u8 tmp; int old_div; int new_min; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; tmp = val == 8 ? 0xc0 : val == 4 ? 0x80 : @@ -631,9 +666,13 @@ static ssize_t set_temp_offset(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; - val = simple_strtol(buf, NULL, 10); val = SENSORS_LIMIT(val, -15000, 15000); mutex_lock(&data->update_lock); data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val); @@ -648,9 +687,13 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; - val = simple_strtol(buf, NULL, 10); val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_min[nr] = TEMP_TO_REG(val); @@ -665,9 +708,13 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; - val = simple_strtol(buf, NULL, 10); val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_max[nr] = TEMP_TO_REG(val); @@ -682,9 +729,13 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; - val = simple_strtol(buf, NULL, 10); val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_crit[nr] = TEMP_TO_REG(val); @@ -711,7 +762,8 @@ temp_reg(2); temp_reg(3); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", data->alarm); @@ -919,12 +971,13 @@ static int adm1031_probe(struct i2c_client *client, adm1031_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group))) + err = sysfs_create_group(&client->dev.kobj, &adm1031_group); + if (err) goto exit_free; if (data->chip_type == adm1031) { - if ((err = sysfs_create_group(&client->dev.kobj, - &adm1031_group_opt))) + err = sysfs_create_group(&client->dev.kobj, &adm1031_group_opt); + if (err) goto exit_remove; } @@ -970,14 +1023,13 @@ static void adm1031_init_client(struct i2c_client *client) } /* Initialize the ADM1031 chip (enables fan speed reading ) */ read_val = adm1031_read_value(client, ADM1031_REG_CONF2); - if ((read_val | mask) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); - } + if ((read_val | mask) != read_val) + adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); read_val = adm1031_read_value(client, ADM1031_REG_CONF1); if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF1, read_val | - ADM1031_CONF1_MONITOR_ENABLE); + adm1031_write_value(client, ADM1031_REG_CONF1, + read_val | ADM1031_CONF1_MONITOR_ENABLE); } /* Read the chip's update rate */ @@ -1024,8 +1076,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev) /* oldh is actually newer */ if (newh != oldh) dev_warn(&client->dev, - "Remote temperature may be " - "wrong.\n"); + "Remote temperature may be wrong.\n"); #endif } data->temp[chan] = newh; @@ -1052,22 +1103,24 @@ static struct adm1031_data *adm1031_update_device(struct device *dev) data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) - | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) - << 8); - if (data->chip_type == adm1030) { + | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8); + if (data->chip_type == adm1030) data->alarm &= 0xc0ff; - } - for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { + for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2); + chan++) { data->fan_div[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); + adm1031_read_value(client, + ADM1031_REG_FAN_DIV(chan)); data->fan_min[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan)); + adm1031_read_value(client, + ADM1031_REG_FAN_MIN(chan)); data->fan[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); + adm1031_read_value(client, + ADM1031_REG_FAN_SPEED(chan)); data->pwm[chan] = - 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> - (4*chan)); + (adm1031_read_value(client, + ADM1031_REG_PWM) >> (4 * chan)) & 0x0f; } data->last_updated = jiffies; data->valid = 1; diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index cfcc3b6fb6bf..ed60242d6a0a 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -48,8 +48,8 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; /* Module parameters */ -static int se_input = 1; /* Default is SE, 0 == diff */ -static int int_vref = 1; /* Default is internal ref ON */ +static bool se_input = 1; /* Default is SE, 0 == diff */ +static bool int_vref = 1; /* Default is internal ref ON */ static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */ module_param(se_input, bool, S_IRUGO); module_param(int_vref, bool, S_IRUGO); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 1fdef885341c..a6c6ec36615e 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -190,7 +190,8 @@ static ssize_t show_temp(struct device *dev, return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN; } -static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) +static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, + struct device *dev) { /* The 100C is default for both mobile and non mobile CPUs */ @@ -284,7 +285,8 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) return tjmax; } -static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) +static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id, + struct device *dev) { int err; u32 eax, edx; @@ -323,7 +325,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) return adjust_tjmax(c, id, dev); } -static int create_name_attr(struct platform_data *pdata, struct device *dev) +static int __devinit create_name_attr(struct platform_data *pdata, + struct device *dev) { sysfs_attr_init(&pdata->name_attr.attr); pdata->name_attr.attr.name = "name"; @@ -332,8 +335,8 @@ static int create_name_attr(struct platform_data *pdata, struct device *dev) return device_create_file(dev, &pdata->name_attr); } -static int create_core_attrs(struct temp_data *tdata, struct device *dev, - int attr_no) +static int __cpuinit create_core_attrs(struct temp_data *tdata, + struct device *dev, int attr_no) { int err, i; static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev, @@ -383,7 +386,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu) return 0; } -static struct platform_device *coretemp_get_pdev(unsigned int cpu) +static struct platform_device __cpuinit *coretemp_get_pdev(unsigned int cpu) { u16 phys_proc_id = TO_PHYS_ID(cpu); struct pdev_entry *p; @@ -400,7 +403,8 @@ static struct platform_device *coretemp_get_pdev(unsigned int cpu) return NULL; } -static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) +static struct temp_data __cpuinit *init_temp_data(unsigned int cpu, + int pkg_flag) { struct temp_data *tdata; @@ -418,7 +422,7 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) return tdata; } -static int create_core_data(struct platform_device *pdev, +static int __cpuinit create_core_data(struct platform_device *pdev, unsigned int cpu, int pkg_flag) { struct temp_data *tdata; @@ -489,7 +493,7 @@ exit_free: return err; } -static void coretemp_add_core(unsigned int cpu, int pkg_flag) +static void __cpuinit coretemp_add_core(unsigned int cpu, int pkg_flag) { struct platform_device *pdev = coretemp_get_pdev(cpu); int err; @@ -618,7 +622,7 @@ exit: return err; } -static void coretemp_device_remove(unsigned int cpu) +static void __cpuinit coretemp_device_remove(unsigned int cpu) { struct pdev_entry *p, *n; u16 phys_proc_id = TO_PHYS_ID(cpu); @@ -634,7 +638,7 @@ static void coretemp_device_remove(unsigned int cpu) mutex_unlock(&pdev_list_mutex); } -static bool is_any_core_online(struct platform_data *pdata) +static bool __cpuinit is_any_core_online(struct platform_data *pdata) { int i; diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index d9803958e49f..ffb229af7861 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -45,7 +45,7 @@ static struct platform_device *pdev; /* Module load parameters */ -static int force_start; +static bool force_start; module_param(force_start, bool, 0); MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs"); @@ -53,7 +53,7 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -static int probe_all_addr; +static bool probe_all_addr; module_param(probe_all_addr, bool, 0); MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC " "addresses"); diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 848a2b0bc83f..865063914d76 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -55,7 +55,7 @@ static const u8 REG_TEMP_MAX[4] = { 0x34, 0x30, 0x31, 0x32 }; * it. Default is to leave the device in the state it's already in (-1). * This parameter allows APD mode to be optionally forced on or off */ static int apd = -1; -module_param(apd, bool, 0); +module_param(apd, bint, 0); MODULE_PARM_DESC(init, "Set to zero to disable anti-parallel diode mode"); struct temperature { diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 38c0b87676de..0054d6f9cec9 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -17,6 +17,7 @@ * IT8720F Super I/O chip w/LPC interface * IT8721F Super I/O chip w/LPC interface * IT8726F Super I/O chip w/LPC interface + * IT8728F Super I/O chip w/LPC interface * IT8758E Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F * @@ -58,7 +59,7 @@ #define DRVNAME "it87" -enum chips { it87, it8712, it8716, it8718, it8720, it8721 }; +enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -135,6 +136,7 @@ static inline void superio_exit(void) #define IT8720F_DEVID 0x8720 #define IT8721F_DEVID 0x8721 #define IT8726F_DEVID 0x8726 +#define IT8728F_DEVID 0x8728 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -146,10 +148,10 @@ static inline void superio_exit(void) #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ /* Update battery voltage after every reading if true */ -static int update_vbat; +static bool update_vbat; /* Not all BIOSes properly configure the PWM registers */ -static int fix_pwm_polarity; +static bool fix_pwm_polarity; /* Many IT87 constants specified below */ @@ -274,11 +276,31 @@ struct it87_data { s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ }; +static inline int has_12mv_adc(const struct it87_data *data) +{ + /* + * IT8721F and later have a 12 mV ADC, also with internal scaling + * on selected inputs. + */ + return data->type == it8721 + || data->type == it8728; +} + +static inline int has_newer_autopwm(const struct it87_data *data) +{ + /* + * IT8721F and later have separate registers for the temperature + * mapping and the manual duty cycle. + */ + return data->type == it8721 + || data->type == it8728; +} + static u8 in_to_reg(const struct it87_data *data, int nr, long val) { long lsb; - if (data->type == it8721) { + if (has_12mv_adc(data)) { if (data->in_scaled & (1 << nr)) lsb = 24; else @@ -292,7 +314,7 @@ static u8 in_to_reg(const struct it87_data *data, int nr, long val) static int in_from_reg(const struct it87_data *data, int nr, int val) { - if (data->type == it8721) { + if (has_12mv_adc(data)) { if (data->in_scaled & (1 << nr)) return val * 24; else @@ -329,7 +351,7 @@ static inline u16 FAN16_TO_REG(long rpm) static u8 pwm_to_reg(const struct it87_data *data, long val) { - if (data->type == it8721) + if (has_newer_autopwm(data)) return val; else return val >> 1; @@ -337,7 +359,7 @@ static u8 pwm_to_reg(const struct it87_data *data, long val) static int pwm_from_reg(const struct it87_data *data, u8 reg) { - if (data->type == it8721) + if (has_newer_autopwm(data)) return reg; else return (reg & 0x7f) << 1; @@ -374,7 +396,8 @@ static inline int has_16bit_fans(const struct it87_data *data) || data->type == it8716 || data->type == it8718 || data->type == it8720 - || data->type == it8721; + || data->type == it8721 + || data->type == it8728; } static inline int has_old_autopwm(const struct it87_data *data) @@ -842,7 +865,7 @@ static ssize_t set_pwm_enable(struct device *dev, data->fan_main_ctrl); } else { if (val == 1) /* Manual mode */ - data->pwm_ctrl[nr] = data->type == it8721 ? + data->pwm_ctrl[nr] = has_newer_autopwm(data) ? data->pwm_temp_map[nr] : data->pwm_duty[nr]; else /* Automatic mode */ @@ -870,7 +893,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - if (data->type == it8721) { + if (has_newer_autopwm(data)) { /* If we are in automatic mode, the PWM duty cycle register * is read-only so we can't write the value */ if (data->pwm_ctrl[nr] & 0x80) { @@ -1311,8 +1334,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr(attr)->index; - return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr] - : labels[nr]); + return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr] + : labels[nr]); } static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); @@ -1605,6 +1628,9 @@ static int __init it87_find(unsigned short *address, case IT8721F_DEVID: sio_data->type = it8721; break; + case IT8728F_DEVID: + sio_data->type = it8728; + break; case 0xffff: /* No device at all */ goto exit; default: @@ -1646,8 +1672,11 @@ static int __init it87_find(unsigned short *address, superio_select(GPIO); reg = superio_inb(IT87_SIO_GPIO3_REG); - if (sio_data->type == it8721) { - /* The IT8721F/IT8758E doesn't have VID pins at all */ + if (sio_data->type == it8721 || sio_data->type == it8728) { + /* + * The IT8721F/IT8758E doesn't have VID pins at all, + * not sure about the IT8728F. + */ sio_data->skip_vid = 1; } else { /* We need at least 4 VID pins */ @@ -1692,7 +1721,8 @@ static int __init it87_find(unsigned short *address, } if (reg & (1 << 0)) sio_data->internal |= (1 << 0); - if ((reg & (1 << 1)) || sio_data->type == it8721) + if ((reg & (1 << 1)) || sio_data->type == it8721 || + sio_data->type == it8728) sio_data->internal |= (1 << 1); sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; @@ -1770,6 +1800,7 @@ static int __devinit it87_probe(struct platform_device *pdev) "it8718", "it8720", "it8721", + "it8728", }; res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -1807,7 +1838,7 @@ static int __devinit it87_probe(struct platform_device *pdev) enable_pwm_interface = it87_check_pwm(dev); /* Starting with IT8721F, we handle scaling of internal voltages */ - if (data->type == it8721) { + if (has_12mv_adc(data)) { if (sio_data->internal & (1 << 0)) data->in_scaled |= (1 << 3); /* in3 is AVCC */ if (sio_data->internal & (1 << 1)) @@ -2093,7 +2124,7 @@ static void __devinit it87_init_device(struct platform_device *pdev) static void it87_update_pwm_ctrl(struct it87_data *data, int nr) { data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr)); - if (data->type == it8721) { + if (has_newer_autopwm(data)) { data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; data->pwm_duty[nr] = it87_read_value(data, IT87_REG_PWM_DUTY(nr)); diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 508cb291f71b..5e6457a6644d 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -47,10 +47,14 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> +#include <linux/types.h> /* * Addresses to scan - * Address is fully defined internally and cannot be changed. + * Address is fully defined internally and cannot be changed except for + * LM64 which has one pin dedicated to address selection. + * LM63 and LM96163 have address 0x4c. + * LM64 can have address 0x18 or 0x4e. */ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; @@ -60,6 +64,7 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; */ #define LM63_REG_CONFIG1 0x03 +#define LM63_REG_CONVRATE 0x04 #define LM63_REG_CONFIG2 0xBF #define LM63_REG_CONFIG_FAN 0x4A @@ -70,6 +75,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; #define LM63_REG_PWM_VALUE 0x4C #define LM63_REG_PWM_FREQ 0x4D +#define LM63_REG_LUT_TEMP_HYST 0x4F +#define LM63_REG_LUT_TEMP(nr) (0x50 + 2 * (nr)) +#define LM63_REG_LUT_PWM(nr) (0x51 + 2 * (nr)) #define LM63_REG_LOCAL_TEMP 0x00 #define LM63_REG_LOCAL_HIGH 0x05 @@ -91,6 +99,16 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; #define LM63_REG_MAN_ID 0xFE #define LM63_REG_CHIP_ID 0xFF +#define LM96163_REG_TRUTHERM 0x30 +#define LM96163_REG_REMOTE_TEMP_U_MSB 0x31 +#define LM96163_REG_REMOTE_TEMP_U_LSB 0x32 +#define LM96163_REG_CONFIG_ENHANCED 0x45 + +#define LM63_MAX_CONVRATE 9 + +#define LM63_MAX_CONVRATE_HZ 32 +#define LM96163_MAX_CONVRATE_HZ 26 + /* * Conversions and various macros * For tachometer counts, the LM63 uses 16-bit values. @@ -112,15 +130,24 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; (val) >= 127000 ? 127 : \ (val) < 0 ? ((val) - 500) / 1000 : \ ((val) + 500) / 1000) +#define TEMP8U_TO_REG(val) ((val) <= 0 ? 0 : \ + (val) >= 255000 ? 255 : \ + ((val) + 500) / 1000) #define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) #define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ (val) >= 127875 ? 0x7FE0 : \ (val) < 0 ? ((val) - 62) / 125 * 32 : \ ((val) + 62) / 125 * 32) +#define TEMP11U_TO_REG(val) ((val) <= 0 ? 0 : \ + (val) >= 255875 ? 0xFFE0 : \ + ((val) + 62) / 125 * 32) #define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ (val) >= 127000 ? 127 : \ ((val) + 500) / 1000) +#define UPDATE_INTERVAL(max, rate) \ + ((1000 << (LM63_MAX_CONVRATE - (rate))) / (max)) + /* * Functions declaration */ @@ -134,7 +161,7 @@ static struct lm63_data *lm63_update_device(struct device *dev); static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info); static void lm63_init_client(struct i2c_client *client); -enum chips { lm63, lm64 }; +enum chips { lm63, lm64, lm96163 }; /* * Driver data (common to all clients) @@ -143,6 +170,7 @@ enum chips { lm63, lm64 }; static const struct i2c_device_id lm63_id[] = { { "lm63", lm63 }, { "lm64", lm64 }, + { "lm96163", lm96163 }, { } }; MODULE_DEVICE_TABLE(i2c, lm63_id); @@ -167,26 +195,53 @@ struct lm63_data { struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ + char lut_valid; /* zero until lut fields are valid */ unsigned long last_updated; /* in jiffies */ - int kind; + unsigned long lut_last_updated; /* in jiffies */ + enum chips kind; int temp2_offset; + int update_interval; /* in milliseconds */ + int max_convrate_hz; + int lut_size; /* 8 or 12 */ + /* registers values */ u8 config, config_fan; u16 fan[2]; /* 0: input 1: low limit */ u8 pwm1_freq; - u8 pwm1_value; - s8 temp8[3]; /* 0: local input + u8 pwm1[13]; /* 0: current output + 1-12: lookup table */ + s8 temp8[15]; /* 0: local input 1: local high limit - 2: remote critical limit */ - s16 temp11[3]; /* 0: remote input + 2: remote critical limit + 3-14: lookup table */ + s16 temp11[4]; /* 0: remote input 1: remote low limit - 2: remote high limit */ + 2: remote high limit + 3: remote offset */ + u16 temp11u; /* remote input (unsigned) */ u8 temp2_crit_hyst; + u8 lut_temp_hyst; u8 alarms; + bool pwm_highres; + bool lut_temp_highres; + bool remote_unsigned; /* true if unsigned remote upper limits */ + bool trutherm; }; +static inline int temp8_from_reg(struct lm63_data *data, int nr) +{ + if (data->remote_unsigned) + return TEMP8_FROM_REG((u8)data->temp8[nr]); + return TEMP8_FROM_REG(data->temp8[nr]); +} + +static inline int lut_temp_from_reg(struct lm63_data *data, int nr) +{ + return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000); +} + /* * Sysfs callback functions and files */ @@ -204,7 +259,12 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan[1] = FAN_TO_REG(val); @@ -216,13 +276,22 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, return count; } -static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, +static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? - 255 : (data->pwm1_value * 255 + data->pwm1_freq) / - (2 * data->pwm1_freq)); + int nr = attr->index; + int pwm; + + if (data->pwm_highres) + pwm = data->pwm1[nr]; + else + pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ? + 255 : (data->pwm1[nr] * 255 + data->pwm1_freq) / + (2 * data->pwm1_freq); + + return sprintf(buf, "%d\n", pwm); } static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, @@ -231,22 +300,26 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); unsigned long val; - + int err; + if (!(data->config_fan & 0x20)) /* register is read-only */ return -EPERM; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + val = SENSORS_LIMIT(val, 0, 255); mutex_lock(&data->update_lock); - data->pwm1_value = val <= 0 ? 0 : - val >= 255 ? 2 * data->pwm1_freq : - (val * data->pwm1_freq * 2 + 127) / 255; - i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); + data->pwm1[0] = data->pwm_highres ? val : + (val * data->pwm1_freq * 2 + 127) / 255; + i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]); mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, - char *buf) +static ssize_t show_pwm1_enable(struct device *dev, + struct device_attribute *dummy, char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); @@ -273,21 +346,47 @@ static ssize_t show_remote_temp8(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]) + return sprintf(buf, "%d\n", temp8_from_reg(data, attr->index) + + data->temp2_offset); +} + +static ssize_t show_lut_temp(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index) + data->temp2_offset); } -static ssize_t set_local_temp8(struct device *dev, - struct device_attribute *dummy, - const char *buf, size_t count) +static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH; + long val; + int err; + int temp; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - data->temp8[1] = TEMP8_TO_REG(val); - i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); + if (nr == 2) { + if (data->remote_unsigned) + temp = TEMP8U_TO_REG(val - data->temp2_offset); + else + temp = TEMP8_TO_REG(val - data->temp2_offset); + } else { + temp = TEMP8_TO_REG(val); + } + data->temp8[nr] = temp; + i2c_smbus_write_byte_data(client, reg, temp); mutex_unlock(&data->update_lock); return count; } @@ -297,28 +396,56 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]) - + data->temp2_offset); + int nr = attr->index; + int temp; + + if (!nr) { + /* + * Use unsigned temperature unless its value is zero. + * If it is zero, use signed temperature. + */ + if (data->temp11u) + temp = TEMP11_FROM_REG(data->temp11u); + else + temp = TEMP11_FROM_REG(data->temp11[nr]); + } else { + if (data->remote_unsigned && nr == 2) + temp = TEMP11_FROM_REG((u16)data->temp11[nr]); + else + temp = TEMP11_FROM_REG(data->temp11[nr]); + } + return sprintf(buf, "%d\n", temp + data->temp2_offset); } static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - static const u8 reg[4] = { + static const u8 reg[6] = { LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB, + LM63_REG_REMOTE_OFFSET_MSB, + LM63_REG_REMOTE_OFFSET_LSB, }; struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; int nr = attr->index; + err = kstrtol(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); - data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset); + if (data->remote_unsigned && nr == 2) + data->temp11[nr] = TEMP11U_TO_REG(val - data->temp2_offset); + else + data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], data->temp11[nr] >> 8); i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], @@ -327,35 +454,143 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, return count; } -/* Hysteresis register holds a relative value, while we want to present - an absolute to user-space */ -static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, - char *buf) +/* + * Hysteresis register holds a relative value, while we want to present + * an absolute to user-space + */ +static ssize_t show_temp2_crit_hyst(struct device *dev, + struct device_attribute *dummy, char *buf) { struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) + return sprintf(buf, "%d\n", temp8_from_reg(data, 2) + data->temp2_offset - TEMP8_FROM_REG(data->temp2_crit_hyst)); } -/* And now the other way around, user-space provides an absolute - hysteresis value and we have to store a relative one */ -static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, +static ssize_t show_lut_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + + return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index) + + data->temp2_offset + - TEMP8_FROM_REG(data->lut_temp_hyst)); +} + +/* + * And now the other way around, user-space provides an absolute + * hysteresis value and we have to store a relative one + */ +static ssize_t set_temp2_crit_hyst(struct device *dev, + struct device_attribute *dummy, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; long hyst; + err = kstrtol(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); - hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val; + hyst = temp8_from_reg(data, 2) + data->temp2_offset - val; i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, HYST_TO_REG(hyst)); mutex_unlock(&data->update_lock); return count; } +/* + * Set conversion rate. + * client->update_lock must be held when calling this function. + */ +static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data, + unsigned int interval) +{ + int i; + unsigned int update_interval; + + /* Shift calculations to avoid rounding errors */ + interval <<= 6; + + /* find the nearest update rate */ + update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000 + / data->max_convrate_hz; + for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1) + if (interval >= update_interval * 3 / 4) + break; + + i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i); + data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i); +} + +static ssize_t show_update_interval(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm63_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->update_interval); +} + +static ssize_t set_update_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000)); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_type(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + + return sprintf(buf, data->trutherm ? "1\n" : "2\n"); +} + +static ssize_t set_type(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val; + int ret; + u8 reg; + + ret = kstrtoul(buf, 10, &val); + if (ret < 0) + return ret; + if (val != 1 && val != 2) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->trutherm = val == 1; + reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02; + i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM, + reg | (data->trutherm ? 0x02 : 0x00)); + data->valid = 0; + mutex_unlock(&data->update_lock); + + return count; +} + static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, char *buf) { @@ -377,27 +612,87 @@ static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, set_fan, 1); -static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); +static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0); static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1); +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO, + show_lut_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 3); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, + show_lut_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 4); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO, + show_lut_temp, NULL, 5); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 5); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO, + show_lut_temp, NULL, 6); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 6); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO, + show_lut_temp, NULL, 7); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 7); +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6); +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO, + show_lut_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 8); +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7); +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO, + show_lut_temp, NULL, 9); +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 9); +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8); +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO, + show_lut_temp, NULL, 10); +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 10); +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9); +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO, + show_lut_temp, NULL, 11); +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 11); +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10); +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO, + show_lut_temp, NULL, 12); +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 12); +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11); +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO, + show_lut_temp, NULL, 13); +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 13); +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12); +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO, + show_lut_temp, NULL, 14); +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 14); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8, - set_local_temp8, 1); + set_temp8, 1); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 1); static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 2); -/* - * On LM63, temp2_crit can be set only once, which should be job - * of the bootloader. - */ +static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 3); static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8, - NULL, 2); + set_temp8, 2); static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, set_temp2_crit_hyst); +static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type); + /* Individual alarm files */ static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); @@ -408,14 +703,43 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); /* Raw alarm file for compatibility */ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, + set_update_interval); + static struct attribute *lm63_attributes[] = { - &dev_attr_pwm1.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, &dev_attr_pwm1_enable.attr, + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &dev_attr_temp2_crit_hyst.attr, @@ -425,10 +749,54 @@ static struct attribute *lm63_attributes[] = { &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, &dev_attr_alarms.attr, + &dev_attr_update_interval.attr, NULL }; +static struct attribute *lm63_attributes_extra_lut[] = { + &sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point9_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point10_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point11_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point11_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point11_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point12_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point12_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point12_temp_hyst.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm63_group_extra_lut = { + .attrs = lm63_attributes_extra_lut, +}; + +/* + * On LM63, temp2_crit can be set only once, which should be job + * of the bootloader. + * On LM64, temp2_crit can always be set. + * On LM96163, temp2_crit can be set if bit 1 of the configuration + * register is true. + */ +static umode_t lm63_attribute_mode(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + + if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr + && (data->kind == lm64 || + (data->kind == lm96163 && (data->config & 0x02)))) + return attr->mode | S_IWUSR; + + return attr->mode; +} + static const struct attribute_group lm63_group = { + .is_visible = lm63_attribute_mode, .attrs = lm63_attributes, }; @@ -487,6 +855,8 @@ static int lm63_detect(struct i2c_client *new_client, strlcpy(info->type, "lm63", I2C_NAME_SIZE); else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e)) strlcpy(info->type, "lm64", I2C_NAME_SIZE); + else if (chip_id == 0x49 && address == 0x4c) + strlcpy(info->type, "lm96163", I2C_NAME_SIZE); else return -ENODEV; @@ -518,12 +888,24 @@ static int lm63_probe(struct i2c_client *new_client, lm63_init_client(new_client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, - &lm63_group))) + err = sysfs_create_group(&new_client->dev.kobj, &lm63_group); + if (err) goto exit_free; if (data->config & 0x04) { /* tachometer enabled */ - if ((err = sysfs_create_group(&new_client->dev.kobj, - &lm63_group_fan1))) + err = sysfs_create_group(&new_client->dev.kobj, + &lm63_group_fan1); + if (err) + goto exit_remove_files; + } + if (data->kind == lm96163) { + err = device_create_file(&new_client->dev, + &dev_attr_temp2_type); + if (err) + goto exit_remove_files; + + err = sysfs_create_group(&new_client->dev.kobj, + &lm63_group_extra_lut); + if (err) goto exit_remove_files; } @@ -538,17 +920,25 @@ static int lm63_probe(struct i2c_client *new_client, exit_remove_files: sysfs_remove_group(&new_client->dev.kobj, &lm63_group); sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1); + if (data->kind == lm96163) { + device_remove_file(&new_client->dev, &dev_attr_temp2_type); + sysfs_remove_group(&new_client->dev.kobj, + &lm63_group_extra_lut); + } exit_free: kfree(data); exit: return err; } -/* Idealy we shouldn't have to initialize anything, since the BIOS - should have taken care of everything */ +/* + * Ideally we shouldn't have to initialize anything, since the BIOS + * should have taken care of everything + */ static void lm63_init_client(struct i2c_client *client) { struct lm63_data *data = i2c_get_clientdata(client); + u8 convrate; data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); data->config_fan = i2c_smbus_read_byte_data(client, @@ -561,16 +951,57 @@ static void lm63_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, data->config); } + /* Tachometer is always enabled on LM64 */ + if (data->kind == lm64) + data->config |= 0x04; /* We may need pwm1_freq before ever updating the client data */ data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); if (data->pwm1_freq == 0) data->pwm1_freq = 1; + switch (data->kind) { + case lm63: + case lm64: + data->max_convrate_hz = LM63_MAX_CONVRATE_HZ; + data->lut_size = 8; + break; + case lm96163: + data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ; + data->lut_size = 12; + data->trutherm + = i2c_smbus_read_byte_data(client, + LM96163_REG_TRUTHERM) & 0x02; + break; + } + convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE); + if (unlikely(convrate > LM63_MAX_CONVRATE)) + convrate = LM63_MAX_CONVRATE; + data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, + convrate); + + /* + * For LM96163, check if high resolution PWM + * and unsigned temperature format is enabled. + */ + if (data->kind == lm96163) { + u8 config_enhanced + = i2c_smbus_read_byte_data(client, + LM96163_REG_CONFIG_ENHANCED); + if (config_enhanced & 0x20) + data->lut_temp_highres = true; + if ((config_enhanced & 0x10) + && !(data->config_fan & 0x08) && data->pwm1_freq == 8) + data->pwm_highres = true; + if (config_enhanced & 0x08) + data->remote_unsigned = true; + } + /* Show some debug info about the LM63 configuration */ - dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", - (data->config & 0x04) ? "tachometer input" : - "alert output"); + if (data->kind == lm63) + dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", + (data->config & 0x04) ? "tachometer input" : + "alert output"); dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n", (data->config_fan & 0x08) ? "1.4" : "360", ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); @@ -586,6 +1017,10 @@ static int lm63_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm63_group); sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); + if (data->kind == lm96163) { + device_remove_file(&client->dev, &dev_attr_temp2_type); + sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut); + } kfree(data); return 0; @@ -595,10 +1030,15 @@ static struct lm63_data *lm63_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); + unsigned long next_update; + int i; mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + next_update = data->last_updated + + msecs_to_jiffies(data->update_interval) + 1; + + if (time_after(jiffies, next_update) || !data->valid) { if (data->config & 0x04) { /* tachometer enabled */ /* order matters for fan1_input */ data->fan[0] = i2c_smbus_read_byte_data(client, @@ -615,8 +1055,8 @@ static struct lm63_data *lm63_update_device(struct device *dev) LM63_REG_PWM_FREQ); if (data->pwm1_freq == 0) data->pwm1_freq = 1; - data->pwm1_value = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_VALUE); + data->pwm1[0] = i2c_smbus_read_byte_data(client, + LM63_REG_PWM_VALUE); data->temp8[0] = i2c_smbus_read_byte_data(client, LM63_REG_LOCAL_TEMP); @@ -636,6 +1076,17 @@ static struct lm63_data *lm63_update_device(struct device *dev) LM63_REG_REMOTE_HIGH_MSB) << 8) | i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_HIGH_LSB); + data->temp11[3] = (i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_OFFSET_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_OFFSET_LSB); + + if (data->kind == lm96163) + data->temp11u = (i2c_smbus_read_byte_data(client, + LM96163_REG_REMOTE_TEMP_U_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM96163_REG_REMOTE_TEMP_U_LSB); + data->temp8[2] = i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_TCRIT); data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, @@ -648,6 +1099,21 @@ static struct lm63_data *lm63_update_device(struct device *dev) data->valid = 1; } + if (time_after(jiffies, data->lut_last_updated + 5 * HZ) || + !data->lut_valid) { + for (i = 0; i < data->lut_size; i++) { + data->pwm1[1 + i] = i2c_smbus_read_byte_data(client, + LM63_REG_LUT_PWM(i)); + data->temp8[3 + i] = i2c_smbus_read_byte_data(client, + LM63_REG_LUT_TEMP(i)); + } + data->lut_temp_hyst = i2c_smbus_read_byte_data(client, + LM63_REG_LUT_TEMP_HYST); + + data->lut_last_updated = jiffies; + data->lut_valid = 1; + } + mutex_unlock(&data->update_lock); return data; diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index bdfd675488ae..d2dd5f90496d 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -917,7 +917,7 @@ static ssize_t set_update_interval(struct device *dev, return err; mutex_lock(&data->update_lock); - lm90_set_convrate(client, data, val); + lm90_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000)); mutex_unlock(&data->update_lock); return count; diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index 3b43df418613..8bd6c5c9e05b 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -151,12 +151,12 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; /* Insmod parameters */ -static int disable_block; +static bool disable_block; module_param(disable_block, bool, 0); MODULE_PARM_DESC(disable_block, "Set to non-zero to disable SMBus block data transactions."); -static int init; +static bool init; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization."); diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index 84ef3a898707..482ca901db30 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -106,11 +106,14 @@ static ssize_t show_adc(struct device *dev, if (ret < 0) return ret; - return sprintf(buf, "%d\n", ret); + /* assume the reference voltage to be 2.048V, with an 8-bit sample, + * the LSB weight is 8mV + */ + return sprintf(buf, "%d\n", ret * 8); } #define MAX1111_ADC_ATTR(_id) \ - SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id) + SENSOR_DEVICE_ATTR(in##_id##_input, S_IRUGO, show_adc, NULL, _id) static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static MAX1111_ADC_ATTR(0); @@ -120,10 +123,10 @@ static MAX1111_ADC_ATTR(3); static struct attribute *max1111_attributes[] = { &dev_attr_name.attr, - &sensor_dev_attr_adc0_in.dev_attr.attr, - &sensor_dev_attr_adc1_in.dev_attr.attr, - &sensor_dev_attr_adc2_in.dev_attr.attr, - &sensor_dev_attr_adc3_in.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, NULL, }; diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index 6914195cfd35..88953f99e914 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -59,7 +59,7 @@ static unsigned short max1668_addr_list[] = { #define DEV_ID_MAX1989 0xb /* read only mode module parameter */ -static int read_only; +static bool read_only; module_param(read_only, bool, 0); MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index bde50e34d013..374118f2b9f9 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -71,7 +71,7 @@ module_param(force_i2c, byte, 0); MODULE_PARM_DESC(force_i2c, "Initialize the i2c address of the sensors"); -static int init = 1; +static bool init = 1; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 65b685e2c7b7..17a8fa2d9ae9 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -67,11 +67,11 @@ module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to one to reset chip on load"); -static int init = 1; +static bool init = 1; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 6e5d0ae594b0..35aa5149307a 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -58,11 +58,11 @@ module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to one to force a hardware chip reset"); -static int init; +static bool init; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to one to force extra software initialization"); diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 9ded133e43f0..d3100eab6b2f 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -56,7 +56,7 @@ module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); -static int init; +static bool init; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to one to force chip initialization"); diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 3cc6fef22087..45ec7e7c3c27 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -61,7 +61,7 @@ module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 3ee398d0e4c9..aa58b25565bc 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -42,7 +42,7 @@ static const unsigned short normal_i2c[] = { }; -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 0254e181893d..063bd9508d8a 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -39,7 +39,7 @@ static const unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END }; /* Insmod parameters */ -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a3afac4be734..3101dd59e379 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -299,11 +299,11 @@ config I2C_AT91 unless your system can cope with those limitations. config I2C_AU1550 - tristate "Au1550/Au1200 SMBus interface" + tristate "Au1550/Au1200/Au1300 SMBus interface" depends on MIPS_ALCHEMY help If you say yes to this option, support will be included for the - Au1550 and Au1200 SMBus interface. + Au1550/Au1200/Au1300 SMBus interface. This driver can also be built as a module. If so, the module will be called i2c-au1550. @@ -682,19 +682,19 @@ config I2C_XILINX will be called xilinx_i2c. config I2C_EG20T - tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)" + tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" depends on PCI help This driver is for PCH(Platform controller Hub) I2C of EG20T which is an IOH(Input/Output Hub) for x86 embedded processor. This driver can access PCH I2C bus device. - This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7213 and ML7223. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is - for MP(Media Phone) use. - ML7213/ML7223 is companion chip for Intel Atom E6xx series. - ML7213/ML7223 is completely compatible for Intel EG20T PCH. + This driver also can be used for LAPIS Semiconductor IOH(Input/ + Output Hub), ML7213, ML7223 and ML7831. + ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is + for MP(Media Phone) use and ML7831 IOH is for general purpose use. + ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. comment "External I2C/SMBus adapter drivers" diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index b6807db7b36f..e66d248fc126 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -132,7 +132,8 @@ #define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */ static struct pci_driver ali1535_driver; -static unsigned short ali1535_smba; +static unsigned long ali1535_smba; +static unsigned short ali1535_offset; /* Detect whether a ALI1535 can be found, and initialize it, where necessary. Note the differences between kernels with the old PCI BIOS interface and @@ -140,7 +141,7 @@ static unsigned short ali1535_smba; defined to make the transition easier. */ static int __devinit ali1535_setup(struct pci_dev *dev) { - int retval = -ENODEV; + int retval; unsigned char temp; /* Check the following things: @@ -149,15 +150,28 @@ static int __devinit ali1535_setup(struct pci_dev *dev) - We can use the addresses */ + retval = pci_enable_device(dev); + if (retval) { + dev_err(&dev->dev, "ALI1535_smb can't enable device\n"); + goto exit; + } + /* Determine the address of the SMBus area */ - pci_read_config_word(dev, SMBBA, &ali1535_smba); - ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1)); - if (ali1535_smba == 0) { + pci_read_config_word(dev, SMBBA, &ali1535_offset); + dev_dbg(&dev->dev, "ALI1535_smb is at offset 0x%04x\n", ali1535_offset); + ali1535_offset &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1)); + if (ali1535_offset == 0) { dev_warn(&dev->dev, "ALI1535_smb region uninitialized - upgrade BIOS?\n"); + retval = -ENODEV; goto exit; } + if (pci_resource_flags(dev, 0) & IORESOURCE_IO) + ali1535_smba = pci_resource_start(dev, 0) + ali1535_offset; + else + ali1535_smba = ali1535_offset; + retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE, ali1535_driver.name); if (retval) @@ -165,8 +179,9 @@ static int __devinit ali1535_setup(struct pci_dev *dev) if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE, ali1535_driver.name)) { - dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n", + dev_err(&dev->dev, "ALI1535_smb region 0x%lx already in use!\n", ali1535_smba); + retval = -EBUSY; goto exit; } @@ -174,6 +189,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) pci_read_config_byte(dev, SMBCFG, &temp); if ((temp & ALI1535_SMBIO_EN) == 0) { dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n"); + retval = -ENODEV; goto exit_free; } @@ -181,6 +197,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) pci_read_config_byte(dev, SMBHSTCFG, &temp); if ((temp & 1) == 0) { dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n"); + retval = -ENODEV; goto exit_free; } @@ -196,14 +213,13 @@ static int __devinit ali1535_setup(struct pci_dev *dev) */ pci_read_config_byte(dev, SMBREV, &temp); dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp); - dev_dbg(&dev->dev, "ALI1535_smba = 0x%X\n", ali1535_smba); + dev_dbg(&dev->dev, "ALI1535_smba = 0x%lx\n", ali1535_smba); - retval = 0; -exit: - return retval; + return 0; exit_free: release_region(ali1535_smba, ALI1535_SMB_IOSIZE); +exit: return retval; } @@ -498,7 +514,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_ ali1535_adapter.dev.parent = &dev->dev; snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), - "SMBus ALI1535 adapter at %04x", ali1535_smba); + "SMBus ALI1535 adapter at %04x", ali1535_offset); return i2c_add_adapter(&ali1535_adapter); } diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index a409cfcf0629..47ae0091e027 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -417,7 +417,7 @@ static void __devexit ali1563_remove(struct pci_dev * dev) ali1563_shutdown(dev); } -static const struct pci_device_id ali1563_id_table[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) }, {}, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 83e8a60cdc86..087ea9caa74d 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -477,7 +477,7 @@ static struct i2c_adapter ali15x3_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id ali15x3_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 03bcd07c4697..eb778bf15c18 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -308,7 +308,7 @@ static const char* chipname[] = { "nVidia nForce", "AMD8111", }; -static const struct pci_device_id amd756_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B), .driver_data = AMD756 }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413), diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 6b6a6b1d7025..e5ac53b99b04 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -415,7 +415,7 @@ static const struct i2c_algorithm smbus_algorithm = { }; -static const struct pci_device_id amd8111_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 305c07504f7e..1679deef9c89 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -295,9 +295,6 @@ static int at91_i2c_resume(struct platform_device *pdev) #define at91_i2c_resume NULL #endif -/* work with "modprobe at91_i2c" from hotplugging or coldplugging */ -MODULE_ALIAS("platform:at91_i2c"); - static struct platform_driver at91_i2c_driver = { .probe = at91_i2c_probe, .remove = __devexit_p(at91_i2c_remove), @@ -309,19 +306,9 @@ static struct platform_driver at91_i2c_driver = { }, }; -static int __init at91_i2c_init(void) -{ - return platform_driver_register(&at91_i2c_driver); -} - -static void __exit at91_i2c_exit(void) -{ - platform_driver_unregister(&at91_i2c_driver); -} - -module_init(at91_i2c_init); -module_exit(at91_i2c_exit); +module_platform_driver(at91_i2c_driver); MODULE_AUTHOR("Rick Bronson"); MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:at91_i2c"); diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index f314d7f433d3..582d616db346 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -426,20 +426,9 @@ static struct platform_driver au1xpsc_smbus_driver = { .remove = __devexit_p(i2c_au1550_remove), }; -static int __init i2c_au1550_init(void) -{ - return platform_driver_register(&au1xpsc_smbus_driver); -} - -static void __exit i2c_au1550_exit(void) -{ - platform_driver_unregister(&au1xpsc_smbus_driver); -} +module_platform_driver(au1xpsc_smbus_driver); MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC."); MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:au1xpsc_smbus"); - -module_init (i2c_au1550_init); -module_exit (i2c_au1550_exit); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index b1d9cd28d8da..c1e1096ba069 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -724,18 +724,7 @@ static struct platform_driver cpm_i2c_driver = { }, }; -static int __init cpm_i2c_init(void) -{ - return platform_driver_register(&cpm_i2c_driver); -} - -static void __exit cpm_i2c_exit(void) -{ - platform_driver_unregister(&cpm_i2c_driver); -} - -module_init(cpm_i2c_init); -module_exit(cpm_i2c_exit); +module_platform_driver(cpm_i2c_driver); MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>"); MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards"); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 9e89e7313d62..37f42113af31 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -349,7 +349,7 @@ static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("i2c_designware-pci"); -DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { +static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { /* Moorestown */ { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 }, { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 }, diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 18936ac9d51c..ca8877641040 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. + * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -136,7 +136,8 @@ /* Set the number of I2C instance max Intel EG20T PCH : 1ch -OKI SEMICONDUCTOR ML7213 IOH : 2ch +LAPIS Semiconductor ML7213 IOH : 2ch +LAPIS Semiconductor ML7831 IOH : 1ch */ #define PCH_I2C_MAX_DEV 2 @@ -180,15 +181,17 @@ static int pch_clk = 50000; /* specifies I2C clock speed in KHz */ static wait_queue_head_t pch_event; static DEFINE_MUTEX(pch_mutex); -/* Definition for ML7213 by OKI SEMICONDUCTOR */ +/* Definition for ML7213 by LAPIS Semiconductor */ #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_I2C 0x802D #define PCI_DEVICE_ID_ML7223_I2C 0x8010 +#define PCI_DEVICE_ID_ML7831_I2C 0x8817 -static struct pci_device_id __devinitdata pch_pcidev_id[] = { +static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, }, {0,} }; @@ -243,7 +246,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap) if (pch_clk > PCH_MAX_CLK) pch_clk = 62500; - pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / pch_i2c_speed * 8; + pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8); /* Set transfer speed in I2CBC */ iowrite32(pch_i2cbc, p + PCH_I2CBC); @@ -918,7 +921,9 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, pch_adap->dev.parent = &pdev->dev; pch_i2c_init(&adap_info->pch_data[i]); - ret = i2c_add_adapter(pch_adap); + + pch_adap->nr = i; + ret = i2c_add_numbered_adapter(pch_adap); if (ret) { pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i); goto err_add_adapter; @@ -1058,8 +1063,8 @@ static void __exit pch_pci_exit(void) } module_exit(pch_pci_exit); -MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver"); +MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C"); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>"); +MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.lapis-semi.com>"); module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR)); module_param(pch_clk, int, (S_IRUSR | S_IWUSR)); diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 63bb1cc2a042..19515df61021 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -52,7 +52,7 @@ struct highlander_i2c_dev { size_t buf_len; }; -static int iic_force_poll, iic_force_normal; +static bool iic_force_poll, iic_force_normal; static int iic_timeout = 1000, iic_read_delay; static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev) @@ -468,18 +468,7 @@ static struct platform_driver highlander_i2c_driver = { .remove = __devexit_p(highlander_i2c_remove), }; -static int __init highlander_i2c_init(void) -{ - return platform_driver_register(&highlander_i2c_driver); -} - -static void __exit highlander_i2c_exit(void) -{ - platform_driver_unregister(&highlander_i2c_driver); -} - -module_init(highlander_i2c_init); -module_exit(highlander_i2c_exit); +module_platform_driver(highlander_i2c_driver); MODULE_AUTHOR("Paul Mundt"); MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter"); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index 9ff1695d8458..c527de17db4f 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -105,7 +105,7 @@ static struct i2c_adapter hydra_adap = { .algo_data = &hydra_bit_data, }; -static const struct pci_device_id hydra_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ab26840d0c70..5d2e2816831f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -609,7 +609,7 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = i801_func, }; -static const struct pci_device_id i801_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 3c110fbc409b..806e225f3de7 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -51,11 +51,11 @@ MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION); MODULE_LICENSE("GPL"); -static int iic_force_poll; +static bool iic_force_poll; module_param(iic_force_poll, bool, 0); MODULE_PARM_DESC(iic_force_poll, "Force polling mode"); -static int iic_force_fast; +static bool iic_force_fast; module_param(iic_force_fast, bool, 0); MODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)"); @@ -815,15 +815,4 @@ static struct platform_driver ibm_iic_driver = { .remove = __devexit_p(iic_remove), }; -static int __init iic_init(void) -{ - return platform_driver_register(&ibm_iic_driver); -} - -static void __exit iic_exit(void) -{ - platform_driver_unregister(&ibm_iic_driver); -} - -module_init(iic_init); -module_exit(iic_exit); +module_platform_driver(ibm_iic_driver); diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c index e828ac85cfa7..365bad5b890b 100644 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -1093,7 +1093,7 @@ static void __devexit intel_mid_i2c_remove(struct pci_dev *dev) pci_release_region(dev, 0); } -static struct pci_device_id intel_mid_i2c_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = { /* Moorestown */ { PCI_VDEVICE(INTEL, 0x0802), 0 }, { PCI_VDEVICE(INTEL, 0x0803), 1 }, diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index f09c9319a2ba..93f147a96b62 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -523,21 +523,7 @@ static struct platform_driver iop3xx_i2c_driver = { }, }; -static int __init -i2c_iop3xx_init (void) -{ - return platform_driver_register(&iop3xx_i2c_driver); -} - -static void __exit -i2c_iop3xx_exit (void) -{ - platform_driver_unregister(&iop3xx_i2c_driver); - return; -} - -module_init (i2c_iop3xx_init); -module_exit (i2c_iop3xx_exit); +module_platform_driver(iop3xx_i2c_driver); MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>"); MODULE_DESCRIPTION("IOP3xx iic algorithm and driver"); diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index 0682f8f277b0..6561d275b8cf 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -306,20 +306,9 @@ static struct platform_driver smbus_sch_driver = { .remove = __devexit_p(smbus_sch_remove), }; -static int __init i2c_sch_init(void) -{ - return platform_driver_register(&smbus_sch_driver); -} - -static void __exit i2c_sch_exit(void) -{ - platform_driver_unregister(&smbus_sch_driver); -} +module_platform_driver(smbus_sch_driver); MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>"); MODULE_DESCRIPTION("Intel SCH SMBus driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_sch_init); -module_exit(i2c_sch_exit); MODULE_ALIAS("platform:isch_smbus"); diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index c01e9519f6c1..5d263f9014d6 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -148,18 +148,7 @@ static struct platform_driver ixp2000_i2c_driver = { }, }; -static int __init ixp2000_i2c_init(void) -{ - return platform_driver_register(&ixp2000_i2c_driver); -} - -static void __exit ixp2000_i2c_exit(void) -{ - platform_driver_unregister(&ixp2000_i2c_driver); -} - -module_init(ixp2000_i2c_init); -module_exit(ixp2000_i2c_exit); +module_platform_driver(ixp2000_i2c_driver); MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>"); MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver"); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 107397a606b4..a8ebb84e23f9 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -715,18 +715,7 @@ static struct platform_driver mpc_i2c_driver = { }, }; -static int __init fsl_i2c_init(void) -{ - return platform_driver_register(&mpc_i2c_driver); -} - -static void __exit fsl_i2c_exit(void) -{ - platform_driver_unregister(&mpc_i2c_driver); -} - -module_init(fsl_i2c_init); -module_exit(fsl_i2c_exit); +module_platform_driver(mpc_i2c_driver); MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>"); MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and " diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a9941c65f226..4f44a33017b0 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -611,20 +611,7 @@ static struct platform_driver mv64xxx_i2c_driver = { }, }; -static int __init -mv64xxx_i2c_init(void) -{ - return platform_driver_register(&mv64xxx_i2c_driver); -} - -static void __exit -mv64xxx_i2c_exit(void) -{ - platform_driver_unregister(&mv64xxx_i2c_driver); -} - -module_init(mv64xxx_i2c_init); -module_exit(mv64xxx_i2c_exit); +module_platform_driver(mv64xxx_i2c_driver); MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>"); MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver"); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index ff1e127dfea8..43a96a123920 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -309,7 +309,7 @@ static struct i2c_algorithm smbus_algorithm = { }; -static const struct pci_device_id nforce2_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, @@ -356,7 +356,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, error = acpi_check_region(smbus->base, smbus->size, nforce2_driver.name); if (error) - return -1; + return error; if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 1b46a9d9f907..18068dee48f1 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -394,9 +394,6 @@ static struct of_device_id ocores_i2c_match[] = { }; MODULE_DEVICE_TABLE(of, ocores_i2c_match); -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:ocores-i2c"); - static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, .remove = __devexit_p(ocores_i2c_remove), @@ -409,19 +406,9 @@ static struct platform_driver ocores_i2c_driver = { }, }; -static int __init ocores_i2c_init(void) -{ - return platform_driver_register(&ocores_i2c_driver); -} - -static void __exit ocores_i2c_exit(void) -{ - platform_driver_unregister(&ocores_i2c_driver); -} - -module_init(ocores_i2c_init); -module_exit(ocores_i2c_exit); +module_platform_driver(ocores_i2c_driver); MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); MODULE_DESCRIPTION("OpenCores I2C bus driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-i2c"); diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index 56dbe54e8811..ee139a598814 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -629,24 +629,10 @@ static struct platform_driver octeon_i2c_driver = { }, }; -static int __init octeon_i2c_init(void) -{ - int rv; - - rv = platform_driver_register(&octeon_i2c_driver); - return rv; -} - -static void __exit octeon_i2c_exit(void) -{ - platform_driver_unregister(&octeon_i2c_driver); -} +module_platform_driver(octeon_i2c_driver); MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); MODULE_ALIAS("platform:" DRV_NAME); - -module_init(octeon_i2c_init); -module_exit(octeon_i2c_exit); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index fa23faa20f0e..f713eac55047 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -37,6 +37,9 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_i2c.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/i2c-omap.h> #include <linux/pm_runtime.h> @@ -182,7 +185,9 @@ struct omap_i2c_dev { u32 latency; /* maximum mpu wkup latency */ void (*set_mpu_wkup_lat)(struct device *dev, long latency); - u32 speed; /* Speed of bus in Khz */ + u32 speed; /* Speed of bus in kHz */ + u32 dtrev; /* extra revision from DT */ + u32 flags; u16 cmd_err; u8 *buf; u8 *regs; @@ -235,7 +240,7 @@ static const u8 reg_map_ip_v2[] = { [OMAP_I2C_BUF_REG] = 0x94, [OMAP_I2C_CNT_REG] = 0x98, [OMAP_I2C_DATA_REG] = 0x9c, - [OMAP_I2C_SYSC_REG] = 0x20, + [OMAP_I2C_SYSC_REG] = 0x10, [OMAP_I2C_CON_REG] = 0xa4, [OMAP_I2C_OA_REG] = 0xa8, [OMAP_I2C_SA_REG] = 0xac, @@ -266,11 +271,7 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) static void omap_i2c_unidle(struct omap_i2c_dev *dev) { - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; - - if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { + if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); @@ -291,13 +292,10 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev) static void omap_i2c_idle(struct omap_i2c_dev *dev) { - struct omap_i2c_bus_platform_data *pdata; u16 iv; - pdata = dev->dev->platform_data; - dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - if (pdata->rev == OMAP_I2C_IP_VERSION_2) + if (dev->dtrev == OMAP_I2C_IP_VERSION_2) omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1); else omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); @@ -320,9 +318,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) unsigned long timeout; unsigned long internal_clk = 0; struct clk *fclk; - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { /* Disable I2C controller before soft reset */ @@ -373,7 +368,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) } omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - if (pdata->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { + if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* * The I2C functional clock is the armxor_ck, so there's * no need to get "armxor_ck" separately. Now, if OMAP2420 @@ -397,7 +392,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate / 12000000; } - if (!(pdata->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { + if (!(dev->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { /* * HSI2C controller internal clk rate should be 19.2 Mhz for @@ -406,7 +401,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * The filter is iclk (fclk for HS) period. */ if (dev->speed > 400 || - pdata->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) + dev->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) internal_clk = 19200; else if (dev->speed > 100) internal_clk = 9600; @@ -475,7 +470,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) dev->errata = 0; - if (pdata->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) + if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) dev->errata |= I2C_OMAP_ERRATA_I207; /* Enable interrupts */ @@ -484,7 +479,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) OMAP_I2C_IE_AL) | ((dev->fifo_size) ? (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); - if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { + if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { dev->pscstate = psc; dev->scllstate = scll; dev->sclhstate = sclh; @@ -804,9 +799,6 @@ omap_i2c_isr(int this_irq, void *dev_id) u16 bits; u16 stat, w; int err, count = 0; - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; if (pm_runtime_suspended(dev->dev)) return IRQ_NONE; @@ -830,11 +822,9 @@ complete: ~(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_write_reg(dev, OMAP_I2C_CON_REG, - OMAP_I2C_CON_STP); - } + if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; @@ -875,7 +865,7 @@ complete: * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (pdata->flags & + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { if (dev->buf_len) { *dev->buf++ = w >> 8; @@ -918,7 +908,7 @@ complete: * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (pdata->flags & + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { if (dev->buf_len) { w |= *dev->buf++ << 8; @@ -965,6 +955,32 @@ static const struct i2c_algorithm omap_i2c_algo = { .functionality = omap_i2c_func, }; +#ifdef CONFIG_OF +static struct omap_i2c_bus_platform_data omap3_pdata = { + .rev = OMAP_I2C_IP_VERSION_1, + .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | + OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + OMAP_I2C_FLAG_BUS_SHIFT_2, +}; + +static struct omap_i2c_bus_platform_data omap4_pdata = { + .rev = OMAP_I2C_IP_VERSION_2, +}; + +static const struct of_device_id omap_i2c_of_match[] = { + { + .compatible = "ti,omap4-i2c", + .data = &omap4_pdata, + }, + { + .compatible = "ti,omap3-i2c", + .data = &omap3_pdata, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_i2c_of_match); +#endif + static int __devinit omap_i2c_probe(struct platform_device *pdev) { @@ -972,9 +988,10 @@ omap_i2c_probe(struct platform_device *pdev) struct i2c_adapter *adap; struct resource *mem, *irq, *ioarea; 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 r; - u32 speed = 0; /* NOTE: driver uses the static register mapping */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1001,15 +1018,24 @@ omap_i2c_probe(struct platform_device *pdev) goto err_release_region; } - if (pdata != NULL) { - speed = pdata->clkrate; + match = of_match_device(omap_i2c_of_match, &pdev->dev); + if (match) { + u32 freq = 100000; /* default to 100000 Hz */ + + pdata = match->data; + dev->dtrev = pdata->rev; + dev->flags = pdata->flags; + + of_property_read_u32(node, "clock-frequency", &freq); + /* convert DT freq value in Hz into kHz for speed */ + dev->speed = freq / 1000; + } else if (pdata != NULL) { + dev->speed = pdata->clkrate; + dev->flags = pdata->flags; dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; - } else { - speed = 100; /* Default speed */ - dev->set_mpu_wkup_lat = NULL; + dev->dtrev = pdata->rev; } - dev->speed = speed; dev->dev = &pdev->dev; dev->irq = irq->start; dev->base = ioremap(mem->start, resource_size(mem)); @@ -1020,9 +1046,9 @@ omap_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - dev->reg_shift = (pdata->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; + dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; - if (pdata->rev == OMAP_I2C_IP_VERSION_2) + if (dev->dtrev == OMAP_I2C_IP_VERSION_2) dev->regs = (u8 *)reg_map_ip_v2; else dev->regs = (u8 *)reg_map_ip_v1; @@ -1035,7 +1061,7 @@ omap_i2c_probe(struct platform_device *pdev) if (dev->rev <= OMAP_I2C_REV_ON_3430) dev->errata |= I2C_OMAP3_1P153; - if (!(pdata->flags & OMAP_I2C_FLAG_NO_FIFO)) { + if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { u16 s; /* Set up the fifo size - Get total size */ @@ -1058,7 +1084,7 @@ omap_i2c_probe(struct platform_device *pdev) /* calculate wakeup latency constraint for MPU */ if (dev->set_mpu_wkup_lat != NULL) dev->latency = (1000000 * dev->fifo_size) / - (1000 * speed / 8); + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ @@ -1074,7 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev) } dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, - pdata->rev, dev->rev >> 4, dev->rev & 0xf, dev->speed); + dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); pm_runtime_put(dev->dev); @@ -1085,6 +1111,7 @@ omap_i2c_probe(struct platform_device *pdev) strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); adap->algo = &omap_i2c_algo; adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; /* i2c device drivers may be active on return from add_adapter() */ adap->nr = pdev->id; @@ -1094,6 +1121,8 @@ omap_i2c_probe(struct platform_device *pdev) goto err_free_irq; } + of_i2c_register_devices(adap); + return 0; err_free_irq: @@ -1166,6 +1195,7 @@ static struct platform_driver omap_i2c_driver = { .name = "omap_i2c", .owner = THIS_MODULE, .pm = OMAP_I2C_PM_OPS, + .of_match_table = of_match_ptr(omap_i2c_of_match), }, }; diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 837b8c1aa02a..eaaea73209c5 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -401,7 +401,7 @@ static void __devexit pasemi_smb_remove(struct pci_dev *dev) kfree(smbus); } -static const struct pci_device_id pasemi_smb_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = { { PCI_DEVICE(0x1959, 0xa003) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index ace67995d7de..2adbf1a8fdea 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -286,20 +286,8 @@ static struct platform_driver i2c_pca_pf_driver = { }, }; -static int __init i2c_pca_pf_init(void) -{ - return platform_driver_register(&i2c_pca_pf_driver); -} - -static void __exit i2c_pca_pf_exit(void) -{ - platform_driver_unregister(&i2c_pca_pf_driver); -} +module_platform_driver(i2c_pca_pf_driver); MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_pca_pf_init); -module_exit(i2c_pca_pf_exit); - diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 6d14ac2e3c41..c14d48dd601a 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -472,7 +472,7 @@ static struct i2c_adapter piix4_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id piix4_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 127051b06921..07b7447ecbc9 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -627,9 +627,6 @@ static struct i2c_adapter pmcmsptwi_adapter = { .name = DRV_NAME, }; -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:" DRV_NAME); - static struct platform_driver pmcmsptwi_driver = { .probe = pmcmsptwi_probe, .remove = __devexit_p(pmcmsptwi_remove), @@ -639,18 +636,8 @@ static struct platform_driver pmcmsptwi_driver = { }, }; -static int __init pmcmsptwi_init(void) -{ - return platform_driver_register(&pmcmsptwi_driver); -} - -static void __exit pmcmsptwi_exit(void) -{ - platform_driver_unregister(&pmcmsptwi_driver); -} +module_platform_driver(pmcmsptwi_driver); MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver"); MODULE_LICENSE("GPL"); - -module_init(pmcmsptwi_init); -module_exit(pmcmsptwi_exit); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index b289ec99eeba..7b397c6f607e 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -312,10 +312,6 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev) return rc; } - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:i2c-powermac"); - static struct platform_driver i2c_powermac_driver = { .probe = i2c_powermac_probe, .remove = __devexit_p(i2c_powermac_remove), @@ -325,17 +321,6 @@ static struct platform_driver i2c_powermac_driver = { }, }; -static int __init i2c_powermac_init(void) -{ - platform_driver_register(&i2c_powermac_driver); - return 0; -} +module_platform_driver(i2c_powermac_driver); - -static void __exit i2c_powermac_cleanup(void) -{ - platform_driver_unregister(&i2c_powermac_driver); -} - -module_init(i2c_powermac_init); -module_exit(i2c_powermac_cleanup); +MODULE_ALIAS("platform:i2c-powermac"); diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 632e088760a3..a05817980556 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -150,7 +150,7 @@ static void __devexit ce4100_i2c_remove(struct pci_dev *dev) kfree(sds); } -static struct pci_device_id ce4100_i2c_devices[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, { }, }; diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index a67132b2e092..c0c9dffbdb12 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -560,18 +560,7 @@ static struct platform_driver sh7760_i2c_drv = { .remove = __devexit_p(sh7760_i2c_remove), }; -static int __init sh7760_i2c_init(void) -{ - return platform_driver_register(&sh7760_i2c_drv); -} - -static void __exit sh7760_i2c_exit(void) -{ - platform_driver_unregister(&sh7760_i2c_drv); -} - -module_init(sh7760_i2c_init); -module_exit(sh7760_i2c_exit); +module_platform_driver(sh7760_i2c_drv); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SH7760 I2C bus driver"); diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 2fc08fbf67a2..4fc87e7c94c9 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -156,12 +156,8 @@ static int simtec_i2c_remove(struct platform_device *dev) return 0; } - /* device driver */ -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:simtec-i2c"); - static struct platform_driver simtec_i2c_driver = { .driver = { .name = "simtec-i2c", @@ -171,19 +167,9 @@ static struct platform_driver simtec_i2c_driver = { .remove = simtec_i2c_remove, }; -static int __init i2c_adap_simtec_init(void) -{ - return platform_driver_register(&simtec_i2c_driver); -} - -static void __exit i2c_adap_simtec_exit(void) -{ - platform_driver_unregister(&simtec_i2c_driver); -} - -module_init(i2c_adap_simtec_init); -module_exit(i2c_adap_simtec_exit); +module_platform_driver(simtec_i2c_driver); MODULE_DESCRIPTION("Simtec Generic I2C Bus driver"); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:simtec-i2c"); diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 437586611d4a..87e5126d449c 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -147,7 +147,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev) u16 a; u8 val; int *i; - int retval = -ENODEV; + int retval; /* Look for imposters */ for (i = blacklist; *i != 0; i++) { @@ -223,7 +223,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev) error: release_region(sis5595_base + SMB_INDEX, 2); - return retval; + return -ENODEV; } static int sis5595_transaction(struct i2c_adapter *adap) @@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis5595_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index e6f539e26f65..15cf78f65ce0 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -93,8 +93,8 @@ static struct pci_driver sis630_driver; /* insmod parameters */ -static int high_clock; -static int force; +static bool high_clock; +static bool force; module_param(high_clock, bool, 0); MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); module_param(force, bool, 0); @@ -393,7 +393,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) { unsigned char b; struct pci_dev *dummy = NULL; - int retval = -ENODEV, i; + int retval, i; /* check for supported SiS devices */ for (i=0; supported[i] > 0 ; i++) { @@ -418,18 +418,21 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) */ if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) { dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n"); + retval = -ENODEV; goto exit; } /* if ACPI already enabled , do nothing */ if (!(b & 0x80) && pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) { dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n"); + retval = -ENODEV; goto exit; } /* Determine the ACPI base address */ if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) { dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n"); + retval = -ENODEV; goto exit; } @@ -445,6 +448,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) sis630_driver.name)) { dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already " "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA); + retval = -EBUSY; goto exit; } @@ -468,7 +472,7 @@ static struct i2c_adapter sis630_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis630_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, { 0, } diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 86837f0c4cb9..cc5d149413f7 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -245,7 +245,7 @@ static struct i2c_adapter sis96x_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis96x_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 7799fe5bda88..713d31ade26b 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -89,7 +89,7 @@ static struct i2c_adapter vt586b_adapter = { }; -static const struct pci_device_id vt586b_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 0b012f1f8ac5..333011c83d52 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -91,7 +91,7 @@ static unsigned short SMBHSTCFG = 0xD2; /* If force is set to anything different from 0, we forcibly enable the VT596. DANGEROUS! */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!"); @@ -324,7 +324,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, const struct pci_device_id *id) { unsigned char temp; - int error = -ENODEV; + int error; /* Determine the address of the SMBus areas */ if (force_addr) { @@ -390,6 +390,7 @@ found: dev_err(&pdev->dev, "SMBUS: Error: Host SMBus " "controller not enabled! - upgrade BIOS or " "use force=1\n"); + error = -ENODEV; goto release_region; } } @@ -422,9 +423,11 @@ found: "SMBus Via Pro adapter at %04x", vt596_smba); vt596_pdev = pci_dev_get(pdev); - if (i2c_add_adapter(&vt596_adapter)) { + error = i2c_add_adapter(&vt596_adapter); + if (error) { pci_dev_put(vt596_pdev); vt596_pdev = NULL; + goto release_region; } /* Always return failure here. This is to allow other drivers to bind @@ -438,7 +441,7 @@ release_region: return error; } -static const struct pci_device_id vt596_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3), .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3), diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index ac083a28ae08..2bded7647ef2 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -795,10 +795,6 @@ static int __devexit xiic_i2c_remove(struct platform_device* pdev) return 0; } - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:"DRIVER_NAME); - static struct platform_driver xiic_i2c_driver = { .probe = xiic_i2c_probe, .remove = __devexit_p(xiic_i2c_remove), @@ -808,19 +804,9 @@ static struct platform_driver xiic_i2c_driver = { }, }; -static int __init xiic_i2c_init(void) -{ - return platform_driver_register(&xiic_i2c_driver); -} - -static void __exit xiic_i2c_exit(void) -{ - platform_driver_unregister(&xiic_i2c_driver); -} - -module_init(xiic_i2c_init); -module_exit(xiic_i2c_exit); +module_platform_driver(xiic_i2c_driver); MODULE_AUTHOR("info@mocean-labs.com"); MODULE_DESCRIPTION("Xilinx I2C bus driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRIVER_NAME); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 91e349c884c5..2eacb7784d56 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -559,7 +559,7 @@ static struct platform_driver scx200_pci_driver = { .remove = __devexit_p(scx200_remove), }; -static const struct pci_device_id scx200_isa[] __initconst = { +static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, { 0, } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 57a45ce84b2d..10e7f1e76586 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -251,15 +251,10 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) return -EINVAL; - rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); - if (!rdwr_pa) - return -ENOMEM; - - if (copy_from_user(rdwr_pa, rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { - kfree(rdwr_pa); - return -EFAULT; - } + rdwr_pa = memdup_user(rdwr_arg.msgs, + rdwr_arg.nmsgs * sizeof(struct i2c_msg)); + if (IS_ERR(rdwr_pa)) + return PTR_ERR(rdwr_pa); data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { diff --git a/drivers/i2c/muxes/gpio-i2cmux.c b/drivers/i2c/muxes/gpio-i2cmux.c index 7b6ce624cd6e..e5fa695eb0fa 100644 --- a/drivers/i2c/muxes/gpio-i2cmux.c +++ b/drivers/i2c/muxes/gpio-i2cmux.c @@ -165,18 +165,7 @@ static struct platform_driver gpiomux_driver = { }, }; -static int __init gpiomux_init(void) -{ - return platform_driver_register(&gpiomux_driver); -} - -static void __exit gpiomux_exit(void) -{ - platform_driver_unregister(&gpiomux_driver); -} - -module_init(gpiomux_init); -module_exit(gpiomux_exit); +module_platform_driver(gpiomux_driver); MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver"); MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>"); diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c index 25b9fe3a9f8e..d3be99fb4154 100644 --- a/drivers/ide/ali14xx.c +++ b/drivers/ide/ali14xx.c @@ -221,7 +221,7 @@ static int __init ali14xx_probe(void) return ide_legacy_device_add(&ali14xx_port_info, 0); } -static int probe_ali14xx; +static bool probe_ali14xx; module_param_named(probe, probe_ali14xx, bool, 0); MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets"); diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index a81bd7575792..14717304b388 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -111,7 +111,7 @@ #define DRV_NAME "cmd640" -static int cmd640_vlb; +static bool cmd640_vlb; /* * CMD640 specific registers definition. diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c index 6929f7fce93a..46af4743b3e6 100644 --- a/drivers/ide/dtc2278.c +++ b/drivers/ide/dtc2278.c @@ -130,7 +130,7 @@ static int __init dtc2278_probe(void) return ide_legacy_device_add(&dtc2278_port_info, 0); } -static int probe_dtc2278; +static bool probe_dtc2278; module_param_named(probe, probe_dtc2278, bool, 0); MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets"); diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c index 3feaa26410be..51beb85250d4 100644 --- a/drivers/ide/gayle.c +++ b/drivers/ide/gayle.c @@ -50,7 +50,7 @@ GAYLE_NUM_HWIFS-1) #define GAYLE_HAS_CONTROL_REG (!ide_doubler) -static int ide_doubler; +static bool ide_doubler; module_param_named(doubler, ide_doubler, bool, 0); MODULE_PARM_DESC(doubler, "enable support for IDE doublers"); diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c index 808bcdcbf8e1..986f2513eab4 100644 --- a/drivers/ide/ht6560b.c +++ b/drivers/ide/ht6560b.c @@ -317,7 +317,7 @@ static void __init ht6560b_init_dev(ide_drive_t *drive) ide_set_drivedata(drive, (void *)t); } -static int probe_ht6560b; +static bool probe_ht6560b; module_param_named(probe, probe_ht6560b, bool, 0); MODULE_PARM_DESC(probe, "probe for HT6560B chipset"); diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c index 979d342c338a..547d7cf2e016 100644 --- a/drivers/ide/ide-4drives.c +++ b/drivers/ide/ide-4drives.c @@ -6,7 +6,7 @@ #define DRV_NAME "ide-4drives" -static int probe_4drives; +static bool probe_4drives; module_param_named(probe, probe_4drives, bool, 0); MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port"); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index f22edc66b030..f1a6796b165c 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -53,15 +53,15 @@ struct ide_acpi_hwif_link { #define DEBPRINT(fmt, args...) do {} while (0) #endif /* DEBUGGING */ -static int ide_noacpi; +static bool ide_noacpi; module_param_named(noacpi, ide_noacpi, bool, 0); MODULE_PARM_DESC(noacpi, "disable IDE ACPI support"); -static int ide_acpigtf; +static bool ide_acpigtf; module_param_named(acpigtf, ide_acpigtf, bool, 0); MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support"); -static int ide_acpionboot; +static bool ide_acpionboot; module_param_named(acpionboot, ide_acpionboot, bool, 0); MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot"); diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c index d267b7affad6..a22ca8467010 100644 --- a/drivers/ide/ide-floppy_ioctl.c +++ b/drivers/ide/ide-floppy_ioctl.c @@ -292,8 +292,7 @@ int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev, * and CDROM_SEND_PACKET (legacy) ioctls */ if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND) - err = scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk, - mode, cmd, argp); + err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); if (err == -ENOTTY) err = generic_ide_ioctl(drive, bdev, cmd, arg); diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c index a743e68a8903..7f56b738d762 100644 --- a/drivers/ide/ide-pci-generic.c +++ b/drivers/ide/ide-pci-generic.c @@ -28,7 +28,7 @@ #define DRV_NAME "ide_pci_generic" -static int ide_generic_all; /* Set to claim all devices */ +static bool ide_generic_all; /* Set to claim all devices */ module_param_named(all_generic_ide, ide_generic_all, bool, 0444); MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers."); diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c index 3f0244fd8e62..8bbfe5557c7b 100644 --- a/drivers/ide/qd65xx.c +++ b/drivers/ide/qd65xx.c @@ -417,7 +417,7 @@ static int __init qd_probe(int base) return rc; } -static int probe_qd65xx; +static bool probe_qd65xx; module_param_named(probe, probe_qd65xx, bool, 0); MODULE_PARM_DESC(probe, "probe for QD65xx chipsets"); diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c index 47adcd09cb26..5cfb78120669 100644 --- a/drivers/ide/umc8672.c +++ b/drivers/ide/umc8672.c @@ -160,7 +160,7 @@ static int __init umc8672_probe(void) return ide_legacy_device_add(&umc8672_port_info, 0); } -static int probe_umc8672; +static bool probe_umc8672; module_param_named(probe, probe_umc8672, bool, 0); MODULE_PARM_DESC(probe, "probe for UMC8672 chipset"); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 5d2f8e13cf0e..20bce51c2e82 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -197,7 +197,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { .enter = &intel_idle }, }; -static int get_driver_data(int cstate) +static long get_driver_data(int cstate) { int driver_data; switch (cstate) { @@ -232,6 +232,7 @@ static int get_driver_data(int cstate) * @drv: cpuidle driver * @index: index of cpuidle state * + * Must be called under local_irq_disable(). */ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -247,8 +248,6 @@ static int intel_idle(struct cpuidle_device *dev, cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1; - local_irq_disable(); - /* * leave_mm() to avoid costly and often unnecessary wakeups * for flushing the user TLB's associated with the active mm. @@ -348,7 +347,8 @@ static int intel_idle_probe(void) cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &mwait_substates); if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) || - !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) + !(ecx & CPUID5_ECX_INTERRUPT_BREAK) || + !mwait_substates) return -ENODEV; pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates); @@ -394,7 +394,7 @@ static int intel_idle_probe(void) if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; else { - smp_call_function(__setup_broadcast_timer, (void *)true, 1); + on_each_cpu(__setup_broadcast_timer, (void *)true, 1); register_cpu_notifier(&setup_broadcast_notifier); } @@ -471,71 +471,67 @@ static int intel_idle_cpuidle_driver_init(void) } if (auto_demotion_disable_flags) - smp_call_function(auto_demotion_disable, NULL, 1); + on_each_cpu(auto_demotion_disable, NULL, 1); return 0; } /* - * intel_idle_cpuidle_devices_init() + * intel_idle_cpu_init() * allocate, initialize, register cpuidle_devices + * @cpu: cpu/core to initialize */ -static int intel_idle_cpuidle_devices_init(void) +int intel_idle_cpu_init(int cpu) { - int i, cstate; + int cstate; struct cpuidle_device *dev; - intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); - if (intel_idle_cpuidle_devices == NULL) - return -ENOMEM; - - for_each_online_cpu(i) { - dev = per_cpu_ptr(intel_idle_cpuidle_devices, i); + dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); - dev->state_count = 1; + dev->state_count = 1; - for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { - int num_substates; + for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { + int num_substates; - if (cstate > max_cstate) { - printk(PREFIX "max_cstate %d reached\n", - max_cstate); - break; - } + if (cstate > max_cstate) { + printk(PREFIX "max_cstate %d reached\n", + max_cstate); + break; + } - /* does the state exist in CPUID.MWAIT? */ - num_substates = (mwait_substates >> ((cstate) * 4)) - & MWAIT_SUBSTATE_MASK; - if (num_substates == 0) - continue; - /* is the state not enabled? */ - if (cpuidle_state_table[cstate].enter == NULL) { - continue; - } + /* does the state exist in CPUID.MWAIT? */ + num_substates = (mwait_substates >> ((cstate) * 4)) + & MWAIT_SUBSTATE_MASK; + if (num_substates == 0) + continue; + /* is the state not enabled? */ + if (cpuidle_state_table[cstate].enter == NULL) + continue; - dev->states_usage[dev->state_count].driver_data = - (void *)get_driver_data(cstate); + dev->states_usage[dev->state_count].driver_data = + (void *)get_driver_data(cstate); dev->state_count += 1; } + dev->cpu = cpu; - dev->cpu = i; - if (cpuidle_register_device(dev)) { - pr_debug(PREFIX "cpuidle_register_device %d failed!\n", - i); - intel_idle_cpuidle_devices_uninit(); - return -EIO; - } + if (cpuidle_register_device(dev)) { + pr_debug(PREFIX "cpuidle_register_device %d failed!\n", cpu); + intel_idle_cpuidle_devices_uninit(); + return -EIO; } + if (auto_demotion_disable_flags) + smp_call_function_single(cpu, auto_demotion_disable, NULL, 1); + return 0; } static int __init intel_idle_init(void) { - int retval; + int retval, i; /* Do not load intel_idle at all for now if idle= is passed */ if (boot_option_idle_override != IDLE_NO_OVERRIDE) @@ -553,10 +549,16 @@ static int __init intel_idle_init(void) return retval; } - retval = intel_idle_cpuidle_devices_init(); - if (retval) { - cpuidle_unregister_driver(&intel_idle_driver); - return retval; + intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); + if (intel_idle_cpuidle_devices == NULL) + return -ENOMEM; + + for_each_online_cpu(i) { + retval = intel_idle_cpu_init(i); + if (retval) { + cpuidle_unregister_driver(&intel_idle_driver); + return retval; + } } return 0; @@ -568,7 +570,7 @@ static void __exit intel_idle_exit(void) cpuidle_unregister_driver(&intel_idle_driver); if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) { - smp_call_function(__setup_broadcast_timer, (void *)false, 1); + on_each_cpu(__setup_broadcast_timer, (void *)false, 1); unregister_cpu_notifier(&setup_broadcast_notifier); } diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 0f9a84c1046a..eb0add311dc8 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -55,6 +55,7 @@ source "drivers/infiniband/hw/nes/Kconfig" source "drivers/infiniband/ulp/ipoib/Kconfig" source "drivers/infiniband/ulp/srp/Kconfig" +source "drivers/infiniband/ulp/srpt/Kconfig" source "drivers/infiniband/ulp/iser/Kconfig" diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile index 9cc7a47d3e67..a3b2d8eac86e 100644 --- a/drivers/infiniband/Makefile +++ b/drivers/infiniband/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_MLX4_INFINIBAND) += hw/mlx4/ obj-$(CONFIG_INFINIBAND_NES) += hw/nes/ obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/ obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/ +obj-$(CONFIG_INFINIBAND_SRPT) += ulp/srpt/ obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/ diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index aaf6023a4835..f08f6eaf3fa8 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -379,8 +379,8 @@ extern spinlock_t shca_list_lock; extern int ehca_static_rate; extern int ehca_port_act_time; -extern int ehca_use_hp_mr; -extern int ehca_scaling_code; +extern bool ehca_use_hp_mr; +extern bool ehca_scaling_code; extern int ehca_lock_hcalls; extern int ehca_nr_ports; extern int ehca_max_cq; diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index c240e9972cb0..832e7a7d0aee 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -59,16 +59,16 @@ MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); MODULE_VERSION(HCAD_VERSION); -static int ehca_open_aqp1 = 0; +static bool ehca_open_aqp1 = 0; static int ehca_hw_level = 0; -static int ehca_poll_all_eqs = 1; +static bool ehca_poll_all_eqs = 1; int ehca_debug_level = 0; int ehca_nr_ports = -1; -int ehca_use_hp_mr = 0; +bool ehca_use_hp_mr = 0; int ehca_port_act_time = 30; int ehca_static_rate = -1; -int ehca_scaling_code = 0; +bool ehca_scaling_code = 0; int ehca_lock_hcalls = -1; int ehca_max_cq = -1; int ehca_max_qp = -1; @@ -82,7 +82,7 @@ module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO); module_param_named(poll_all_eqs, ehca_poll_all_eqs, bool, S_IRUGO); module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO); -module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO); +module_param_named(lock_hcalls, ehca_lock_hcalls, bint, S_IRUGO); module_param_named(number_of_cqs, ehca_max_cq, int, S_IRUGO); module_param_named(number_of_qps, ehca_max_qp, int, S_IRUGO); diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 5965b3df8f2f..7013da5e9eda 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -96,7 +96,7 @@ unsigned int wqm_quanta = 0x10000; module_param(wqm_quanta, int, 0644); MODULE_PARM_DESC(wqm_quanta, "WQM quanta"); -static unsigned int limit_maxrdreqsz; +static bool limit_maxrdreqsz; module_param(limit_maxrdreqsz, bool, 0644); MODULE_PARM_DESC(limit_maxrdreqsz, "Limit max read request size to 256 Bytes"); diff --git a/drivers/infiniband/ulp/srpt/Kconfig b/drivers/infiniband/ulp/srpt/Kconfig new file mode 100644 index 000000000000..31ee83d528d9 --- /dev/null +++ b/drivers/infiniband/ulp/srpt/Kconfig @@ -0,0 +1,12 @@ +config INFINIBAND_SRPT + tristate "InfiniBand SCSI RDMA Protocol target support" + depends on INFINIBAND && TARGET_CORE + ---help--- + + Support for the SCSI RDMA Protocol (SRP) Target driver. The + SRP protocol is a protocol that allows an initiator to access + a block storage device on another host (target) over a network + that supports the RDMA protocol. Currently the RDMA protocol is + supported by InfiniBand and by iWarp network hardware. More + information about the SRP protocol can be found on the website + of the INCITS T10 technical committee (http://www.t10.org/). diff --git a/drivers/infiniband/ulp/srpt/Makefile b/drivers/infiniband/ulp/srpt/Makefile new file mode 100644 index 000000000000..e3ee4bdfffa5 --- /dev/null +++ b/drivers/infiniband/ulp/srpt/Makefile @@ -0,0 +1,2 @@ +ccflags-y := -Idrivers/target +obj-$(CONFIG_INFINIBAND_SRPT) += ib_srpt.o diff --git a/drivers/infiniband/ulp/srpt/ib_dm_mad.h b/drivers/infiniband/ulp/srpt/ib_dm_mad.h new file mode 100644 index 000000000000..fb1de1f6f297 --- /dev/null +++ b/drivers/infiniband/ulp/srpt/ib_dm_mad.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2006 - 2009 Mellanox Technology Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef IB_DM_MAD_H +#define IB_DM_MAD_H + +#include <linux/types.h> + +#include <rdma/ib_mad.h> + +enum { + /* + * See also section 13.4.7 Status Field, table 115 MAD Common Status + * Field Bit Values and also section 16.3.1.1 Status Field in the + * InfiniBand Architecture Specification. + */ + DM_MAD_STATUS_UNSUP_METHOD = 0x0008, + DM_MAD_STATUS_UNSUP_METHOD_ATTR = 0x000c, + DM_MAD_STATUS_INVALID_FIELD = 0x001c, + DM_MAD_STATUS_NO_IOC = 0x0100, + + /* + * See also the Device Management chapter, section 16.3.3 Attributes, + * table 279 Device Management Attributes in the InfiniBand + * Architecture Specification. + */ + DM_ATTR_CLASS_PORT_INFO = 0x01, + DM_ATTR_IOU_INFO = 0x10, + DM_ATTR_IOC_PROFILE = 0x11, + DM_ATTR_SVC_ENTRIES = 0x12 +}; + +struct ib_dm_hdr { + u8 reserved[28]; +}; + +/* + * Structure of management datagram sent by the SRP target implementation. + * Contains a management datagram header, reliable multi-packet transaction + * protocol (RMPP) header and ib_dm_hdr. Notes: + * - The SRP target implementation does not use RMPP or ib_dm_hdr when sending + * management datagrams. + * - The header size must be exactly 64 bytes (IB_MGMT_DEVICE_HDR), since this + * is the header size that is passed to ib_create_send_mad() in ib_srpt.c. + * - The maximum supported size for a management datagram when not using RMPP + * is 256 bytes -- 64 bytes header and 192 (IB_MGMT_DEVICE_DATA) bytes data. + */ +struct ib_dm_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + struct ib_dm_hdr dm_hdr; + u8 data[IB_MGMT_DEVICE_DATA]; +}; + +/* + * IOUnitInfo as defined in section 16.3.3.3 IOUnitInfo of the InfiniBand + * Architecture Specification. + */ +struct ib_dm_iou_info { + __be16 change_id; + u8 max_controllers; + u8 op_rom; + u8 controller_list[128]; +}; + +/* + * IOControllerprofile as defined in section 16.3.3.4 IOControllerProfile of + * the InfiniBand Architecture Specification. + */ +struct ib_dm_ioc_profile { + __be64 guid; + __be32 vendor_id; + __be32 device_id; + __be16 device_version; + __be16 reserved1; + __be32 subsys_vendor_id; + __be32 subsys_device_id; + __be16 io_class; + __be16 io_subclass; + __be16 protocol; + __be16 protocol_version; + __be16 service_conn; + __be16 initiators_supported; + __be16 send_queue_depth; + u8 reserved2; + u8 rdma_read_depth; + __be32 send_size; + __be32 rdma_size; + u8 op_cap_mask; + u8 svc_cap_mask; + u8 num_svc_entries; + u8 reserved3[9]; + u8 id_string[64]; +}; + +struct ib_dm_svc_entry { + u8 name[40]; + __be64 id; +}; + +/* + * See also section 16.3.3.5 ServiceEntries in the InfiniBand Architecture + * Specification. See also section B.7, table B.8 in the T10 SRP r16a document. + */ +struct ib_dm_svc_entries { + struct ib_dm_svc_entry service_entries[4]; +}; + +#endif diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c new file mode 100644 index 000000000000..cd5d05e22a77 --- /dev/null +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -0,0 +1,4073 @@ +/* + * Copyright (c) 2006 - 2009 Mellanox Technology Inc. All rights reserved. + * Copyright (C) 2008 - 2011 Bart Van Assche <bvanassche@acm.org>. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/ctype.h> +#include <linux/kthread.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/atomic.h> +#include <scsi/scsi_tcq.h> +#include <target/configfs_macros.h> +#include <target/target_core_base.h> +#include <target/target_core_fabric_configfs.h> +#include <target/target_core_fabric.h> +#include <target/target_core_configfs.h> +#include "ib_srpt.h" + +/* Name of this kernel module. */ +#define DRV_NAME "ib_srpt" +#define DRV_VERSION "2.0.0" +#define DRV_RELDATE "2011-02-14" + +#define SRPT_ID_STRING "Linux SRP target" + +#undef pr_fmt +#define pr_fmt(fmt) DRV_NAME " " fmt + +MODULE_AUTHOR("Vu Pham and Bart Van Assche"); +MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol target " + "v" DRV_VERSION " (" DRV_RELDATE ")"); +MODULE_LICENSE("Dual BSD/GPL"); + +/* + * Global Variables + */ + +static u64 srpt_service_guid; +static spinlock_t srpt_dev_lock; /* Protects srpt_dev_list. */ +static struct list_head srpt_dev_list; /* List of srpt_device structures. */ + +static unsigned srp_max_req_size = DEFAULT_MAX_REQ_SIZE; +module_param(srp_max_req_size, int, 0444); +MODULE_PARM_DESC(srp_max_req_size, + "Maximum size of SRP request messages in bytes."); + +static int srpt_srq_size = DEFAULT_SRPT_SRQ_SIZE; +module_param(srpt_srq_size, int, 0444); +MODULE_PARM_DESC(srpt_srq_size, + "Shared receive queue (SRQ) size."); + +static int srpt_get_u64_x(char *buffer, struct kernel_param *kp) +{ + return sprintf(buffer, "0x%016llx", *(u64 *)kp->arg); +} +module_param_call(srpt_service_guid, NULL, srpt_get_u64_x, &srpt_service_guid, + 0444); +MODULE_PARM_DESC(srpt_service_guid, + "Using this value for ioc_guid, id_ext, and cm_listen_id" + " instead of using the node_guid of the first HCA."); + +static struct ib_client srpt_client; +static struct target_fabric_configfs *srpt_target; +static void srpt_release_channel(struct srpt_rdma_ch *ch); +static int srpt_queue_status(struct se_cmd *cmd); + +/** + * opposite_dma_dir() - Swap DMA_TO_DEVICE and DMA_FROM_DEVICE. + */ +static inline +enum dma_data_direction opposite_dma_dir(enum dma_data_direction dir) +{ + switch (dir) { + case DMA_TO_DEVICE: return DMA_FROM_DEVICE; + case DMA_FROM_DEVICE: return DMA_TO_DEVICE; + default: return dir; + } +} + +/** + * srpt_sdev_name() - Return the name associated with the HCA. + * + * Examples are ib0, ib1, ... + */ +static inline const char *srpt_sdev_name(struct srpt_device *sdev) +{ + return sdev->device->name; +} + +static enum rdma_ch_state srpt_get_ch_state(struct srpt_rdma_ch *ch) +{ + unsigned long flags; + enum rdma_ch_state state; + + spin_lock_irqsave(&ch->spinlock, flags); + state = ch->state; + spin_unlock_irqrestore(&ch->spinlock, flags); + return state; +} + +static enum rdma_ch_state +srpt_set_ch_state(struct srpt_rdma_ch *ch, enum rdma_ch_state new_state) +{ + unsigned long flags; + enum rdma_ch_state prev; + + spin_lock_irqsave(&ch->spinlock, flags); + prev = ch->state; + ch->state = new_state; + spin_unlock_irqrestore(&ch->spinlock, flags); + return prev; +} + +/** + * srpt_test_and_set_ch_state() - Test and set the channel state. + * + * Returns true if and only if the channel state has been set to the new state. + */ +static bool +srpt_test_and_set_ch_state(struct srpt_rdma_ch *ch, enum rdma_ch_state old, + enum rdma_ch_state new) +{ + unsigned long flags; + enum rdma_ch_state prev; + + spin_lock_irqsave(&ch->spinlock, flags); + prev = ch->state; + if (prev == old) + ch->state = new; + spin_unlock_irqrestore(&ch->spinlock, flags); + return prev == old; +} + +/** + * srpt_event_handler() - Asynchronous IB event callback function. + * + * Callback function called by the InfiniBand core when an asynchronous IB + * event occurs. This callback may occur in interrupt context. See also + * section 11.5.2, Set Asynchronous Event Handler in the InfiniBand + * Architecture Specification. + */ +static void srpt_event_handler(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct srpt_device *sdev; + struct srpt_port *sport; + + sdev = ib_get_client_data(event->device, &srpt_client); + if (!sdev || sdev->device != event->device) + return; + + pr_debug("ASYNC event= %d on device= %s\n", event->event, + srpt_sdev_name(sdev)); + + switch (event->event) { + case IB_EVENT_PORT_ERR: + if (event->element.port_num <= sdev->device->phys_port_cnt) { + sport = &sdev->port[event->element.port_num - 1]; + sport->lid = 0; + sport->sm_lid = 0; + } + break; + case IB_EVENT_PORT_ACTIVE: + case IB_EVENT_LID_CHANGE: + case IB_EVENT_PKEY_CHANGE: + case IB_EVENT_SM_CHANGE: + case IB_EVENT_CLIENT_REREGISTER: + /* Refresh port data asynchronously. */ + if (event->element.port_num <= sdev->device->phys_port_cnt) { + sport = &sdev->port[event->element.port_num - 1]; + if (!sport->lid && !sport->sm_lid) + schedule_work(&sport->work); + } + break; + default: + printk(KERN_ERR "received unrecognized IB event %d\n", + event->event); + break; + } +} + +/** + * srpt_srq_event() - SRQ event callback function. + */ +static void srpt_srq_event(struct ib_event *event, void *ctx) +{ + printk(KERN_INFO "SRQ event %d\n", event->event); +} + +/** + * srpt_qp_event() - QP event callback function. + */ +static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch) +{ + pr_debug("QP event %d on cm_id=%p sess_name=%s state=%d\n", + event->event, ch->cm_id, ch->sess_name, srpt_get_ch_state(ch)); + + switch (event->event) { + case IB_EVENT_COMM_EST: + ib_cm_notify(ch->cm_id, event->event); + break; + case IB_EVENT_QP_LAST_WQE_REACHED: + if (srpt_test_and_set_ch_state(ch, CH_DRAINING, + CH_RELEASING)) + srpt_release_channel(ch); + else + pr_debug("%s: state %d - ignored LAST_WQE.\n", + ch->sess_name, srpt_get_ch_state(ch)); + break; + default: + printk(KERN_ERR "received unrecognized IB QP event %d\n", + event->event); + break; + } +} + +/** + * srpt_set_ioc() - Helper function for initializing an IOUnitInfo structure. + * + * @slot: one-based slot number. + * @value: four-bit value. + * + * Copies the lowest four bits of value in element slot of the array of four + * bit elements called c_list (controller list). The index slot is one-based. + */ +static void srpt_set_ioc(u8 *c_list, u32 slot, u8 value) +{ + u16 id; + u8 tmp; + + id = (slot - 1) / 2; + if (slot & 0x1) { + tmp = c_list[id] & 0xf; + c_list[id] = (value << 4) | tmp; + } else { + tmp = c_list[id] & 0xf0; + c_list[id] = (value & 0xf) | tmp; + } +} + +/** + * srpt_get_class_port_info() - Copy ClassPortInfo to a management datagram. + * + * See also section 16.3.3.1 ClassPortInfo in the InfiniBand Architecture + * Specification. + */ +static void srpt_get_class_port_info(struct ib_dm_mad *mad) +{ + struct ib_class_port_info *cif; + + cif = (struct ib_class_port_info *)mad->data; + memset(cif, 0, sizeof *cif); + cif->base_version = 1; + cif->class_version = 1; + cif->resp_time_value = 20; + + mad->mad_hdr.status = 0; +} + +/** + * srpt_get_iou() - Write IOUnitInfo to a management datagram. + * + * See also section 16.3.3.3 IOUnitInfo in the InfiniBand Architecture + * Specification. See also section B.7, table B.6 in the SRP r16a document. + */ +static void srpt_get_iou(struct ib_dm_mad *mad) +{ + struct ib_dm_iou_info *ioui; + u8 slot; + int i; + + ioui = (struct ib_dm_iou_info *)mad->data; + ioui->change_id = __constant_cpu_to_be16(1); + ioui->max_controllers = 16; + + /* set present for slot 1 and empty for the rest */ + srpt_set_ioc(ioui->controller_list, 1, 1); + for (i = 1, slot = 2; i < 16; i++, slot++) + srpt_set_ioc(ioui->controller_list, slot, 0); + + mad->mad_hdr.status = 0; +} + +/** + * srpt_get_ioc() - Write IOControllerprofile to a management datagram. + * + * See also section 16.3.3.4 IOControllerProfile in the InfiniBand + * Architecture Specification. See also section B.7, table B.7 in the SRP + * r16a document. + */ +static void srpt_get_ioc(struct srpt_port *sport, u32 slot, + struct ib_dm_mad *mad) +{ + struct srpt_device *sdev = sport->sdev; + struct ib_dm_ioc_profile *iocp; + + iocp = (struct ib_dm_ioc_profile *)mad->data; + + if (!slot || slot > 16) { + mad->mad_hdr.status + = __constant_cpu_to_be16(DM_MAD_STATUS_INVALID_FIELD); + return; + } + + if (slot > 2) { + mad->mad_hdr.status + = __constant_cpu_to_be16(DM_MAD_STATUS_NO_IOC); + return; + } + + memset(iocp, 0, sizeof *iocp); + strcpy(iocp->id_string, SRPT_ID_STRING); + iocp->guid = cpu_to_be64(srpt_service_guid); + iocp->vendor_id = cpu_to_be32(sdev->dev_attr.vendor_id); + iocp->device_id = cpu_to_be32(sdev->dev_attr.vendor_part_id); + iocp->device_version = cpu_to_be16(sdev->dev_attr.hw_ver); + iocp->subsys_vendor_id = cpu_to_be32(sdev->dev_attr.vendor_id); + iocp->subsys_device_id = 0x0; + iocp->io_class = __constant_cpu_to_be16(SRP_REV16A_IB_IO_CLASS); + iocp->io_subclass = __constant_cpu_to_be16(SRP_IO_SUBCLASS); + iocp->protocol = __constant_cpu_to_be16(SRP_PROTOCOL); + iocp->protocol_version = __constant_cpu_to_be16(SRP_PROTOCOL_VERSION); + iocp->send_queue_depth = cpu_to_be16(sdev->srq_size); + iocp->rdma_read_depth = 4; + iocp->send_size = cpu_to_be32(srp_max_req_size); + iocp->rdma_size = cpu_to_be32(min(sport->port_attrib.srp_max_rdma_size, + 1U << 24)); + iocp->num_svc_entries = 1; + iocp->op_cap_mask = SRP_SEND_TO_IOC | SRP_SEND_FROM_IOC | + SRP_RDMA_READ_FROM_IOC | SRP_RDMA_WRITE_FROM_IOC; + + mad->mad_hdr.status = 0; +} + +/** + * srpt_get_svc_entries() - Write ServiceEntries to a management datagram. + * + * See also section 16.3.3.5 ServiceEntries in the InfiniBand Architecture + * Specification. See also section B.7, table B.8 in the SRP r16a document. + */ +static void srpt_get_svc_entries(u64 ioc_guid, + u16 slot, u8 hi, u8 lo, struct ib_dm_mad *mad) +{ + struct ib_dm_svc_entries *svc_entries; + + WARN_ON(!ioc_guid); + + if (!slot || slot > 16) { + mad->mad_hdr.status + = __constant_cpu_to_be16(DM_MAD_STATUS_INVALID_FIELD); + return; + } + + if (slot > 2 || lo > hi || hi > 1) { + mad->mad_hdr.status + = __constant_cpu_to_be16(DM_MAD_STATUS_NO_IOC); + return; + } + + svc_entries = (struct ib_dm_svc_entries *)mad->data; + memset(svc_entries, 0, sizeof *svc_entries); + svc_entries->service_entries[0].id = cpu_to_be64(ioc_guid); + snprintf(svc_entries->service_entries[0].name, + sizeof(svc_entries->service_entries[0].name), + "%s%016llx", + SRP_SERVICE_NAME_PREFIX, + ioc_guid); + + mad->mad_hdr.status = 0; +} + +/** + * srpt_mgmt_method_get() - Process a received management datagram. + * @sp: source port through which the MAD has been received. + * @rq_mad: received MAD. + * @rsp_mad: response MAD. + */ +static void srpt_mgmt_method_get(struct srpt_port *sp, struct ib_mad *rq_mad, + struct ib_dm_mad *rsp_mad) +{ + u16 attr_id; + u32 slot; + u8 hi, lo; + + attr_id = be16_to_cpu(rq_mad->mad_hdr.attr_id); + switch (attr_id) { + case DM_ATTR_CLASS_PORT_INFO: + srpt_get_class_port_info(rsp_mad); + break; + case DM_ATTR_IOU_INFO: + srpt_get_iou(rsp_mad); + break; + case DM_ATTR_IOC_PROFILE: + slot = be32_to_cpu(rq_mad->mad_hdr.attr_mod); + srpt_get_ioc(sp, slot, rsp_mad); + break; + case DM_ATTR_SVC_ENTRIES: + slot = be32_to_cpu(rq_mad->mad_hdr.attr_mod); + hi = (u8) ((slot >> 8) & 0xff); + lo = (u8) (slot & 0xff); + slot = (u16) ((slot >> 16) & 0xffff); + srpt_get_svc_entries(srpt_service_guid, + slot, hi, lo, rsp_mad); + break; + default: + rsp_mad->mad_hdr.status = + __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD_ATTR); + break; + } +} + +/** + * srpt_mad_send_handler() - Post MAD-send callback function. + */ +static void srpt_mad_send_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_send_wc *mad_wc) +{ + ib_destroy_ah(mad_wc->send_buf->ah); + ib_free_send_mad(mad_wc->send_buf); +} + +/** + * srpt_mad_recv_handler() - MAD reception callback function. + */ +static void srpt_mad_recv_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_wc) +{ + struct srpt_port *sport = (struct srpt_port *)mad_agent->context; + struct ib_ah *ah; + struct ib_mad_send_buf *rsp; + struct ib_dm_mad *dm_mad; + + if (!mad_wc || !mad_wc->recv_buf.mad) + return; + + ah = ib_create_ah_from_wc(mad_agent->qp->pd, mad_wc->wc, + mad_wc->recv_buf.grh, mad_agent->port_num); + if (IS_ERR(ah)) + goto err; + + BUILD_BUG_ON(offsetof(struct ib_dm_mad, data) != IB_MGMT_DEVICE_HDR); + + rsp = ib_create_send_mad(mad_agent, mad_wc->wc->src_qp, + mad_wc->wc->pkey_index, 0, + IB_MGMT_DEVICE_HDR, IB_MGMT_DEVICE_DATA, + GFP_KERNEL); + if (IS_ERR(rsp)) + goto err_rsp; + + rsp->ah = ah; + + dm_mad = rsp->mad; + memcpy(dm_mad, mad_wc->recv_buf.mad, sizeof *dm_mad); + dm_mad->mad_hdr.method = IB_MGMT_METHOD_GET_RESP; + dm_mad->mad_hdr.status = 0; + + switch (mad_wc->recv_buf.mad->mad_hdr.method) { + case IB_MGMT_METHOD_GET: + srpt_mgmt_method_get(sport, mad_wc->recv_buf.mad, dm_mad); + break; + case IB_MGMT_METHOD_SET: + dm_mad->mad_hdr.status = + __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD_ATTR); + break; + default: + dm_mad->mad_hdr.status = + __constant_cpu_to_be16(DM_MAD_STATUS_UNSUP_METHOD); + break; + } + + if (!ib_post_send_mad(rsp, NULL)) { + ib_free_recv_mad(mad_wc); + /* will destroy_ah & free_send_mad in send completion */ + return; + } + + ib_free_send_mad(rsp); + +err_rsp: + ib_destroy_ah(ah); +err: + ib_free_recv_mad(mad_wc); +} + +/** + * srpt_refresh_port() - Configure a HCA port. + * + * Enable InfiniBand management datagram processing, update the cached sm_lid, + * lid and gid values, and register a callback function for processing MADs + * on the specified port. + * + * Note: It is safe to call this function more than once for the same port. + */ +static int srpt_refresh_port(struct srpt_port *sport) +{ + struct ib_mad_reg_req reg_req; + struct ib_port_modify port_modify; + struct ib_port_attr port_attr; + int ret; + + memset(&port_modify, 0, sizeof port_modify); + port_modify.set_port_cap_mask = IB_PORT_DEVICE_MGMT_SUP; + port_modify.clr_port_cap_mask = 0; + + ret = ib_modify_port(sport->sdev->device, sport->port, 0, &port_modify); + if (ret) + goto err_mod_port; + + ret = ib_query_port(sport->sdev->device, sport->port, &port_attr); + if (ret) + goto err_query_port; + + sport->sm_lid = port_attr.sm_lid; + sport->lid = port_attr.lid; + + ret = ib_query_gid(sport->sdev->device, sport->port, 0, &sport->gid); + if (ret) + goto err_query_port; + + if (!sport->mad_agent) { + memset(®_req, 0, sizeof reg_req); + reg_req.mgmt_class = IB_MGMT_CLASS_DEVICE_MGMT; + reg_req.mgmt_class_version = IB_MGMT_BASE_VERSION; + set_bit(IB_MGMT_METHOD_GET, reg_req.method_mask); + set_bit(IB_MGMT_METHOD_SET, reg_req.method_mask); + + sport->mad_agent = ib_register_mad_agent(sport->sdev->device, + sport->port, + IB_QPT_GSI, + ®_req, 0, + srpt_mad_send_handler, + srpt_mad_recv_handler, + sport); + if (IS_ERR(sport->mad_agent)) { + ret = PTR_ERR(sport->mad_agent); + sport->mad_agent = NULL; + goto err_query_port; + } + } + + return 0; + +err_query_port: + + port_modify.set_port_cap_mask = 0; + port_modify.clr_port_cap_mask = IB_PORT_DEVICE_MGMT_SUP; + ib_modify_port(sport->sdev->device, sport->port, 0, &port_modify); + +err_mod_port: + + return ret; +} + +/** + * srpt_unregister_mad_agent() - Unregister MAD callback functions. + * + * Note: It is safe to call this function more than once for the same device. + */ +static void srpt_unregister_mad_agent(struct srpt_device *sdev) +{ + struct ib_port_modify port_modify = { + .clr_port_cap_mask = IB_PORT_DEVICE_MGMT_SUP, + }; + struct srpt_port *sport; + int i; + + for (i = 1; i <= sdev->device->phys_port_cnt; i++) { + sport = &sdev->port[i - 1]; + WARN_ON(sport->port != i); + if (ib_modify_port(sdev->device, i, 0, &port_modify) < 0) + printk(KERN_ERR "disabling MAD processing failed.\n"); + if (sport->mad_agent) { + ib_unregister_mad_agent(sport->mad_agent); + sport->mad_agent = NULL; + } + } +} + +/** + * srpt_alloc_ioctx() - Allocate an SRPT I/O context structure. + */ +static struct srpt_ioctx *srpt_alloc_ioctx(struct srpt_device *sdev, + int ioctx_size, int dma_size, + enum dma_data_direction dir) +{ + struct srpt_ioctx *ioctx; + + ioctx = kmalloc(ioctx_size, GFP_KERNEL); + if (!ioctx) + goto err; + + ioctx->buf = kmalloc(dma_size, GFP_KERNEL); + if (!ioctx->buf) + goto err_free_ioctx; + + ioctx->dma = ib_dma_map_single(sdev->device, ioctx->buf, dma_size, dir); + if (ib_dma_mapping_error(sdev->device, ioctx->dma)) + goto err_free_buf; + + return ioctx; + +err_free_buf: + kfree(ioctx->buf); +err_free_ioctx: + kfree(ioctx); +err: + return NULL; +} + +/** + * srpt_free_ioctx() - Free an SRPT I/O context structure. + */ +static void srpt_free_ioctx(struct srpt_device *sdev, struct srpt_ioctx *ioctx, + int dma_size, enum dma_data_direction dir) +{ + if (!ioctx) + return; + + ib_dma_unmap_single(sdev->device, ioctx->dma, dma_size, dir); + kfree(ioctx->buf); + kfree(ioctx); +} + +/** + * srpt_alloc_ioctx_ring() - Allocate a ring of SRPT I/O context structures. + * @sdev: Device to allocate the I/O context ring for. + * @ring_size: Number of elements in the I/O context ring. + * @ioctx_size: I/O context size. + * @dma_size: DMA buffer size. + * @dir: DMA data direction. + */ +static struct srpt_ioctx **srpt_alloc_ioctx_ring(struct srpt_device *sdev, + int ring_size, int ioctx_size, + int dma_size, enum dma_data_direction dir) +{ + struct srpt_ioctx **ring; + int i; + + WARN_ON(ioctx_size != sizeof(struct srpt_recv_ioctx) + && ioctx_size != sizeof(struct srpt_send_ioctx)); + + ring = kmalloc(ring_size * sizeof(ring[0]), GFP_KERNEL); + if (!ring) + goto out; + for (i = 0; i < ring_size; ++i) { + ring[i] = srpt_alloc_ioctx(sdev, ioctx_size, dma_size, dir); + if (!ring[i]) + goto err; + ring[i]->index = i; + } + goto out; + +err: + while (--i >= 0) + srpt_free_ioctx(sdev, ring[i], dma_size, dir); + kfree(ring); +out: + return ring; +} + +/** + * srpt_free_ioctx_ring() - Free the ring of SRPT I/O context structures. + */ +static void srpt_free_ioctx_ring(struct srpt_ioctx **ioctx_ring, + struct srpt_device *sdev, int ring_size, + int dma_size, enum dma_data_direction dir) +{ + int i; + + for (i = 0; i < ring_size; ++i) + srpt_free_ioctx(sdev, ioctx_ring[i], dma_size, dir); + kfree(ioctx_ring); +} + +/** + * srpt_get_cmd_state() - Get the state of a SCSI command. + */ +static enum srpt_command_state srpt_get_cmd_state(struct srpt_send_ioctx *ioctx) +{ + enum srpt_command_state state; + unsigned long flags; + + BUG_ON(!ioctx); + + spin_lock_irqsave(&ioctx->spinlock, flags); + state = ioctx->state; + spin_unlock_irqrestore(&ioctx->spinlock, flags); + return state; +} + +/** + * srpt_set_cmd_state() - Set the state of a SCSI command. + * + * Does not modify the state of aborted commands. Returns the previous command + * state. + */ +static enum srpt_command_state srpt_set_cmd_state(struct srpt_send_ioctx *ioctx, + enum srpt_command_state new) +{ + enum srpt_command_state previous; + unsigned long flags; + + BUG_ON(!ioctx); + + spin_lock_irqsave(&ioctx->spinlock, flags); + previous = ioctx->state; + if (previous != SRPT_STATE_DONE) + ioctx->state = new; + spin_unlock_irqrestore(&ioctx->spinlock, flags); + + return previous; +} + +/** + * srpt_test_and_set_cmd_state() - Test and set the state of a command. + * + * Returns true if and only if the previous command state was equal to 'old'. + */ +static bool srpt_test_and_set_cmd_state(struct srpt_send_ioctx *ioctx, + enum srpt_command_state old, + enum srpt_command_state new) +{ + enum srpt_command_state previous; + unsigned long flags; + + WARN_ON(!ioctx); + WARN_ON(old == SRPT_STATE_DONE); + WARN_ON(new == SRPT_STATE_NEW); + + spin_lock_irqsave(&ioctx->spinlock, flags); + previous = ioctx->state; + if (previous == old) + ioctx->state = new; + spin_unlock_irqrestore(&ioctx->spinlock, flags); + return previous == old; +} + +/** + * srpt_post_recv() - Post an IB receive request. + */ +static int srpt_post_recv(struct srpt_device *sdev, + struct srpt_recv_ioctx *ioctx) +{ + struct ib_sge list; + struct ib_recv_wr wr, *bad_wr; + + BUG_ON(!sdev); + wr.wr_id = encode_wr_id(SRPT_RECV, ioctx->ioctx.index); + + list.addr = ioctx->ioctx.dma; + list.length = srp_max_req_size; + list.lkey = sdev->mr->lkey; + + wr.next = NULL; + wr.sg_list = &list; + wr.num_sge = 1; + + return ib_post_srq_recv(sdev->srq, &wr, &bad_wr); +} + +/** + * srpt_post_send() - Post an IB send request. + * + * Returns zero upon success and a non-zero value upon failure. + */ +static int srpt_post_send(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx, int len) +{ + struct ib_sge list; + struct ib_send_wr wr, *bad_wr; + struct srpt_device *sdev = ch->sport->sdev; + int ret; + + atomic_inc(&ch->req_lim); + + ret = -ENOMEM; + if (unlikely(atomic_dec_return(&ch->sq_wr_avail) < 0)) { + printk(KERN_WARNING "IB send queue full (needed 1)\n"); + goto out; + } + + ib_dma_sync_single_for_device(sdev->device, ioctx->ioctx.dma, len, + DMA_TO_DEVICE); + + list.addr = ioctx->ioctx.dma; + list.length = len; + list.lkey = sdev->mr->lkey; + + wr.next = NULL; + wr.wr_id = encode_wr_id(SRPT_SEND, ioctx->ioctx.index); + wr.sg_list = &list; + wr.num_sge = 1; + wr.opcode = IB_WR_SEND; + wr.send_flags = IB_SEND_SIGNALED; + + ret = ib_post_send(ch->qp, &wr, &bad_wr); + +out: + if (ret < 0) { + atomic_inc(&ch->sq_wr_avail); + atomic_dec(&ch->req_lim); + } + return ret; +} + +/** + * srpt_get_desc_tbl() - Parse the data descriptors of an SRP_CMD request. + * @ioctx: Pointer to the I/O context associated with the request. + * @srp_cmd: Pointer to the SRP_CMD request data. + * @dir: Pointer to the variable to which the transfer direction will be + * written. + * @data_len: Pointer to the variable to which the total data length of all + * descriptors in the SRP_CMD request will be written. + * + * This function initializes ioctx->nrbuf and ioctx->r_bufs. + * + * Returns -EINVAL when the SRP_CMD request contains inconsistent descriptors; + * -ENOMEM when memory allocation fails and zero upon success. + */ +static int srpt_get_desc_tbl(struct srpt_send_ioctx *ioctx, + struct srp_cmd *srp_cmd, + enum dma_data_direction *dir, u64 *data_len) +{ + struct srp_indirect_buf *idb; + struct srp_direct_buf *db; + unsigned add_cdb_offset; + int ret; + + /* + * The pointer computations below will only be compiled correctly + * if srp_cmd::add_data is declared as s8*, u8*, s8[] or u8[], so check + * whether srp_cmd::add_data has been declared as a byte pointer. + */ + BUILD_BUG_ON(!__same_type(srp_cmd->add_data[0], (s8)0) + && !__same_type(srp_cmd->add_data[0], (u8)0)); + + BUG_ON(!dir); + BUG_ON(!data_len); + + ret = 0; + *data_len = 0; + + /* + * The lower four bits of the buffer format field contain the DATA-IN + * buffer descriptor format, and the highest four bits contain the + * DATA-OUT buffer descriptor format. + */ + *dir = DMA_NONE; + if (srp_cmd->buf_fmt & 0xf) + /* DATA-IN: transfer data from target to initiator (read). */ + *dir = DMA_FROM_DEVICE; + else if (srp_cmd->buf_fmt >> 4) + /* DATA-OUT: transfer data from initiator to target (write). */ + *dir = DMA_TO_DEVICE; + + /* + * According to the SRP spec, the lower two bits of the 'ADDITIONAL + * CDB LENGTH' field are reserved and the size in bytes of this field + * is four times the value specified in bits 3..7. Hence the "& ~3". + */ + add_cdb_offset = srp_cmd->add_cdb_len & ~3; + if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_DIRECT) || + ((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_DIRECT)) { + ioctx->n_rbuf = 1; + ioctx->rbufs = &ioctx->single_rbuf; + + db = (struct srp_direct_buf *)(srp_cmd->add_data + + add_cdb_offset); + memcpy(ioctx->rbufs, db, sizeof *db); + *data_len = be32_to_cpu(db->len); + } else if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_INDIRECT) || + ((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_INDIRECT)) { + idb = (struct srp_indirect_buf *)(srp_cmd->add_data + + add_cdb_offset); + + ioctx->n_rbuf = be32_to_cpu(idb->table_desc.len) / sizeof *db; + + if (ioctx->n_rbuf > + (srp_cmd->data_out_desc_cnt + srp_cmd->data_in_desc_cnt)) { + printk(KERN_ERR "received unsupported SRP_CMD request" + " type (%u out + %u in != %u / %zu)\n", + srp_cmd->data_out_desc_cnt, + srp_cmd->data_in_desc_cnt, + be32_to_cpu(idb->table_desc.len), + sizeof(*db)); + ioctx->n_rbuf = 0; + ret = -EINVAL; + goto out; + } + + if (ioctx->n_rbuf == 1) + ioctx->rbufs = &ioctx->single_rbuf; + else { + ioctx->rbufs = + kmalloc(ioctx->n_rbuf * sizeof *db, GFP_ATOMIC); + if (!ioctx->rbufs) { + ioctx->n_rbuf = 0; + ret = -ENOMEM; + goto out; + } + } + + db = idb->desc_list; + memcpy(ioctx->rbufs, db, ioctx->n_rbuf * sizeof *db); + *data_len = be32_to_cpu(idb->len); + } +out: + return ret; +} + +/** + * srpt_init_ch_qp() - Initialize queue pair attributes. + * + * Initialized the attributes of queue pair 'qp' by allowing local write, + * remote read and remote write. Also transitions 'qp' to state IB_QPS_INIT. + */ +static int srpt_init_ch_qp(struct srpt_rdma_ch *ch, struct ib_qp *qp) +{ + struct ib_qp_attr *attr; + int ret; + + attr = kzalloc(sizeof *attr, GFP_KERNEL); + if (!attr) + return -ENOMEM; + + attr->qp_state = IB_QPS_INIT; + attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ | + IB_ACCESS_REMOTE_WRITE; + attr->port_num = ch->sport->port; + attr->pkey_index = 0; + + ret = ib_modify_qp(qp, attr, + IB_QP_STATE | IB_QP_ACCESS_FLAGS | IB_QP_PORT | + IB_QP_PKEY_INDEX); + + kfree(attr); + return ret; +} + +/** + * srpt_ch_qp_rtr() - Change the state of a channel to 'ready to receive' (RTR). + * @ch: channel of the queue pair. + * @qp: queue pair to change the state of. + * + * Returns zero upon success and a negative value upon failure. + * + * Note: currently a struct ib_qp_attr takes 136 bytes on a 64-bit system. + * If this structure ever becomes larger, it might be necessary to allocate + * it dynamically instead of on the stack. + */ +static int srpt_ch_qp_rtr(struct srpt_rdma_ch *ch, struct ib_qp *qp) +{ + struct ib_qp_attr qp_attr; + int attr_mask; + int ret; + + qp_attr.qp_state = IB_QPS_RTR; + ret = ib_cm_init_qp_attr(ch->cm_id, &qp_attr, &attr_mask); + if (ret) + goto out; + + qp_attr.max_dest_rd_atomic = 4; + + ret = ib_modify_qp(qp, &qp_attr, attr_mask); + +out: + return ret; +} + +/** + * srpt_ch_qp_rts() - Change the state of a channel to 'ready to send' (RTS). + * @ch: channel of the queue pair. + * @qp: queue pair to change the state of. + * + * Returns zero upon success and a negative value upon failure. + * + * Note: currently a struct ib_qp_attr takes 136 bytes on a 64-bit system. + * If this structure ever becomes larger, it might be necessary to allocate + * it dynamically instead of on the stack. + */ +static int srpt_ch_qp_rts(struct srpt_rdma_ch *ch, struct ib_qp *qp) +{ + struct ib_qp_attr qp_attr; + int attr_mask; + int ret; + + qp_attr.qp_state = IB_QPS_RTS; + ret = ib_cm_init_qp_attr(ch->cm_id, &qp_attr, &attr_mask); + if (ret) + goto out; + + qp_attr.max_rd_atomic = 4; + + ret = ib_modify_qp(qp, &qp_attr, attr_mask); + +out: + return ret; +} + +/** + * srpt_ch_qp_err() - Set the channel queue pair state to 'error'. + */ +static int srpt_ch_qp_err(struct srpt_rdma_ch *ch) +{ + struct ib_qp_attr qp_attr; + + qp_attr.qp_state = IB_QPS_ERR; + return ib_modify_qp(ch->qp, &qp_attr, IB_QP_STATE); +} + +/** + * srpt_unmap_sg_to_ib_sge() - Unmap an IB SGE list. + */ +static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx) +{ + struct scatterlist *sg; + enum dma_data_direction dir; + + BUG_ON(!ch); + BUG_ON(!ioctx); + BUG_ON(ioctx->n_rdma && !ioctx->rdma_ius); + + while (ioctx->n_rdma) + kfree(ioctx->rdma_ius[--ioctx->n_rdma].sge); + + kfree(ioctx->rdma_ius); + ioctx->rdma_ius = NULL; + + if (ioctx->mapped_sg_count) { + sg = ioctx->sg; + WARN_ON(!sg); + dir = ioctx->cmd.data_direction; + BUG_ON(dir == DMA_NONE); + ib_dma_unmap_sg(ch->sport->sdev->device, sg, ioctx->sg_cnt, + opposite_dma_dir(dir)); + ioctx->mapped_sg_count = 0; + } +} + +/** + * srpt_map_sg_to_ib_sge() - Map an SG list to an IB SGE list. + */ +static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx) +{ + struct se_cmd *cmd; + struct scatterlist *sg, *sg_orig; + int sg_cnt; + enum dma_data_direction dir; + struct rdma_iu *riu; + struct srp_direct_buf *db; + dma_addr_t dma_addr; + struct ib_sge *sge; + u64 raddr; + u32 rsize; + u32 tsize; + u32 dma_len; + int count, nrdma; + int i, j, k; + + BUG_ON(!ch); + BUG_ON(!ioctx); + cmd = &ioctx->cmd; + dir = cmd->data_direction; + BUG_ON(dir == DMA_NONE); + + transport_do_task_sg_chain(cmd); + ioctx->sg = sg = sg_orig = cmd->t_tasks_sg_chained; + ioctx->sg_cnt = sg_cnt = cmd->t_tasks_sg_chained_no; + + count = ib_dma_map_sg(ch->sport->sdev->device, sg, sg_cnt, + opposite_dma_dir(dir)); + if (unlikely(!count)) + return -EAGAIN; + + ioctx->mapped_sg_count = count; + + if (ioctx->rdma_ius && ioctx->n_rdma_ius) + nrdma = ioctx->n_rdma_ius; + else { + nrdma = (count + SRPT_DEF_SG_PER_WQE - 1) / SRPT_DEF_SG_PER_WQE + + ioctx->n_rbuf; + + ioctx->rdma_ius = kzalloc(nrdma * sizeof *riu, GFP_KERNEL); + if (!ioctx->rdma_ius) + goto free_mem; + + ioctx->n_rdma_ius = nrdma; + } + + db = ioctx->rbufs; + tsize = cmd->data_length; + dma_len = sg_dma_len(&sg[0]); + riu = ioctx->rdma_ius; + + /* + * For each remote desc - calculate the #ib_sge. + * If #ib_sge < SRPT_DEF_SG_PER_WQE per rdma operation then + * each remote desc rdma_iu is required a rdma wr; + * else + * we need to allocate extra rdma_iu to carry extra #ib_sge in + * another rdma wr + */ + for (i = 0, j = 0; + j < count && i < ioctx->n_rbuf && tsize > 0; ++i, ++riu, ++db) { + rsize = be32_to_cpu(db->len); + raddr = be64_to_cpu(db->va); + riu->raddr = raddr; + riu->rkey = be32_to_cpu(db->key); + riu->sge_cnt = 0; + + /* calculate how many sge required for this remote_buf */ + while (rsize > 0 && tsize > 0) { + + if (rsize >= dma_len) { + tsize -= dma_len; + rsize -= dma_len; + raddr += dma_len; + + if (tsize > 0) { + ++j; + if (j < count) { + sg = sg_next(sg); + dma_len = sg_dma_len(sg); + } + } + } else { + tsize -= rsize; + dma_len -= rsize; + rsize = 0; + } + + ++riu->sge_cnt; + + if (rsize > 0 && riu->sge_cnt == SRPT_DEF_SG_PER_WQE) { + ++ioctx->n_rdma; + riu->sge = + kmalloc(riu->sge_cnt * sizeof *riu->sge, + GFP_KERNEL); + if (!riu->sge) + goto free_mem; + + ++riu; + riu->sge_cnt = 0; + riu->raddr = raddr; + riu->rkey = be32_to_cpu(db->key); + } + } + + ++ioctx->n_rdma; + riu->sge = kmalloc(riu->sge_cnt * sizeof *riu->sge, + GFP_KERNEL); + if (!riu->sge) + goto free_mem; + } + + db = ioctx->rbufs; + tsize = cmd->data_length; + riu = ioctx->rdma_ius; + sg = sg_orig; + dma_len = sg_dma_len(&sg[0]); + dma_addr = sg_dma_address(&sg[0]); + + /* this second loop is really mapped sg_addres to rdma_iu->ib_sge */ + for (i = 0, j = 0; + j < count && i < ioctx->n_rbuf && tsize > 0; ++i, ++riu, ++db) { + rsize = be32_to_cpu(db->len); + sge = riu->sge; + k = 0; + + while (rsize > 0 && tsize > 0) { + sge->addr = dma_addr; + sge->lkey = ch->sport->sdev->mr->lkey; + + if (rsize >= dma_len) { + sge->length = + (tsize < dma_len) ? tsize : dma_len; + tsize -= dma_len; + rsize -= dma_len; + + if (tsize > 0) { + ++j; + if (j < count) { + sg = sg_next(sg); + dma_len = sg_dma_len(sg); + dma_addr = sg_dma_address(sg); + } + } + } else { + sge->length = (tsize < rsize) ? tsize : rsize; + tsize -= rsize; + dma_len -= rsize; + dma_addr += rsize; + rsize = 0; + } + + ++k; + if (k == riu->sge_cnt && rsize > 0 && tsize > 0) { + ++riu; + sge = riu->sge; + k = 0; + } else if (rsize > 0 && tsize > 0) + ++sge; + } + } + + return 0; + +free_mem: + srpt_unmap_sg_to_ib_sge(ch, ioctx); + + return -ENOMEM; +} + +/** + * srpt_get_send_ioctx() - Obtain an I/O context for sending to the initiator. + */ +static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch) +{ + struct srpt_send_ioctx *ioctx; + unsigned long flags; + + BUG_ON(!ch); + + ioctx = NULL; + spin_lock_irqsave(&ch->spinlock, flags); + if (!list_empty(&ch->free_list)) { + ioctx = list_first_entry(&ch->free_list, + struct srpt_send_ioctx, free_list); + list_del(&ioctx->free_list); + } + spin_unlock_irqrestore(&ch->spinlock, flags); + + if (!ioctx) + return ioctx; + + BUG_ON(ioctx->ch != ch); + kref_init(&ioctx->kref); + spin_lock_init(&ioctx->spinlock); + ioctx->state = SRPT_STATE_NEW; + ioctx->n_rbuf = 0; + ioctx->rbufs = NULL; + ioctx->n_rdma = 0; + ioctx->n_rdma_ius = 0; + ioctx->rdma_ius = NULL; + ioctx->mapped_sg_count = 0; + init_completion(&ioctx->tx_done); + ioctx->queue_status_only = false; + /* + * transport_init_se_cmd() does not initialize all fields, so do it + * here. + */ + memset(&ioctx->cmd, 0, sizeof(ioctx->cmd)); + memset(&ioctx->sense_data, 0, sizeof(ioctx->sense_data)); + + return ioctx; +} + +/** + * srpt_put_send_ioctx() - Free up resources. + */ +static void srpt_put_send_ioctx(struct srpt_send_ioctx *ioctx) +{ + struct srpt_rdma_ch *ch; + unsigned long flags; + + BUG_ON(!ioctx); + ch = ioctx->ch; + BUG_ON(!ch); + + WARN_ON(srpt_get_cmd_state(ioctx) != SRPT_STATE_DONE); + + srpt_unmap_sg_to_ib_sge(ioctx->ch, ioctx); + transport_generic_free_cmd(&ioctx->cmd, 0); + + if (ioctx->n_rbuf > 1) { + kfree(ioctx->rbufs); + ioctx->rbufs = NULL; + ioctx->n_rbuf = 0; + } + + spin_lock_irqsave(&ch->spinlock, flags); + list_add(&ioctx->free_list, &ch->free_list); + spin_unlock_irqrestore(&ch->spinlock, flags); +} + +static void srpt_put_send_ioctx_kref(struct kref *kref) +{ + srpt_put_send_ioctx(container_of(kref, struct srpt_send_ioctx, kref)); +} + +/** + * srpt_abort_cmd() - Abort a SCSI command. + * @ioctx: I/O context associated with the SCSI command. + * @context: Preferred execution context. + */ +static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) +{ + enum srpt_command_state state; + unsigned long flags; + + BUG_ON(!ioctx); + + /* + * If the command is in a state where the target core is waiting for + * the ib_srpt driver, change the state to the next state. Changing + * the state of the command from SRPT_STATE_NEED_DATA to + * SRPT_STATE_DATA_IN ensures that srpt_xmit_response() will call this + * function a second time. + */ + + spin_lock_irqsave(&ioctx->spinlock, flags); + state = ioctx->state; + switch (state) { + case SRPT_STATE_NEED_DATA: + ioctx->state = SRPT_STATE_DATA_IN; + break; + case SRPT_STATE_DATA_IN: + case SRPT_STATE_CMD_RSP_SENT: + case SRPT_STATE_MGMT_RSP_SENT: + ioctx->state = SRPT_STATE_DONE; + break; + default: + break; + } + spin_unlock_irqrestore(&ioctx->spinlock, flags); + + if (state == SRPT_STATE_DONE) + goto out; + + pr_debug("Aborting cmd with state %d and tag %lld\n", state, + ioctx->tag); + + switch (state) { + case SRPT_STATE_NEW: + case SRPT_STATE_DATA_IN: + case SRPT_STATE_MGMT: + /* + * Do nothing - defer abort processing until + * srpt_queue_response() is invoked. + */ + WARN_ON(!transport_check_aborted_status(&ioctx->cmd, false)); + break; + case SRPT_STATE_NEED_DATA: + /* DMA_TO_DEVICE (write) - RDMA read error. */ + atomic_set(&ioctx->cmd.transport_lun_stop, 1); + transport_generic_handle_data(&ioctx->cmd); + break; + case SRPT_STATE_CMD_RSP_SENT: + /* + * SRP_RSP sending failed or the SRP_RSP send completion has + * not been received in time. + */ + srpt_unmap_sg_to_ib_sge(ioctx->ch, ioctx); + atomic_set(&ioctx->cmd.transport_lun_stop, 1); + kref_put(&ioctx->kref, srpt_put_send_ioctx_kref); + break; + case SRPT_STATE_MGMT_RSP_SENT: + srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); + kref_put(&ioctx->kref, srpt_put_send_ioctx_kref); + break; + default: + WARN_ON("ERROR: unexpected command state"); + break; + } + +out: + return state; +} + +/** + * srpt_handle_send_err_comp() - Process an IB_WC_SEND error completion. + */ +static void srpt_handle_send_err_comp(struct srpt_rdma_ch *ch, u64 wr_id) +{ + struct srpt_send_ioctx *ioctx; + enum srpt_command_state state; + struct se_cmd *cmd; + u32 index; + + atomic_inc(&ch->sq_wr_avail); + + index = idx_from_wr_id(wr_id); + ioctx = ch->ioctx_ring[index]; + state = srpt_get_cmd_state(ioctx); + cmd = &ioctx->cmd; + + WARN_ON(state != SRPT_STATE_CMD_RSP_SENT + && state != SRPT_STATE_MGMT_RSP_SENT + && state != SRPT_STATE_NEED_DATA + && state != SRPT_STATE_DONE); + + /* If SRP_RSP sending failed, undo the ch->req_lim change. */ + if (state == SRPT_STATE_CMD_RSP_SENT + || state == SRPT_STATE_MGMT_RSP_SENT) + atomic_dec(&ch->req_lim); + + srpt_abort_cmd(ioctx); +} + +/** + * srpt_handle_send_comp() - Process an IB send completion notification. + */ +static void srpt_handle_send_comp(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx) +{ + enum srpt_command_state state; + + atomic_inc(&ch->sq_wr_avail); + + state = srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); + + if (WARN_ON(state != SRPT_STATE_CMD_RSP_SENT + && state != SRPT_STATE_MGMT_RSP_SENT + && state != SRPT_STATE_DONE)) + pr_debug("state = %d\n", state); + + if (state != SRPT_STATE_DONE) + kref_put(&ioctx->kref, srpt_put_send_ioctx_kref); + else + printk(KERN_ERR "IB completion has been received too late for" + " wr_id = %u.\n", ioctx->ioctx.index); +} + +/** + * srpt_handle_rdma_comp() - Process an IB RDMA completion notification. + * + * Note: transport_generic_handle_data() is asynchronous so unmapping the + * data that has been transferred via IB RDMA must be postponed until the + * check_stop_free() callback. + */ +static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx, + enum srpt_opcode opcode) +{ + WARN_ON(ioctx->n_rdma <= 0); + atomic_add(ioctx->n_rdma, &ch->sq_wr_avail); + + if (opcode == SRPT_RDMA_READ_LAST) { + if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA, + SRPT_STATE_DATA_IN)) + transport_generic_handle_data(&ioctx->cmd); + else + printk(KERN_ERR "%s[%d]: wrong state = %d\n", __func__, + __LINE__, srpt_get_cmd_state(ioctx)); + } else if (opcode == SRPT_RDMA_ABORT) { + ioctx->rdma_aborted = true; + } else { + WARN(true, "unexpected opcode %d\n", opcode); + } +} + +/** + * srpt_handle_rdma_err_comp() - Process an IB RDMA error completion. + */ +static void srpt_handle_rdma_err_comp(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx, + enum srpt_opcode opcode) +{ + struct se_cmd *cmd; + enum srpt_command_state state; + + cmd = &ioctx->cmd; + state = srpt_get_cmd_state(ioctx); + switch (opcode) { + case SRPT_RDMA_READ_LAST: + if (ioctx->n_rdma <= 0) { + printk(KERN_ERR "Received invalid RDMA read" + " error completion with idx %d\n", + ioctx->ioctx.index); + break; + } + atomic_add(ioctx->n_rdma, &ch->sq_wr_avail); + if (state == SRPT_STATE_NEED_DATA) + srpt_abort_cmd(ioctx); + else + printk(KERN_ERR "%s[%d]: wrong state = %d\n", + __func__, __LINE__, state); + break; + case SRPT_RDMA_WRITE_LAST: + atomic_set(&ioctx->cmd.transport_lun_stop, 1); + break; + default: + printk(KERN_ERR "%s[%d]: opcode = %u\n", __func__, + __LINE__, opcode); + break; + } +} + +/** + * srpt_build_cmd_rsp() - Build an SRP_RSP response. + * @ch: RDMA channel through which the request has been received. + * @ioctx: I/O context associated with the SRP_CMD request. The response will + * be built in the buffer ioctx->buf points at and hence this function will + * overwrite the request data. + * @tag: tag of the request for which this response is being generated. + * @status: value for the STATUS field of the SRP_RSP information unit. + * + * Returns the size in bytes of the SRP_RSP response. + * + * An SRP_RSP response contains a SCSI status or service response. See also + * section 6.9 in the SRP r16a document for the format of an SRP_RSP + * response. See also SPC-2 for more information about sense data. + */ +static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx, u64 tag, + int status) +{ + struct srp_rsp *srp_rsp; + const u8 *sense_data; + int sense_data_len, max_sense_len; + + /* + * The lowest bit of all SAM-3 status codes is zero (see also + * paragraph 5.3 in SAM-3). + */ + WARN_ON(status & 1); + + srp_rsp = ioctx->ioctx.buf; + BUG_ON(!srp_rsp); + + sense_data = ioctx->sense_data; + sense_data_len = ioctx->cmd.scsi_sense_length; + WARN_ON(sense_data_len > sizeof(ioctx->sense_data)); + + memset(srp_rsp, 0, sizeof *srp_rsp); + srp_rsp->opcode = SRP_RSP; + srp_rsp->req_lim_delta = + __constant_cpu_to_be32(1 + atomic_xchg(&ch->req_lim_delta, 0)); + srp_rsp->tag = tag; + srp_rsp->status = status; + + if (sense_data_len) { + BUILD_BUG_ON(MIN_MAX_RSP_SIZE <= sizeof(*srp_rsp)); + max_sense_len = ch->max_ti_iu_len - sizeof(*srp_rsp); + if (sense_data_len > max_sense_len) { + printk(KERN_WARNING "truncated sense data from %d to %d" + " bytes\n", sense_data_len, max_sense_len); + sense_data_len = max_sense_len; + } + + srp_rsp->flags |= SRP_RSP_FLAG_SNSVALID; + srp_rsp->sense_data_len = cpu_to_be32(sense_data_len); + memcpy(srp_rsp + 1, sense_data, sense_data_len); + } + + return sizeof(*srp_rsp) + sense_data_len; +} + +/** + * srpt_build_tskmgmt_rsp() - Build a task management response. + * @ch: RDMA channel through which the request has been received. + * @ioctx: I/O context in which the SRP_RSP response will be built. + * @rsp_code: RSP_CODE that will be stored in the response. + * @tag: Tag of the request for which this response is being generated. + * + * Returns the size in bytes of the SRP_RSP response. + * + * An SRP_RSP response contains a SCSI status or service response. See also + * section 6.9 in the SRP r16a document for the format of an SRP_RSP + * response. + */ +static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx, + u8 rsp_code, u64 tag) +{ + struct srp_rsp *srp_rsp; + int resp_data_len; + int resp_len; + + resp_data_len = (rsp_code == SRP_TSK_MGMT_SUCCESS) ? 0 : 4; + resp_len = sizeof(*srp_rsp) + resp_data_len; + + srp_rsp = ioctx->ioctx.buf; + BUG_ON(!srp_rsp); + memset(srp_rsp, 0, sizeof *srp_rsp); + + srp_rsp->opcode = SRP_RSP; + srp_rsp->req_lim_delta = __constant_cpu_to_be32(1 + + atomic_xchg(&ch->req_lim_delta, 0)); + srp_rsp->tag = tag; + + if (rsp_code != SRP_TSK_MGMT_SUCCESS) { + srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID; + srp_rsp->resp_data_len = cpu_to_be32(resp_data_len); + srp_rsp->data[3] = rsp_code; + } + + return resp_len; +} + +#define NO_SUCH_LUN ((uint64_t)-1LL) + +/* + * SCSI LUN addressing method. See also SAM-2 and the section about + * eight byte LUNs. + */ +enum scsi_lun_addr_method { + SCSI_LUN_ADDR_METHOD_PERIPHERAL = 0, + SCSI_LUN_ADDR_METHOD_FLAT = 1, + SCSI_LUN_ADDR_METHOD_LUN = 2, + SCSI_LUN_ADDR_METHOD_EXTENDED_LUN = 3, +}; + +/* + * srpt_unpack_lun() - Convert from network LUN to linear LUN. + * + * Convert an 2-byte, 4-byte, 6-byte or 8-byte LUN structure in network byte + * order (big endian) to a linear LUN. Supports three LUN addressing methods: + * peripheral, flat and logical unit. See also SAM-2, section 4.9.4 (page 40). + */ +static uint64_t srpt_unpack_lun(const uint8_t *lun, int len) +{ + uint64_t res = NO_SUCH_LUN; + int addressing_method; + + if (unlikely(len < 2)) { + printk(KERN_ERR "Illegal LUN length %d, expected 2 bytes or " + "more", len); + goto out; + } + + switch (len) { + case 8: + if ((*((__be64 *)lun) & + __constant_cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0) + goto out_err; + break; + case 4: + if (*((__be16 *)&lun[2]) != 0) + goto out_err; + break; + case 6: + if (*((__be32 *)&lun[2]) != 0) + goto out_err; + break; + case 2: + break; + default: + goto out_err; + } + + addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */ + switch (addressing_method) { + case SCSI_LUN_ADDR_METHOD_PERIPHERAL: + case SCSI_LUN_ADDR_METHOD_FLAT: + case SCSI_LUN_ADDR_METHOD_LUN: + res = *(lun + 1) | (((*lun) & 0x3f) << 8); + break; + + case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN: + default: + printk(KERN_ERR "Unimplemented LUN addressing method %u", + addressing_method); + break; + } + +out: + return res; + +out_err: + printk(KERN_ERR "Support for multi-level LUNs has not yet been" + " implemented"); + goto out; +} + +static int srpt_check_stop_free(struct se_cmd *cmd) +{ + struct srpt_send_ioctx *ioctx; + + ioctx = container_of(cmd, struct srpt_send_ioctx, cmd); + return kref_put(&ioctx->kref, srpt_put_send_ioctx_kref); +} + +/** + * srpt_handle_cmd() - Process SRP_CMD. + */ +static int srpt_handle_cmd(struct srpt_rdma_ch *ch, + struct srpt_recv_ioctx *recv_ioctx, + struct srpt_send_ioctx *send_ioctx) +{ + struct se_cmd *cmd; + struct srp_cmd *srp_cmd; + uint64_t unpacked_lun; + u64 data_len; + enum dma_data_direction dir; + int ret; + + BUG_ON(!send_ioctx); + + srp_cmd = recv_ioctx->ioctx.buf; + kref_get(&send_ioctx->kref); + cmd = &send_ioctx->cmd; + send_ioctx->tag = srp_cmd->tag; + + switch (srp_cmd->task_attr) { + case SRP_CMD_SIMPLE_Q: + cmd->sam_task_attr = MSG_SIMPLE_TAG; + break; + case SRP_CMD_ORDERED_Q: + default: + cmd->sam_task_attr = MSG_ORDERED_TAG; + break; + case SRP_CMD_HEAD_OF_Q: + cmd->sam_task_attr = MSG_HEAD_TAG; + break; + case SRP_CMD_ACA: + cmd->sam_task_attr = MSG_ACA_TAG; + break; + } + + ret = srpt_get_desc_tbl(send_ioctx, srp_cmd, &dir, &data_len); + if (ret) { + printk(KERN_ERR "0x%llx: parsing SRP descriptor table failed.\n", + srp_cmd->tag); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + goto send_sense; + } + + cmd->data_length = data_len; + cmd->data_direction = dir; + unpacked_lun = srpt_unpack_lun((uint8_t *)&srp_cmd->lun, + sizeof(srp_cmd->lun)); + if (transport_lookup_cmd_lun(cmd, unpacked_lun) < 0) + goto send_sense; + ret = transport_generic_allocate_tasks(cmd, srp_cmd->cdb); + if (cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) + srpt_queue_status(cmd); + else if (cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) + goto send_sense; + else + WARN_ON_ONCE(ret); + + transport_handle_cdb_direct(cmd); + return 0; + +send_sense: + transport_send_check_condition_and_sense(cmd, cmd->scsi_sense_reason, + 0); + return -1; +} + +/** + * srpt_rx_mgmt_fn_tag() - Process a task management function by tag. + * @ch: RDMA channel of the task management request. + * @fn: Task management function to perform. + * @req_tag: Tag of the SRP task management request. + * @mgmt_ioctx: I/O context of the task management request. + * + * Returns zero if the target core will process the task management + * request asynchronously. + * + * Note: It is assumed that the initiator serializes tag-based task management + * requests. + */ +static int srpt_rx_mgmt_fn_tag(struct srpt_send_ioctx *ioctx, u64 tag) +{ + struct srpt_device *sdev; + struct srpt_rdma_ch *ch; + struct srpt_send_ioctx *target; + int ret, i; + + ret = -EINVAL; + ch = ioctx->ch; + BUG_ON(!ch); + BUG_ON(!ch->sport); + sdev = ch->sport->sdev; + BUG_ON(!sdev); + spin_lock_irq(&sdev->spinlock); + for (i = 0; i < ch->rq_size; ++i) { + target = ch->ioctx_ring[i]; + if (target->cmd.se_lun == ioctx->cmd.se_lun && + target->tag == tag && + srpt_get_cmd_state(target) != SRPT_STATE_DONE) { + ret = 0; + /* now let the target core abort &target->cmd; */ + break; + } + } + spin_unlock_irq(&sdev->spinlock); + return ret; +} + +static int srp_tmr_to_tcm(int fn) +{ + switch (fn) { + case SRP_TSK_ABORT_TASK: + return TMR_ABORT_TASK; + case SRP_TSK_ABORT_TASK_SET: + return TMR_ABORT_TASK_SET; + case SRP_TSK_CLEAR_TASK_SET: + return TMR_CLEAR_TASK_SET; + case SRP_TSK_LUN_RESET: + return TMR_LUN_RESET; + case SRP_TSK_CLEAR_ACA: + return TMR_CLEAR_ACA; + default: + return -1; + } +} + +/** + * srpt_handle_tsk_mgmt() - Process an SRP_TSK_MGMT information unit. + * + * Returns 0 if and only if the request will be processed by the target core. + * + * For more information about SRP_TSK_MGMT information units, see also section + * 6.7 in the SRP r16a document. + */ +static void srpt_handle_tsk_mgmt(struct srpt_rdma_ch *ch, + struct srpt_recv_ioctx *recv_ioctx, + struct srpt_send_ioctx *send_ioctx) +{ + struct srp_tsk_mgmt *srp_tsk; + struct se_cmd *cmd; + uint64_t unpacked_lun; + int tcm_tmr; + int res; + + BUG_ON(!send_ioctx); + + srp_tsk = recv_ioctx->ioctx.buf; + cmd = &send_ioctx->cmd; + + pr_debug("recv tsk_mgmt fn %d for task_tag %lld and cmd tag %lld" + " cm_id %p sess %p\n", srp_tsk->tsk_mgmt_func, + srp_tsk->task_tag, srp_tsk->tag, ch->cm_id, ch->sess); + + srpt_set_cmd_state(send_ioctx, SRPT_STATE_MGMT); + send_ioctx->tag = srp_tsk->tag; + tcm_tmr = srp_tmr_to_tcm(srp_tsk->tsk_mgmt_func); + if (tcm_tmr < 0) { + send_ioctx->cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + send_ioctx->cmd.se_tmr_req->response = + TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; + goto process_tmr; + } + cmd->se_tmr_req = core_tmr_alloc_req(cmd, NULL, tcm_tmr, GFP_KERNEL); + if (!cmd->se_tmr_req) { + send_ioctx->cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + send_ioctx->cmd.se_tmr_req->response = TMR_FUNCTION_REJECTED; + goto process_tmr; + } + + unpacked_lun = srpt_unpack_lun((uint8_t *)&srp_tsk->lun, + sizeof(srp_tsk->lun)); + res = transport_lookup_tmr_lun(&send_ioctx->cmd, unpacked_lun); + if (res) { + pr_debug("rejecting TMR for LUN %lld\n", unpacked_lun); + send_ioctx->cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + send_ioctx->cmd.se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; + goto process_tmr; + } + + if (srp_tsk->tsk_mgmt_func == SRP_TSK_ABORT_TASK) + srpt_rx_mgmt_fn_tag(send_ioctx, srp_tsk->task_tag); + +process_tmr: + kref_get(&send_ioctx->kref); + if (!(send_ioctx->cmd.se_cmd_flags & SCF_SCSI_CDB_EXCEPTION)) + transport_generic_handle_tmr(&send_ioctx->cmd); + else + transport_send_check_condition_and_sense(cmd, + cmd->scsi_sense_reason, 0); + +} + +/** + * srpt_handle_new_iu() - Process a newly received information unit. + * @ch: RDMA channel through which the information unit has been received. + * @ioctx: SRPT I/O context associated with the information unit. + */ +static void srpt_handle_new_iu(struct srpt_rdma_ch *ch, + struct srpt_recv_ioctx *recv_ioctx, + struct srpt_send_ioctx *send_ioctx) +{ + struct srp_cmd *srp_cmd; + enum rdma_ch_state ch_state; + + BUG_ON(!ch); + BUG_ON(!recv_ioctx); + + ib_dma_sync_single_for_cpu(ch->sport->sdev->device, + recv_ioctx->ioctx.dma, srp_max_req_size, + DMA_FROM_DEVICE); + + ch_state = srpt_get_ch_state(ch); + if (unlikely(ch_state == CH_CONNECTING)) { + list_add_tail(&recv_ioctx->wait_list, &ch->cmd_wait_list); + goto out; + } + + if (unlikely(ch_state != CH_LIVE)) + goto out; + + srp_cmd = recv_ioctx->ioctx.buf; + if (srp_cmd->opcode == SRP_CMD || srp_cmd->opcode == SRP_TSK_MGMT) { + if (!send_ioctx) + send_ioctx = srpt_get_send_ioctx(ch); + if (unlikely(!send_ioctx)) { + list_add_tail(&recv_ioctx->wait_list, + &ch->cmd_wait_list); + goto out; + } + } + + transport_init_se_cmd(&send_ioctx->cmd, &srpt_target->tf_ops, ch->sess, + 0, DMA_NONE, MSG_SIMPLE_TAG, + send_ioctx->sense_data); + + switch (srp_cmd->opcode) { + case SRP_CMD: + srpt_handle_cmd(ch, recv_ioctx, send_ioctx); + break; + case SRP_TSK_MGMT: + srpt_handle_tsk_mgmt(ch, recv_ioctx, send_ioctx); + break; + case SRP_I_LOGOUT: + printk(KERN_ERR "Not yet implemented: SRP_I_LOGOUT\n"); + break; + case SRP_CRED_RSP: + pr_debug("received SRP_CRED_RSP\n"); + break; + case SRP_AER_RSP: + pr_debug("received SRP_AER_RSP\n"); + break; + case SRP_RSP: + printk(KERN_ERR "Received SRP_RSP\n"); + break; + default: + printk(KERN_ERR "received IU with unknown opcode 0x%x\n", + srp_cmd->opcode); + break; + } + + srpt_post_recv(ch->sport->sdev, recv_ioctx); +out: + return; +} + +static void srpt_process_rcv_completion(struct ib_cq *cq, + struct srpt_rdma_ch *ch, + struct ib_wc *wc) +{ + struct srpt_device *sdev = ch->sport->sdev; + struct srpt_recv_ioctx *ioctx; + u32 index; + + index = idx_from_wr_id(wc->wr_id); + if (wc->status == IB_WC_SUCCESS) { + int req_lim; + + req_lim = atomic_dec_return(&ch->req_lim); + if (unlikely(req_lim < 0)) + printk(KERN_ERR "req_lim = %d < 0\n", req_lim); + ioctx = sdev->ioctx_ring[index]; + srpt_handle_new_iu(ch, ioctx, NULL); + } else { + printk(KERN_INFO "receiving failed for idx %u with status %d\n", + index, wc->status); + } +} + +/** + * srpt_process_send_completion() - Process an IB send completion. + * + * Note: Although this has not yet been observed during tests, at least in + * theory it is possible that the srpt_get_send_ioctx() call invoked by + * srpt_handle_new_iu() fails. This is possible because the req_lim_delta + * value in each response is set to one, and it is possible that this response + * makes the initiator send a new request before the send completion for that + * response has been processed. This could e.g. happen if the call to + * srpt_put_send_iotcx() is delayed because of a higher priority interrupt or + * if IB retransmission causes generation of the send completion to be + * delayed. Incoming information units for which srpt_get_send_ioctx() fails + * are queued on cmd_wait_list. The code below processes these delayed + * requests one at a time. + */ +static void srpt_process_send_completion(struct ib_cq *cq, + struct srpt_rdma_ch *ch, + struct ib_wc *wc) +{ + struct srpt_send_ioctx *send_ioctx; + uint32_t index; + enum srpt_opcode opcode; + + index = idx_from_wr_id(wc->wr_id); + opcode = opcode_from_wr_id(wc->wr_id); + send_ioctx = ch->ioctx_ring[index]; + if (wc->status == IB_WC_SUCCESS) { + if (opcode == SRPT_SEND) + srpt_handle_send_comp(ch, send_ioctx); + else { + WARN_ON(opcode != SRPT_RDMA_ABORT && + wc->opcode != IB_WC_RDMA_READ); + srpt_handle_rdma_comp(ch, send_ioctx, opcode); + } + } else { + if (opcode == SRPT_SEND) { + printk(KERN_INFO "sending response for idx %u failed" + " with status %d\n", index, wc->status); + srpt_handle_send_err_comp(ch, wc->wr_id); + } else if (opcode != SRPT_RDMA_MID) { + printk(KERN_INFO "RDMA t %d for idx %u failed with" + " status %d", opcode, index, wc->status); + srpt_handle_rdma_err_comp(ch, send_ioctx, opcode); + } + } + + while (unlikely(opcode == SRPT_SEND + && !list_empty(&ch->cmd_wait_list) + && srpt_get_ch_state(ch) == CH_LIVE + && (send_ioctx = srpt_get_send_ioctx(ch)) != NULL)) { + struct srpt_recv_ioctx *recv_ioctx; + + recv_ioctx = list_first_entry(&ch->cmd_wait_list, + struct srpt_recv_ioctx, + wait_list); + list_del(&recv_ioctx->wait_list); + srpt_handle_new_iu(ch, recv_ioctx, send_ioctx); + } +} + +static void srpt_process_completion(struct ib_cq *cq, struct srpt_rdma_ch *ch) +{ + struct ib_wc *const wc = ch->wc; + int i, n; + + WARN_ON(cq != ch->cq); + + ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); + while ((n = ib_poll_cq(cq, ARRAY_SIZE(ch->wc), wc)) > 0) { + for (i = 0; i < n; i++) { + if (opcode_from_wr_id(wc[i].wr_id) == SRPT_RECV) + srpt_process_rcv_completion(cq, ch, &wc[i]); + else + srpt_process_send_completion(cq, ch, &wc[i]); + } + } +} + +/** + * srpt_completion() - IB completion queue callback function. + * + * Notes: + * - It is guaranteed that a completion handler will never be invoked + * concurrently on two different CPUs for the same completion queue. See also + * Documentation/infiniband/core_locking.txt and the implementation of + * handle_edge_irq() in kernel/irq/chip.c. + * - When threaded IRQs are enabled, completion handlers are invoked in thread + * context instead of interrupt context. + */ +static void srpt_completion(struct ib_cq *cq, void *ctx) +{ + struct srpt_rdma_ch *ch = ctx; + + wake_up_interruptible(&ch->wait_queue); +} + +static int srpt_compl_thread(void *arg) +{ + struct srpt_rdma_ch *ch; + + /* Hibernation / freezing of the SRPT kernel thread is not supported. */ + current->flags |= PF_NOFREEZE; + + ch = arg; + BUG_ON(!ch); + printk(KERN_INFO "Session %s: kernel thread %s (PID %d) started\n", + ch->sess_name, ch->thread->comm, current->pid); + while (!kthread_should_stop()) { + wait_event_interruptible(ch->wait_queue, + (srpt_process_completion(ch->cq, ch), + kthread_should_stop())); + } + printk(KERN_INFO "Session %s: kernel thread %s (PID %d) stopped\n", + ch->sess_name, ch->thread->comm, current->pid); + return 0; +} + +/** + * srpt_create_ch_ib() - Create receive and send completion queues. + */ +static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) +{ + struct ib_qp_init_attr *qp_init; + struct srpt_port *sport = ch->sport; + struct srpt_device *sdev = sport->sdev; + u32 srp_sq_size = sport->port_attrib.srp_sq_size; + int ret; + + WARN_ON(ch->rq_size < 1); + + ret = -ENOMEM; + qp_init = kzalloc(sizeof *qp_init, GFP_KERNEL); + if (!qp_init) + goto out; + + ch->cq = ib_create_cq(sdev->device, srpt_completion, NULL, ch, + ch->rq_size + srp_sq_size, 0); + if (IS_ERR(ch->cq)) { + ret = PTR_ERR(ch->cq); + printk(KERN_ERR "failed to create CQ cqe= %d ret= %d\n", + ch->rq_size + srp_sq_size, ret); + goto out; + } + + qp_init->qp_context = (void *)ch; + qp_init->event_handler + = (void(*)(struct ib_event *, void*))srpt_qp_event; + qp_init->send_cq = ch->cq; + qp_init->recv_cq = ch->cq; + qp_init->srq = sdev->srq; + qp_init->sq_sig_type = IB_SIGNAL_REQ_WR; + qp_init->qp_type = IB_QPT_RC; + qp_init->cap.max_send_wr = srp_sq_size; + qp_init->cap.max_send_sge = SRPT_DEF_SG_PER_WQE; + + ch->qp = ib_create_qp(sdev->pd, qp_init); + if (IS_ERR(ch->qp)) { + ret = PTR_ERR(ch->qp); + printk(KERN_ERR "failed to create_qp ret= %d\n", ret); + goto err_destroy_cq; + } + + atomic_set(&ch->sq_wr_avail, qp_init->cap.max_send_wr); + + pr_debug("%s: max_cqe= %d max_sge= %d sq_size = %d cm_id= %p\n", + __func__, ch->cq->cqe, qp_init->cap.max_send_sge, + qp_init->cap.max_send_wr, ch->cm_id); + + ret = srpt_init_ch_qp(ch, ch->qp); + if (ret) + goto err_destroy_qp; + + init_waitqueue_head(&ch->wait_queue); + + pr_debug("creating thread for session %s\n", ch->sess_name); + + ch->thread = kthread_run(srpt_compl_thread, ch, "ib_srpt_compl"); + if (IS_ERR(ch->thread)) { + printk(KERN_ERR "failed to create kernel thread %ld\n", + PTR_ERR(ch->thread)); + ch->thread = NULL; + goto err_destroy_qp; + } + +out: + kfree(qp_init); + return ret; + +err_destroy_qp: + ib_destroy_qp(ch->qp); +err_destroy_cq: + ib_destroy_cq(ch->cq); + goto out; +} + +static void srpt_destroy_ch_ib(struct srpt_rdma_ch *ch) +{ + if (ch->thread) + kthread_stop(ch->thread); + + ib_destroy_qp(ch->qp); + ib_destroy_cq(ch->cq); +} + +/** + * __srpt_close_ch() - Close an RDMA channel by setting the QP error state. + * + * Reset the QP and make sure all resources associated with the channel will + * be deallocated at an appropriate time. + * + * Note: The caller must hold ch->sport->sdev->spinlock. + */ +static void __srpt_close_ch(struct srpt_rdma_ch *ch) +{ + struct srpt_device *sdev; + enum rdma_ch_state prev_state; + unsigned long flags; + + sdev = ch->sport->sdev; + + spin_lock_irqsave(&ch->spinlock, flags); + prev_state = ch->state; + switch (prev_state) { + case CH_CONNECTING: + case CH_LIVE: + ch->state = CH_DISCONNECTING; + break; + default: + break; + } + spin_unlock_irqrestore(&ch->spinlock, flags); + + switch (prev_state) { + case CH_CONNECTING: + ib_send_cm_rej(ch->cm_id, IB_CM_REJ_NO_RESOURCES, NULL, 0, + NULL, 0); + /* fall through */ + case CH_LIVE: + if (ib_send_cm_dreq(ch->cm_id, NULL, 0) < 0) + printk(KERN_ERR "sending CM DREQ failed.\n"); + break; + case CH_DISCONNECTING: + break; + case CH_DRAINING: + case CH_RELEASING: + break; + } +} + +/** + * srpt_close_ch() - Close an RDMA channel. + */ +static void srpt_close_ch(struct srpt_rdma_ch *ch) +{ + struct srpt_device *sdev; + + sdev = ch->sport->sdev; + spin_lock_irq(&sdev->spinlock); + __srpt_close_ch(ch); + spin_unlock_irq(&sdev->spinlock); +} + +/** + * srpt_drain_channel() - Drain a channel by resetting the IB queue pair. + * @cm_id: Pointer to the CM ID of the channel to be drained. + * + * Note: Must be called from inside srpt_cm_handler to avoid a race between + * accessing sdev->spinlock and the call to kfree(sdev) in srpt_remove_one() + * (the caller of srpt_cm_handler holds the cm_id spinlock; srpt_remove_one() + * waits until all target sessions for the associated IB device have been + * unregistered and target session registration involves a call to + * ib_destroy_cm_id(), which locks the cm_id spinlock and hence waits until + * this function has finished). + */ +static void srpt_drain_channel(struct ib_cm_id *cm_id) +{ + struct srpt_device *sdev; + struct srpt_rdma_ch *ch; + int ret; + bool do_reset = false; + + WARN_ON_ONCE(irqs_disabled()); + + sdev = cm_id->context; + BUG_ON(!sdev); + spin_lock_irq(&sdev->spinlock); + list_for_each_entry(ch, &sdev->rch_list, list) { + if (ch->cm_id == cm_id) { + do_reset = srpt_test_and_set_ch_state(ch, + CH_CONNECTING, CH_DRAINING) || + srpt_test_and_set_ch_state(ch, + CH_LIVE, CH_DRAINING) || + srpt_test_and_set_ch_state(ch, + CH_DISCONNECTING, CH_DRAINING); + break; + } + } + spin_unlock_irq(&sdev->spinlock); + + if (do_reset) { + ret = srpt_ch_qp_err(ch); + if (ret < 0) + printk(KERN_ERR "Setting queue pair in error state" + " failed: %d\n", ret); + } +} + +/** + * srpt_find_channel() - Look up an RDMA channel. + * @cm_id: Pointer to the CM ID of the channel to be looked up. + * + * Return NULL if no matching RDMA channel has been found. + */ +static struct srpt_rdma_ch *srpt_find_channel(struct srpt_device *sdev, + struct ib_cm_id *cm_id) +{ + struct srpt_rdma_ch *ch; + bool found; + + WARN_ON_ONCE(irqs_disabled()); + BUG_ON(!sdev); + + found = false; + spin_lock_irq(&sdev->spinlock); + list_for_each_entry(ch, &sdev->rch_list, list) { + if (ch->cm_id == cm_id) { + found = true; + break; + } + } + spin_unlock_irq(&sdev->spinlock); + + return found ? ch : NULL; +} + +/** + * srpt_release_channel() - Release channel resources. + * + * Schedules the actual release because: + * - Calling the ib_destroy_cm_id() call from inside an IB CM callback would + * trigger a deadlock. + * - It is not safe to call TCM transport_* functions from interrupt context. + */ +static void srpt_release_channel(struct srpt_rdma_ch *ch) +{ + schedule_work(&ch->release_work); +} + +static void srpt_release_channel_work(struct work_struct *w) +{ + struct srpt_rdma_ch *ch; + struct srpt_device *sdev; + + ch = container_of(w, struct srpt_rdma_ch, release_work); + pr_debug("ch = %p; ch->sess = %p; release_done = %p\n", ch, ch->sess, + ch->release_done); + + sdev = ch->sport->sdev; + BUG_ON(!sdev); + + transport_deregister_session_configfs(ch->sess); + transport_deregister_session(ch->sess); + ch->sess = NULL; + + srpt_destroy_ch_ib(ch); + + srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring, + ch->sport->sdev, ch->rq_size, + ch->rsp_size, DMA_TO_DEVICE); + + spin_lock_irq(&sdev->spinlock); + list_del(&ch->list); + spin_unlock_irq(&sdev->spinlock); + + ib_destroy_cm_id(ch->cm_id); + + if (ch->release_done) + complete(ch->release_done); + + wake_up(&sdev->ch_releaseQ); + + kfree(ch); +} + +static struct srpt_node_acl *__srpt_lookup_acl(struct srpt_port *sport, + u8 i_port_id[16]) +{ + struct srpt_node_acl *nacl; + + list_for_each_entry(nacl, &sport->port_acl_list, list) + if (memcmp(nacl->i_port_id, i_port_id, + sizeof(nacl->i_port_id)) == 0) + return nacl; + + return NULL; +} + +static struct srpt_node_acl *srpt_lookup_acl(struct srpt_port *sport, + u8 i_port_id[16]) +{ + struct srpt_node_acl *nacl; + + spin_lock_irq(&sport->port_acl_lock); + nacl = __srpt_lookup_acl(sport, i_port_id); + spin_unlock_irq(&sport->port_acl_lock); + + return nacl; +} + +/** + * srpt_cm_req_recv() - Process the event IB_CM_REQ_RECEIVED. + * + * Ownership of the cm_id is transferred to the target session if this + * functions returns zero. Otherwise the caller remains the owner of cm_id. + */ +static int srpt_cm_req_recv(struct ib_cm_id *cm_id, + struct ib_cm_req_event_param *param, + void *private_data) +{ + struct srpt_device *sdev = cm_id->context; + struct srpt_port *sport = &sdev->port[param->port - 1]; + struct srp_login_req *req; + struct srp_login_rsp *rsp; + struct srp_login_rej *rej; + struct ib_cm_rep_param *rep_param; + struct srpt_rdma_ch *ch, *tmp_ch; + struct srpt_node_acl *nacl; + u32 it_iu_len; + int i; + int ret = 0; + + WARN_ON_ONCE(irqs_disabled()); + + if (WARN_ON(!sdev || !private_data)) + return -EINVAL; + + req = (struct srp_login_req *)private_data; + + it_iu_len = be32_to_cpu(req->req_it_iu_len); + + printk(KERN_INFO "Received SRP_LOGIN_REQ with i_port_id 0x%llx:0x%llx," + " t_port_id 0x%llx:0x%llx and it_iu_len %d on port %d" + " (guid=0x%llx:0x%llx)\n", + be64_to_cpu(*(__be64 *)&req->initiator_port_id[0]), + be64_to_cpu(*(__be64 *)&req->initiator_port_id[8]), + be64_to_cpu(*(__be64 *)&req->target_port_id[0]), + be64_to_cpu(*(__be64 *)&req->target_port_id[8]), + it_iu_len, + param->port, + be64_to_cpu(*(__be64 *)&sdev->port[param->port - 1].gid.raw[0]), + be64_to_cpu(*(__be64 *)&sdev->port[param->port - 1].gid.raw[8])); + + rsp = kzalloc(sizeof *rsp, GFP_KERNEL); + rej = kzalloc(sizeof *rej, GFP_KERNEL); + rep_param = kzalloc(sizeof *rep_param, GFP_KERNEL); + + if (!rsp || !rej || !rep_param) { + ret = -ENOMEM; + goto out; + } + + if (it_iu_len > srp_max_req_size || it_iu_len < 64) { + rej->reason = __constant_cpu_to_be32( + SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE); + ret = -EINVAL; + printk(KERN_ERR "rejected SRP_LOGIN_REQ because its" + " length (%d bytes) is out of range (%d .. %d)\n", + it_iu_len, 64, srp_max_req_size); + goto reject; + } + + if (!sport->enabled) { + rej->reason = __constant_cpu_to_be32( + SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + ret = -EINVAL; + printk(KERN_ERR "rejected SRP_LOGIN_REQ because the target port" + " has not yet been enabled\n"); + goto reject; + } + + if ((req->req_flags & SRP_MTCH_ACTION) == SRP_MULTICHAN_SINGLE) { + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN; + + spin_lock_irq(&sdev->spinlock); + + list_for_each_entry_safe(ch, tmp_ch, &sdev->rch_list, list) { + if (!memcmp(ch->i_port_id, req->initiator_port_id, 16) + && !memcmp(ch->t_port_id, req->target_port_id, 16) + && param->port == ch->sport->port + && param->listen_id == ch->sport->sdev->cm_id + && ch->cm_id) { + enum rdma_ch_state ch_state; + + ch_state = srpt_get_ch_state(ch); + if (ch_state != CH_CONNECTING + && ch_state != CH_LIVE) + continue; + + /* found an existing channel */ + pr_debug("Found existing channel %s" + " cm_id= %p state= %d\n", + ch->sess_name, ch->cm_id, ch_state); + + __srpt_close_ch(ch); + + rsp->rsp_flags = + SRP_LOGIN_RSP_MULTICHAN_TERMINATED; + } + } + + spin_unlock_irq(&sdev->spinlock); + + } else + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED; + + if (*(__be64 *)req->target_port_id != cpu_to_be64(srpt_service_guid) + || *(__be64 *)(req->target_port_id + 8) != + cpu_to_be64(srpt_service_guid)) { + rej->reason = __constant_cpu_to_be32( + SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL); + ret = -ENOMEM; + printk(KERN_ERR "rejected SRP_LOGIN_REQ because it" + " has an invalid target port identifier.\n"); + goto reject; + } + + ch = kzalloc(sizeof *ch, GFP_KERNEL); + if (!ch) { + rej->reason = __constant_cpu_to_be32( + SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + printk(KERN_ERR "rejected SRP_LOGIN_REQ because no memory.\n"); + ret = -ENOMEM; + goto reject; + } + + INIT_WORK(&ch->release_work, srpt_release_channel_work); + memcpy(ch->i_port_id, req->initiator_port_id, 16); + memcpy(ch->t_port_id, req->target_port_id, 16); + ch->sport = &sdev->port[param->port - 1]; + ch->cm_id = cm_id; + /* + * Avoid QUEUE_FULL conditions by limiting the number of buffers used + * for the SRP protocol to the command queue size. + */ + ch->rq_size = SRPT_RQ_SIZE; + spin_lock_init(&ch->spinlock); + ch->state = CH_CONNECTING; + INIT_LIST_HEAD(&ch->cmd_wait_list); + ch->rsp_size = ch->sport->port_attrib.srp_max_rsp_size; + + ch->ioctx_ring = (struct srpt_send_ioctx **) + srpt_alloc_ioctx_ring(ch->sport->sdev, ch->rq_size, + sizeof(*ch->ioctx_ring[0]), + ch->rsp_size, DMA_TO_DEVICE); + if (!ch->ioctx_ring) + goto free_ch; + + INIT_LIST_HEAD(&ch->free_list); + for (i = 0; i < ch->rq_size; i++) { + ch->ioctx_ring[i]->ch = ch; + list_add_tail(&ch->ioctx_ring[i]->free_list, &ch->free_list); + } + + ret = srpt_create_ch_ib(ch); + if (ret) { + rej->reason = __constant_cpu_to_be32( + SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + printk(KERN_ERR "rejected SRP_LOGIN_REQ because creating" + " a new RDMA channel failed.\n"); + goto free_ring; + } + + ret = srpt_ch_qp_rtr(ch, ch->qp); + if (ret) { + rej->reason = __constant_cpu_to_be32( + SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + printk(KERN_ERR "rejected SRP_LOGIN_REQ because enabling" + " RTR failed (error code = %d)\n", ret); + goto destroy_ib; + } + /* + * Use the initator port identifier as the session name. + */ + snprintf(ch->sess_name, sizeof(ch->sess_name), "0x%016llx%016llx", + be64_to_cpu(*(__be64 *)ch->i_port_id), + be64_to_cpu(*(__be64 *)(ch->i_port_id + 8))); + + pr_debug("registering session %s\n", ch->sess_name); + + nacl = srpt_lookup_acl(sport, ch->i_port_id); + if (!nacl) { + printk(KERN_INFO "Rejected login because no ACL has been" + " configured yet for initiator %s.\n", ch->sess_name); + rej->reason = __constant_cpu_to_be32( + SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED); + goto destroy_ib; + } + + ch->sess = transport_init_session(); + if (!ch->sess) { + rej->reason = __constant_cpu_to_be32( + SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + pr_debug("Failed to create session\n"); + goto deregister_session; + } + ch->sess->se_node_acl = &nacl->nacl; + transport_register_session(&sport->port_tpg_1, &nacl->nacl, ch->sess, ch); + + pr_debug("Establish connection sess=%p name=%s cm_id=%p\n", ch->sess, + ch->sess_name, ch->cm_id); + + /* create srp_login_response */ + rsp->opcode = SRP_LOGIN_RSP; + rsp->tag = req->tag; + rsp->max_it_iu_len = req->req_it_iu_len; + rsp->max_ti_iu_len = req->req_it_iu_len; + ch->max_ti_iu_len = it_iu_len; + rsp->buf_fmt = __constant_cpu_to_be16(SRP_BUF_FORMAT_DIRECT + | SRP_BUF_FORMAT_INDIRECT); + rsp->req_lim_delta = cpu_to_be32(ch->rq_size); + atomic_set(&ch->req_lim, ch->rq_size); + atomic_set(&ch->req_lim_delta, 0); + + /* create cm reply */ + rep_param->qp_num = ch->qp->qp_num; + rep_param->private_data = (void *)rsp; + rep_param->private_data_len = sizeof *rsp; + rep_param->rnr_retry_count = 7; + rep_param->flow_control = 1; + rep_param->failover_accepted = 0; + rep_param->srq = 1; + rep_param->responder_resources = 4; + rep_param->initiator_depth = 4; + + ret = ib_send_cm_rep(cm_id, rep_param); + if (ret) { + printk(KERN_ERR "sending SRP_LOGIN_REQ response failed" + " (error code = %d)\n", ret); + goto release_channel; + } + + spin_lock_irq(&sdev->spinlock); + list_add_tail(&ch->list, &sdev->rch_list); + spin_unlock_irq(&sdev->spinlock); + + goto out; + +release_channel: + srpt_set_ch_state(ch, CH_RELEASING); + transport_deregister_session_configfs(ch->sess); + +deregister_session: + transport_deregister_session(ch->sess); + ch->sess = NULL; + +destroy_ib: + srpt_destroy_ch_ib(ch); + +free_ring: + srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring, + ch->sport->sdev, ch->rq_size, + ch->rsp_size, DMA_TO_DEVICE); +free_ch: + kfree(ch); + +reject: + rej->opcode = SRP_LOGIN_REJ; + rej->tag = req->tag; + rej->buf_fmt = __constant_cpu_to_be16(SRP_BUF_FORMAT_DIRECT + | SRP_BUF_FORMAT_INDIRECT); + + ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, NULL, 0, + (void *)rej, sizeof *rej); + +out: + kfree(rep_param); + kfree(rsp); + kfree(rej); + + return ret; +} + +static void srpt_cm_rej_recv(struct ib_cm_id *cm_id) +{ + printk(KERN_INFO "Received IB REJ for cm_id %p.\n", cm_id); + srpt_drain_channel(cm_id); +} + +/** + * srpt_cm_rtu_recv() - Process an IB_CM_RTU_RECEIVED or USER_ESTABLISHED event. + * + * An IB_CM_RTU_RECEIVED message indicates that the connection is established + * and that the recipient may begin transmitting (RTU = ready to use). + */ +static void srpt_cm_rtu_recv(struct ib_cm_id *cm_id) +{ + struct srpt_rdma_ch *ch; + int ret; + + ch = srpt_find_channel(cm_id->context, cm_id); + BUG_ON(!ch); + + if (srpt_test_and_set_ch_state(ch, CH_CONNECTING, CH_LIVE)) { + struct srpt_recv_ioctx *ioctx, *ioctx_tmp; + + ret = srpt_ch_qp_rts(ch, ch->qp); + + list_for_each_entry_safe(ioctx, ioctx_tmp, &ch->cmd_wait_list, + wait_list) { + list_del(&ioctx->wait_list); + srpt_handle_new_iu(ch, ioctx, NULL); + } + if (ret) + srpt_close_ch(ch); + } +} + +static void srpt_cm_timewait_exit(struct ib_cm_id *cm_id) +{ + printk(KERN_INFO "Received IB TimeWait exit for cm_id %p.\n", cm_id); + srpt_drain_channel(cm_id); +} + +static void srpt_cm_rep_error(struct ib_cm_id *cm_id) +{ + printk(KERN_INFO "Received IB REP error for cm_id %p.\n", cm_id); + srpt_drain_channel(cm_id); +} + +/** + * srpt_cm_dreq_recv() - Process reception of a DREQ message. + */ +static void srpt_cm_dreq_recv(struct ib_cm_id *cm_id) +{ + struct srpt_rdma_ch *ch; + unsigned long flags; + bool send_drep = false; + + ch = srpt_find_channel(cm_id->context, cm_id); + BUG_ON(!ch); + + pr_debug("cm_id= %p ch->state= %d\n", cm_id, srpt_get_ch_state(ch)); + + spin_lock_irqsave(&ch->spinlock, flags); + switch (ch->state) { + case CH_CONNECTING: + case CH_LIVE: + send_drep = true; + ch->state = CH_DISCONNECTING; + break; + case CH_DISCONNECTING: + case CH_DRAINING: + case CH_RELEASING: + WARN(true, "unexpected channel state %d\n", ch->state); + break; + } + spin_unlock_irqrestore(&ch->spinlock, flags); + + if (send_drep) { + if (ib_send_cm_drep(ch->cm_id, NULL, 0) < 0) + printk(KERN_ERR "Sending IB DREP failed.\n"); + printk(KERN_INFO "Received DREQ and sent DREP for session %s.\n", + ch->sess_name); + } +} + +/** + * srpt_cm_drep_recv() - Process reception of a DREP message. + */ +static void srpt_cm_drep_recv(struct ib_cm_id *cm_id) +{ + printk(KERN_INFO "Received InfiniBand DREP message for cm_id %p.\n", + cm_id); + srpt_drain_channel(cm_id); +} + +/** + * srpt_cm_handler() - IB connection manager callback function. + * + * A non-zero return value will cause the caller destroy the CM ID. + * + * Note: srpt_cm_handler() must only return a non-zero value when transferring + * ownership of the cm_id to a channel by srpt_cm_req_recv() failed. Returning + * a non-zero value in any other case will trigger a race with the + * ib_destroy_cm_id() call in srpt_release_channel(). + */ +static int srpt_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) +{ + int ret; + + ret = 0; + switch (event->event) { + case IB_CM_REQ_RECEIVED: + ret = srpt_cm_req_recv(cm_id, &event->param.req_rcvd, + event->private_data); + break; + case IB_CM_REJ_RECEIVED: + srpt_cm_rej_recv(cm_id); + break; + case IB_CM_RTU_RECEIVED: + case IB_CM_USER_ESTABLISHED: + srpt_cm_rtu_recv(cm_id); + break; + case IB_CM_DREQ_RECEIVED: + srpt_cm_dreq_recv(cm_id); + break; + case IB_CM_DREP_RECEIVED: + srpt_cm_drep_recv(cm_id); + break; + case IB_CM_TIMEWAIT_EXIT: + srpt_cm_timewait_exit(cm_id); + break; + case IB_CM_REP_ERROR: + srpt_cm_rep_error(cm_id); + break; + case IB_CM_DREQ_ERROR: + printk(KERN_INFO "Received IB DREQ ERROR event.\n"); + break; + case IB_CM_MRA_RECEIVED: + printk(KERN_INFO "Received IB MRA event\n"); + break; + default: + printk(KERN_ERR "received unrecognized IB CM event %d\n", + event->event); + break; + } + + return ret; +} + +/** + * srpt_perform_rdmas() - Perform IB RDMA. + * + * Returns zero upon success or a negative number upon failure. + */ +static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx) +{ + struct ib_send_wr wr; + struct ib_send_wr *bad_wr; + struct rdma_iu *riu; + int i; + int ret; + int sq_wr_avail; + enum dma_data_direction dir; + const int n_rdma = ioctx->n_rdma; + + dir = ioctx->cmd.data_direction; + if (dir == DMA_TO_DEVICE) { + /* write */ + ret = -ENOMEM; + sq_wr_avail = atomic_sub_return(n_rdma, &ch->sq_wr_avail); + if (sq_wr_avail < 0) { + printk(KERN_WARNING "IB send queue full (needed %d)\n", + n_rdma); + goto out; + } + } + + ioctx->rdma_aborted = false; + ret = 0; + riu = ioctx->rdma_ius; + memset(&wr, 0, sizeof wr); + + for (i = 0; i < n_rdma; ++i, ++riu) { + if (dir == DMA_FROM_DEVICE) { + wr.opcode = IB_WR_RDMA_WRITE; + wr.wr_id = encode_wr_id(i == n_rdma - 1 ? + SRPT_RDMA_WRITE_LAST : + SRPT_RDMA_MID, + ioctx->ioctx.index); + } else { + wr.opcode = IB_WR_RDMA_READ; + wr.wr_id = encode_wr_id(i == n_rdma - 1 ? + SRPT_RDMA_READ_LAST : + SRPT_RDMA_MID, + ioctx->ioctx.index); + } + wr.next = NULL; + wr.wr.rdma.remote_addr = riu->raddr; + wr.wr.rdma.rkey = riu->rkey; + wr.num_sge = riu->sge_cnt; + wr.sg_list = riu->sge; + + /* only get completion event for the last rdma write */ + if (i == (n_rdma - 1) && dir == DMA_TO_DEVICE) + wr.send_flags = IB_SEND_SIGNALED; + + ret = ib_post_send(ch->qp, &wr, &bad_wr); + if (ret) + break; + } + + if (ret) + printk(KERN_ERR "%s[%d]: ib_post_send() returned %d for %d/%d", + __func__, __LINE__, ret, i, n_rdma); + if (ret && i > 0) { + wr.num_sge = 0; + wr.wr_id = encode_wr_id(SRPT_RDMA_ABORT, ioctx->ioctx.index); + wr.send_flags = IB_SEND_SIGNALED; + while (ch->state == CH_LIVE && + ib_post_send(ch->qp, &wr, &bad_wr) != 0) { + printk(KERN_INFO "Trying to abort failed RDMA transfer [%d]", + ioctx->ioctx.index); + msleep(1000); + } + while (ch->state != CH_RELEASING && !ioctx->rdma_aborted) { + printk(KERN_INFO "Waiting until RDMA abort finished [%d]", + ioctx->ioctx.index); + msleep(1000); + } + } +out: + if (unlikely(dir == DMA_TO_DEVICE && ret < 0)) + atomic_add(n_rdma, &ch->sq_wr_avail); + return ret; +} + +/** + * srpt_xfer_data() - Start data transfer from initiator to target. + */ +static int srpt_xfer_data(struct srpt_rdma_ch *ch, + struct srpt_send_ioctx *ioctx) +{ + int ret; + + ret = srpt_map_sg_to_ib_sge(ch, ioctx); + if (ret) { + printk(KERN_ERR "%s[%d] ret=%d\n", __func__, __LINE__, ret); + goto out; + } + + ret = srpt_perform_rdmas(ch, ioctx); + if (ret) { + if (ret == -EAGAIN || ret == -ENOMEM) + printk(KERN_INFO "%s[%d] queue full -- ret=%d\n", + __func__, __LINE__, ret); + else + printk(KERN_ERR "%s[%d] fatal error -- ret=%d\n", + __func__, __LINE__, ret); + goto out_unmap; + } + +out: + return ret; +out_unmap: + srpt_unmap_sg_to_ib_sge(ch, ioctx); + goto out; +} + +static int srpt_write_pending_status(struct se_cmd *se_cmd) +{ + struct srpt_send_ioctx *ioctx; + + ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd); + return srpt_get_cmd_state(ioctx) == SRPT_STATE_NEED_DATA; +} + +/* + * srpt_write_pending() - Start data transfer from initiator to target (write). + */ +static int srpt_write_pending(struct se_cmd *se_cmd) +{ + struct srpt_rdma_ch *ch; + struct srpt_send_ioctx *ioctx; + enum srpt_command_state new_state; + enum rdma_ch_state ch_state; + int ret; + + ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd); + + new_state = srpt_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA); + WARN_ON(new_state == SRPT_STATE_DONE); + + ch = ioctx->ch; + BUG_ON(!ch); + + ch_state = srpt_get_ch_state(ch); + switch (ch_state) { + case CH_CONNECTING: + WARN(true, "unexpected channel state %d\n", ch_state); + ret = -EINVAL; + goto out; + case CH_LIVE: + break; + case CH_DISCONNECTING: + case CH_DRAINING: + case CH_RELEASING: + pr_debug("cmd with tag %lld: channel disconnecting\n", + ioctx->tag); + srpt_set_cmd_state(ioctx, SRPT_STATE_DATA_IN); + ret = -EINVAL; + goto out; + } + ret = srpt_xfer_data(ch, ioctx); + +out: + return ret; +} + +static u8 tcm_to_srp_tsk_mgmt_status(const int tcm_mgmt_status) +{ + switch (tcm_mgmt_status) { + case TMR_FUNCTION_COMPLETE: + return SRP_TSK_MGMT_SUCCESS; + case TMR_FUNCTION_REJECTED: + return SRP_TSK_MGMT_FUNC_NOT_SUPP; + } + return SRP_TSK_MGMT_FAILED; +} + +/** + * srpt_queue_response() - Transmits the response to a SCSI command. + * + * Callback function called by the TCM core. Must not block since it can be + * invoked on the context of the IB completion handler. + */ +static int srpt_queue_response(struct se_cmd *cmd) +{ + struct srpt_rdma_ch *ch; + struct srpt_send_ioctx *ioctx; + enum srpt_command_state state; + unsigned long flags; + int ret; + enum dma_data_direction dir; + int resp_len; + u8 srp_tm_status; + + ret = 0; + + ioctx = container_of(cmd, struct srpt_send_ioctx, cmd); + ch = ioctx->ch; + BUG_ON(!ch); + + spin_lock_irqsave(&ioctx->spinlock, flags); + state = ioctx->state; + switch (state) { + case SRPT_STATE_NEW: + case SRPT_STATE_DATA_IN: + ioctx->state = SRPT_STATE_CMD_RSP_SENT; + break; + case SRPT_STATE_MGMT: + ioctx->state = SRPT_STATE_MGMT_RSP_SENT; + break; + default: + WARN(true, "ch %p; cmd %d: unexpected command state %d\n", + ch, ioctx->ioctx.index, ioctx->state); + break; + } + spin_unlock_irqrestore(&ioctx->spinlock, flags); + + if (unlikely(transport_check_aborted_status(&ioctx->cmd, false) + || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) { + atomic_inc(&ch->req_lim_delta); + srpt_abort_cmd(ioctx); + goto out; + } + + dir = ioctx->cmd.data_direction; + + /* For read commands, transfer the data to the initiator. */ + if (dir == DMA_FROM_DEVICE && ioctx->cmd.data_length && + !ioctx->queue_status_only) { + ret = srpt_xfer_data(ch, ioctx); + if (ret) { + printk(KERN_ERR "xfer_data failed for tag %llu\n", + ioctx->tag); + goto out; + } + } + + if (state != SRPT_STATE_MGMT) + resp_len = srpt_build_cmd_rsp(ch, ioctx, ioctx->tag, + cmd->scsi_status); + else { + srp_tm_status + = tcm_to_srp_tsk_mgmt_status(cmd->se_tmr_req->response); + resp_len = srpt_build_tskmgmt_rsp(ch, ioctx, srp_tm_status, + ioctx->tag); + } + ret = srpt_post_send(ch, ioctx, resp_len); + if (ret) { + printk(KERN_ERR "sending cmd response failed for tag %llu\n", + ioctx->tag); + srpt_unmap_sg_to_ib_sge(ch, ioctx); + srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); + kref_put(&ioctx->kref, srpt_put_send_ioctx_kref); + } + +out: + return ret; +} + +static int srpt_queue_status(struct se_cmd *cmd) +{ + struct srpt_send_ioctx *ioctx; + + ioctx = container_of(cmd, struct srpt_send_ioctx, cmd); + BUG_ON(ioctx->sense_data != cmd->sense_buffer); + if (cmd->se_cmd_flags & + (SCF_TRANSPORT_TASK_SENSE | SCF_EMULATED_TASK_SENSE)) + WARN_ON(cmd->scsi_status != SAM_STAT_CHECK_CONDITION); + ioctx->queue_status_only = true; + return srpt_queue_response(cmd); +} + +static void srpt_refresh_port_work(struct work_struct *work) +{ + struct srpt_port *sport = container_of(work, struct srpt_port, work); + + srpt_refresh_port(sport); +} + +static int srpt_ch_list_empty(struct srpt_device *sdev) +{ + int res; + + spin_lock_irq(&sdev->spinlock); + res = list_empty(&sdev->rch_list); + spin_unlock_irq(&sdev->spinlock); + + return res; +} + +/** + * srpt_release_sdev() - Free the channel resources associated with a target. + */ +static int srpt_release_sdev(struct srpt_device *sdev) +{ + struct srpt_rdma_ch *ch, *tmp_ch; + int res; + + WARN_ON_ONCE(irqs_disabled()); + + BUG_ON(!sdev); + + spin_lock_irq(&sdev->spinlock); + list_for_each_entry_safe(ch, tmp_ch, &sdev->rch_list, list) + __srpt_close_ch(ch); + spin_unlock_irq(&sdev->spinlock); + + res = wait_event_interruptible(sdev->ch_releaseQ, + srpt_ch_list_empty(sdev)); + if (res) + printk(KERN_ERR "%s: interrupted.\n", __func__); + + return 0; +} + +static struct srpt_port *__srpt_lookup_port(const char *name) +{ + struct ib_device *dev; + struct srpt_device *sdev; + struct srpt_port *sport; + int i; + + list_for_each_entry(sdev, &srpt_dev_list, list) { + dev = sdev->device; + if (!dev) + continue; + + for (i = 0; i < dev->phys_port_cnt; i++) { + sport = &sdev->port[i]; + + if (!strcmp(sport->port_guid, name)) + return sport; + } + } + + return NULL; +} + +static struct srpt_port *srpt_lookup_port(const char *name) +{ + struct srpt_port *sport; + + spin_lock(&srpt_dev_lock); + sport = __srpt_lookup_port(name); + spin_unlock(&srpt_dev_lock); + + return sport; +} + +/** + * srpt_add_one() - Infiniband device addition callback function. + */ +static void srpt_add_one(struct ib_device *device) +{ + struct srpt_device *sdev; + struct srpt_port *sport; + struct ib_srq_init_attr srq_attr; + int i; + + pr_debug("device = %p, device->dma_ops = %p\n", device, + device->dma_ops); + + sdev = kzalloc(sizeof *sdev, GFP_KERNEL); + if (!sdev) + goto err; + + sdev->device = device; + INIT_LIST_HEAD(&sdev->rch_list); + init_waitqueue_head(&sdev->ch_releaseQ); + spin_lock_init(&sdev->spinlock); + + if (ib_query_device(device, &sdev->dev_attr)) + goto free_dev; + + sdev->pd = ib_alloc_pd(device); + if (IS_ERR(sdev->pd)) + goto free_dev; + + sdev->mr = ib_get_dma_mr(sdev->pd, IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(sdev->mr)) + goto err_pd; + + sdev->srq_size = min(srpt_srq_size, sdev->dev_attr.max_srq_wr); + + srq_attr.event_handler = srpt_srq_event; + srq_attr.srq_context = (void *)sdev; + srq_attr.attr.max_wr = sdev->srq_size; + srq_attr.attr.max_sge = 1; + srq_attr.attr.srq_limit = 0; + + sdev->srq = ib_create_srq(sdev->pd, &srq_attr); + if (IS_ERR(sdev->srq)) + goto err_mr; + + pr_debug("%s: create SRQ #wr= %d max_allow=%d dev= %s\n", + __func__, sdev->srq_size, sdev->dev_attr.max_srq_wr, + device->name); + + if (!srpt_service_guid) + srpt_service_guid = be64_to_cpu(device->node_guid); + + sdev->cm_id = ib_create_cm_id(device, srpt_cm_handler, sdev); + if (IS_ERR(sdev->cm_id)) + goto err_srq; + + /* print out target login information */ + pr_debug("Target login info: id_ext=%016llx,ioc_guid=%016llx," + "pkey=ffff,service_id=%016llx\n", srpt_service_guid, + srpt_service_guid, srpt_service_guid); + + /* + * We do not have a consistent service_id (ie. also id_ext of target_id) + * to identify this target. We currently use the guid of the first HCA + * in the system as service_id; therefore, the target_id will change + * if this HCA is gone bad and replaced by different HCA + */ + if (ib_cm_listen(sdev->cm_id, cpu_to_be64(srpt_service_guid), 0, NULL)) + goto err_cm; + + INIT_IB_EVENT_HANDLER(&sdev->event_handler, sdev->device, + srpt_event_handler); + if (ib_register_event_handler(&sdev->event_handler)) + goto err_cm; + + sdev->ioctx_ring = (struct srpt_recv_ioctx **) + srpt_alloc_ioctx_ring(sdev, sdev->srq_size, + sizeof(*sdev->ioctx_ring[0]), + srp_max_req_size, DMA_FROM_DEVICE); + if (!sdev->ioctx_ring) + goto err_event; + + for (i = 0; i < sdev->srq_size; ++i) + srpt_post_recv(sdev, sdev->ioctx_ring[i]); + + WARN_ON(sdev->device->phys_port_cnt + > sizeof(sdev->port)/sizeof(sdev->port[0])); + + for (i = 1; i <= sdev->device->phys_port_cnt; i++) { + sport = &sdev->port[i - 1]; + sport->sdev = sdev; + sport->port = i; + sport->port_attrib.srp_max_rdma_size = DEFAULT_MAX_RDMA_SIZE; + sport->port_attrib.srp_max_rsp_size = DEFAULT_MAX_RSP_SIZE; + sport->port_attrib.srp_sq_size = DEF_SRPT_SQ_SIZE; + INIT_WORK(&sport->work, srpt_refresh_port_work); + INIT_LIST_HEAD(&sport->port_acl_list); + spin_lock_init(&sport->port_acl_lock); + + if (srpt_refresh_port(sport)) { + printk(KERN_ERR "MAD registration failed for %s-%d.\n", + srpt_sdev_name(sdev), i); + goto err_ring; + } + snprintf(sport->port_guid, sizeof(sport->port_guid), + "0x%016llx%016llx", + be64_to_cpu(sport->gid.global.subnet_prefix), + be64_to_cpu(sport->gid.global.interface_id)); + } + + spin_lock(&srpt_dev_lock); + list_add_tail(&sdev->list, &srpt_dev_list); + spin_unlock(&srpt_dev_lock); + +out: + ib_set_client_data(device, &srpt_client, sdev); + pr_debug("added %s.\n", device->name); + return; + +err_ring: + srpt_free_ioctx_ring((struct srpt_ioctx **)sdev->ioctx_ring, sdev, + sdev->srq_size, srp_max_req_size, + DMA_FROM_DEVICE); +err_event: + ib_unregister_event_handler(&sdev->event_handler); +err_cm: + ib_destroy_cm_id(sdev->cm_id); +err_srq: + ib_destroy_srq(sdev->srq); +err_mr: + ib_dereg_mr(sdev->mr); +err_pd: + ib_dealloc_pd(sdev->pd); +free_dev: + kfree(sdev); +err: + sdev = NULL; + printk(KERN_INFO "%s(%s) failed.\n", __func__, device->name); + goto out; +} + +/** + * srpt_remove_one() - InfiniBand device removal callback function. + */ +static void srpt_remove_one(struct ib_device *device) +{ + struct srpt_device *sdev; + int i; + + sdev = ib_get_client_data(device, &srpt_client); + if (!sdev) { + printk(KERN_INFO "%s(%s): nothing to do.\n", __func__, + device->name); + return; + } + + srpt_unregister_mad_agent(sdev); + + ib_unregister_event_handler(&sdev->event_handler); + + /* Cancel any work queued by the just unregistered IB event handler. */ + for (i = 0; i < sdev->device->phys_port_cnt; i++) + cancel_work_sync(&sdev->port[i].work); + + ib_destroy_cm_id(sdev->cm_id); + + /* + * Unregistering a target must happen after destroying sdev->cm_id + * such that no new SRP_LOGIN_REQ information units can arrive while + * destroying the target. + */ + spin_lock(&srpt_dev_lock); + list_del(&sdev->list); + spin_unlock(&srpt_dev_lock); + srpt_release_sdev(sdev); + + ib_destroy_srq(sdev->srq); + ib_dereg_mr(sdev->mr); + ib_dealloc_pd(sdev->pd); + + srpt_free_ioctx_ring((struct srpt_ioctx **)sdev->ioctx_ring, sdev, + sdev->srq_size, srp_max_req_size, DMA_FROM_DEVICE); + sdev->ioctx_ring = NULL; + kfree(sdev); +} + +static struct ib_client srpt_client = { + .name = DRV_NAME, + .add = srpt_add_one, + .remove = srpt_remove_one +}; + +static int srpt_check_true(struct se_portal_group *se_tpg) +{ + return 1; +} + +static int srpt_check_false(struct se_portal_group *se_tpg) +{ + return 0; +} + +static char *srpt_get_fabric_name(void) +{ + return "srpt"; +} + +static u8 srpt_get_fabric_proto_ident(struct se_portal_group *se_tpg) +{ + return SCSI_TRANSPORTID_PROTOCOLID_SRP; +} + +static char *srpt_get_fabric_wwn(struct se_portal_group *tpg) +{ + struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1); + + return sport->port_guid; +} + +static u16 srpt_get_tag(struct se_portal_group *tpg) +{ + return 1; +} + +static u32 srpt_get_default_depth(struct se_portal_group *se_tpg) +{ + return 1; +} + +static u32 srpt_get_pr_transport_id(struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code, unsigned char *buf) +{ + struct srpt_node_acl *nacl; + struct spc_rdma_transport_id *tr_id; + + nacl = container_of(se_nacl, struct srpt_node_acl, nacl); + tr_id = (void *)buf; + tr_id->protocol_identifier = SCSI_TRANSPORTID_PROTOCOLID_SRP; + memcpy(tr_id->i_port_id, nacl->i_port_id, sizeof(tr_id->i_port_id)); + return sizeof(*tr_id); +} + +static u32 srpt_get_pr_transport_id_len(struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code) +{ + *format_code = 0; + return sizeof(struct spc_rdma_transport_id); +} + +static char *srpt_parse_pr_out_transport_id(struct se_portal_group *se_tpg, + const char *buf, u32 *out_tid_len, + char **port_nexus_ptr) +{ + struct spc_rdma_transport_id *tr_id; + + *port_nexus_ptr = NULL; + *out_tid_len = sizeof(struct spc_rdma_transport_id); + tr_id = (void *)buf; + return (char *)tr_id->i_port_id; +} + +static struct se_node_acl *srpt_alloc_fabric_acl(struct se_portal_group *se_tpg) +{ + struct srpt_node_acl *nacl; + + nacl = kzalloc(sizeof(struct srpt_node_acl), GFP_KERNEL); + if (!nacl) { + printk(KERN_ERR "Unable to alocate struct srpt_node_acl\n"); + return NULL; + } + + return &nacl->nacl; +} + +static void srpt_release_fabric_acl(struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl) +{ + struct srpt_node_acl *nacl; + + nacl = container_of(se_nacl, struct srpt_node_acl, nacl); + kfree(nacl); +} + +static u32 srpt_tpg_get_inst_index(struct se_portal_group *se_tpg) +{ + return 1; +} + +static void srpt_release_cmd(struct se_cmd *se_cmd) +{ +} + +/** + * srpt_shutdown_session() - Whether or not a session may be shut down. + */ +static int srpt_shutdown_session(struct se_session *se_sess) +{ + return true; +} + +/** + * srpt_close_session() - Forcibly close a session. + * + * Callback function invoked by the TCM core to clean up sessions associated + * with a node ACL when the user invokes + * rmdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id + */ +static void srpt_close_session(struct se_session *se_sess) +{ + DECLARE_COMPLETION_ONSTACK(release_done); + struct srpt_rdma_ch *ch; + struct srpt_device *sdev; + int res; + + ch = se_sess->fabric_sess_ptr; + WARN_ON(ch->sess != se_sess); + + pr_debug("ch %p state %d\n", ch, srpt_get_ch_state(ch)); + + sdev = ch->sport->sdev; + spin_lock_irq(&sdev->spinlock); + BUG_ON(ch->release_done); + ch->release_done = &release_done; + __srpt_close_ch(ch); + spin_unlock_irq(&sdev->spinlock); + + res = wait_for_completion_timeout(&release_done, 60 * HZ); + WARN_ON(res <= 0); +} + +/** + * To do: Find out whether stop_session() has a meaning for transports + * other than iSCSI. + */ +static void srpt_stop_session(struct se_session *se_sess, int sess_sleep, + int conn_sleep) +{ +} + +static void srpt_reset_nexus(struct se_session *sess) +{ + printk(KERN_ERR "This is the SRP protocol, not iSCSI\n"); +} + +static int srpt_sess_logged_in(struct se_session *se_sess) +{ + return true; +} + +/** + * srpt_sess_get_index() - Return the value of scsiAttIntrPortIndex (SCSI-MIB). + * + * A quote from RFC 4455 (SCSI-MIB) about this MIB object: + * This object represents an arbitrary integer used to uniquely identify a + * particular attached remote initiator port to a particular SCSI target port + * within a particular SCSI target device within a particular SCSI instance. + */ +static u32 srpt_sess_get_index(struct se_session *se_sess) +{ + return 0; +} + +static void srpt_set_default_node_attrs(struct se_node_acl *nacl) +{ +} + +static u32 srpt_get_task_tag(struct se_cmd *se_cmd) +{ + struct srpt_send_ioctx *ioctx; + + ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd); + return ioctx->tag; +} + +/* Note: only used from inside debug printk's by the TCM core. */ +static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd) +{ + struct srpt_send_ioctx *ioctx; + + ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd); + return srpt_get_cmd_state(ioctx); +} + +static u16 srpt_set_fabric_sense_len(struct se_cmd *cmd, u32 sense_length) +{ + return 0; +} + +static u16 srpt_get_fabric_sense_len(void) +{ + return 0; +} + +static int srpt_is_state_remove(struct se_cmd *se_cmd) +{ + return 0; +} + +/** + * srpt_parse_i_port_id() - Parse an initiator port ID. + * @name: ASCII representation of a 128-bit initiator port ID. + * @i_port_id: Binary 128-bit port ID. + */ +static int srpt_parse_i_port_id(u8 i_port_id[16], const char *name) +{ + const char *p; + unsigned len, count, leading_zero_bytes; + int ret, rc; + + p = name; + if (strnicmp(p, "0x", 2) == 0) + p += 2; + ret = -EINVAL; + len = strlen(p); + if (len % 2) + goto out; + count = min(len / 2, 16U); + leading_zero_bytes = 16 - count; + memset(i_port_id, 0, leading_zero_bytes); + rc = hex2bin(i_port_id + leading_zero_bytes, p, count); + if (rc < 0) + pr_debug("hex2bin failed for srpt_parse_i_port_id: %d\n", rc); + ret = 0; +out: + return ret; +} + +/* + * configfs callback function invoked for + * mkdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id + */ +static struct se_node_acl *srpt_make_nodeacl(struct se_portal_group *tpg, + struct config_group *group, + const char *name) +{ + struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1); + struct se_node_acl *se_nacl, *se_nacl_new; + struct srpt_node_acl *nacl; + int ret = 0; + u32 nexus_depth = 1; + u8 i_port_id[16]; + + if (srpt_parse_i_port_id(i_port_id, name) < 0) { + printk(KERN_ERR "invalid initiator port ID %s\n", name); + ret = -EINVAL; + goto err; + } + + se_nacl_new = srpt_alloc_fabric_acl(tpg); + if (!se_nacl_new) { + ret = -ENOMEM; + goto err; + } + /* + * nacl_new may be released by core_tpg_add_initiator_node_acl() + * when converting a node ACL from demo mode to explict + */ + se_nacl = core_tpg_add_initiator_node_acl(tpg, se_nacl_new, name, + nexus_depth); + if (IS_ERR(se_nacl)) { + ret = PTR_ERR(se_nacl); + goto err; + } + /* Locate our struct srpt_node_acl and set sdev and i_port_id. */ + nacl = container_of(se_nacl, struct srpt_node_acl, nacl); + memcpy(&nacl->i_port_id[0], &i_port_id[0], 16); + nacl->sport = sport; + + spin_lock_irq(&sport->port_acl_lock); + list_add_tail(&nacl->list, &sport->port_acl_list); + spin_unlock_irq(&sport->port_acl_lock); + + return se_nacl; +err: + return ERR_PTR(ret); +} + +/* + * configfs callback function invoked for + * rmdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id + */ +static void srpt_drop_nodeacl(struct se_node_acl *se_nacl) +{ + struct srpt_node_acl *nacl; + struct srpt_device *sdev; + struct srpt_port *sport; + + nacl = container_of(se_nacl, struct srpt_node_acl, nacl); + sport = nacl->sport; + sdev = sport->sdev; + spin_lock_irq(&sport->port_acl_lock); + list_del(&nacl->list); + spin_unlock_irq(&sport->port_acl_lock); + core_tpg_del_initiator_node_acl(&sport->port_tpg_1, se_nacl, 1); + srpt_release_fabric_acl(NULL, se_nacl); +} + +static ssize_t srpt_tpg_attrib_show_srp_max_rdma_size( + struct se_portal_group *se_tpg, + char *page) +{ + struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); + + return sprintf(page, "%u\n", sport->port_attrib.srp_max_rdma_size); +} + +static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); + unsigned long val; + int ret; + + ret = strict_strtoul(page, 0, &val); + if (ret < 0) { + pr_err("strict_strtoul() failed with ret: %d\n", ret); + return -EINVAL; + } + if (val > MAX_SRPT_RDMA_SIZE) { + pr_err("val: %lu exceeds MAX_SRPT_RDMA_SIZE: %d\n", val, + MAX_SRPT_RDMA_SIZE); + return -EINVAL; + } + if (val < DEFAULT_MAX_RDMA_SIZE) { + pr_err("val: %lu smaller than DEFAULT_MAX_RDMA_SIZE: %d\n", + val, DEFAULT_MAX_RDMA_SIZE); + return -EINVAL; + } + sport->port_attrib.srp_max_rdma_size = val; + + return count; +} + +TF_TPG_ATTRIB_ATTR(srpt, srp_max_rdma_size, S_IRUGO | S_IWUSR); + +static ssize_t srpt_tpg_attrib_show_srp_max_rsp_size( + struct se_portal_group *se_tpg, + char *page) +{ + struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); + + return sprintf(page, "%u\n", sport->port_attrib.srp_max_rsp_size); +} + +static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); + unsigned long val; + int ret; + + ret = strict_strtoul(page, 0, &val); + if (ret < 0) { + pr_err("strict_strtoul() failed with ret: %d\n", ret); + return -EINVAL; + } + if (val > MAX_SRPT_RSP_SIZE) { + pr_err("val: %lu exceeds MAX_SRPT_RSP_SIZE: %d\n", val, + MAX_SRPT_RSP_SIZE); + return -EINVAL; + } + if (val < MIN_MAX_RSP_SIZE) { + pr_err("val: %lu smaller than MIN_MAX_RSP_SIZE: %d\n", val, + MIN_MAX_RSP_SIZE); + return -EINVAL; + } + sport->port_attrib.srp_max_rsp_size = val; + + return count; +} + +TF_TPG_ATTRIB_ATTR(srpt, srp_max_rsp_size, S_IRUGO | S_IWUSR); + +static ssize_t srpt_tpg_attrib_show_srp_sq_size( + struct se_portal_group *se_tpg, + char *page) +{ + struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); + + return sprintf(page, "%u\n", sport->port_attrib.srp_sq_size); +} + +static ssize_t srpt_tpg_attrib_store_srp_sq_size( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); + unsigned long val; + int ret; + + ret = strict_strtoul(page, 0, &val); + if (ret < 0) { + pr_err("strict_strtoul() failed with ret: %d\n", ret); + return -EINVAL; + } + if (val > MAX_SRPT_SRQ_SIZE) { + pr_err("val: %lu exceeds MAX_SRPT_SRQ_SIZE: %d\n", val, + MAX_SRPT_SRQ_SIZE); + return -EINVAL; + } + if (val < MIN_SRPT_SRQ_SIZE) { + pr_err("val: %lu smaller than MIN_SRPT_SRQ_SIZE: %d\n", val, + MIN_SRPT_SRQ_SIZE); + return -EINVAL; + } + sport->port_attrib.srp_sq_size = val; + + return count; +} + +TF_TPG_ATTRIB_ATTR(srpt, srp_sq_size, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *srpt_tpg_attrib_attrs[] = { + &srpt_tpg_attrib_srp_max_rdma_size.attr, + &srpt_tpg_attrib_srp_max_rsp_size.attr, + &srpt_tpg_attrib_srp_sq_size.attr, + NULL, +}; + +static ssize_t srpt_tpg_show_enable( + struct se_portal_group *se_tpg, + char *page) +{ + struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); + + return snprintf(page, PAGE_SIZE, "%d\n", (sport->enabled) ? 1: 0); +} + +static ssize_t srpt_tpg_store_enable( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1); + unsigned long tmp; + int ret; + + ret = strict_strtoul(page, 0, &tmp); + if (ret < 0) { + printk(KERN_ERR "Unable to extract srpt_tpg_store_enable\n"); + return -EINVAL; + } + + if ((tmp != 0) && (tmp != 1)) { + printk(KERN_ERR "Illegal value for srpt_tpg_store_enable: %lu\n", tmp); + return -EINVAL; + } + if (tmp == 1) + sport->enabled = true; + else + sport->enabled = false; + + return count; +} + +TF_TPG_BASE_ATTR(srpt, enable, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *srpt_tpg_attrs[] = { + &srpt_tpg_enable.attr, + NULL, +}; + +/** + * configfs callback invoked for + * mkdir /sys/kernel/config/target/$driver/$port/$tpg + */ +static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, + struct config_group *group, + const char *name) +{ + struct srpt_port *sport = container_of(wwn, struct srpt_port, port_wwn); + int res; + + /* Initialize sport->port_wwn and sport->port_tpg_1 */ + res = core_tpg_register(&srpt_target->tf_ops, &sport->port_wwn, + &sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL); + if (res) + return ERR_PTR(res); + + return &sport->port_tpg_1; +} + +/** + * configfs callback invoked for + * rmdir /sys/kernel/config/target/$driver/$port/$tpg + */ +static void srpt_drop_tpg(struct se_portal_group *tpg) +{ + struct srpt_port *sport = container_of(tpg, + struct srpt_port, port_tpg_1); + + sport->enabled = false; + core_tpg_deregister(&sport->port_tpg_1); +} + +/** + * configfs callback invoked for + * mkdir /sys/kernel/config/target/$driver/$port + */ +static struct se_wwn *srpt_make_tport(struct target_fabric_configfs *tf, + struct config_group *group, + const char *name) +{ + struct srpt_port *sport; + int ret; + + sport = srpt_lookup_port(name); + pr_debug("make_tport(%s)\n", name); + ret = -EINVAL; + if (!sport) + goto err; + + return &sport->port_wwn; + +err: + return ERR_PTR(ret); +} + +/** + * configfs callback invoked for + * rmdir /sys/kernel/config/target/$driver/$port + */ +static void srpt_drop_tport(struct se_wwn *wwn) +{ + struct srpt_port *sport = container_of(wwn, struct srpt_port, port_wwn); + + pr_debug("drop_tport(%s\n", config_item_name(&sport->port_wwn.wwn_group.cg_item)); +} + +static ssize_t srpt_wwn_show_attr_version(struct target_fabric_configfs *tf, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", DRV_VERSION); +} + +TF_WWN_ATTR_RO(srpt, version); + +static struct configfs_attribute *srpt_wwn_attrs[] = { + &srpt_wwn_version.attr, + NULL, +}; + +static struct target_core_fabric_ops srpt_template = { + .get_fabric_name = srpt_get_fabric_name, + .get_fabric_proto_ident = srpt_get_fabric_proto_ident, + .tpg_get_wwn = srpt_get_fabric_wwn, + .tpg_get_tag = srpt_get_tag, + .tpg_get_default_depth = srpt_get_default_depth, + .tpg_get_pr_transport_id = srpt_get_pr_transport_id, + .tpg_get_pr_transport_id_len = srpt_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = srpt_parse_pr_out_transport_id, + .tpg_check_demo_mode = srpt_check_false, + .tpg_check_demo_mode_cache = srpt_check_true, + .tpg_check_demo_mode_write_protect = srpt_check_true, + .tpg_check_prod_mode_write_protect = srpt_check_false, + .tpg_alloc_fabric_acl = srpt_alloc_fabric_acl, + .tpg_release_fabric_acl = srpt_release_fabric_acl, + .tpg_get_inst_index = srpt_tpg_get_inst_index, + .release_cmd = srpt_release_cmd, + .check_stop_free = srpt_check_stop_free, + .shutdown_session = srpt_shutdown_session, + .close_session = srpt_close_session, + .stop_session = srpt_stop_session, + .fall_back_to_erl0 = srpt_reset_nexus, + .sess_logged_in = srpt_sess_logged_in, + .sess_get_index = srpt_sess_get_index, + .sess_get_initiator_sid = NULL, + .write_pending = srpt_write_pending, + .write_pending_status = srpt_write_pending_status, + .set_default_node_attributes = srpt_set_default_node_attrs, + .get_task_tag = srpt_get_task_tag, + .get_cmd_state = srpt_get_tcm_cmd_state, + .queue_data_in = srpt_queue_response, + .queue_status = srpt_queue_status, + .queue_tm_rsp = srpt_queue_response, + .get_fabric_sense_len = srpt_get_fabric_sense_len, + .set_fabric_sense_len = srpt_set_fabric_sense_len, + .is_state_remove = srpt_is_state_remove, + /* + * Setup function pointers for generic logic in + * target_core_fabric_configfs.c + */ + .fabric_make_wwn = srpt_make_tport, + .fabric_drop_wwn = srpt_drop_tport, + .fabric_make_tpg = srpt_make_tpg, + .fabric_drop_tpg = srpt_drop_tpg, + .fabric_post_link = NULL, + .fabric_pre_unlink = NULL, + .fabric_make_np = NULL, + .fabric_drop_np = NULL, + .fabric_make_nodeacl = srpt_make_nodeacl, + .fabric_drop_nodeacl = srpt_drop_nodeacl, +}; + +/** + * srpt_init_module() - Kernel module initialization. + * + * Note: Since ib_register_client() registers callback functions, and since at + * least one of these callback functions (srpt_add_one()) calls target core + * functions, this driver must be registered with the target core before + * ib_register_client() is called. + */ +static int __init srpt_init_module(void) +{ + int ret; + + ret = -EINVAL; + if (srp_max_req_size < MIN_MAX_REQ_SIZE) { + printk(KERN_ERR "invalid value %d for kernel module parameter" + " srp_max_req_size -- must be at least %d.\n", + srp_max_req_size, MIN_MAX_REQ_SIZE); + goto out; + } + + if (srpt_srq_size < MIN_SRPT_SRQ_SIZE + || srpt_srq_size > MAX_SRPT_SRQ_SIZE) { + printk(KERN_ERR "invalid value %d for kernel module parameter" + " srpt_srq_size -- must be in the range [%d..%d].\n", + srpt_srq_size, MIN_SRPT_SRQ_SIZE, MAX_SRPT_SRQ_SIZE); + goto out; + } + + spin_lock_init(&srpt_dev_lock); + INIT_LIST_HEAD(&srpt_dev_list); + + ret = -ENODEV; + srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt"); + if (!srpt_target) { + printk(KERN_ERR "couldn't register\n"); + goto out; + } + + srpt_target->tf_ops = srpt_template; + + /* Enable SG chaining */ + srpt_target->tf_ops.task_sg_chaining = true; + + /* + * Set up default attribute lists. + */ + srpt_target->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = srpt_wwn_attrs; + srpt_target->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = srpt_tpg_attrs; + srpt_target->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = srpt_tpg_attrib_attrs; + srpt_target->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; + srpt_target->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; + srpt_target->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; + srpt_target->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; + srpt_target->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; + srpt_target->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; + + ret = target_fabric_configfs_register(srpt_target); + if (ret < 0) { + printk(KERN_ERR "couldn't register\n"); + goto out_free_target; + } + + ret = ib_register_client(&srpt_client); + if (ret) { + printk(KERN_ERR "couldn't register IB client\n"); + goto out_unregister_target; + } + + return 0; + +out_unregister_target: + target_fabric_configfs_deregister(srpt_target); + srpt_target = NULL; +out_free_target: + if (srpt_target) + target_fabric_configfs_free(srpt_target); +out: + return ret; +} + +static void __exit srpt_cleanup_module(void) +{ + ib_unregister_client(&srpt_client); + target_fabric_configfs_deregister(srpt_target); + srpt_target = NULL; +} + +module_init(srpt_init_module); +module_exit(srpt_cleanup_module); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h new file mode 100644 index 000000000000..b4b4bbcd7f16 --- /dev/null +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2006 - 2009 Mellanox Technology Inc. All rights reserved. + * Copyright (C) 2009 - 2010 Bart Van Assche <bvanassche@acm.org>. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef IB_SRPT_H +#define IB_SRPT_H + +#include <linux/version.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/wait.h> + +#include <rdma/ib_verbs.h> +#include <rdma/ib_sa.h> +#include <rdma/ib_cm.h> + +#include <scsi/srp.h> + +#include "ib_dm_mad.h" + +/* + * The prefix the ServiceName field must start with in the device management + * ServiceEntries attribute pair. See also the SRP specification. + */ +#define SRP_SERVICE_NAME_PREFIX "SRP.T10:" + +enum { + /* + * SRP IOControllerProfile attributes for SRP target ports that have + * not been defined in <scsi/srp.h>. Source: section B.7, table B.7 + * in the SRP specification. + */ + SRP_PROTOCOL = 0x0108, + SRP_PROTOCOL_VERSION = 0x0001, + SRP_IO_SUBCLASS = 0x609e, + SRP_SEND_TO_IOC = 0x01, + SRP_SEND_FROM_IOC = 0x02, + SRP_RDMA_READ_FROM_IOC = 0x08, + SRP_RDMA_WRITE_FROM_IOC = 0x20, + + /* + * srp_login_cmd.req_flags bitmasks. See also table 9 in the SRP + * specification. + */ + SRP_MTCH_ACTION = 0x03, /* MULTI-CHANNEL ACTION */ + SRP_LOSOLNT = 0x10, /* logout solicited notification */ + SRP_CRSOLNT = 0x20, /* credit request solicited notification */ + SRP_AESOLNT = 0x40, /* asynchronous event solicited notification */ + + /* + * srp_cmd.sol_nt / srp_tsk_mgmt.sol_not bitmasks. See also tables + * 18 and 20 in the SRP specification. + */ + SRP_SCSOLNT = 0x02, /* SCSOLNT = successful solicited notification */ + SRP_UCSOLNT = 0x04, /* UCSOLNT = unsuccessful solicited notification */ + + /* + * srp_rsp.sol_not / srp_t_logout.sol_not bitmasks. See also tables + * 16 and 22 in the SRP specification. + */ + SRP_SOLNT = 0x01, /* SOLNT = solicited notification */ + + /* See also table 24 in the SRP specification. */ + SRP_TSK_MGMT_SUCCESS = 0x00, + SRP_TSK_MGMT_FUNC_NOT_SUPP = 0x04, + SRP_TSK_MGMT_FAILED = 0x05, + + /* See also table 21 in the SRP specification. */ + SRP_CMD_SIMPLE_Q = 0x0, + SRP_CMD_HEAD_OF_Q = 0x1, + SRP_CMD_ORDERED_Q = 0x2, + SRP_CMD_ACA = 0x4, + + SRP_LOGIN_RSP_MULTICHAN_NO_CHAN = 0x0, + SRP_LOGIN_RSP_MULTICHAN_TERMINATED = 0x1, + SRP_LOGIN_RSP_MULTICHAN_MAINTAINED = 0x2, + + SRPT_DEF_SG_TABLESIZE = 128, + SRPT_DEF_SG_PER_WQE = 16, + + MIN_SRPT_SQ_SIZE = 16, + DEF_SRPT_SQ_SIZE = 4096, + SRPT_RQ_SIZE = 128, + MIN_SRPT_SRQ_SIZE = 4, + DEFAULT_SRPT_SRQ_SIZE = 4095, + MAX_SRPT_SRQ_SIZE = 65535, + MAX_SRPT_RDMA_SIZE = 1U << 24, + MAX_SRPT_RSP_SIZE = 1024, + + MIN_MAX_REQ_SIZE = 996, + DEFAULT_MAX_REQ_SIZE + = sizeof(struct srp_cmd)/*48*/ + + sizeof(struct srp_indirect_buf)/*20*/ + + 128 * sizeof(struct srp_direct_buf)/*16*/, + + MIN_MAX_RSP_SIZE = sizeof(struct srp_rsp)/*36*/ + 4, + DEFAULT_MAX_RSP_SIZE = 256, /* leaves 220 bytes for sense data */ + + DEFAULT_MAX_RDMA_SIZE = 65536, +}; + +enum srpt_opcode { + SRPT_RECV, + SRPT_SEND, + SRPT_RDMA_MID, + SRPT_RDMA_ABORT, + SRPT_RDMA_READ_LAST, + SRPT_RDMA_WRITE_LAST, +}; + +static inline u64 encode_wr_id(u8 opcode, u32 idx) +{ + return ((u64)opcode << 32) | idx; +} +static inline enum srpt_opcode opcode_from_wr_id(u64 wr_id) +{ + return wr_id >> 32; +} +static inline u32 idx_from_wr_id(u64 wr_id) +{ + return (u32)wr_id; +} + +struct rdma_iu { + u64 raddr; + u32 rkey; + struct ib_sge *sge; + u32 sge_cnt; + int mem_id; +}; + +/** + * enum srpt_command_state - SCSI command state managed by SRPT. + * @SRPT_STATE_NEW: New command arrived and is being processed. + * @SRPT_STATE_NEED_DATA: Processing a write or bidir command and waiting + * for data arrival. + * @SRPT_STATE_DATA_IN: Data for the write or bidir command arrived and is + * being processed. + * @SRPT_STATE_CMD_RSP_SENT: SRP_RSP for SRP_CMD has been sent. + * @SRPT_STATE_MGMT: Processing a SCSI task management command. + * @SRPT_STATE_MGMT_RSP_SENT: SRP_RSP for SRP_TSK_MGMT has been sent. + * @SRPT_STATE_DONE: Command processing finished successfully, command + * processing has been aborted or command processing + * failed. + */ +enum srpt_command_state { + SRPT_STATE_NEW = 0, + SRPT_STATE_NEED_DATA = 1, + SRPT_STATE_DATA_IN = 2, + SRPT_STATE_CMD_RSP_SENT = 3, + SRPT_STATE_MGMT = 4, + SRPT_STATE_MGMT_RSP_SENT = 5, + SRPT_STATE_DONE = 6, +}; + +/** + * struct srpt_ioctx - Shared SRPT I/O context information. + * @buf: Pointer to the buffer. + * @dma: DMA address of the buffer. + * @index: Index of the I/O context in its ioctx_ring array. + */ +struct srpt_ioctx { + void *buf; + dma_addr_t dma; + uint32_t index; +}; + +/** + * struct srpt_recv_ioctx - SRPT receive I/O context. + * @ioctx: See above. + * @wait_list: Node for insertion in srpt_rdma_ch.cmd_wait_list. + */ +struct srpt_recv_ioctx { + struct srpt_ioctx ioctx; + struct list_head wait_list; +}; + +/** + * struct srpt_send_ioctx - SRPT send I/O context. + * @ioctx: See above. + * @ch: Channel pointer. + * @free_list: Node in srpt_rdma_ch.free_list. + * @n_rbuf: Number of data buffers in the received SRP command. + * @rbufs: Pointer to SRP data buffer array. + * @single_rbuf: SRP data buffer if the command has only a single buffer. + * @sg: Pointer to sg-list associated with this I/O context. + * @sg_cnt: SG-list size. + * @mapped_sg_count: ib_dma_map_sg() return value. + * @n_rdma_ius: Number of elements in the rdma_ius array. + * @rdma_ius: Array with information about the RDMA mapping. + * @tag: Tag of the received SRP information unit. + * @spinlock: Protects 'state'. + * @state: I/O context state. + * @rdma_aborted: If initiating a multipart RDMA transfer failed, whether + * the already initiated transfers have finished. + * @cmd: Target core command data structure. + * @sense_data: SCSI sense data. + */ +struct srpt_send_ioctx { + struct srpt_ioctx ioctx; + struct srpt_rdma_ch *ch; + struct kref kref; + struct rdma_iu *rdma_ius; + struct srp_direct_buf *rbufs; + struct srp_direct_buf single_rbuf; + struct scatterlist *sg; + struct list_head free_list; + spinlock_t spinlock; + enum srpt_command_state state; + bool rdma_aborted; + struct se_cmd cmd; + struct completion tx_done; + u64 tag; + int sg_cnt; + int mapped_sg_count; + u16 n_rdma_ius; + u8 n_rdma; + u8 n_rbuf; + bool queue_status_only; + u8 sense_data[SCSI_SENSE_BUFFERSIZE]; +}; + +/** + * enum rdma_ch_state - SRP channel state. + * @CH_CONNECTING: QP is in RTR state; waiting for RTU. + * @CH_LIVE: QP is in RTS state. + * @CH_DISCONNECTING: DREQ has been received; waiting for DREP + * or DREQ has been send and waiting for DREP + * or . + * @CH_DRAINING: QP is in ERR state; waiting for last WQE event. + * @CH_RELEASING: Last WQE event has been received; releasing resources. + */ +enum rdma_ch_state { + CH_CONNECTING, + CH_LIVE, + CH_DISCONNECTING, + CH_DRAINING, + CH_RELEASING +}; + +/** + * struct srpt_rdma_ch - RDMA channel. + * @wait_queue: Allows the kernel thread to wait for more work. + * @thread: Kernel thread that processes the IB queues associated with + * the channel. + * @cm_id: IB CM ID associated with the channel. + * @qp: IB queue pair used for communicating over this channel. + * @cq: IB completion queue for this channel. + * @rq_size: IB receive queue size. + * @rsp_size IB response message size in bytes. + * @sq_wr_avail: number of work requests available in the send queue. + * @sport: pointer to the information of the HCA port used by this + * channel. + * @i_port_id: 128-bit initiator port identifier copied from SRP_LOGIN_REQ. + * @t_port_id: 128-bit target port identifier copied from SRP_LOGIN_REQ. + * @max_ti_iu_len: maximum target-to-initiator information unit length. + * @req_lim: request limit: maximum number of requests that may be sent + * by the initiator without having received a response. + * @req_lim_delta: Number of credits not yet sent back to the initiator. + * @spinlock: Protects free_list and state. + * @free_list: Head of list with free send I/O contexts. + * @state: channel state. See also enum rdma_ch_state. + * @ioctx_ring: Send ring. + * @wc: IB work completion array for srpt_process_completion(). + * @list: Node for insertion in the srpt_device.rch_list list. + * @cmd_wait_list: List of SCSI commands that arrived before the RTU event. This + * list contains struct srpt_ioctx elements and is protected + * against concurrent modification by the cm_id spinlock. + * @sess: Session information associated with this SRP channel. + * @sess_name: Session name. + * @release_work: Allows scheduling of srpt_release_channel(). + * @release_done: Enables waiting for srpt_release_channel() completion. + */ +struct srpt_rdma_ch { + wait_queue_head_t wait_queue; + struct task_struct *thread; + struct ib_cm_id *cm_id; + struct ib_qp *qp; + struct ib_cq *cq; + int rq_size; + u32 rsp_size; + atomic_t sq_wr_avail; + struct srpt_port *sport; + u8 i_port_id[16]; + u8 t_port_id[16]; + int max_ti_iu_len; + atomic_t req_lim; + atomic_t req_lim_delta; + spinlock_t spinlock; + struct list_head free_list; + enum rdma_ch_state state; + struct srpt_send_ioctx **ioctx_ring; + struct ib_wc wc[16]; + struct list_head list; + struct list_head cmd_wait_list; + struct se_session *sess; + u8 sess_name[36]; + struct work_struct release_work; + struct completion *release_done; +}; + +/** + * struct srpt_port_attib - Attributes for SRPT port + * @srp_max_rdma_size: Maximum size of SRP RDMA transfers for new connections. + * @srp_max_rsp_size: Maximum size of SRP response messages in bytes. + * @srp_sq_size: Shared receive queue (SRQ) size. + */ +struct srpt_port_attrib { + u32 srp_max_rdma_size; + u32 srp_max_rsp_size; + u32 srp_sq_size; +}; + +/** + * struct srpt_port - Information associated by SRPT with a single IB port. + * @sdev: backpointer to the HCA information. + * @mad_agent: per-port management datagram processing information. + * @enabled: Whether or not this target port is enabled. + * @port_guid: ASCII representation of Port GUID + * @port: one-based port number. + * @sm_lid: cached value of the port's sm_lid. + * @lid: cached value of the port's lid. + * @gid: cached value of the port's gid. + * @port_acl_lock spinlock for port_acl_list: + * @work: work structure for refreshing the aforementioned cached values. + * @port_tpg_1 Target portal group = 1 data. + * @port_wwn: Target core WWN data. + * @port_acl_list: Head of the list with all node ACLs for this port. + */ +struct srpt_port { + struct srpt_device *sdev; + struct ib_mad_agent *mad_agent; + bool enabled; + u8 port_guid[64]; + u8 port; + u16 sm_lid; + u16 lid; + union ib_gid gid; + spinlock_t port_acl_lock; + struct work_struct work; + struct se_portal_group port_tpg_1; + struct se_wwn port_wwn; + struct list_head port_acl_list; + struct srpt_port_attrib port_attrib; +}; + +/** + * struct srpt_device - Information associated by SRPT with a single HCA. + * @device: Backpointer to the struct ib_device managed by the IB core. + * @pd: IB protection domain. + * @mr: L_Key (local key) with write access to all local memory. + * @srq: Per-HCA SRQ (shared receive queue). + * @cm_id: Connection identifier. + * @dev_attr: Attributes of the InfiniBand device as obtained during the + * ib_client.add() callback. + * @srq_size: SRQ size. + * @ioctx_ring: Per-HCA SRQ. + * @rch_list: Per-device channel list -- see also srpt_rdma_ch.list. + * @ch_releaseQ: Enables waiting for removal from rch_list. + * @spinlock: Protects rch_list and tpg. + * @port: Information about the ports owned by this HCA. + * @event_handler: Per-HCA asynchronous IB event handler. + * @list: Node in srpt_dev_list. + */ +struct srpt_device { + struct ib_device *device; + struct ib_pd *pd; + struct ib_mr *mr; + struct ib_srq *srq; + struct ib_cm_id *cm_id; + struct ib_device_attr dev_attr; + int srq_size; + struct srpt_recv_ioctx **ioctx_ring; + struct list_head rch_list; + wait_queue_head_t ch_releaseQ; + spinlock_t spinlock; + struct srpt_port port[2]; + struct ib_event_handler event_handler; + struct list_head list; +}; + +/** + * struct srpt_node_acl - Per-initiator ACL data (managed via configfs). + * @i_port_id: 128-bit SRP initiator port ID. + * @sport: port information. + * @nacl: Target core node ACL information. + * @list: Element of the per-HCA ACL list. + */ +struct srpt_node_acl { + u8 i_port_id[16]; + struct srpt_port *sport; + struct se_node_acl nacl; + struct list_head list; +}; + +/* + * SRP-releated SCSI persistent reservation definitions. + * + * See also SPC4r28, section 7.6.1 (Protocol specific parameters introduction). + * See also SPC4r28, section 7.6.4.5 (TransportID for initiator ports using + * SCSI over an RDMA interface). + */ + +enum { + SCSI_TRANSPORTID_PROTOCOLID_SRP = 4, +}; + +struct spc_rdma_transport_id { + uint8_t protocol_identifier; + uint8_t reserved[7]; + uint8_t i_port_id[16]; +}; + +#endif /* IB_SRPT_H */ diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 32bbd4c77b7c..fd7a0d5bc94d 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -98,15 +98,15 @@ #define XTYPE_XBOX360W 2 #define XTYPE_UNKNOWN 3 -static int dpad_to_buttons; +static bool dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); -static int triggers_to_buttons; +static bool triggers_to_buttons; module_param(triggers_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads"); -static int sticks_to_null; +static bool sticks_to_null; module_param(sticks_to_null, bool, S_IRUGO); MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads"); diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index 79d901633635..350fd0c385d2 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -12,7 +12,7 @@ #include <linux/platform_device.h> #include <linux/input.h> #include <linux/interrupt.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/slab.h> /** diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 52b419348983..e2bdfd4bea70 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -48,7 +48,7 @@ MODULE_DESCRIPTION("Wistron laptop button driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION("0.3"); -static int force; /* = 0; */ +static bool force; /* = 0; */ module_param(force, bool, 0); MODULE_PARM_DESC(force, "Load even if computer is not in database"); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index de7e8bc17b1f..e6c9931f02c7 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -60,7 +60,7 @@ static unsigned int psmouse_rate = 100; module_param_named(rate, psmouse_rate, uint, 0644); MODULE_PARM_DESC(rate, "Report rate, in reports per second."); -static unsigned int psmouse_smartscroll = 1; +static bool psmouse_smartscroll = 1; module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 4b755cb5b38c..1c58aafa523f 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -185,17 +185,17 @@ #define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4) /* Control touchpad's No Deceleration option */ -static int no_decel = 1; +static bool no_decel = 1; module_param(no_decel, bool, 0644); MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)"); /* Control touchpad's Reduced Reporting option */ -static int reduce_report; +static bool reduce_report; module_param(reduce_report, bool, 0644); MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)"); /* Control touchpad's No Filter option */ -static int no_filter; +static bool no_filter; module_param(no_filter, bool, 0644); MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)"); diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 979c443bf1ef..be3316073ae7 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -105,7 +105,7 @@ EXPORT_SYMBOL(__hp_sdc_enqueue_transaction); EXPORT_SYMBOL(hp_sdc_enqueue_transaction); EXPORT_SYMBOL(hp_sdc_dequeue_transaction); -static unsigned int hp_sdc_disabled; +static bool hp_sdc_disabled; module_param_named(no_hpsdc, hp_sdc_disabled, bool, 0); MODULE_PARM_DESC(no_hpsdc, "Do not enable HP SDC driver."); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 7f8f538a9806..1df19bb8534a 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -35,11 +35,11 @@ #include <linux/input/eeti_ts.h> #include <linux/slab.h> -static int flip_x; +static bool flip_x; module_param(flip_x, bool, 0644); MODULE_PARM_DESC(flip_x, "flip x coordinate"); -static int flip_y; +static bool flip_y; module_param(flip_y, bool, 0644); MODULE_PARM_DESC(flip_y, "flip y coordinate"); diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index 81e338623944..d13143b68b3e 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -40,10 +40,10 @@ MODULE_LICENSE("GPL"); #define X_AXIS_MAX 2040 #define Y_AXIS_MAX 2040 -static int invert_x; +static bool invert_x; module_param(invert_x, bool, 0644); MODULE_PARM_DESC(invert_x, "If set, X axis is inverted"); -static int invert_y; +static bool invert_y; module_param(invert_y, bool, 0644); MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted"); diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index d2b57536feea..46e83ad53f43 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -30,7 +30,7 @@ #define UCB1400_TS_POLL_PERIOD 10 /* ms */ -static int adcsync; +static bool adcsync; static int ts_delay = 55; /* us */ static int ts_delay_pressure; /* us */ diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 06cef3ccc63a..3a5ebf452e81 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -60,11 +60,11 @@ #define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>" #define DRIVER_DESC "USB Touchscreen Driver" -static int swap_xy; +static bool swap_xy; module_param(swap_xy, bool, 0644); MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped."); -static int hwcalib_xy; +static bool hwcalib_xy; module_param(hwcalib_xy, bool, 0644); MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available"); diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 9c8d7aa053c5..a0ed668d4d2a 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -40,7 +40,7 @@ MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -static int suppress_pollack = 0; +static bool suppress_pollack = 0; module_param(suppress_pollack, bool, 0); /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index d3530f6e8115..9743b24ef9d6 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -40,7 +40,7 @@ static char *revision = "$Revision: 1.1.2.2 $"; /* ------------------------------------------------------------- */ -static int suppress_pollack; +static bool suppress_pollack; static struct pci_device_id c4_pci_tbl[] = { { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 }, diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index ca710ab278ec..023de789f250 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -30,7 +30,7 @@ static const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCo static unsigned int io[] = {0,0,0,0}; static unsigned char irq[] = {0,0,0,0}; static unsigned long ram[] = {0,0,0,0}; -static int do_reset = 0; +static bool do_reset = 0; module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 897a77dfa9d7..9ca28fced2b9 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -396,6 +396,20 @@ config LEDS_TCA6507 LED driver chips accessed via the I2C bus. Driver support brightness control and hardware-assisted blinking. +config LEDS_MAX8997 + tristate "LED support for MAX8997 PMIC" + depends on LEDS_CLASS && MFD_MAX8997 + help + This option enables support for on-chip LED drivers on + MAXIM MAX8997 PMIC. + +config LEDS_OT200 + tristate "LED support for the Bachmann OT200" + depends on LEDS_CLASS && HAS_IOMEM + help + This option enables support for the LEDs on the Bachmann OT200. + Say Y to enable LEDs on the Bachmann OT200. + config LEDS_TRIGGERS bool "LED Trigger support" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 5c9dc4b000d5..1fc6875a8b20 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o +obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o @@ -44,6 +45,7 @@ obj-$(CONFIG_LEDS_NS2) += leds-ns2.o obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o +obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c index a498135a4e80..1ed1677c916f 100644 --- a/drivers/leds/leds-clevo-mail.c +++ b/drivers/leds/leds-clevo-mail.c @@ -18,7 +18,7 @@ MODULE_AUTHOR("Márton NĂ©meth <nm127@freemail.hu>"); MODULE_DESCRIPTION("Clevo mail LED driver"); MODULE_LICENSE("GPL"); -static unsigned int __initdata nodetect; +static bool __initdata nodetect; module_param_named(nodetect, nodetect, bool, 0); MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection"); diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c new file mode 100644 index 000000000000..f4c0e37fad1e --- /dev/null +++ b/drivers/leds/leds-max8997.c @@ -0,0 +1,372 @@ +/* + * leds-max8997.c - LED class driver for MAX8997 LEDs. + * + * Copyright (C) 2011 Samsung Electronics + * Donggeun Kim <dg77.kim@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 <linux/module.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/leds.h> +#include <linux/mfd/max8997.h> +#include <linux/mfd/max8997-private.h> +#include <linux/platform_device.h> + +#define MAX8997_LED_FLASH_SHIFT 3 +#define MAX8997_LED_FLASH_CUR_MASK 0xf8 +#define MAX8997_LED_MOVIE_SHIFT 4 +#define MAX8997_LED_MOVIE_CUR_MASK 0xf0 + +#define MAX8997_LED_FLASH_MAX_BRIGHTNESS 0x1f +#define MAX8997_LED_MOVIE_MAX_BRIGHTNESS 0xf +#define MAX8997_LED_NONE_MAX_BRIGHTNESS 0 + +#define MAX8997_LED0_FLASH_MASK 0x1 +#define MAX8997_LED0_FLASH_PIN_MASK 0x5 +#define MAX8997_LED0_MOVIE_MASK 0x8 +#define MAX8997_LED0_MOVIE_PIN_MASK 0x28 + +#define MAX8997_LED1_FLASH_MASK 0x2 +#define MAX8997_LED1_FLASH_PIN_MASK 0x6 +#define MAX8997_LED1_MOVIE_MASK 0x10 +#define MAX8997_LED1_MOVIE_PIN_MASK 0x30 + +#define MAX8997_LED_BOOST_ENABLE_MASK (1 << 6) + +struct max8997_led { + struct max8997_dev *iodev; + struct led_classdev cdev; + bool enabled; + int id; + enum max8997_led_mode led_mode; + struct mutex mutex; +}; + +static void max8997_led_clear_mode(struct max8997_led *led, + enum max8997_led_mode mode) +{ + struct i2c_client *client = led->iodev->i2c; + u8 val = 0, mask = 0; + int ret; + + switch (mode) { + case MAX8997_FLASH_MODE: + mask = led->id ? + MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; + break; + case MAX8997_MOVIE_MODE: + mask = led->id ? + MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; + break; + case MAX8997_FLASH_PIN_CONTROL_MODE: + mask = led->id ? + MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; + break; + case MAX8997_MOVIE_PIN_CONTROL_MODE: + mask = led->id ? + MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; + break; + default: + break; + } + + if (mask) { + ret = max8997_update_reg(client, + MAX8997_REG_LEN_CNTL, val, mask); + if (ret) + dev_err(led->iodev->dev, + "failed to update register(%d)\n", ret); + } +} + +static void max8997_led_set_mode(struct max8997_led *led, + enum max8997_led_mode mode) +{ + int ret; + struct i2c_client *client = led->iodev->i2c; + u8 mask = 0; + + /* First, clear the previous mode */ + max8997_led_clear_mode(led, led->led_mode); + + switch (mode) { + case MAX8997_FLASH_MODE: + mask = led->id ? + MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; + led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; + break; + case MAX8997_MOVIE_MODE: + mask = led->id ? + MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; + led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; + break; + case MAX8997_FLASH_PIN_CONTROL_MODE: + mask = led->id ? + MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; + led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; + break; + case MAX8997_MOVIE_PIN_CONTROL_MODE: + mask = led->id ? + MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; + led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; + break; + default: + led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS; + break; + } + + if (mask) { + ret = max8997_update_reg(client, + MAX8997_REG_LEN_CNTL, mask, mask); + if (ret) + dev_err(led->iodev->dev, + "failed to update register(%d)\n", ret); + } + + led->led_mode = mode; +} + +static void max8997_led_enable(struct max8997_led *led, bool enable) +{ + int ret; + struct i2c_client *client = led->iodev->i2c; + u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK; + + if (led->enabled == enable) + return; + + val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0; + + ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask); + if (ret) + dev_err(led->iodev->dev, + "failed to update register(%d)\n", ret); + + led->enabled = enable; +} + +static void max8997_led_set_current(struct max8997_led *led, + enum led_brightness value) +{ + int ret; + struct i2c_client *client = led->iodev->i2c; + u8 val = 0, mask = 0, reg = 0; + + switch (led->led_mode) { + case MAX8997_FLASH_MODE: + case MAX8997_FLASH_PIN_CONTROL_MODE: + val = value << MAX8997_LED_FLASH_SHIFT; + mask = MAX8997_LED_FLASH_CUR_MASK; + reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR; + break; + case MAX8997_MOVIE_MODE: + case MAX8997_MOVIE_PIN_CONTROL_MODE: + val = value << MAX8997_LED_MOVIE_SHIFT; + mask = MAX8997_LED_MOVIE_CUR_MASK; + reg = MAX8997_REG_MOVIE_CUR; + break; + default: + break; + } + + if (mask) { + ret = max8997_update_reg(client, reg, val, mask); + if (ret) + dev_err(led->iodev->dev, + "failed to update register(%d)\n", ret); + } +} + +static void max8997_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct max8997_led *led = + container_of(led_cdev, struct max8997_led, cdev); + + if (value) { + max8997_led_set_current(led, value); + max8997_led_enable(led, true); + } else { + max8997_led_set_current(led, value); + max8997_led_enable(led, false); + } +} + +static ssize_t max8997_led_show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct max8997_led *led = + container_of(led_cdev, struct max8997_led, cdev); + ssize_t ret = 0; + + mutex_lock(&led->mutex); + + switch (led->led_mode) { + case MAX8997_FLASH_MODE: + ret += sprintf(buf, "FLASH\n"); + break; + case MAX8997_MOVIE_MODE: + ret += sprintf(buf, "MOVIE\n"); + break; + case MAX8997_FLASH_PIN_CONTROL_MODE: + ret += sprintf(buf, "FLASH_PIN_CONTROL\n"); + break; + case MAX8997_MOVIE_PIN_CONTROL_MODE: + ret += sprintf(buf, "MOVIE_PIN_CONTROL\n"); + break; + default: + ret += sprintf(buf, "NONE\n"); + break; + } + + mutex_unlock(&led->mutex); + + return ret; +} + +static ssize_t max8997_led_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct max8997_led *led = + container_of(led_cdev, struct max8997_led, cdev); + enum max8997_led_mode mode; + + mutex_lock(&led->mutex); + + if (!strncmp(buf, "FLASH_PIN_CONTROL", 17)) + mode = MAX8997_FLASH_PIN_CONTROL_MODE; + else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17)) + mode = MAX8997_MOVIE_PIN_CONTROL_MODE; + else if (!strncmp(buf, "FLASH", 5)) + mode = MAX8997_FLASH_MODE; + else if (!strncmp(buf, "MOVIE", 5)) + mode = MAX8997_MOVIE_MODE; + else + mode = MAX8997_NONE; + + max8997_led_set_mode(led, mode); + + mutex_unlock(&led->mutex); + + return size; +} + +static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode); + +static int __devinit max8997_led_probe(struct platform_device *pdev) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); + struct max8997_led *led; + char name[20]; + int ret = 0; + + if (pdata == NULL) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENODEV; + } + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (led == NULL) { + ret = -ENOMEM; + goto err_mem; + } + + led->id = pdev->id; + snprintf(name, sizeof(name), "max8997-led%d", pdev->id); + + led->cdev.name = name; + led->cdev.brightness_set = max8997_led_brightness_set; + led->cdev.flags |= LED_CORE_SUSPENDRESUME; + led->cdev.brightness = 0; + led->iodev = iodev; + + /* initialize mode and brightness according to platform_data */ + if (pdata->led_pdata) { + u8 mode = 0, brightness = 0; + + mode = pdata->led_pdata->mode[led->id]; + brightness = pdata->led_pdata->brightness[led->id]; + + max8997_led_set_mode(led, pdata->led_pdata->mode[led->id]); + + if (brightness > led->cdev.max_brightness) + brightness = led->cdev.max_brightness; + max8997_led_set_current(led, brightness); + led->cdev.brightness = brightness; + } else { + max8997_led_set_mode(led, MAX8997_NONE); + max8997_led_set_current(led, 0); + } + + mutex_init(&led->mutex); + + platform_set_drvdata(pdev, led); + + ret = led_classdev_register(&pdev->dev, &led->cdev); + if (ret < 0) + goto err_led; + + ret = device_create_file(led->cdev.dev, &dev_attr_mode); + if (ret != 0) { + dev_err(&pdev->dev, + "failed to create file: %d\n", ret); + goto err_file; + } + + return 0; + +err_file: + led_classdev_unregister(&led->cdev); +err_led: + kfree(led); +err_mem: + return ret; +} + +static int __devexit max8997_led_remove(struct platform_device *pdev) +{ + struct max8997_led *led = platform_get_drvdata(pdev); + + device_remove_file(led->cdev.dev, &dev_attr_mode); + led_classdev_unregister(&led->cdev); + kfree(led); + + return 0; +} + +static struct platform_driver max8997_led_driver = { + .driver = { + .name = "max8997-led", + .owner = THIS_MODULE, + }, + .probe = max8997_led_probe, + .remove = __devexit_p(max8997_led_remove), +}; + +static int __init max8997_led_init(void) +{ + return platform_driver_register(&max8997_led_driver); +} +module_init(max8997_led_init); + +static void __exit max8997_led_exit(void) +{ + platform_driver_unregister(&max8997_led_driver); +} +module_exit(max8997_led_exit); + +MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); +MODULE_DESCRIPTION("MAX8997 LED driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:max8997-led"); diff --git a/drivers/leds/leds-ot200.c b/drivers/leds/leds-ot200.c new file mode 100644 index 000000000000..c4646825a620 --- /dev/null +++ b/drivers/leds/leds-ot200.c @@ -0,0 +1,171 @@ +/* + * Bachmann ot200 leds driver. + * + * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> + * Christian Gmeiner <christian.gmeiner@gmail.com> + * + * License: GPL as published by the FSF. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/leds.h> +#include <linux/io.h> +#include <linux/module.h> + + +struct ot200_led { + struct led_classdev cdev; + const char *name; + unsigned long port; + u8 mask; +}; + +/* + * The device has three leds on the back panel (led_err, led_init and led_run) + * and can handle up to seven leds on the front panel. + */ + +static struct ot200_led leds[] = { + { + .name = "led_run", + .port = 0x5a, + .mask = BIT(0), + }, + { + .name = "led_init", + .port = 0x5a, + .mask = BIT(1), + }, + { + .name = "led_err", + .port = 0x5a, + .mask = BIT(2), + }, + { + .name = "led_1", + .port = 0x49, + .mask = BIT(7), + }, + { + .name = "led_2", + .port = 0x49, + .mask = BIT(6), + }, + { + .name = "led_3", + .port = 0x49, + .mask = BIT(5), + }, + { + .name = "led_4", + .port = 0x49, + .mask = BIT(4), + }, + { + .name = "led_5", + .port = 0x49, + .mask = BIT(3), + }, + { + .name = "led_6", + .port = 0x49, + .mask = BIT(2), + }, + { + .name = "led_7", + .port = 0x49, + .mask = BIT(1), + } +}; + +static DEFINE_SPINLOCK(value_lock); + +/* + * we need to store the current led states, as it is not + * possible to read the current led state via inb(). + */ +static u8 leds_back; +static u8 leds_front; + +static void ot200_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct ot200_led *led = container_of(led_cdev, struct ot200_led, cdev); + u8 *val; + unsigned long flags; + + spin_lock_irqsave(&value_lock, flags); + + if (led->port == 0x49) + val = &leds_front; + else if (led->port == 0x5a) + val = &leds_back; + else + BUG(); + + if (value == LED_OFF) + *val &= ~led->mask; + else + *val |= led->mask; + + outb(*val, led->port); + spin_unlock_irqrestore(&value_lock, flags); +} + +static int __devinit ot200_led_probe(struct platform_device *pdev) +{ + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(leds); i++) { + + leds[i].cdev.name = leds[i].name; + leds[i].cdev.brightness_set = ot200_led_brightness_set; + + ret = led_classdev_register(&pdev->dev, &leds[i].cdev); + if (ret < 0) + goto err; + } + + leds_front = 0; /* turn off all front leds */ + leds_back = BIT(1); /* turn on init led */ + outb(leds_front, 0x49); + outb(leds_back, 0x5a); + + return 0; + +err: + for (i = i - 1; i >= 0; i--) + led_classdev_unregister(&leds[i].cdev); + + return ret; +} + +static int __devexit ot200_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(leds); i++) + led_classdev_unregister(&leds[i].cdev); + + return 0; +} + +static struct platform_driver ot200_led_driver = { + .probe = ot200_led_probe, + .remove = __devexit_p(ot200_led_remove), + .driver = { + .name = "leds-ot200", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(ot200_led_driver); + +MODULE_AUTHOR("Sebastian A. Siewior <bigeasy@linutronix.de>"); +MODULE_DESCRIPTION("ot200 LED driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:leds-ot200"); diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c index 614ebebaaa28..57371e1485ab 100644 --- a/drivers/leds/leds-ss4200.c +++ b/drivers/leds/leds-ss4200.c @@ -79,7 +79,7 @@ static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id) return 1; } -static unsigned int __initdata nodetect; +static bool __initdata nodetect; module_param_named(nodetect, nodetect, bool, 0); MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection"); diff --git a/drivers/macintosh/ams/ams-core.c b/drivers/macintosh/ams/ams-core.c index 399beb1638d1..5c6a2d876562 100644 --- a/drivers/macintosh/ams/ams-core.c +++ b/drivers/macintosh/ams/ams-core.c @@ -31,7 +31,7 @@ /* There is only one motion sensor per machine */ struct ams ams_info; -static unsigned int verbose; +static bool verbose; module_param(verbose, bool, 0644); MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output"); diff --git a/drivers/macintosh/ams/ams-input.c b/drivers/macintosh/ams/ams-input.c index 8a712392cd38..b27e530a87a4 100644 --- a/drivers/macintosh/ams/ams-input.c +++ b/drivers/macintosh/ams/ams-input.c @@ -19,11 +19,11 @@ #include "ams.h" -static unsigned int joystick; +static bool joystick; module_param(joystick, bool, S_IRUGO); MODULE_PARM_DESC(joystick, "Enable the input class device on module load"); -static unsigned int invert; +static bool invert; module_param(invert, bool, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 02367308ff2e..c60d025044ee 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -52,7 +52,7 @@ static const char *sensor_location[3]; static int limit_adjust; static int fan_speed = -1; -static int verbose; +static bool verbose; MODULE_AUTHOR("Colin Leroy <colin@colino.net>"); MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and " diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index f84c08029b21..9fb18c147825 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -368,8 +368,17 @@ static int flakey_status(struct dm_target *ti, status_type_t type, static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) { struct flakey_c *fc = ti->private; + struct dm_dev *dev = fc->dev; + int r = 0; - return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (fc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); } static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 3921e3bb43c1..9728839f844a 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -116,7 +116,17 @@ static int linear_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) { struct linear_c *lc = (struct linear_c *) ti->private; - return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg); + struct dm_dev *dev = lc->dev; + int r = 0; + + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (lc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); } static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm, diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 5e0090ef4182..801d92d237cf 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1520,6 +1520,12 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, spin_unlock_irqrestore(&m->lock, flags); + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg); } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 8e9132130142..63cc54289aff 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -699,7 +699,7 @@ static int validate_hardware_logical_block_alignment(struct dm_table *table, while (i < dm_table_get_num_targets(table)) { ti = dm_table_get_target(table, i++); - blk_set_default_limits(&ti_limits); + blk_set_stacking_limits(&ti_limits); /* combine all target devices' limits */ if (ti->type->iterate_devices) @@ -1221,10 +1221,10 @@ int dm_calculate_queue_limits(struct dm_table *table, struct queue_limits ti_limits; unsigned i = 0; - blk_set_default_limits(limits); + blk_set_stacking_limits(limits); while (i < dm_table_get_num_targets(table)) { - blk_set_default_limits(&ti_limits); + blk_set_stacking_limits(&ti_limits); ti = dm_table_get_target(table, i++); diff --git a/drivers/md/md.c b/drivers/md/md.c index da52acb60f52..9417ae2fa0bb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4666,6 +4666,7 @@ static int md_alloc(dev_t dev, char *name) mddev->queue->queuedata = mddev; blk_queue_make_request(mddev->queue, md_make_request); + blk_set_stacking_limits(&mddev->queue->limits); disk = alloc_disk(1 << shift); if (!disk) { diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 996302ae210e..4a6d5cef3964 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -26,7 +26,7 @@ config MEDIA_TUNER select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && EXPERIMENTAL select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE @@ -116,6 +116,13 @@ config MEDIA_TUNER_MT2060 help A driver for the silicon IF tuner MT2060 from Microtune. +config MEDIA_TUNER_MT2063 + tristate "Microtune MT2063 silicon IF tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon IF tuner MT2063 from Microtune. + config MEDIA_TUNER_MT2266 tristate "Microtune MT2266 silicon tuner" depends on VIDEO_MEDIA && I2C diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile index 196c12a55f9a..8295854ab94b 100644 --- a/drivers/media/common/tuners/Makefile +++ b/drivers/media/common/tuners/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c index 9883617b7862..cb2c98fbad1b 100644 --- a/drivers/media/common/tuners/max2165.c +++ b/drivers/media/common/tuners/max2165.c @@ -151,7 +151,7 @@ static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) { u8 val; - if (bw == BANDWIDTH_8_MHZ) + if (bw == 8000000) val = priv->bb_filter_8mhz_cfg; else val = priv->bb_filter_7mhz_cfg; @@ -257,39 +257,28 @@ static void max2165_debug_status(struct max2165_priv *priv) dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc); } -static int max2165_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int max2165_set_params(struct dvb_frontend *fe) { struct max2165_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency); - if (fe->ops.info.type == FE_ATSC) { - return -EINVAL; - } else if (fe->ops.info.type == FE_OFDM) { - dprintk("%s() OFDM\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - return -EINVAL; - case BANDWIDTH_7_MHZ: - case BANDWIDTH_8_MHZ: - priv->frequency = params->frequency; - priv->bandwidth = params->u.ofdm.bandwidth; - break; - default: - printk(KERN_ERR "MAX2165 bandwidth not set!\n"); - return -EINVAL; - } - } else { - printk(KERN_ERR "MAX2165 modulation type not supported!\n"); + switch (c->bandwidth_hz) { + case 7000000: + case 8000000: + priv->frequency = c->frequency; + break; + default: + printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n", + c->bandwidth_hz); return -EINVAL; } - dprintk("%s() frequency=%d\n", __func__, priv->frequency); + dprintk("%s() frequency=%d\n", __func__, c->frequency); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - max2165_set_bandwidth(priv, priv->bandwidth); + max2165_set_bandwidth(priv, c->bandwidth_hz); ret = max2165_set_rf(priv, priv->frequency); mdelay(50); max2165_debug_status(priv); @@ -370,7 +359,7 @@ static int max2165_init(struct dvb_frontend *fe) max2165_read_rom_table(priv); - max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ); + max2165_set_bandwidth(priv, 8000000); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/common/tuners/mc44s803.c index fe5c4b8d83ee..5ddce7e326f7 100644 --- a/drivers/media/common/tuners/mc44s803.c +++ b/drivers/media/common/tuners/mc44s803.c @@ -214,22 +214,22 @@ exit: return err; } -static int mc44s803_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mc44s803_set_params(struct dvb_frontend *fe) { struct mc44s803_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 r1, r2, n1, n2, lo1, lo2, freq, val; int err; - priv->frequency = params->frequency; + priv->frequency = c->frequency; r1 = MC44S803_OSC / 1000000; r2 = MC44S803_OSC / 100000; - n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000; + n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000; freq = MC44S803_OSC / r1 * n1; lo1 = ((60 * n1) + (r1 / 2)) / r1; - freq = freq - params->frequency; + freq = freq - c->frequency; n2 = (freq - MC44S803_IF2 + 50000) / 100000; lo2 = ((60 * n2) + (r2 / 2)) / r2; diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c index 2d0e7689c6a2..13381de58a84 100644 --- a/drivers/media/common/tuners/mt2060.c +++ b/drivers/media/common/tuners/mt2060.c @@ -153,8 +153,9 @@ static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) #define IF2 36150 // IF2 frequency = 36.150 MHz #define FREF 16000 // Quartz oscillator 16 MHz -static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int mt2060_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct mt2060_priv *priv; int ret=0; int i=0; @@ -176,8 +177,7 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame mt2060_writeregs(priv,b,2); - freq = params->frequency / 1000; // Hz -> kHz - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + freq = c->frequency / 1000; /* Hz -> kHz */ f_lo1 = freq + if1 * 1000; f_lo1 = (f_lo1 / 250) * 250; @@ -293,10 +293,9 @@ static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct mt2060_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; + *frequency = IF2 * 1000; return 0; } @@ -356,7 +355,7 @@ static const struct dvb_tuner_ops mt2060_tuner_ops = { .set_params = mt2060_set_params, .get_frequency = mt2060_get_frequency, - .get_bandwidth = mt2060_get_bandwidth + .get_if_frequency = mt2060_get_if_frequency, }; /* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ diff --git a/drivers/media/common/tuners/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h index 5eaccdefd0b0..2b60de6c707d 100644 --- a/drivers/media/common/tuners/mt2060_priv.h +++ b/drivers/media/common/tuners/mt2060_priv.h @@ -97,7 +97,6 @@ struct mt2060_priv { struct i2c_adapter *i2c; u32 frequency; - u32 bandwidth; u16 if1_freq; u8 fmfreq; }; diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c new file mode 100644 index 000000000000..c89af3cd5eba --- /dev/null +++ b/drivers/media/common/tuners/mt2063.c @@ -0,0 +1,2307 @@ +/* + * Driver for mt2063 Micronas tuner + * + * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com> + * + * This driver came from a driver originally written by: + * Henry Wang <Henry.wang@AzureWave.com> + * Made publicly available by Terratec, at: + * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz + * The original driver's license is GPL, as declared with MODULE_LICENSE() + * + * 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 under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/videodev2.h> + +#include "mt2063.h" + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Set Verbosity level"); + +#define dprintk(level, fmt, arg...) do { \ +if (debug >= level) \ + printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \ +} while (0) + + +/* positive error codes used internally */ + +/* Info: Unavoidable LO-related spur may be present in the output */ +#define MT2063_SPUR_PRESENT_ERR (0x00800000) + +/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */ +#define MT2063_SPUR_CNT_MASK (0x001f0000) +#define MT2063_SPUR_SHIFT (16) + +/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */ +#define MT2063_UPC_RANGE (0x04000000) + +/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */ +#define MT2063_DNC_RANGE (0x08000000) + +/* + * Constant defining the version of the following structure + * and therefore the API for this code. + * + * When compiling the tuner driver, the preprocessor will + * check against this version number to make sure that + * it matches the version that the tuner driver knows about. + */ + +/* DECT Frequency Avoidance */ +#define MT2063_DECT_AVOID_US_FREQS 0x00000001 + +#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002 + +#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0) + +#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0) + +enum MT2063_DECT_Avoid_Type { + MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */ + MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */ + MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */ + MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */ +}; + +#define MT2063_MAX_ZONES 48 + +struct MT2063_ExclZone_t { + u32 min_; + u32 max_; + struct MT2063_ExclZone_t *next_; +}; + +/* + * Structure of data needed for Spur Avoidance + */ +struct MT2063_AvoidSpursData_t { + u32 f_ref; + u32 f_in; + u32 f_LO1; + u32 f_if1_Center; + u32 f_if1_Request; + u32 f_if1_bw; + u32 f_LO2; + u32 f_out; + u32 f_out_bw; + u32 f_LO1_Step; + u32 f_LO2_Step; + u32 f_LO1_FracN_Avoid; + u32 f_LO2_FracN_Avoid; + u32 f_zif_bw; + u32 f_min_LO_Separation; + u32 maxH1; + u32 maxH2; + enum MT2063_DECT_Avoid_Type avoidDECT; + u32 bSpurPresent; + u32 bSpurAvoided; + u32 nSpursFound; + u32 nZones; + struct MT2063_ExclZone_t *freeZones; + struct MT2063_ExclZone_t *usedZones; + struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES]; +}; + +/* + * Parameter for function MT2063_SetPowerMask that specifies the power down + * of various sections of the MT2063. + */ +enum MT2063_Mask_Bits { + MT2063_REG_SD = 0x0040, /* Shutdown regulator */ + MT2063_SRO_SD = 0x0020, /* Shutdown SRO */ + MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */ + MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */ + MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */ + MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */ + MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */ + MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */ + MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */ + MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */ + MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */ + MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */ + MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */ + MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */ + MT2063_NONE_SD = 0x0000 /* No shutdown bits */ +}; + +/* + * Possible values for MT2063_DNC_OUTPUT + */ +enum MT2063_DNC_Output_Enable { + MT2063_DNC_NONE = 0, + MT2063_DNC_1, + MT2063_DNC_2, + MT2063_DNC_BOTH +}; + +/* + * Two-wire serial bus subaddresses of the tuner registers. + * Also known as the tuner's register addresses. + */ +enum MT2063_Register_Offsets { + MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */ + MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */ + MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */ + MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */ + MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */ + MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */ + MT2063_REG_RSVD_06, /* 0x06: Reserved */ + MT2063_REG_LO_STATUS, /* 0x07: LO Status */ + MT2063_REG_FIFFC, /* 0x08: FIFF Center */ + MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */ + MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */ + MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */ + MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */ + MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */ + MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */ + MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */ + MT2063_REG_RSVD_10, /* 0x10: Reserved */ + MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */ + MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */ + MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */ + MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */ + MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */ + MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */ + MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */ + MT2063_REG_RF_OV, /* 0x18: RF Attn Override */ + MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */ + MT2063_REG_LNA_TGT, /* 0x1A: Reserved */ + MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */ + MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */ + MT2063_REG_RSVD_1D, /* 0x1D: Reserved */ + MT2063_REG_RSVD_1E, /* 0x1E: Reserved */ + MT2063_REG_RSVD_1F, /* 0x1F: Reserved */ + MT2063_REG_RSVD_20, /* 0x20: Reserved */ + MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */ + MT2063_REG_RSVD_22, /* 0x22: Reserved */ + MT2063_REG_RSVD_23, /* 0x23: Reserved */ + MT2063_REG_RSVD_24, /* 0x24: Reserved */ + MT2063_REG_RSVD_25, /* 0x25: Reserved */ + MT2063_REG_RSVD_26, /* 0x26: Reserved */ + MT2063_REG_RSVD_27, /* 0x27: Reserved */ + MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */ + MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */ + MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */ + MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */ + MT2063_REG_CTRL_2C, /* 0x2C: Reserved */ + MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */ + MT2063_REG_RSVD_2E, /* 0x2E: Reserved */ + MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */ + MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */ + MT2063_REG_RSVD_31, /* 0x31: Reserved */ + MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */ + MT2063_REG_RSVD_33, /* 0x33: Reserved */ + MT2063_REG_RSVD_34, /* 0x34: Reserved */ + MT2063_REG_RSVD_35, /* 0x35: Reserved */ + MT2063_REG_RSVD_36, /* 0x36: Reserved */ + MT2063_REG_RSVD_37, /* 0x37: Reserved */ + MT2063_REG_RSVD_38, /* 0x38: Reserved */ + MT2063_REG_RSVD_39, /* 0x39: Reserved */ + MT2063_REG_RSVD_3A, /* 0x3A: Reserved */ + MT2063_REG_RSVD_3B, /* 0x3B: Reserved */ + MT2063_REG_RSVD_3C, /* 0x3C: Reserved */ + MT2063_REG_END_REGS +}; + +struct mt2063_state { + struct i2c_adapter *i2c; + + bool init; + + const struct mt2063_config *config; + struct dvb_tuner_ops ops; + struct dvb_frontend *frontend; + struct tuner_state status; + + u32 frequency; + u32 srate; + u32 bandwidth; + u32 reference; + + u32 tuner_id; + struct MT2063_AvoidSpursData_t AS_Data; + u32 f_IF1_actual; + u32 rcvr_mode; + u32 ctfilt_sw; + u32 CTFiltMax[31]; + u32 num_regs; + u8 reg[MT2063_REG_END_REGS]; +}; + +/* + * mt2063_write - Write data into the I2C bus + */ +static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) +{ + struct dvb_frontend *fe = state->frontend; + int ret; + u8 buf[60]; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = 0, + .buf = buf, + .len = len + 1 + }; + + dprintk(2, "\n"); + + msg.buf[0] = reg; + memcpy(msg.buf + 1, data, len); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = i2c_transfer(state->i2c, &msg, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret < 0) + printk(KERN_ERR "%s error ret=%d\n", __func__, ret); + + return ret; +} + +/* + * mt2063_write - Write register data into the I2C bus, caching the value + */ +static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) +{ + u32 status; + + dprintk(2, "\n"); + + if (reg >= MT2063_REG_END_REGS) + return -ERANGE; + + status = mt2063_write(state, reg, &val, 1); + if (status < 0) + return status; + + state->reg[reg] = val; + + return 0; +} + +/* + * mt2063_read - Read data from the I2C bus + */ +static u32 mt2063_read(struct mt2063_state *state, + u8 subAddress, u8 *pData, u32 cnt) +{ + u32 status = 0; /* Status to be returned */ + struct dvb_frontend *fe = state->frontend; + u32 i = 0; + + dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + for (i = 0; i < cnt; i++) { + u8 b0[] = { subAddress + i }; + struct i2c_msg msg[] = { + { + .addr = state->config->tuner_address, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = state->config->tuner_address, + .flags = I2C_M_RD, + .buf = pData + i, + .len = 1 + } + }; + + status = i2c_transfer(state->i2c, msg, 2); + dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n", + subAddress + i, status, *(pData + i)); + if (status < 0) + break; + } + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (status < 0) + printk(KERN_ERR "Can't read from address 0x%02x,\n", + subAddress + i); + + return status; +} + +/* + * FIXME: Is this really needed? + */ +static int MT2063_Sleep(struct dvb_frontend *fe) +{ + /* + * ToDo: Add code here to implement a OS blocking + */ + msleep(10); + + return 0; +} + +/* + * Microtune spur avoidance + */ + +/* Implement ceiling, floor functions. */ +#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0)) +#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d)) + +struct MT2063_FIFZone_t { + s32 min_; + s32 max_; +}; + +static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t + *pAS_Info, + struct MT2063_ExclZone_t *pPrevNode) +{ + struct MT2063_ExclZone_t *pNode; + + dprintk(2, "\n"); + + /* Check for a node in the free list */ + if (pAS_Info->freeZones != NULL) { + /* Use one from the free list */ + pNode = pAS_Info->freeZones; + pAS_Info->freeZones = pNode->next_; + } else { + /* Grab a node from the array */ + pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones]; + } + + if (pPrevNode != NULL) { + pNode->next_ = pPrevNode->next_; + pPrevNode->next_ = pNode; + } else { /* insert at the beginning of the list */ + + pNode->next_ = pAS_Info->usedZones; + pAS_Info->usedZones = pNode; + } + + pAS_Info->nZones++; + return pNode; +} + +static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t + *pAS_Info, + struct MT2063_ExclZone_t *pPrevNode, + struct MT2063_ExclZone_t + *pNodeToRemove) +{ + struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_; + + dprintk(2, "\n"); + + /* Make previous node point to the subsequent node */ + if (pPrevNode != NULL) + pPrevNode->next_ = pNext; + + /* Add pNodeToRemove to the beginning of the freeZones */ + pNodeToRemove->next_ = pAS_Info->freeZones; + pAS_Info->freeZones = pNodeToRemove; + + /* Decrement node count */ + pAS_Info->nZones--; + + return pNext; +} + +/* + * MT_AddExclZone() + * + * Add (and merge) an exclusion zone into the list. + * If the range (f_min, f_max) is totally outside the + * 1st IF BW, ignore the entry. + * If the range (f_min, f_max) is negative, ignore the entry. + */ +static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, + u32 f_min, u32 f_max) +{ + struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; + struct MT2063_ExclZone_t *pPrev = NULL; + struct MT2063_ExclZone_t *pNext = NULL; + + dprintk(2, "\n"); + + /* Check to see if this overlaps the 1st IF filter */ + if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2))) + && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2))) + && (f_min < f_max)) { + /* + * 1 2 3 4 5 6 + * + * New entry: |---| |--| |--| |-| |---| |--| + * or or or or or + * Existing: |--| |--| |--| |---| |-| |--| + */ + + /* Check for our place in the list */ + while ((pNode != NULL) && (pNode->max_ < f_min)) { + pPrev = pNode; + pNode = pNode->next_; + } + + if ((pNode != NULL) && (pNode->min_ < f_max)) { + /* Combine me with pNode */ + if (f_min < pNode->min_) + pNode->min_ = f_min; + if (f_max > pNode->max_) + pNode->max_ = f_max; + } else { + pNode = InsertNode(pAS_Info, pPrev); + pNode->min_ = f_min; + pNode->max_ = f_max; + } + + /* Look for merging possibilities */ + pNext = pNode->next_; + while ((pNext != NULL) && (pNext->min_ < pNode->max_)) { + if (pNext->max_ > pNode->max_) + pNode->max_ = pNext->max_; + /* Remove pNext, return ptr to pNext->next */ + pNext = RemoveNode(pAS_Info, pNode, pNext); + } + } +} + +/* + * Reset all exclusion zones. + * Add zones to protect the PLL FracN regions near zero + */ +static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + u32 center; + + dprintk(2, "\n"); + + pAS_Info->nZones = 0; /* this clears the used list */ + pAS_Info->usedZones = NULL; /* reset ptr */ + pAS_Info->freeZones = NULL; /* reset ptr */ + + center = + pAS_Info->f_ref * + ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 + + pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in; + while (center < + pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + + pAS_Info->f_LO1_FracN_Avoid) { + /* Exclude LO1 FracN */ + MT2063_AddExclZone(pAS_Info, + center - pAS_Info->f_LO1_FracN_Avoid, + center - 1); + MT2063_AddExclZone(pAS_Info, center + 1, + center + pAS_Info->f_LO1_FracN_Avoid); + center += pAS_Info->f_ref; + } + + center = + pAS_Info->f_ref * + ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 - + pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out; + while (center < + pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + + pAS_Info->f_LO2_FracN_Avoid) { + /* Exclude LO2 FracN */ + MT2063_AddExclZone(pAS_Info, + center - pAS_Info->f_LO2_FracN_Avoid, + center - 1); + MT2063_AddExclZone(pAS_Info, center + 1, + center + pAS_Info->f_LO2_FracN_Avoid); + center += pAS_Info->f_ref; + } + + if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { + /* Exclude LO1 values that conflict with DECT channels */ + MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */ + MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */ + MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */ + MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */ + MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */ + } + + if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { + MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */ + MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */ + MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */ + MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */ + MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */ + MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */ + MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */ + MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */ + MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */ + MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */ + } +} + +/* + * MT_ChooseFirstIF - Choose the best available 1st IF + * If f_Desired is not excluded, choose that first. + * Otherwise, return the value closest to f_Center that is + * not excluded + */ +static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + /* + * Update "f_Desired" to be the nearest "combinational-multiple" of + * "f_LO1_Step". + * The resulting number, F_LO1 must be a multiple of f_LO1_Step. + * And F_LO1 is the arithmetic sum of f_in + f_Center. + * Neither f_in, nor f_Center must be a multiple of f_LO1_Step. + * However, the sum must be. + */ + const u32 f_Desired = + pAS_Info->f_LO1_Step * + ((pAS_Info->f_if1_Request + pAS_Info->f_in + + pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) - + pAS_Info->f_in; + const u32 f_Step = + (pAS_Info->f_LO1_Step > + pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info-> + f_LO2_Step; + u32 f_Center; + s32 i; + s32 j = 0; + u32 bDesiredExcluded = 0; + u32 bZeroExcluded = 0; + s32 tmpMin, tmpMax; + s32 bestDiff; + struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; + struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES]; + + dprintk(2, "\n"); + + if (pAS_Info->nZones == 0) + return f_Desired; + + /* + * f_Center needs to be an integer multiple of f_Step away + * from f_Desired + */ + if (pAS_Info->f_if1_Center > f_Desired) + f_Center = + f_Desired + + f_Step * + ((pAS_Info->f_if1_Center - f_Desired + + f_Step / 2) / f_Step); + else + f_Center = + f_Desired - + f_Step * + ((f_Desired - pAS_Info->f_if1_Center + + f_Step / 2) / f_Step); + + /* + * Take MT_ExclZones, center around f_Center and change the + * resolution to f_Step + */ + while (pNode != NULL) { + /* floor function */ + tmpMin = + floor((s32) (pNode->min_ - f_Center), (s32) f_Step); + + /* ceil function */ + tmpMax = + ceil((s32) (pNode->max_ - f_Center), (s32) f_Step); + + if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired)) + bDesiredExcluded = 1; + + if ((tmpMin < 0) && (tmpMax > 0)) + bZeroExcluded = 1; + + /* See if this zone overlaps the previous */ + if ((j > 0) && (tmpMin < zones[j - 1].max_)) + zones[j - 1].max_ = tmpMax; + else { + /* Add new zone */ + zones[j].min_ = tmpMin; + zones[j].max_ = tmpMax; + j++; + } + pNode = pNode->next_; + } + + /* + * If the desired is okay, return with it + */ + if (bDesiredExcluded == 0) + return f_Desired; + + /* + * If the desired is excluded and the center is okay, return with it + */ + if (bZeroExcluded == 0) + return f_Center; + + /* Find the value closest to 0 (f_Center) */ + bestDiff = zones[0].min_; + for (i = 0; i < j; i++) { + if (abs(zones[i].min_) < abs(bestDiff)) + bestDiff = zones[i].min_; + if (abs(zones[i].max_) < abs(bestDiff)) + bestDiff = zones[i].max_; + } + + if (bestDiff < 0) + return f_Center - ((u32) (-bestDiff) * f_Step); + + return f_Center + (bestDiff * f_Step); +} + +/** + * gcd() - Uses Euclid's algorithm + * + * @u, @v: Unsigned values whose GCD is desired. + * + * Returns THE greatest common divisor of u and v, if either value is 0, + * the other value is returned as the result. + */ +static u32 MT2063_gcd(u32 u, u32 v) +{ + u32 r; + + while (v != 0) { + r = u % v; + u = v; + v = r; + } + + return u; +} + +/** + * IsSpurInBand() - Checks to see if a spur will be present within the IF's + * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) + * + * ma mb mc md + * <--+-+-+-------------------+-------------------+-+-+--> + * | ^ 0 ^ | + * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ + * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 + * + * Note that some equations are doubled to prevent round-off + * problems when calculating fIFBW/2 + * + * @pAS_Info: Avoid Spurs information block + * @fm: If spur, amount f_IF1 has to move negative + * @fp: If spur, amount f_IF1 has to move positive + * + * Returns 1 if an LO spur would be present, otherwise 0. + */ +static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, + u32 *fm, u32 * fp) +{ + /* + ** Calculate LO frequency settings. + */ + u32 n, n0; + const u32 f_LO1 = pAS_Info->f_LO1; + const u32 f_LO2 = pAS_Info->f_LO2; + const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2; + const u32 c = d - pAS_Info->f_out_bw; + const u32 f = pAS_Info->f_zif_bw / 2; + const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1; + s32 f_nsLO1, f_nsLO2; + s32 f_Spur; + u32 ma, mb, mc, md, me, mf; + u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs; + + dprintk(2, "\n"); + + *fm = 0; + + /* + ** For each edge (d, c & f), calculate a scale, based on the gcd + ** of f_LO1, f_LO2 and the edge value. Use the larger of this + ** gcd-based scale factor or f_Scale. + */ + lo_gcd = MT2063_gcd(f_LO1, f_LO2); + gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale); + hgds = gd_Scale / 2; + gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale); + hgcs = gc_Scale / 2; + gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale); + hgfs = gf_Scale / 2; + + n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); + + /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */ + for (n = n0; n <= pAS_Info->maxH1; ++n) { + md = (n * ((f_LO1 + hgds) / gd_Scale) - + ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); + + /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */ + if (md >= pAS_Info->maxH1) + break; + + ma = (n * ((f_LO1 + hgds) / gd_Scale) + + ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); + + /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */ + if (md == ma) + continue; + + mc = (n * ((f_LO1 + hgcs) / gc_Scale) - + ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); + if (mc != md) { + f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale)); + f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale)); + f_Spur = + (gc_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale); + + *fp = ((f_Spur - (s32) c) / (mc - n)) + 1; + *fm = (((s32) d - f_Spur) / (mc - n)) + 1; + return 1; + } + + /* Location of Zero-IF-spur to be checked */ + me = (n * ((f_LO1 + hgfs) / gf_Scale) + + ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); + mf = (n * ((f_LO1 + hgfs) / gf_Scale) - + ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); + if (me != mf) { + f_nsLO1 = n * (f_LO1 / gf_Scale); + f_nsLO2 = me * (f_LO2 / gf_Scale); + f_Spur = + (gf_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale); + + *fp = ((f_Spur + (s32) f) / (me - n)) + 1; + *fm = (((s32) f - f_Spur) / (me - n)) + 1; + return 1; + } + + mb = (n * ((f_LO1 + hgcs) / gc_Scale) + + ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); + if (ma != mb) { + f_nsLO1 = n * (f_LO1 / gc_Scale); + f_nsLO2 = ma * (f_LO2 / gc_Scale); + f_Spur = + (gc_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale); + + *fp = (((s32) d + f_Spur) / (ma - n)) + 1; + *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1; + return 1; + } + } + + /* No spurs found */ + return 0; +} + +/* + * MT_AvoidSpurs() - Main entry point to avoid spurs. + * Checks for existing spurs in present LO1, LO2 freqs + * and if present, chooses spur-free LO1, LO2 combination + * that tunes the same input/output frequencies. + */ +static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + u32 status = 0; + u32 fm, fp; /* restricted range on LO's */ + pAS_Info->bSpurAvoided = 0; + pAS_Info->nSpursFound = 0; + + dprintk(2, "\n"); + + if (pAS_Info->maxH1 == 0) + return 0; + + /* + * Avoid LO Generated Spurs + * + * Make sure that have no LO-related spurs within the IF output + * bandwidth. + * + * If there is an LO spur in this band, start at the current IF1 frequency + * and work out until we find a spur-free frequency or run up against the + * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they + * will be unchanged if a spur-free setting is not found. + */ + pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); + if (pAS_Info->bSpurPresent) { + u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */ + u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */ + u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */ + u32 delta_IF1; + u32 new_IF1; + + /* + ** Spur was found, attempt to find a spur-free 1st IF + */ + do { + pAS_Info->nSpursFound++; + + /* Raise f_IF1_upper, if needed */ + MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp); + + /* Choose next IF1 that is closest to f_IF1_CENTER */ + new_IF1 = MT2063_ChooseFirstIF(pAS_Info); + + if (new_IF1 > zfIF1) { + pAS_Info->f_LO1 += (new_IF1 - zfIF1); + pAS_Info->f_LO2 += (new_IF1 - zfIF1); + } else { + pAS_Info->f_LO1 -= (zfIF1 - new_IF1); + pAS_Info->f_LO2 -= (zfIF1 - new_IF1); + } + zfIF1 = new_IF1; + + if (zfIF1 > pAS_Info->f_if1_Center) + delta_IF1 = zfIF1 - pAS_Info->f_if1_Center; + else + delta_IF1 = pAS_Info->f_if1_Center - zfIF1; + + pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); + /* + * Continue while the new 1st IF is still within the 1st IF bandwidth + * and there is a spur in the band (again) + */ + } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent); + + /* + * Use the LO-spur free values found. If the search went all + * the way to the 1st IF band edge and always found spurs, just + * leave the original choice. It's as "good" as any other. + */ + if (pAS_Info->bSpurPresent == 1) { + status |= MT2063_SPUR_PRESENT_ERR; + pAS_Info->f_LO1 = zfLO1; + pAS_Info->f_LO2 = zfLO2; + } else + pAS_Info->bSpurAvoided = 1; + } + + status |= + ((pAS_Info-> + nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK); + + return status; +} + +/* + * Constants used by the tuning algorithm + */ +#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */ +#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */ +#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */ +#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */ +#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */ +#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */ +#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */ +#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */ +#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */ +#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */ +#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */ +#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */ +#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */ +#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */ +#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */ +#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */ +#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */ +#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */ + +/* + * Define the supported Part/Rev codes for the MT2063 + */ +#define MT2063_B0 (0x9B) +#define MT2063_B1 (0x9C) +#define MT2063_B2 (0x9D) +#define MT2063_B3 (0x9E) + +/** + * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked + * + * @state: struct mt2063_state pointer + * + * 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) +{ + 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; + u32 nDelays = 0; + + dprintk(2, "\n"); + + /* LO2 Lock bit was in a different place for B0 version */ + if (state->tuner_id == MT2063_B0) + LO2LK = 0x40; + + do { + status = mt2063_read(state, MT2063_REG_LO_STATUS, + &state->reg[MT2063_REG_LO_STATUS], 1); + + if (status < 0) + return status; + + if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) == + (LO1LK | LO2LK)) { + return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO; + } + msleep(nPollRate); /* Wait between retries */ + } while (++nDelays < nMaxLoops); + + /* + * Got no lock or partial lock + */ + return 0; +} + +/* + * Constants for setting receiver modes. + * (6 modes defined at this time, enumerated by mt2063_delivery_sys) + * (DNC1GC & DNC2GC are the values, which are used, when the specific + * DNC Output is selected, the other is always off) + * + * enum mt2063_delivery_sys + * -------------+---------------------------------------------- + * Mode 0 : | MT2063_CABLE_QAM + * Mode 1 : | MT2063_CABLE_ANALOG + * Mode 2 : | MT2063_OFFAIR_COFDM + * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS + * Mode 4 : | MT2063_OFFAIR_ANALOG + * Mode 5 : | MT2063_OFFAIR_8VSB + * --------------+---------------------------------------------- + * + * |<---------- Mode -------------->| + * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | + * ------------+-----+-----+-----+-----+-----+-----+ + * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF + * LNARin | 0 | 0 | 3 | 3 | 3 | 3 + * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 + * FIFFq | 0 | 0 | 0 | 0 | 0 | 0 + * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 + * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 + * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 + * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 + * LNA Target | 44 | 43 | 43 | 43 | 43 | 43 + * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 + * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 + * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 + * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 + * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 + * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 + */ + +enum mt2063_delivery_sys { + MT2063_CABLE_QAM = 0, + MT2063_CABLE_ANALOG, + MT2063_OFFAIR_COFDM, + MT2063_OFFAIR_COFDM_SAWLESS, + MT2063_OFFAIR_ANALOG, + MT2063_OFFAIR_8VSB, + MT2063_NUM_RCVR_MODES +}; + +static const char *mt2063_mode_name[] = { + [MT2063_CABLE_QAM] = "digital cable", + [MT2063_CABLE_ANALOG] = "analog cable", + [MT2063_OFFAIR_COFDM] = "digital offair", + [MT2063_OFFAIR_COFDM_SAWLESS] = "digital offair without SAW", + [MT2063_OFFAIR_ANALOG] = "analog offair", + [MT2063_OFFAIR_8VSB] = "analog offair 8vsb", +}; + +static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 }; +static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 }; +static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 }; +static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 }; +static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 }; +static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 }; +static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 }; +static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 }; + +/* + * mt2063_set_dnc_output_enable() + */ +static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, + enum MT2063_DNC_Output_Enable *pValue) +{ + dprintk(2, "\n"); + + if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */ + if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ + *pValue = MT2063_DNC_NONE; + else + *pValue = MT2063_DNC_2; + } else { /* DNC1 is on */ + if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ + *pValue = MT2063_DNC_1; + else + *pValue = MT2063_DNC_BOTH; + } + return 0; +} + +/* + * mt2063_set_dnc_output_enable() + */ +static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, + enum MT2063_DNC_Output_Enable nValue) +{ + u32 status = 0; /* Status to be returned */ + u8 val = 0; + + dprintk(2, "\n"); + + /* selects, which DNC output is used */ + switch (nValue) { + case MT2063_DNC_NONE: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_1: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_2: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_BOTH: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + default: + break; + } + + return status; +} + +/* + * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with + * the selected enum mt2063_delivery_sys type. + * + * (DNC1GC & DNC2GC are the values, which are used, when the specific + * DNC Output is selected, the other is always off) + * + * @state: ptr to mt2063_state structure + * @Mode: desired reciever delivery system + * + * Note: Register cache must be valid for it to work + */ + +static u32 MT2063_SetReceiverMode(struct mt2063_state *state, + enum mt2063_delivery_sys Mode) +{ + u32 status = 0; /* Status to be returned */ + u8 val; + u32 longval; + + dprintk(2, "\n"); + + if (Mode >= MT2063_NUM_RCVR_MODES) + status = -ERANGE; + + /* RFAGCen */ + if (status >= 0) { + val = + (state-> + reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode] + ? 0x40 : + 0x00); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + /* LNARin */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) | + (LNARIN[Mode] & 0x03); + if (state->reg[MT2063_REG_CTRL_2C] != val) + status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); + } + + /* FIFFQEN and FIFFQ */ + if (status >= 0) { + val = + (state-> + reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) | + (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); + if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); + /* trigger FIFF calibration, needed after changing FIFFQ */ + val = + (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01); + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); + val = + (state-> + reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01); + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); + } + } + + /* DNC1GC & DNC2GC */ + status |= mt2063_get_dnc_output_enable(state, &longval); + status |= mt2063_set_dnc_output_enable(state, longval); + + /* acLNAmax */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) | + (ACLNAMAX[Mode] & 0x1F); + if (state->reg[MT2063_REG_LNA_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); + } + + /* LNATGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) | + (LNATGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_LNA_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); + } + + /* ACRF */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) | + (ACRFMAX[Mode] & 0x1F); + if (state->reg[MT2063_REG_RF_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); + } + + /* PD1TGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) | + (PD1TGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + /* FIFATN */ + if (status >= 0) { + u8 val = ACFIFMAX[Mode]; + if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) + val = 5; + val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) | + (val & 0x1F); + if (state->reg[MT2063_REG_FIF_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); + } + + /* PD2TGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) | + (PD2TGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_PD2_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); + } + + /* Ignore ATN Overload */ + if (status >= 0) { + val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) | + (RFOVDIS[Mode] ? 0x80 : 0x00); + if (state->reg[MT2063_REG_LNA_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); + } + + /* Ignore FIF Overload */ + if (status >= 0) { + val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) | + (FIFOVDIS[Mode] ? 0x80 : 0x00); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + if (status >= 0) { + state->rcvr_mode = Mode; + dprintk(1, "mt2063 mode changed to %s\n", + mt2063_mode_name[state->rcvr_mode]); + } + + return status; +} + +/* + * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various + * sections of the MT2063 + * + * @Bits: Mask bits to be cleared. + * + * See definition of MT2063_Mask_Bits type for description + * of each of the power bits. + */ +static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, + enum MT2063_Mask_Bits Bits) +{ + u32 status = 0; + + dprintk(2, "\n"); + Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ + if ((Bits & 0xFF00) != 0) { + state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8); + status |= + mt2063_write(state, + MT2063_REG_PWR_2, + &state->reg[MT2063_REG_PWR_2], 1); + } + if ((Bits & 0xFF) != 0) { + state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF); + status |= + mt2063_write(state, + MT2063_REG_PWR_1, + &state->reg[MT2063_REG_PWR_1], 1); + } + + return status; +} + +/* + * MT2063_SoftwareShutdown() - Enables or disables software shutdown function. + * When Shutdown is 1, any section whose power + * mask is set will be shutdown. + */ +static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) +{ + u32 status; + + dprintk(2, "\n"); + if (Shutdown == 1) + state->reg[MT2063_REG_PWR_1] |= 0x04; + else + state->reg[MT2063_REG_PWR_1] &= ~0x04; + + status = mt2063_write(state, + MT2063_REG_PWR_1, + &state->reg[MT2063_REG_PWR_1], 1); + + if (Shutdown != 1) { + state->reg[MT2063_REG_BYP_CTRL] = + (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40; + status |= + mt2063_write(state, + MT2063_REG_BYP_CTRL, + &state->reg[MT2063_REG_BYP_CTRL], + 1); + state->reg[MT2063_REG_BYP_CTRL] = + (state->reg[MT2063_REG_BYP_CTRL] & 0x9F); + status |= + mt2063_write(state, + MT2063_REG_BYP_CTRL, + &state->reg[MT2063_REG_BYP_CTRL], + 1); + } + + return status; +} + +static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) +{ + return f_ref * (f_LO / f_ref) + + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step); +} + +/** + * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom. + * This function preserves maximum precision without + * risk of overflow. It accurately calculates + * f_ref * num / denom to within 1 HZ with fixed math. + * + * @num : Fractional portion of the multiplier + * @denom: denominator portion of the ratio + * @f_Ref: SRO frequency. + * + * This calculation handles f_ref as two separate 14-bit fields. + * Therefore, a maximum value of 2^28-1 may safely be used for f_ref. + * This is the genesis of the magic number "14" and the magic mask value of + * 0x03FFF. + * + * This routine successfully handles denom values up to and including 2^18. + * Returns: f_ref * num / denom + */ +static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) +{ + u32 t1 = (f_ref >> 14) * num; + u32 term1 = t1 / denom; + u32 loss = t1 % denom; + u32 term2 = + (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom; + return (term1 << 14) + term2; +} + +/* + * CalcLO1Mult()- Calculates Integer divider value and the numerator + * value for a FracN PLL. + * + * This function assumes that the f_LO and f_Ref are + * evenly divisible by f_LO_Step. + * + * @Div: OUTPUT: Whole number portion of the multiplier + * @FracN: OUTPUT: Fractional portion of the multiplier + * @f_LO: desired LO frequency. + * @f_LO_Step: Minimum step size for the LO (in Hz). + * @f_Ref: SRO frequency. + * @f_Avoid: Range of PLL frequencies to avoid near integer multiples + * of f_Ref (in Hz). + * + * Returns: Recalculated LO frequency. + */ +static u32 MT2063_CalcLO1Mult(u32 *Div, + u32 *FracN, + u32 f_LO, + u32 f_LO_Step, u32 f_Ref) +{ + /* Calculate the whole number portion of the divider */ + *Div = f_LO / f_Ref; + + /* Calculate the numerator value (round to nearest f_LO_Step) */ + *FracN = + (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + + (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); + + return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64); +} + +/** + * CalcLO2Mult() - Calculates Integer divider value and the numerator + * value for a FracN PLL. + * + * This function assumes that the f_LO and f_Ref are + * evenly divisible by f_LO_Step. + * + * @Div: OUTPUT: Whole number portion of the multiplier + * @FracN: OUTPUT: Fractional portion of the multiplier + * @f_LO: desired LO frequency. + * @f_LO_Step: Minimum step size for the LO (in Hz). + * @f_Ref: SRO frequency. + * @f_Avoid: Range of PLL frequencies to avoid near + * integer multiples of f_Ref (in Hz). + * + * Returns: Recalculated LO frequency. + */ +static u32 MT2063_CalcLO2Mult(u32 *Div, + u32 *FracN, + u32 f_LO, + u32 f_LO_Step, u32 f_Ref) +{ + /* Calculate the whole number portion of the divider */ + *Div = f_LO / f_Ref; + + /* Calculate the numerator value (round to nearest f_LO_Step) */ + *FracN = + (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + + (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); + + return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, + 8191); +} + +/* + * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be + * used for a given input frequency. + * + * @state: ptr to tuner data structure + * @f_in: RF input center frequency (in Hz). + * + * Returns: ClearTune filter number (0-31) + */ +static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) +{ + u32 RFBand; + u32 idx; /* index loop */ + + /* + ** Find RF Band setting + */ + RFBand = 31; /* def when f_in > all */ + for (idx = 0; idx < 31; ++idx) { + if (state->CTFiltMax[idx] >= f_in) { + RFBand = idx; + break; + } + } + return RFBand; +} + +/* + * MT2063_Tune() - Change the tuner's tuned frequency to RFin. + */ +static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) +{ /* RF input center frequency */ + + u32 status = 0; + u32 LO1; /* 1st LO register value */ + u32 Num1; /* Numerator for LO1 reg. value */ + u32 f_IF1; /* 1st IF requested */ + u32 LO2; /* 2nd LO register value */ + u32 Num2; /* Numerator for LO2 reg. value */ + u32 ofLO1, ofLO2; /* last time's LO frequencies */ + u8 fiffc = 0x80; /* FIFF center freq from tuner */ + u32 fiffof; /* Offset from FIFF center freq */ + const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */ + u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */ + u8 val; + u32 RFBand; + + dprintk(2, "\n"); + /* Check the input and output frequency ranges */ + if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ)) + return -EINVAL; + + if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ) + || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ)) + return -EINVAL; + + /* + * Save original LO1 and LO2 register values + */ + ofLO1 = state->AS_Data.f_LO1; + ofLO2 = state->AS_Data.f_LO2; + + /* + * Find and set RF Band setting + */ + if (state->ctfilt_sw == 1) { + val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08); + if (state->reg[MT2063_REG_CTUNE_CTRL] != val) { + status |= + mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val); + } + val = state->reg[MT2063_REG_CTUNE_OV]; + RFBand = FindClearTuneFilter(state, f_in); + state->reg[MT2063_REG_CTUNE_OV] = + (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F) + | RFBand); + if (state->reg[MT2063_REG_CTUNE_OV] != val) { + status |= + mt2063_setreg(state, MT2063_REG_CTUNE_OV, val); + } + } + + /* + * Read the FIFF Center Frequency from the tuner + */ + if (status >= 0) { + status |= + mt2063_read(state, + MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + fiffc = state->reg[MT2063_REG_FIFFC]; + } + /* + * Assign in the requested values + */ + state->AS_Data.f_in = f_in; + /* Request a 1st IF such that LO1 is on a step size */ + state->AS_Data.f_if1_Request = + MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in, + state->AS_Data.f_LO1_Step, + state->AS_Data.f_ref) - f_in; + + /* + * Calculate frequency settings. f_IF1_FREQ + f_in is the + * desired LO1 frequency + */ + MT2063_ResetExclZones(&state->AS_Data); + + f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data); + + state->AS_Data.f_LO1 = + MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step, + state->AS_Data.f_ref); + + state->AS_Data.f_LO2 = + MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + + /* + * Check for any LO spurs in the output bandwidth and adjust + * the LO settings to avoid them if needed + */ + status |= MT2063_AvoidSpurs(&state->AS_Data); + /* + * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values. + * Recalculate the LO frequencies and the values to be placed + * in the tuning registers. + */ + state->AS_Data.f_LO1 = + MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1, + state->AS_Data.f_LO1_Step, state->AS_Data.f_ref); + state->AS_Data.f_LO2 = + MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + state->AS_Data.f_LO2 = + MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + + /* + * Check the upconverter and downconverter frequency ranges + */ + if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ) + || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ)) + status |= MT2063_UPC_RANGE; + if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ) + || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ)) + status |= MT2063_DNC_RANGE; + /* LO2 Lock bit was in a different place for B0 version */ + if (state->tuner_id == MT2063_B0) + LO2LK = 0x40; + + /* + * If we have the same LO frequencies and we're already locked, + * then skip re-programming the LO registers. + */ + if ((ofLO1 != state->AS_Data.f_LO1) + || (ofLO2 != state->AS_Data.f_LO2) + || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) != + (LO1LK | LO2LK))) { + /* + * Calculate the FIFFOF register value + * + * IF1_Actual + * FIFFOF = ------------ - 8 * FIFFC - 4992 + * f_ref/64 + */ + fiffof = + (state->AS_Data.f_LO1 - + f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc - + 4992; + if (fiffof > 0xFF) + fiffof = 0xFF; + + /* + * Place all of the calculated values into the local tuner + * register fields. + */ + if (status >= 0) { + state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */ + state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */ + state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */ + |(Num2 >> 12)); /* NUM2q (hi) */ + state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */ + state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */ + + /* + * Now write out the computed register values + * IMPORTANT: There is a required order for writing + * (0x05 must follow all the others). + */ + status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */ + if (state->tuner_id == MT2063_B0) { + /* Re-write the one-shot bits to trigger the tune operation */ + status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */ + } + /* Write out the FIFF offset only if it's changing */ + if (state->reg[MT2063_REG_FIFF_OFFSET] != + (u8) fiffof) { + state->reg[MT2063_REG_FIFF_OFFSET] = + (u8) fiffof; + status |= + mt2063_write(state, + MT2063_REG_FIFF_OFFSET, + &state-> + reg[MT2063_REG_FIFF_OFFSET], + 1); + } + } + + /* + * Check for LO's locking + */ + + if (status < 0) + return status; + + status = mt2063_lockStatus(state); + if (status < 0) + return status; + if (!status) + return -EINVAL; /* Couldn't lock */ + + /* + * If we locked OK, assign calculated data to mt2063_state structure + */ + state->f_IF1_actual = state->AS_Data.f_LO1 - f_in; + } + + return status; +} + +static const u8 MT2063B0_defaults[] = { + /* Reg, Value */ + 0x19, 0x05, + 0x1B, 0x1D, + 0x1C, 0x1F, + 0x1D, 0x0F, + 0x1E, 0x3F, + 0x1F, 0x0F, + 0x20, 0x3F, + 0x22, 0x21, + 0x23, 0x3F, + 0x24, 0x20, + 0x25, 0x3F, + 0x27, 0xEE, + 0x2C, 0x27, /* bit at 0x20 is cleared below */ + 0x30, 0x03, + 0x2C, 0x07, /* bit at 0x20 is cleared here */ + 0x2D, 0x87, + 0x2E, 0xAA, + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ +static const u8 MT2063B1_defaults[] = { + /* Reg, Value */ + 0x05, 0xF0, + 0x11, 0x10, /* New Enable AFCsd */ + 0x19, 0x05, + 0x1A, 0x6C, + 0x1B, 0x24, + 0x1C, 0x28, + 0x1D, 0x8F, + 0x1E, 0x14, + 0x1F, 0x8F, + 0x20, 0x57, + 0x22, 0x21, /* New - ver 1.03 */ + 0x23, 0x3C, /* New - ver 1.10 */ + 0x24, 0x20, /* New - ver 1.03 */ + 0x2C, 0x24, /* bit at 0x20 is cleared below */ + 0x2D, 0x87, /* FIFFQ=0 */ + 0x2F, 0xF3, + 0x30, 0x0C, /* New - ver 1.11 */ + 0x31, 0x1B, /* New - ver 1.11 */ + 0x2C, 0x04, /* bit at 0x20 is cleared here */ + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ +static const u8 MT2063B3_defaults[] = { + /* Reg, Value */ + 0x05, 0xF0, + 0x19, 0x3D, + 0x2C, 0x24, /* bit at 0x20 is cleared below */ + 0x2C, 0x04, /* bit at 0x20 is cleared here */ + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +static int mt2063_init(struct dvb_frontend *fe) +{ + u32 status; + struct mt2063_state *state = fe->tuner_priv; + u8 all_resets = 0xF0; /* reset/load bits */ + const u8 *def = NULL; + char *step; + u32 FCRUN; + s32 maxReads; + u32 fcu_osc; + u32 i; + + dprintk(2, "\n"); + + state->rcvr_mode = MT2063_CABLE_QAM; + + /* Read the Part/Rev code from the tuner */ + status = mt2063_read(state, MT2063_REG_PART_REV, + &state->reg[MT2063_REG_PART_REV], 1); + if (status < 0) { + printk(KERN_ERR "Can't read mt2063 part ID\n"); + return status; + } + + /* Check the part/rev code */ + switch (state->reg[MT2063_REG_PART_REV]) { + case MT2063_B0: + step = "B0"; + break; + case MT2063_B1: + step = "B1"; + break; + case MT2063_B2: + step = "B2"; + break; + case MT2063_B3: + step = "B3"; + break; + default: + printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n", + state->reg[MT2063_REG_PART_REV]); + return -ENODEV; /* Wrong tuner Part/Rev code */ + } + + /* Check the 2nd byte of the Part/Rev code from the tuner */ + status = mt2063_read(state, MT2063_REG_RSVD_3B, + &state->reg[MT2063_REG_RSVD_3B], 1); + + /* b7 != 0 ==> NOT MT2063 */ + if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) { + printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n", + state->reg[MT2063_REG_PART_REV], + state->reg[MT2063_REG_RSVD_3B]); + return -ENODEV; /* Wrong tuner Part/Rev code */ + } + + printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step); + + /* Reset the tuner */ + status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1); + if (status < 0) + return status; + + /* change all of the default values that vary from the HW reset values */ + /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */ + switch (state->reg[MT2063_REG_PART_REV]) { + case MT2063_B3: + def = MT2063B3_defaults; + break; + + case MT2063_B1: + def = MT2063B1_defaults; + break; + + case MT2063_B0: + def = MT2063B0_defaults; + break; + + default: + return -ENODEV; + break; + } + + while (status >= 0 && *def) { + u8 reg = *def++; + u8 val = *def++; + status = mt2063_write(state, reg, &val, 1); + } + if (status < 0) + return status; + + /* Wait for FIFF location to complete. */ + FCRUN = 1; + maxReads = 10; + while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) { + msleep(2); + status = mt2063_read(state, + MT2063_REG_XO_STATUS, + &state-> + reg[MT2063_REG_XO_STATUS], 1); + FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6; + } + + if (FCRUN != 0 || status < 0) + return -ENODEV; + + status = mt2063_read(state, + MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + if (status < 0) + return status; + + /* Read back all the registers from the tuner */ + status = mt2063_read(state, + MT2063_REG_PART_REV, + state->reg, MT2063_REG_END_REGS); + if (status < 0) + return status; + + /* Initialize the tuner state. */ + state->tuner_id = state->reg[MT2063_REG_PART_REV]; + state->AS_Data.f_ref = MT2063_REF_FREQ; + state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) * + ((u32) state->reg[MT2063_REG_FIFFC] + 640); + state->AS_Data.f_if1_bw = MT2063_IF1_BW; + state->AS_Data.f_out = 43750000UL; + state->AS_Data.f_out_bw = 6750000UL; + state->AS_Data.f_zif_bw = MT2063_ZIF_BW; + state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64; + state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE; + state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1; + state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2; + state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP; + state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center; + state->AS_Data.f_LO1 = 2181000000UL; + state->AS_Data.f_LO2 = 1486249786UL; + state->f_IF1_actual = state->AS_Data.f_if1_Center; + state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual; + state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID; + state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID; + state->num_regs = MT2063_REG_END_REGS; + state->AS_Data.avoidDECT = MT2063_AVOID_BOTH; + state->ctfilt_sw = 0; + + state->CTFiltMax[0] = 69230000; + state->CTFiltMax[1] = 105770000; + state->CTFiltMax[2] = 140350000; + state->CTFiltMax[3] = 177110000; + state->CTFiltMax[4] = 212860000; + state->CTFiltMax[5] = 241130000; + state->CTFiltMax[6] = 274370000; + state->CTFiltMax[7] = 309820000; + state->CTFiltMax[8] = 342450000; + state->CTFiltMax[9] = 378870000; + state->CTFiltMax[10] = 416210000; + state->CTFiltMax[11] = 456500000; + state->CTFiltMax[12] = 495790000; + state->CTFiltMax[13] = 534530000; + state->CTFiltMax[14] = 572610000; + state->CTFiltMax[15] = 598970000; + state->CTFiltMax[16] = 635910000; + state->CTFiltMax[17] = 672130000; + state->CTFiltMax[18] = 714840000; + state->CTFiltMax[19] = 739660000; + state->CTFiltMax[20] = 770410000; + state->CTFiltMax[21] = 814660000; + state->CTFiltMax[22] = 846950000; + state->CTFiltMax[23] = 867820000; + state->CTFiltMax[24] = 915980000; + state->CTFiltMax[25] = 947450000; + state->CTFiltMax[26] = 983110000; + state->CTFiltMax[27] = 1021630000; + state->CTFiltMax[28] = 1061870000; + state->CTFiltMax[29] = 1098330000; + state->CTFiltMax[30] = 1138990000; + + /* + ** Fetch the FCU osc value and use it and the fRef value to + ** scale all of the Band Max values + */ + + state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A; + status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, + &state->reg[MT2063_REG_CTUNE_CTRL], 1); + if (status < 0) + return status; + + /* Read the ClearTune filter calibration value */ + status = mt2063_read(state, MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + if (status < 0) + return status; + + fcu_osc = state->reg[MT2063_REG_FIFFC]; + + state->reg[MT2063_REG_CTUNE_CTRL] = 0x00; + status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, + &state->reg[MT2063_REG_CTUNE_CTRL], 1); + if (status < 0) + return status; + + /* Adjust each of the values in the ClearTune filter cross-over table */ + for (i = 0; i < 31; i++) + state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640); + + status = MT2063_SoftwareShutdown(state, 1); + if (status < 0) + return status; + status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); + if (status < 0) + return status; + + state->init = true; + + return 0; +} + +static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) +{ + struct mt2063_state *state = fe->tuner_priv; + int status; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *tuner_status = 0; + status = mt2063_lockStatus(state); + if (status < 0) + return status; + if (status) + *tuner_status = TUNER_STATUS_LOCKED; + + dprintk(1, "Tuner status: %d", *tuner_status); + + return 0; +} + +static int mt2063_release(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + fe->tuner_priv = NULL; + kfree(state); + + return 0; +} + +static int mt2063_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct mt2063_state *state = fe->tuner_priv; + s32 pict_car; + s32 pict2chanb_vsb; + s32 ch_bw; + s32 if_mid; + s32 rcvr_mode; + int status; + + dprintk(2, "\n"); + + if (!state->init) { + status = mt2063_init(fe); + if (status < 0) + return status; + } + + switch (params->mode) { + case V4L2_TUNER_RADIO: + pict_car = 38900000; + ch_bw = 8000000; + pict2chanb_vsb = -(ch_bw / 2); + rcvr_mode = MT2063_OFFAIR_ANALOG; + break; + case V4L2_TUNER_ANALOG_TV: + rcvr_mode = MT2063_CABLE_ANALOG; + if (params->std & ~V4L2_STD_MN) { + pict_car = 38900000; + ch_bw = 6000000; + pict2chanb_vsb = -1250000; + } else if (params->std & V4L2_STD_PAL_G) { + pict_car = 38900000; + ch_bw = 7000000; + pict2chanb_vsb = -1250000; + } else { /* PAL/SECAM standards */ + pict_car = 38900000; + ch_bw = 8000000; + pict2chanb_vsb = -1250000; + } + break; + default: + return -EINVAL; + } + if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); + + state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ + state->AS_Data.f_out = if_mid; + state->AS_Data.f_out_bw = ch_bw + 750000; + status = MT2063_SetReceiverMode(state, rcvr_mode); + if (status < 0) + return status; + + dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", + params->frequency, ch_bw, pict2chanb_vsb); + + status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2)))); + if (status < 0) + return status; + + state->frequency = params->frequency; + return 0; +} + +/* + * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. + * So, the amount of the needed bandwith is given by: + * Bw = Symbol_rate * (1 + 0.15) + * As such, the maximum symbol rate supported by 6 MHz is given by: + * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds + */ +#define MAX_SYMBOL_RATE_6MHz 5217391 + +static int mt2063_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct mt2063_state *state = fe->tuner_priv; + int status; + s32 pict_car; + s32 pict2chanb_vsb; + s32 ch_bw; + s32 if_mid; + s32 rcvr_mode; + + if (!state->init) { + status = mt2063_init(fe); + if (status < 0) + return status; + } + + dprintk(2, "\n"); + + if (c->bandwidth_hz == 0) + return -EINVAL; + if (c->bandwidth_hz <= 6000000) + ch_bw = 6000000; + else if (c->bandwidth_hz <= 7000000) + ch_bw = 7000000; + else + ch_bw = 8000000; + + switch (c->delivery_system) { + case SYS_DVBT: + rcvr_mode = MT2063_OFFAIR_COFDM; + pict_car = 36125000; + pict2chanb_vsb = -(ch_bw / 2); + break; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + rcvr_mode = MT2063_CABLE_QAM; + pict_car = 36125000; + pict2chanb_vsb = -(ch_bw / 2); + break; + default: + return -EINVAL; + } + if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); + + state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ + state->AS_Data.f_out = if_mid; + state->AS_Data.f_out_bw = ch_bw + 750000; + status = MT2063_SetReceiverMode(state, rcvr_mode); + if (status < 0) + return status; + + dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", + c->frequency, ch_bw, pict2chanb_vsb); + + status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2)))); + + if (status < 0) + return status; + + state->frequency = c->frequency; + return 0; +} + +static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *freq = state->AS_Data.f_out; + + dprintk(1, "IF frequency: %d\n", *freq); + + return 0; +} + +static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *bw = state->AS_Data.f_out_bw - 750000; + + dprintk(1, "bandwidth: %d\n", *bw); + + return 0; +} + +static struct dvb_tuner_ops mt2063_ops = { + .info = { + .name = "MT2063 Silicon Tuner", + .frequency_min = 45000000, + .frequency_max = 850000000, + .frequency_step = 0, + }, + + .init = mt2063_init, + .sleep = MT2063_Sleep, + .get_status = mt2063_get_status, + .set_analog_params = mt2063_set_analog_params, + .set_params = mt2063_set_params, + .get_if_frequency = mt2063_get_if_frequency, + .get_bandwidth = mt2063_get_bandwidth, + .release = mt2063_release, +}; + +struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c) +{ + struct mt2063_state *state = NULL; + + dprintk(2, "\n"); + + state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->config = config; + state->i2c = i2c; + state->frontend = fe; + state->reference = config->refclock / 1000; /* kHz */ + fe->tuner_priv = state; + fe->ops.tuner_ops = mt2063_ops; + + printk(KERN_INFO "%s: Attaching MT2063\n", __func__); + return fe; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL_GPL(mt2063_attach); + +/* + * Ancillary routines visible outside mt2063 + * FIXME: Remove them in favor of using standard tuner callbacks + */ +unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + int err = 0; + + dprintk(2, "\n"); + + err = MT2063_SoftwareShutdown(state, 1); + if (err < 0) + printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); + + return err; +} +EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); + +unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + int err = 0; + + dprintk(2, "\n"); + + err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); + if (err < 0) + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + + return err; +} +EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); + +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_DESCRIPTION("MT2063 Silicon tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h new file mode 100644 index 000000000000..62d0e8ec4e99 --- /dev/null +++ b/drivers/media/common/tuners/mt2063.h @@ -0,0 +1,36 @@ +#ifndef __MT2063_H__ +#define __MT2063_H__ + +#include "dvb_frontend.h" + +struct mt2063_config { + u8 tuner_address; + u32 refclock; +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE)) +struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, + u32 bw_in, + enum MTTune_atv_standard tv_type); + +/* 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/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c index a4f830bb25d1..f83b0c1ea6c8 100644 --- a/drivers/media/common/tuners/mt2131.c +++ b/drivers/media/common/tuners/mt2131.c @@ -92,9 +92,9 @@ static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) return 0; } -static int mt2131_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mt2131_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct mt2131_priv *priv; int ret=0, i; u32 freq; @@ -105,12 +105,8 @@ static int mt2131_set_params(struct dvb_frontend *fe, u8 lockval = 0; priv = fe->tuner_priv; - if (fe->ops.info.type == FE_OFDM) - priv->bandwidth = params->u.ofdm.bandwidth; - else - priv->bandwidth = 0; - freq = params->frequency / 1000; // Hz -> kHz + freq = c->frequency / 1000; /* Hz -> kHz */ dprintk(1, "%s() freq=%d\n", __func__, freq); f_lo1 = freq + MT2131_IF1 * 1000; @@ -193,14 +189,6 @@ static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mt2131_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - *bandwidth = priv->bandwidth; - return 0; -} - static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) { struct mt2131_priv *priv = fe->tuner_priv; @@ -263,7 +251,6 @@ static const struct dvb_tuner_ops mt2131_tuner_ops = { .set_params = mt2131_set_params, .get_frequency = mt2131_get_frequency, - .get_bandwidth = mt2131_get_bandwidth, .get_status = mt2131_get_status }; @@ -281,7 +268,6 @@ struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, return NULL; priv->cfg = cfg; - priv->bandwidth = 6000000; /* 6MHz */ priv->i2c = i2c; if (mt2131_readreg(priv, 0, &id) != 0) { diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h index 4e05a67e88c1..62aeedf5c550 100644 --- a/drivers/media/common/tuners/mt2131_priv.h +++ b/drivers/media/common/tuners/mt2131_priv.h @@ -38,7 +38,6 @@ struct mt2131_priv { struct i2c_adapter *i2c; u32 frequency; - u32 bandwidth; }; #endif /* __MT2131_PRIV_H__ */ diff --git a/drivers/media/common/tuners/mt2266.c b/drivers/media/common/tuners/mt2266.c index 25a8ea342c46..bca4d75e42d4 100644 --- a/drivers/media/common/tuners/mt2266.c +++ b/drivers/media/common/tuners/mt2266.c @@ -122,8 +122,9 @@ static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, #define FREF 30000 // Quartz oscillator 30 MHz -static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int mt2266_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct mt2266_priv *priv; int ret=0; u32 freq; @@ -135,32 +136,32 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame priv = fe->tuner_priv; - freq = params->frequency / 1000; // Hz -> kHz + freq = priv->frequency / 1000; /* Hz -> kHz */ if (freq < 470000 && freq > 230000) return -EINVAL; /* Gap between VHF and UHF bands */ - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - priv->frequency = freq * 1000; + priv->frequency = c->frequency; tune = 2 * freq * (8192/16) / (FREF/16); band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; if (band == MT2266_VHF) tune *= 2; - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: mt2266_writeregs(priv, mt2266_init_6mhz, sizeof(mt2266_init_6mhz)); break; - case BANDWIDTH_7_MHZ: - mt2266_writeregs(priv, mt2266_init_7mhz, - sizeof(mt2266_init_7mhz)); - break; - case BANDWIDTH_8_MHZ: - default: + case 8000000: mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); break; + case 7000000: + default: + mt2266_writeregs(priv, mt2266_init_7mhz, + sizeof(mt2266_init_7mhz)); + break; } + priv->bandwidth = c->bandwidth_hz; if (band == MT2266_VHF && priv->band == MT2266_UHF) { dprintk("Switch from UHF to VHF"); diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c index 54be9e6faaaf..6133315fb0e3 100644 --- a/drivers/media/common/tuners/mxl5005s.c +++ b/drivers/media/common/tuners/mxl5005s.c @@ -3979,54 +3979,47 @@ static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, return 0; } -static int mxl5005s_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mxl5005s_set_params(struct dvb_frontend *fe) { struct mxl5005s_state *state = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; u32 req_mode, req_bw = 0; int ret; dprintk(1, "%s()\n", __func__); - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - req_mode = MXL_ATSC; break; - default: - case QAM_64: - case QAM_256: - case QAM_AUTO: - req_mode = MXL_QAM; break; - } - } else + switch (delsys) { + case SYS_ATSC: + req_mode = MXL_ATSC; + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case SYS_DVBC_ANNEX_B: + req_mode = MXL_QAM; + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + default: /* Assume DVB-T */ req_mode = MXL_DVBT; - - /* Change tuner for new modulation type if reqd */ - if (req_mode != state->current_mode) { - switch (req_mode) { - case MXL_ATSC: - case MXL_QAM: - req_bw = MXL5005S_BANDWIDTH_6MHZ; + switch (bw) { + case 6000000: + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case 7000000: + req_bw = MXL5005S_BANDWIDTH_7MHZ; + break; + case 8000000: + case 0: + req_bw = MXL5005S_BANDWIDTH_8MHZ; break; - case MXL_DVBT: default: - /* Assume DVB-T */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - req_bw = MXL5005S_BANDWIDTH_6MHZ; - break; - case BANDWIDTH_7_MHZ: - req_bw = MXL5005S_BANDWIDTH_7MHZ; - break; - case BANDWIDTH_AUTO: - case BANDWIDTH_8_MHZ: - req_bw = MXL5005S_BANDWIDTH_8MHZ; - break; - default: - return -EINVAL; - } + return -EINVAL; } + } + /* Change tuner for new modulation type if reqd */ + if (req_mode != state->current_mode || + req_bw != state->Chan_Bandwidth) { state->current_mode = req_mode; ret = mxl5005s_reconfigure(fe, req_mode, req_bw); @@ -4034,8 +4027,8 @@ static int mxl5005s_set_params(struct dvb_frontend *fe, ret = 0; if (ret == 0) { - dprintk(1, "%s() freq=%d\n", __func__, params->frequency); - ret = mxl5005s_SetRfFreqHz(fe, params->frequency); + dprintk(1, "%s() freq=%d\n", __func__, c->frequency); + ret = mxl5005s_SetRfFreqHz(fe, c->frequency); } return ret; diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c index 5d02221e99dd..69e453ef0a1a 100644 --- a/drivers/media/common/tuners/mxl5007t.c +++ b/drivers/media/common/tuners/mxl5007t.c @@ -165,6 +165,8 @@ struct mxl5007t_state { struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; + enum mxl5007t_if_freq if_freq; + u32 frequency; u32 bandwidth; }; @@ -286,6 +288,8 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, /* set inverted IF or normal IF */ set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); + state->if_freq = if_freq; + return; } @@ -612,47 +616,43 @@ fail: /* ------------------------------------------------------------------------- */ -static int mxl5007t_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mxl5007t_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; struct mxl5007t_state *state = fe->tuner_priv; enum mxl5007t_bw_mhz bw; enum mxl5007t_mode mode; int ret; - u32 freq = params->frequency; + u32 freq = c->frequency; - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - mode = MxL_MODE_ATSC; - break; - case QAM_64: - case QAM_256: - mode = MxL_MODE_CABLE; - break; - default: - mxl_err("modulation not set!"); - return -EINVAL; - } + switch (delsys) { + case SYS_ATSC: + mode = MxL_MODE_ATSC; + bw = MxL_BW_6MHz; + break; + case SYS_DVBC_ANNEX_B: + mode = MxL_MODE_CABLE; bw = MxL_BW_6MHz; - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + break; + case SYS_DVBT: + case SYS_DVBT2: + mode = MxL_MODE_DVBT; + switch (c->bandwidth_hz) { + case 6000000: bw = MxL_BW_6MHz; break; - case BANDWIDTH_7_MHZ: + case 7000000: bw = MxL_BW_7MHz; break; - case BANDWIDTH_8_MHZ: + case 8000000: bw = MxL_BW_8MHz; break; default: - mxl_err("bandwidth not set!"); return -EINVAL; } - mode = MxL_MODE_DVBT; - } else { + break; + default: mxl_err("modulation type not supported!"); return -EINVAL; } @@ -671,8 +671,7 @@ static int mxl5007t_set_params(struct dvb_frontend *fe, goto fail; state->frequency = freq; - state->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; + state->bandwidth = c->bandwidth_hz; fail: mutex_unlock(&state->lock); @@ -738,6 +737,50 @@ static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5007t_state *state = fe->tuner_priv; + + *frequency = 0; + + switch (state->if_freq) { + case MxL_IF_4_MHZ: + *frequency = 4000000; + break; + case MxL_IF_4_5_MHZ: + *frequency = 4500000; + break; + case MxL_IF_4_57_MHZ: + *frequency = 4570000; + break; + case MxL_IF_5_MHZ: + *frequency = 5000000; + break; + case MxL_IF_5_38_MHZ: + *frequency = 5380000; + break; + case MxL_IF_6_MHZ: + *frequency = 6000000; + break; + case MxL_IF_6_28_MHZ: + *frequency = 6280000; + break; + case MxL_IF_9_1915_MHZ: + *frequency = 9191500; + break; + case MxL_IF_35_25_MHZ: + *frequency = 35250000; + break; + case MxL_IF_36_15_MHZ: + *frequency = 36150000; + break; + case MxL_IF_44_MHZ: + *frequency = 44000000; + break; + } + return 0; +} + static int mxl5007t_release(struct dvb_frontend *fe) { struct mxl5007t_state *state = fe->tuner_priv; @@ -767,6 +810,7 @@ static struct dvb_tuner_ops mxl5007t_tuner_ops = { .get_frequency = mxl5007t_get_frequency, .get_bandwidth = mxl5007t_get_bandwidth, .release = mxl5007t_release, + .get_if_frequency = mxl5007t_get_if_frequency, }; static int mxl5007t_get_chip_id(struct mxl5007t_state *state) diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c index 9f5dba244cb8..2d79b1f5d5eb 100644 --- a/drivers/media/common/tuners/qt1010.c +++ b/drivers/media/common/tuners/qt1010.c @@ -82,9 +82,9 @@ static void qt1010_dump_regs(struct qt1010_priv *priv) printk(KERN_CONT "\n"); } -static int qt1010_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int qt1010_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct qt1010_priv *priv; int err; u32 freq, div, mod1, mod2; @@ -144,13 +144,11 @@ static int qt1010_set_params(struct dvb_frontend *fe, #define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ priv = fe->tuner_priv; - freq = params->frequency; + freq = c->frequency; div = (freq + QT1010_OFFSET) / QT1010_STEP; freq = (div * QT1010_STEP) - QT1010_OFFSET; mod1 = (freq + QT1010_OFFSET) % FREQ1; mod2 = (freq + QT1010_OFFSET) % FREQ2; - priv->bandwidth = - (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; priv->frequency = freq; if (fe->ops.i2c_gate_ctrl) @@ -320,7 +318,7 @@ static u8 qt1010_init_meas2(struct qt1010_priv *priv, static int qt1010_init(struct dvb_frontend *fe) { struct qt1010_priv *priv = fe->tuner_priv; - struct dvb_frontend_parameters params; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int err = 0; u8 i, tmpval, *valptr = NULL; @@ -397,9 +395,9 @@ static int qt1010_init(struct dvb_frontend *fe) if ((err = qt1010_init_meas2(priv, i, &tmpval))) return err; - params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */ + c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */ /* MSI Megasky 580 GL861 533000000 */ - return qt1010_set_params(fe, ¶ms); + return qt1010_set_params(fe); } static int qt1010_release(struct dvb_frontend *fe) @@ -416,10 +414,9 @@ static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct qt1010_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; + *frequency = 36125000; return 0; } @@ -437,7 +434,7 @@ static const struct dvb_tuner_ops qt1010_tuner_ops = { .set_params = qt1010_set_params, .get_frequency = qt1010_get_frequency, - .get_bandwidth = qt1010_get_bandwidth + .get_if_frequency = qt1010_get_if_frequency, }; struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, diff --git a/drivers/media/common/tuners/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h index 090cf475f099..2c42d3f01636 100644 --- a/drivers/media/common/tuners/qt1010_priv.h +++ b/drivers/media/common/tuners/qt1010_priv.h @@ -99,7 +99,6 @@ struct qt1010_priv { u8 reg25_init_val; u32 frequency; - u32 bandwidth; }; #endif diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c index e29cc2bc113a..602c2e392b17 100644 --- a/drivers/media/common/tuners/tda18212.c +++ b/drivers/media/common/tuners/tda18212.c @@ -25,6 +25,8 @@ struct tda18212_priv { struct tda18212_config *cfg; struct i2c_adapter *i2c; + + u32 if_frequency; }; #define dbg(fmt, arg...) \ @@ -128,20 +130,31 @@ static void tda18212_dump_regs(struct tda18212_priv *priv) } #endif -static int tda18212_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int tda18212_set_params(struct dvb_frontend *fe) { struct tda18212_priv *priv = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u32 if_khz; u8 buf[9]; + #define DVBT_6 0 + #define DVBT_7 1 + #define DVBT_8 2 + #define DVBT2_6 3 + #define DVBT2_7 4 + #define DVBT2_8 5 + #define DVBC_6 6 + #define DVBC_8 7 static const u8 bw_params[][3] = { - /* 0f 13 23 */ - { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */ - { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */ - { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */ - { 0x92, 0x53, 0x03 }, /* DVB-C */ + /* reg: 0f 13 23 */ + [DVBT_6] = { 0xb3, 0x20, 0x03 }, + [DVBT_7] = { 0xb3, 0x31, 0x01 }, + [DVBT_8] = { 0xb3, 0x22, 0x01 }, + [DVBT2_6] = { 0xbc, 0x20, 0x03 }, + [DVBT2_7] = { 0xbc, 0x72, 0x03 }, + [DVBT2_8] = { 0xbc, 0x22, 0x01 }, + [DVBC_6] = { 0x92, 0x50, 0x03 }, + [DVBC_8] = { 0x92, 0x53, 0x03 }, }; dbg("delsys=%d RF=%d BW=%d\n", @@ -155,24 +168,44 @@ static int tda18212_set_params(struct dvb_frontend *fe, switch (c->bandwidth_hz) { case 6000000: if_khz = priv->cfg->if_dvbt_6; - i = 0; + i = DVBT_6; break; case 7000000: if_khz = priv->cfg->if_dvbt_7; - i = 1; + i = DVBT_7; break; case 8000000: if_khz = priv->cfg->if_dvbt_8; - i = 2; + i = DVBT_8; break; default: ret = -EINVAL; goto error; } break; - case SYS_DVBC_ANNEX_AC: + case SYS_DVBT2: + switch (c->bandwidth_hz) { + case 6000000: + if_khz = priv->cfg->if_dvbt2_6; + i = DVBT2_6; + break; + case 7000000: + if_khz = priv->cfg->if_dvbt2_7; + i = DVBT2_7; + break; + case 8000000: + if_khz = priv->cfg->if_dvbt2_8; + i = DVBT2_8; + break; + default: + ret = -EINVAL; + goto error; + } + break; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: if_khz = priv->cfg->if_dvbc; - i = 3; + i = DVBC_8; break; default: ret = -EINVAL; @@ -194,7 +227,7 @@ static int tda18212_set_params(struct dvb_frontend *fe, buf[0] = 0x02; buf[1] = bw_params[i][1]; buf[2] = 0x03; /* default value */ - buf[3] = if_khz / 50; + buf[3] = DIV_ROUND_CLOSEST(if_khz, 50); buf[4] = ((c->frequency / 1000) >> 16) & 0xff; buf[5] = ((c->frequency / 1000) >> 8) & 0xff; buf[6] = ((c->frequency / 1000) >> 0) & 0xff; @@ -204,6 +237,9 @@ static int tda18212_set_params(struct dvb_frontend *fe, if (ret) goto error; + /* actual IF rounded as it is on register */ + priv->if_frequency = buf[3] * 50 * 1000; + exit: if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ @@ -215,6 +251,15 @@ error: goto exit; } +static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18212_priv *priv = fe->tuner_priv; + + *frequency = priv->if_frequency; + + return 0; +} + static int tda18212_release(struct dvb_frontend *fe) { kfree(fe->tuner_priv); @@ -234,6 +279,7 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = { .release = tda18212_release, .set_params = tda18212_set_params, + .get_if_frequency = tda18212_get_if_frequency, }; struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h index 83b497f59e1b..9bd5da4aabb7 100644 --- a/drivers/media/common/tuners/tda18212.h +++ b/drivers/media/common/tuners/tda18212.h @@ -29,6 +29,10 @@ struct tda18212_config { u16 if_dvbt_6; u16 if_dvbt_7; u16 if_dvbt_8; + u16 if_dvbt2_5; + u16 if_dvbt2_6; + u16 if_dvbt2_7; + u16 if_dvbt2_8; u16 if_dvbc; }; diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c index 4fc29730a12c..dfb3a831df45 100644 --- a/drivers/media/common/tuners/tda18218.c +++ b/drivers/media/common/tuners/tda18218.c @@ -109,10 +109,11 @@ static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) return tda18218_rd_regs(priv, reg, val, 1); } -static int tda18218_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda18218_set_params(struct dvb_frontend *fe) { struct tda18218_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 bw = c->bandwidth_hz; int ret; u8 buf[3], i, BP_Filter, LP_Fc; u32 LO_Frac; @@ -138,22 +139,19 @@ static int tda18218_set_params(struct dvb_frontend *fe, fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ /* low-pass filter cut-off frequency */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + if (bw <= 6000000) { LP_Fc = 0; - LO_Frac = params->frequency + 3000000; - break; - case BANDWIDTH_7_MHZ: + priv->if_frequency = 3000000; + } else if (bw <= 7000000) { LP_Fc = 1; - LO_Frac = params->frequency + 3500000; - break; - case BANDWIDTH_8_MHZ: - default: + priv->if_frequency = 3500000; + } else { LP_Fc = 2; - LO_Frac = params->frequency + 4000000; - break; + priv->if_frequency = 4000000; } + LO_Frac = c->frequency + priv->if_frequency; + /* band-pass filter */ if (LO_Frac < 188000000) BP_Filter = 3; @@ -206,6 +204,14 @@ error: return ret; } +static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18218_priv *priv = fe->tuner_priv; + *frequency = priv->if_frequency; + dbg("%s: if=%d", __func__, *frequency); + return 0; +} + static int tda18218_sleep(struct dvb_frontend *fe) { struct tda18218_priv *priv = fe->tuner_priv; @@ -268,6 +274,8 @@ static const struct dvb_tuner_ops tda18218_tuner_ops = { .sleep = tda18218_sleep, .set_params = tda18218_set_params, + + .get_if_frequency = tda18218_get_if_frequency, }; struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h index 904e5365c78c..dc52b72e1407 100644 --- a/drivers/media/common/tuners/tda18218_priv.h +++ b/drivers/media/common/tuners/tda18218_priv.h @@ -100,6 +100,8 @@ struct tda18218_priv { struct tda18218_config *cfg; struct i2c_adapter *i2c; + u32 if_frequency; + u8 regs[TDA18218_NUM_REGS]; }; diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 63cc4004e211..2e67f4459904 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -928,59 +928,49 @@ fail: /* ------------------------------------------------------------------ */ -static int tda18271_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda18271_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + u32 freq = c->frequency; struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_std_map *std_map = &priv->std; struct tda18271_std_map_item *map; int ret; - u32 bw, freq = params->frequency; priv->mode = TDA18271_DIGITAL; - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - map = &std_map->atsc_6; - break; - case QAM_64: - case QAM_256: - map = &std_map->qam_6; - break; - default: - tda_warn("modulation not set!\n"); - return -EINVAL; - } -#if 0 - /* userspace request is already center adjusted */ - freq += 1750000; /* Adjust to center (+1.75MHZ) */ -#endif + switch (delsys) { + case SYS_ATSC: + map = &std_map->atsc_6; bw = 6000000; - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - bw = 6000000; + break; + case SYS_ISDBT: + case SYS_DVBT: + case SYS_DVBT2: + if (bw <= 6000000) { map = &std_map->dvbt_6; - break; - case BANDWIDTH_7_MHZ: - bw = 7000000; + } else if (bw <= 7000000) { map = &std_map->dvbt_7; - break; - case BANDWIDTH_8_MHZ: - bw = 8000000; + } else { map = &std_map->dvbt_8; - break; - default: - tda_warn("bandwidth not set!\n"); - return -EINVAL; } - } else if (fe->ops.info.type == FE_QAM) { - /* DVB-C */ - map = &std_map->qam_8; - bw = 8000000; - } else { + break; + case SYS_DVBC_ANNEX_B: + bw = 6000000; + /* falltrough */ + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + if (bw <= 6000000) { + map = &std_map->qam_6; + } else if (bw <= 7000000) { + map = &std_map->qam_7; + } else { + map = &std_map->qam_8; + } + break; + default: tda_warn("modulation type not supported!\n"); return -EINVAL; } @@ -994,9 +984,9 @@ static int tda18271_set_params(struct dvb_frontend *fe, if (tda_fail(ret)) goto fail; + priv->if_freq = map->if_freq; priv->frequency = freq; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; + priv->bandwidth = bw; fail: return ret; } @@ -1050,6 +1040,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, if (tda_fail(ret)) goto fail; + priv->if_freq = map->if_freq; priv->frequency = freq; priv->bandwidth = 0; fail: @@ -1086,6 +1077,13 @@ static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = (u32)priv->if_freq * 1000; + return 0; +} + /* ------------------------------------------------------------------ */ #define tda18271_update_std(std_cfg, name) do { \ @@ -1245,6 +1243,7 @@ static const struct dvb_tuner_ops tda18271_tuner_ops = { .set_config = tda18271_set_config, .get_frequency = tda18271_get_frequency, .get_bandwidth = tda18271_get_bandwidth, + .get_if_frequency = tda18271_get_if_frequency, }; struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index 3d5b6ab7e332..fb881c667c94 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -1213,6 +1213,8 @@ static struct tda18271_std_map tda18271c1_std_map = { .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ }; @@ -1244,6 +1246,8 @@ static struct tda18271_std_map tda18271c2_std_map = { .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ }; diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h index 94340f47562b..454c152ccaa0 100644 --- a/drivers/media/common/tuners/tda18271-priv.h +++ b/drivers/media/common/tuners/tda18271-priv.h @@ -122,6 +122,8 @@ struct tda18271_priv { struct mutex lock; + u16 if_freq; + u32 frequency; u32 bandwidth; }; diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h index 50cfa8cebb93..640bae4e6a5a 100644 --- a/drivers/media/common/tuners/tda18271.h +++ b/drivers/media/common/tuners/tda18271.h @@ -53,6 +53,7 @@ struct tda18271_std_map { struct tda18271_std_map_item dvbt_7; struct tda18271_std_map_item dvbt_8; struct tda18271_std_map_item qam_6; + struct tda18271_std_map_item qam_7; struct tda18271_std_map_item qam_8; }; diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c index e0d5b43772b8..a0d176267470 100644 --- a/drivers/media/common/tuners/tda827x.c +++ b/drivers/media/common/tuners/tda827x.c @@ -152,9 +152,9 @@ static int tuner_transfer(struct dvb_frontend *fe, return rc; } -static int tda827xo_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda827xo_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct tda827x_priv *priv = fe->tuner_priv; u8 buf[14]; int rc; @@ -165,18 +165,16 @@ static int tda827xo_set_params(struct dvb_frontend *fe, u32 N; dprintk("%s:\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + if (c->bandwidth_hz == 0) { + if_freq = 5000000; + } else if (c->bandwidth_hz <= 6000000) { if_freq = 4000000; - break; - case BANDWIDTH_7_MHZ: + } else if (c->bandwidth_hz <= 7000000) { if_freq = 4500000; - break; - default: /* 8 MHz or Auto */ + } else { /* 8 MHz */ if_freq = 5000000; - break; } - tuner_freq = params->frequency; + tuner_freq = c->frequency; i = 0; while (tda827x_table[i].lomax < tuner_freq) { @@ -220,8 +218,8 @@ static int tda827xo_set_params(struct dvb_frontend *fe, if (rc < 0) goto err; - priv->frequency = params->frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = c->frequency; + priv->bandwidth = c->bandwidth_hz; return 0; @@ -513,9 +511,9 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, } } -static int tda827xa_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda827xa_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct tda827x_priv *priv = fe->tuner_priv; struct tda827xa_data *frequency_map = tda827xa_dvbt; u8 buf[11]; @@ -531,22 +529,25 @@ static int tda827xa_set_params(struct dvb_frontend *fe, tda827xa_lna_gain(fe, 1, NULL); msleep(20); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + if (c->bandwidth_hz == 0) { + if_freq = 5000000; + } else if (c->bandwidth_hz <= 6000000) { if_freq = 4000000; - break; - case BANDWIDTH_7_MHZ: + } else if (c->bandwidth_hz <= 7000000) { if_freq = 4500000; - break; - default: /* 8 MHz or Auto */ + } else { /* 8 MHz */ if_freq = 5000000; - break; } - tuner_freq = params->frequency; + tuner_freq = c->frequency; - if (fe->ops.info.type == FE_QAM) { + switch (c->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: dprintk("%s select tda827xa_dvbc\n", __func__); frequency_map = tda827xa_dvbc; + break; + default: + break; } i = 0; @@ -645,9 +646,8 @@ static int tda827xa_set_params(struct dvb_frontend *fe, if (rc < 0) goto err; - priv->frequency = params->frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - + priv->frequency = c->frequency; + priv->bandwidth = c->bandwidth_hz; return 0; diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index f8ee29e6059c..39e7e583c8c0 100644 --- a/drivers/media/common/tuners/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c @@ -751,6 +751,17 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, if (4 != rc) tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + /* Write AUX byte */ + switch (priv->type) { + case TUNER_PHILIPS_FM1216ME_MK3: + buffer[2] = 0x98; + buffer[3] = 0x20; /* set TOP AGC */ + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + break; + } + return 0; } @@ -780,24 +791,26 @@ static int simple_set_params(struct dvb_frontend *fe, } static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) + const u32 delsys, + const u32 frequency, + const u32 bandwidth) { struct tuner_simple_priv *priv = fe->tuner_priv; switch (priv->type) { case TUNER_PHILIPS_FMD1216ME_MK3: case TUNER_PHILIPS_FMD1216MEX_MK3: - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && - params->frequency >= 158870000) + if (bandwidth == 8000000 && + frequency >= 158870000) buf[3] |= 0x08; break; case TUNER_PHILIPS_TD1316: /* determine band */ - buf[3] |= (params->frequency < 161000000) ? 1 : - (params->frequency < 444000000) ? 2 : 4; + buf[3] |= (frequency < 161000000) ? 1 : + (frequency < 444000000) ? 2 : 4; /* setup PLL filter */ - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + if (bandwidth == 8000000) buf[3] |= 1 << 3; break; case TUNER_PHILIPS_TUV1236D: @@ -808,12 +821,11 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, if (dtv_input[priv->nr]) new_rf = dtv_input[priv->nr]; else - switch (params->u.vsb.modulation) { - case QAM_64: - case QAM_256: + switch (delsys) { + case SYS_DVBC_ANNEX_B: new_rf = 1; break; - case VSB_8: + case SYS_ATSC: default: new_rf = 0; break; @@ -827,7 +839,9 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, } static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) + const u32 delsys, + const u32 freq, + const u32 bw) { /* This function returns the tuned frequency on success, 0 on error */ struct tuner_simple_priv *priv = fe->tuner_priv; @@ -836,7 +850,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, u8 config, cb; u32 div; int ret; - unsigned frequency = params->frequency / 62500; + u32 frequency = freq / 62500; if (!tun->stepsize) { /* tuner-core was loaded before the digital tuner was @@ -860,7 +874,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, buf[2] = config; buf[3] = cb; - simple_set_dvb(fe, buf, params); + simple_set_dvb(fe, buf, delsys, freq, bw); tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", tun->name, div, buf[0], buf[1], buf[2], buf[3]); @@ -870,32 +884,37 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, } static int simple_dvb_calc_regs(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, u8 *buf, int buf_len) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; struct tuner_simple_priv *priv = fe->tuner_priv; u32 frequency; if (buf_len < 5) return -EINVAL; - frequency = simple_dvb_configure(fe, buf+1, params); + frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw); if (frequency == 0) return -EINVAL; buf[0] = priv->i2c_props.addr; priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; + priv->bandwidth = c->bandwidth_hz; return 5; } -static int simple_dvb_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int simple_dvb_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + u32 freq = c->frequency; struct tuner_simple_priv *priv = fe->tuner_priv; + u32 frequency; u32 prev_freq, prev_bw; int ret; u8 buf[5]; @@ -906,9 +925,14 @@ static int simple_dvb_set_params(struct dvb_frontend *fe, prev_freq = priv->frequency; prev_bw = priv->bandwidth; - ret = simple_dvb_calc_regs(fe, params, buf, 5); - if (ret != 5) - goto fail; + frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw); + if (frequency == 0) + return -EINVAL; + + buf[0] = priv->i2c_props.addr; + + priv->frequency = frequency; + priv->bandwidth = bw; /* put analog demod in standby when tuning digital */ if (fe->ops.analog_ops.standby) diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index 3acbaa04e1b3..b5ee3ebfcfca 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -24,6 +24,21 @@ #include <linux/dvb/frontend.h> #include "dvb_frontend.h" +/* Registers (Write-only) */ +#define XREG_INIT 0x00 +#define XREG_RF_FREQ 0x02 +#define XREG_POWER_DOWN 0x08 + +/* Registers (Read-only) */ +#define XREG_FREQ_ERROR 0x01 +#define XREG_LOCK 0x02 +#define XREG_VERSION 0x04 +#define XREG_PRODUCT_ID 0x08 +#define XREG_HSYNC_FREQ 0x10 +#define XREG_FRAME_LINES 0x20 +#define XREG_SNR 0x40 + +#define XREG_ADC_ENV 0x0100 static int debug; module_param(debug, int, 0644); @@ -311,7 +326,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) n_array, fname, name, priv->firm_version >> 8, priv->firm_version & 0xff); - priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); if (priv->firm == NULL) { tuner_err("Not enough memory to load firmware file.\n"); rc = -ENOMEM; @@ -885,16 +900,16 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) mutex_lock(&priv->lock); /* Sync Lock Indicator */ - rc = xc2028_get_reg(priv, 0x0002, &frq_lock); + rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); if (rc < 0) goto ret; /* Frequency is locked */ if (frq_lock == 1) - signal = 32768; + signal = 1 << 11; /* Get SNR of the video signal */ - rc = xc2028_get_reg(priv, 0x0040, &signal); + rc = xc2028_get_reg(priv, XREG_SNR, &signal); if (rc < 0) goto ret; @@ -962,14 +977,24 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * For DTV 7/8, the firmware uses BW = 8000, so it needs a * further adjustment to get the frequency center on VHF */ + + /* + * The firmware DTV78 used to work fine in UHF band (8 MHz + * bandwidth) but not at all in VHF band (7 MHz bandwidth). + * The real problem was connected to the formula used to + * calculate the center frequency offset in VHF band. + * In fact, removing the 500KHz adjustment fixed the problem. + * This is coherent to what was implemented for the DTV7 + * firmware. + * In the end, now the center frequency is the same for all 3 + * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel + * bandwidth. + */ + if (priv->cur_fw.type & DTV6) offset = 1750000; - else if (priv->cur_fw.type & DTV7) - offset = 2250000; - else /* DTV8 or DTV78 */ + else /* DTV7 or DTV8 or DTV78 */ offset = 2750000; - if ((priv->cur_fw.type & DTV78) && freq < 470000000) - offset -= 500000; /* * xc3028 additional "magic" @@ -979,17 +1004,13 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * newer firmwares */ -#if 1 /* * The proper adjustment would be to do it at s-code table. * However, this didn't work, as reported by * Robert Lowery <rglowery@exemail.com.au> */ - if (priv->cur_fw.type & DTV7) - offset += 500000; - -#else +#if 0 /* * Still need tests for XC3028L (firmware 3.2 or upper) * So, for now, let's just comment the per-firmware @@ -1013,9 +1034,9 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, /* CMD= Set frequency */ if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); + rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00}); else - rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00}); + rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00}); if (rc < 0) goto ret; @@ -1084,68 +1105,28 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, V4L2_TUNER_ANALOG_TV, type, p->std, 0); } -static int xc2028_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int xc2028_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; struct xc2028_data *priv = fe->tuner_priv; unsigned int type=0; - fe_bandwidth_t bw = BANDWIDTH_8_MHZ; u16 demod = 0; tuner_dbg("%s called\n", __func__); - switch(fe->ops.info.type) { - case FE_OFDM: - bw = p->u.ofdm.bandwidth; + switch (delsys) { + case SYS_DVBT: + case SYS_DVBT2: /* * The only countries with 6MHz seem to be Taiwan/Uruguay. * Both seem to require QAM firmware for OFDM decoding * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com> */ - if (bw == BANDWIDTH_6_MHZ) + if (bw <= 6000000) type |= QAM; - break; - case FE_ATSC: - bw = BANDWIDTH_6_MHZ; - /* The only ATSC firmware (at least on v2.7) is D2633 */ - type |= ATSC | D2633; - break; - /* DVB-S and pure QAM (FE_QAM) are not supported */ - default: - return -EINVAL; - } - - switch (bw) { - case BANDWIDTH_8_MHZ: - if (p->frequency < 470000000) - priv->ctrl.vhfbw7 = 0; - else - priv->ctrl.uhfbw8 = 1; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; - type |= F8MHZ; - break; - case BANDWIDTH_7_MHZ: - if (p->frequency < 470000000) - priv->ctrl.vhfbw7 = 1; - else - priv->ctrl.uhfbw8 = 0; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; - type |= F8MHZ; - break; - case BANDWIDTH_6_MHZ: - type |= DTV6; - priv->ctrl.vhfbw7 = 0; - priv->ctrl.uhfbw8 = 0; - break; - default: - tuner_err("error: bandwidth not supported.\n"); - }; - /* - Selects between D2633 or D2620 firmware. - It doesn't make sense for ATSC, since it should be D2633 on all cases - */ - if (fe->ops.info.type != FE_ATSC) { switch (priv->ctrl.type) { case XC2028_D2633: type |= D2633; @@ -1161,6 +1142,34 @@ static int xc2028_set_params(struct dvb_frontend *fe, else type |= D2620; } + break; + case SYS_ATSC: + /* The only ATSC firmware (at least on v2.7) is D2633 */ + type |= ATSC | D2633; + break; + /* DVB-S and pure QAM (FE_QAM) are not supported */ + default: + return -EINVAL; + } + + if (bw <= 6000000) { + type |= DTV6; + priv->ctrl.vhfbw7 = 0; + priv->ctrl.uhfbw8 = 0; + } else if (bw <= 7000000) { + if (c->frequency < 470000000) + priv->ctrl.vhfbw7 = 1; + else + priv->ctrl.uhfbw8 = 0; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; + type |= F8MHZ; + } else { + if (c->frequency < 470000000) + priv->ctrl.vhfbw7 = 0; + else + priv->ctrl.uhfbw8 = 1; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; + type |= F8MHZ; } /* All S-code tables need a 200kHz shift */ @@ -1185,7 +1194,7 @@ static int xc2028_set_params(struct dvb_frontend *fe, */ } - return generic_set_freq(fe, p->frequency, + return generic_set_freq(fe, c->frequency, V4L2_TUNER_DIGITAL_TV, type, 0, demod); } @@ -1207,9 +1216,9 @@ static int xc2028_sleep(struct dvb_frontend *fe) mutex_lock(&priv->lock); if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00}); + rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00}); else - rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00}); + rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); priv->cur_fw.type = 0; /* need firmware reload */ diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c index 634f4d9b6c63..68397110b7d9 100644 --- a/drivers/media/common/tuners/xc4000.c +++ b/drivers/media/common/tuners/xc4000.c @@ -154,6 +154,8 @@ struct xc4000_priv { #define XREG_SNR 0x06 #define XREG_VERSION 0x07 #define XREG_PRODUCT_ID 0x08 +#define XREG_SIGNAL_LEVEL 0x0A +#define XREG_NOISE_LEVEL 0x0B /* Basic firmware description. This will remain with @@ -486,6 +488,16 @@ static int xc_get_quality(struct xc4000_priv *priv, u16 *quality) return xc4000_readreg(priv, XREG_QUALITY, quality); } +static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal) +{ + return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal); +} + +static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise) +{ + return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise); +} + static u16 xc_wait_for_lock(struct xc4000_priv *priv) { u16 lock_state = 0; @@ -758,7 +770,7 @@ static int xc4000_fwupload(struct dvb_frontend *fe) n_array, fname, name, priv->firm_version >> 8, priv->firm_version & 0xff); - priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); if (priv->firm == NULL) { printk(KERN_ERR "Not enough memory to load firmware file.\n"); rc = -ENOMEM; @@ -1089,6 +1101,8 @@ static void xc_debug_dump(struct xc4000_priv *priv) u32 hsync_freq_hz = 0; u16 frame_lines; u16 quality; + u16 signal = 0; + u16 noise = 0; u8 hw_majorversion = 0, hw_minorversion = 0; u8 fw_majorversion = 0, fw_minorversion = 0; @@ -1119,85 +1133,70 @@ static void xc_debug_dump(struct xc4000_priv *priv) xc_get_quality(priv, &quality); dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); + + xc_get_signal_level(priv, &signal); + dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal); + + xc_get_noise_level(priv, &noise); + dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise); } -static int xc4000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int xc4000_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; struct xc4000_priv *priv = fe->tuner_priv; unsigned int type; int ret = -EREMOTEIO; - dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency); mutex_lock(&priv->lock); - if (fe->ops.info.type == FE_ATSC) { - dprintk(1, "%s() ATSC\n", __func__); - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - dprintk(1, "%s() VSB modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = XC4000_DTV6; - type = DTV6; - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = XC4000_DTV6; - type = DTV6; - break; - default: - ret = -EINVAL; - goto fail; - } - } else if (fe->ops.info.type == FE_OFDM) { + switch (delsys) { + case SYS_ATSC: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = c->frequency - 1750000; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + case SYS_DVBC_ANNEX_B: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = c->frequency - 1750000; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + case SYS_DVBT: + case SYS_DVBT2: dprintk(1, "%s() OFDM\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - priv->bandwidth = BANDWIDTH_6_MHZ; + if (bw == 0) { + if (c->frequency < 400000000) { + priv->freq_hz = c->frequency - 2250000; + } else { + priv->freq_hz = c->frequency - 2750000; + } + priv->video_standard = XC4000_DTV7_8; + type = DTV78; + } else if (bw <= 6000000) { priv->video_standard = XC4000_DTV6; - priv->freq_hz = params->frequency - 1750000; + priv->freq_hz = c->frequency - 1750000; type = DTV6; - break; - case BANDWIDTH_7_MHZ: - priv->bandwidth = BANDWIDTH_7_MHZ; + } else if (bw <= 7000000) { priv->video_standard = XC4000_DTV7; - priv->freq_hz = params->frequency - 2250000; + priv->freq_hz = c->frequency - 2250000; type = DTV7; - break; - case BANDWIDTH_8_MHZ: - priv->bandwidth = BANDWIDTH_8_MHZ; + } else { priv->video_standard = XC4000_DTV8; - priv->freq_hz = params->frequency - 2750000; + priv->freq_hz = c->frequency - 2750000; type = DTV8; - break; - case BANDWIDTH_AUTO: - if (params->frequency < 400000000) { - priv->bandwidth = BANDWIDTH_7_MHZ; - priv->freq_hz = params->frequency - 2250000; - } else { - priv->bandwidth = BANDWIDTH_8_MHZ; - priv->freq_hz = params->frequency - 2750000; - } - priv->video_standard = XC4000_DTV7_8; - type = DTV78; - break; - default: - printk(KERN_ERR "xc4000 bandwidth not set!\n"); - ret = -EINVAL; - goto fail; } priv->rf_mode = XC_RF_MODE_AIR; - } else { - printk(KERN_ERR "xc4000 modulation type not supported!\n"); + break; + default: + printk(KERN_ERR "xc4000 delivery system not supported!\n"); ret = -EINVAL; goto fail; } @@ -1209,6 +1208,8 @@ static int xc4000_set_params(struct dvb_frontend *fe, if (check_firmware(fe, type, 0, priv->if_khz) != 0) goto fail; + priv->bandwidth = c->bandwidth_hz; + ret = xc_set_signal_source(priv, priv->rf_mode); if (ret != 0) { printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", @@ -1451,6 +1452,71 @@ fail: return ret; } +static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength) +{ + struct xc4000_priv *priv = fe->tuner_priv; + u16 value = 0; + int rc; + + mutex_lock(&priv->lock); + rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value); + mutex_unlock(&priv->lock); + + if (rc < 0) + goto ret; + + /* Informations from real testing of DVB-T and radio part, + coeficient for one dB is 0xff. + */ + tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value); + + /* all known digital modes */ + if ((priv->video_standard == XC4000_DTV6) || + (priv->video_standard == XC4000_DTV7) || + (priv->video_standard == XC4000_DTV7_8) || + (priv->video_standard == XC4000_DTV8)) + goto digital; + + /* Analog mode has NOISE LEVEL important, signal + depends only on gain of antenna and amplifiers, + but it doesn't tell anything about real quality + of reception. + */ + mutex_lock(&priv->lock); + rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value); + mutex_unlock(&priv->lock); + + tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value); + + /* highest noise level: 32dB */ + if (value >= 0x2000) { + value = 0; + } else { + value = ~value << 3; + } + + goto ret; + + /* Digital mode has SIGNAL LEVEL important and real + noise level is stored in demodulator registers. + */ +digital: + /* best signal: -50dB */ + if (value <= 0x3200) { + value = 0xffff; + /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */ + } else if (value >= 0x713A) { + value = 0; + } else { + value = ~(value - 0x3200) << 2; + } + +ret: + *strength = value; + + return rc; +} + static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) { struct xc4000_priv *priv = fe->tuner_priv; @@ -1578,6 +1644,7 @@ static const struct dvb_tuner_ops xc4000_tuner_ops = { .set_params = xc4000_set_params, .set_analog_params = xc4000_set_analog_params, .get_frequency = xc4000_get_frequency, + .get_rf_strength = xc4000_get_signal, .get_bandwidth = xc4000_get_bandwidth, .get_status = xc4000_get_status }; @@ -1605,7 +1672,7 @@ struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, break; case 1: /* new tuner instance */ - priv->bandwidth = BANDWIDTH_6_MHZ; + priv->bandwidth = 6000000; /* set default configuration */ priv->if_khz = 4560; priv->default_pm = 0; diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index aa1b2e844d32..296df05b8cda 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c @@ -628,20 +628,13 @@ static void xc_debug_dump(struct xc5000_priv *priv) dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); } -/* - * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. - * So, the amount of the needed bandwith is given by: - * Bw = Symbol_rate * (1 + 0.15) - * As such, the maximum symbol rate supported by 6 MHz is given by: - * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds - */ -#define MAX_SYMBOL_RATE_6MHz 5217391 - -static int xc5000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int xc5000_set_params(struct dvb_frontend *fe) { + int ret, b; struct xc5000_priv *priv = fe->tuner_priv; - int ret; + u32 bw = fe->dtv_property_cache.bandwidth_hz; + u32 freq = fe->dtv_property_cache.frequency; + u32 delsys = fe->dtv_property_cache.delivery_system; if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { @@ -650,88 +643,69 @@ static int xc5000_set_params(struct dvb_frontend *fe, } } - dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); - - if (fe->ops.info.type == FE_ATSC) { - dprintk(1, "%s() ATSC\n", __func__); - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - dprintk(1, "%s() VSB modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - default: - return -EINVAL; - } - } else if (fe->ops.info.type == FE_OFDM) { + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq); + + switch (delsys) { + case SYS_ATSC: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = freq - 1750000; + priv->video_standard = DTV6; + break; + case SYS_DVBC_ANNEX_B: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = freq - 1750000; + priv->video_standard = DTV6; + break; + case SYS_DVBT: + case SYS_DVBT2: dprintk(1, "%s() OFDM\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - priv->bandwidth = BANDWIDTH_6_MHZ; + switch (bw) { + case 6000000: priv->video_standard = DTV6; - priv->freq_hz = params->frequency - 1750000; + priv->freq_hz = freq - 1750000; break; - case BANDWIDTH_7_MHZ: - printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n"); - return -EINVAL; - case BANDWIDTH_8_MHZ: - priv->bandwidth = BANDWIDTH_8_MHZ; + case 7000000: + priv->video_standard = DTV7; + priv->freq_hz = freq - 2250000; + break; + case 8000000: priv->video_standard = DTV8; - priv->freq_hz = params->frequency - 2750000; + priv->freq_hz = freq - 2750000; break; default: printk(KERN_ERR "xc5000 bandwidth not set!\n"); return -EINVAL; } priv->rf_mode = XC_RF_MODE_AIR; - } else if (fe->ops.info.type == FE_QAM) { - switch (params->u.qam.modulation) { - case QAM_256: - case QAM_AUTO: - case QAM_16: - case QAM_32: - case QAM_64: - case QAM_128: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - /* - * Using a 8MHz bandwidth sometimes fail - * with 6MHz-spaced channels, due to inter-carrier - * interference. So, use DTV6 firmware - */ - if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) { - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - priv->freq_hz = params->frequency - 1750000; - } else { - priv->bandwidth = BANDWIDTH_8_MHZ; - priv->video_standard = DTV7_8; - priv->freq_hz = params->frequency - 2750000; - } - break; - default: - dprintk(1, "%s() Unsupported QAM type\n", __func__); - return -EINVAL; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + if (bw <= 6000000) { + priv->video_standard = DTV6; + priv->freq_hz = freq - 1750000; + b = 6; + } else if (bw <= 7000000) { + priv->video_standard = DTV7; + priv->freq_hz = freq - 2250000; + b = 7; + } else { + priv->video_standard = DTV7_8; + priv->freq_hz = freq - 2750000; + b = 8; } - } else { - printk(KERN_ERR "xc5000 modulation type not supported!\n"); + dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__, + b, bw); + break; + default: + printk(KERN_ERR "xc5000: delivery system is not supported!\n"); return -EINVAL; } - dprintk(1, "%s() frequency=%d (compensated)\n", - __func__, priv->freq_hz); + dprintk(1, "%s() frequency=%d (compensated to %d)\n", + __func__, freq, priv->freq_hz); ret = xc_SetSignalSource(priv, priv->rf_mode); if (ret != XC_RESULT_SUCCESS) { @@ -763,6 +737,8 @@ static int xc5000_set_params(struct dvb_frontend *fe, if (debug) xc_debug_dump(priv); + priv->bandwidth = bw; + return 0; } @@ -968,6 +944,14 @@ static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) return 0; } +static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + *freq = priv->if_khz * 1000; + return 0; +} + static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1108,6 +1092,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .set_params = xc5000_set_params, .set_analog_params = xc5000_set_analog_params, .get_frequency = xc5000_get_frequency, + .get_if_frequency = xc5000_get_if_frequency, .get_bandwidth = xc5000_get_bandwidth, .get_status = xc5000_get_status }; @@ -1135,7 +1120,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, break; case 1: /* new tuner instance */ - priv->bandwidth = BANDWIDTH_6_MHZ; + priv->bandwidth = 6000000; fe->tuner_priv = priv; break; default: diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 2df1b0214dcd..b1e8c99f469b 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -86,7 +86,8 @@ static int flexcop_dvb_init(struct flexcop_device *fc) fc->demux.stop_feed = flexcop_dvb_stop_feed; fc->demux.write_to_decoder = NULL; - if ((ret = dvb_dmx_init(&fc->demux)) < 0) { + ret = dvb_dmx_init(&fc->demux); + if (ret < 0) { err("dvb_dmx failed: error %d", ret); goto err_dmx; } @@ -96,32 +97,42 @@ static int flexcop_dvb_init(struct flexcop_device *fc) fc->dmxdev.filternum = fc->demux.feednum; fc->dmxdev.demux = &fc->demux.dmx; fc->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) { + ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter); + if (ret < 0) { err("dvb_dmxdev_init failed: error %d", ret); goto err_dmx_dev; } - if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { + ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend); + if (ret < 0) { err("adding hw_frontend to dmx failed: error %d", ret); goto err_dmx_add_hw_frontend; } fc->mem_frontend.source = DMX_MEMORY_FE; - if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) { + ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend); + if (ret < 0) { err("adding mem_frontend to dmx failed: error %d", ret); goto err_dmx_add_mem_frontend; } - if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { + ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend); + if (ret < 0) { err("connect frontend failed: error %d", ret); goto err_connect_frontend; } - dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); + ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); + if (ret < 0) { + err("dvb_net_init failed: error %d", ret); + goto err_net; + } fc->init_state |= FC_STATE_DVB_INIT; return 0; +err_net: + fc->demux.dmx.disconnect_frontend(&fc->demux.dmx); err_connect_frontend: fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend); err_dmx_add_mem_frontend: @@ -254,7 +265,8 @@ int flexcop_device_initialize(struct flexcop_device *fc) flexcop_hw_filter_init(fc); flexcop_smc_ctrl(fc, 0); - if ((ret = flexcop_dvb_init(fc))) + ret = flexcop_dvb_init(fc); + if (ret) goto error; /* i2c has to be done before doing EEProm stuff - @@ -272,7 +284,8 @@ int flexcop_device_initialize(struct flexcop_device *fc) } else warn("reading of MAC address failed.\n"); - if ((ret = flexcop_frontend_init(fc))) + ret = flexcop_frontend_init(fc); + if (ret) goto error; flexcop_device_name(fc,"initialization of","complete"); diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index caa4e18ed1c1..430b3eb11815 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -386,7 +386,7 @@ static int dst_set_freq(struct dst_state *state, u32 freq) return 0; } -static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) +static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth) { state->bandwidth = bandwidth; @@ -394,7 +394,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) return -EOPNOTSUPP; switch (bandwidth) { - case BANDWIDTH_6_MHZ: + case 6000000: if (state->dst_hw_cap & DST_TYPE_HAS_CA) state->tx_tuna[7] = 0x06; else { @@ -402,7 +402,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) state->tx_tuna[7] = 0x00; } break; - case BANDWIDTH_7_MHZ: + case 7000000: if (state->dst_hw_cap & DST_TYPE_HAS_CA) state->tx_tuna[7] = 0x07; else { @@ -410,7 +410,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) state->tx_tuna[7] = 0x00; } break; - case BANDWIDTH_8_MHZ: + case 8000000: if (state->dst_hw_cap & DST_TYPE_HAS_CA) state->tx_tuna[7] = 0x08; else { @@ -1561,7 +1561,7 @@ static int dst_init(struct dvb_frontend *fe) state->tone = SEC_TONE_OFF; state->diseq_flags = 0; state->k22 = 0x02; - state->bandwidth = BANDWIDTH_7_MHZ; + state->bandwidth = 7000000; state->cur_jiff = jiffies; if (state->dst_type == DST_TYPE_IS_SAT) memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); @@ -1609,8 +1609,9 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) return retval; } -static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dst_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int retval = -EINVAL; struct dst_state *state = fe->demodulator_priv; @@ -1623,17 +1624,17 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); - dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->u.ofdm.bandwidth); + dst_set_bandwidth(state, p->bandwidth_hz); else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->u.qam.fec_inner); - dst_set_symbolrate(state, p->u.qam.symbol_rate); - dst_set_modulation(state, p->u.qam.modulation); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); + dst_set_modulation(state, p->modulation); } retval = dst_write_tuna(fe); } @@ -1642,31 +1643,32 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet } static int dst_tune_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters* p, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { struct dst_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; - if (p != NULL) { + if (re_tune) { dst_set_freq(state, p->frequency); dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); - dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->u.ofdm.bandwidth); + dst_set_bandwidth(state, p->bandwidth_hz); else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->u.qam.fec_inner); - dst_set_symbolrate(state, p->u.qam.symbol_rate); - dst_set_modulation(state, p->u.qam.modulation); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); + dst_set_modulation(state, p->modulation); } dst_write_tuna(fe); } @@ -1683,22 +1685,23 @@ static int dst_get_tuning_algo(struct dvb_frontend *fe) return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; } -static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dst_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dst_state *state = fe->demodulator_priv; p->frequency = state->decode_freq; if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) p->inversion = state->inversion; - p->u.qpsk.symbol_rate = state->symbol_rate; - p->u.qpsk.fec_inner = dst_get_fec(state); + p->symbol_rate = state->symbol_rate; + p->fec_inner = dst_get_fec(state); } else if (state->dst_type == DST_TYPE_IS_TERR) { - p->u.ofdm.bandwidth = state->bandwidth; + p->bandwidth_hz = state->bandwidth; } else if (state->dst_type == DST_TYPE_IS_CABLE) { - p->u.qam.symbol_rate = state->symbol_rate; - p->u.qam.fec_inner = dst_get_fec(state); - p->u.qam.modulation = dst_get_modulation(state); + p->symbol_rate = state->symbol_rate; + p->fec_inner = dst_get_fec(state); + p->modulation = dst_get_modulation(state); } return 0; @@ -1756,10 +1759,9 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad EXPORT_SYMBOL(dst_attach); static struct dvb_frontend_ops dst_dvbt_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "DST DVB-T", - .type = FE_OFDM, .frequency_min = 137000000, .frequency_max = 858000000, .frequency_stepsize = 166667, @@ -1786,10 +1788,9 @@ static struct dvb_frontend_ops dst_dvbt_ops = { }; static struct dvb_frontend_ops dst_dvbs_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "DST DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1000, /* kHz for QPSK frontends */ @@ -1816,10 +1817,9 @@ static struct dvb_frontend_ops dst_dvbs_ops = { }; static struct dvb_frontend_ops dst_dvbc_ops = { - + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "DST DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 51000000, .frequency_max = 858000000, @@ -1846,9 +1846,9 @@ static struct dvb_frontend_ops dst_dvbc_ops = { }; static struct dvb_frontend_ops dst_atsc_ops = { + .delsys = { SYS_ATSC }, .info = { .name = "DST ATSC", - .type = FE_ATSC, .frequency_stepsize = 62500, .frequency_min = 510000000, .frequency_max = 858000000, diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index d88cf2add82b..d70d98f1a571 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -124,7 +124,7 @@ struct dst_state { u16 decode_snr; unsigned long cur_jiff; u8 k22; - fe_bandwidth_t bandwidth; + u32 bandwidth; u32 dst_hw_cap; u8 dst_fw_version; fe_sec_mini_cmd_t minicmd; diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 521d69104982..81fab9adc1ca 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) "dvb_bt8xx: " fmt + #include <linux/bitops.h> #include <linux/module.h> #include <linux/init.h> @@ -148,8 +150,9 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) return 0; } -static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 div; unsigned char bs = 0; unsigned char cp = 0; @@ -157,18 +160,18 @@ static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_f if (buf_len < 5) return -EINVAL; - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - if (params->frequency < 542000000) + if (c->frequency < 542000000) cp = 0xb4; - else if (params->frequency < 771000000) + else if (c->frequency < 771000000) cp = 0xbc; else cp = 0xf4; - if (params->frequency == 0) + if (c->frequency == 0) bs = 0x03; - else if (params->frequency < 443250000) + else if (c->frequency < 443250000) bs = 0x02; else bs = 0x08; @@ -191,13 +194,12 @@ static struct zl10353_config thomson_dtt7579_zl10353_config = { .demod_address = 0x0f, }; -static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int cx24108_tuner_set_params(struct dvb_frontend *fe) { - u32 freq = params->frequency; - + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 freq = c->frequency; int i, a, n, pump; u32 band, pll; - u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, 1576000,1718000,1856000,2036000,2150000}; u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, @@ -205,7 +207,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend 0x00120000,0x00140000}; #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ - printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); + dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq); /* This is really the bit driving the tuner chip cx24108 */ @@ -216,7 +218,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend /* decide which VCO to use for the input frequency */ for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++); - printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq); + dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq); band=bandsel[i]; /* the gain values must be set by SetSymbolrate */ /* compute the pll divider needed, from Conexant data sheet, @@ -232,7 +234,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend ((a&0x1f)<<11); /* everything is shifted left 11 bits to left-align the bits in the 32bit word. Output to the tuner goes MSB-aligned, after all */ - printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a); + dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a); cx24110_pll_write(fe,band); /* set vga and vca to their widest-band settings, as a precaution. SetSymbolrate might not be called to set this up */ @@ -267,31 +269,32 @@ static struct cx24110_config pctvsat_config = { .demod_address = 0x55, }; -static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; u8 cfg, cpump, band_select; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (36000000 + params->frequency + 83333) / 166666; + div = (36000000 + c->frequency + 83333) / 166666; cfg = 0x88; - if (params->frequency < 175000000) + if (c->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) + else if (c->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) + else if (c->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) + else if (c->frequency < 750000000) cpump = 2; else cpump = 3; - if (params->frequency < 175000000) + if (c->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) + else if (c->frequency < 470000000) band_select = 0x05; else band_select = 0x03; @@ -342,50 +345,51 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) return 0; } -static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 div; unsigned char bs = 0; unsigned char cp = 0; if (buf_len < 5) return -EINVAL; - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - if (params->frequency < 150000000) + if (c->frequency < 150000000) cp = 0xB4; - else if (params->frequency < 173000000) + else if (c->frequency < 173000000) cp = 0xBC; - else if (params->frequency < 250000000) + else if (c->frequency < 250000000) cp = 0xB4; - else if (params->frequency < 400000000) + else if (c->frequency < 400000000) cp = 0xBC; - else if (params->frequency < 420000000) + else if (c->frequency < 420000000) cp = 0xF4; - else if (params->frequency < 470000000) + else if (c->frequency < 470000000) cp = 0xFC; - else if (params->frequency < 600000000) + else if (c->frequency < 600000000) cp = 0xBC; - else if (params->frequency < 730000000) + else if (c->frequency < 730000000) cp = 0xF4; else cp = 0xFC; - if (params->frequency < 150000000) + if (c->frequency < 150000000) bs = 0x01; - else if (params->frequency < 173000000) + else if (c->frequency < 173000000) bs = 0x01; - else if (params->frequency < 250000000) + else if (c->frequency < 250000000) bs = 0x02; - else if (params->frequency < 400000000) + else if (c->frequency < 400000000) bs = 0x02; - else if (params->frequency < 420000000) + else if (c->frequency < 420000000) bs = 0x02; - else if (params->frequency < 470000000) + else if (c->frequency < 470000000) bs = 0x02; - else if (params->frequency < 600000000) + else if (c->frequency < 600000000) bs = 0x08; - else if (params->frequency < 730000000) + else if (c->frequency < 730000000) bs = 0x08; else bs = 0x08; @@ -461,25 +465,26 @@ static struct or51211_config or51211_config = { .sleep = or51211_sleep, }; -static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; - div = (params->frequency + 36166667) / 166667; + div = (c->frequency + 36166667) / 166667; buf[0] = (div >> 8) & 0x7F; buf[1] = div & 0xFF; buf[2] = 0x85; - if ((params->frequency >= 47000000) && (params->frequency < 153000000)) + if ((c->frequency >= 47000000) && (c->frequency < 153000000)) buf[3] = 0x01; - else if ((params->frequency >= 153000000) && (params->frequency < 430000000)) + else if ((c->frequency >= 153000000) && (c->frequency < 430000000)) buf[3] = 0x02; - else if ((params->frequency >= 430000000) && (params->frequency < 824000000)) + else if ((c->frequency >= 430000000) && (c->frequency < 824000000)) buf[3] = 0x0C; - else if ((params->frequency >= 824000000) && (params->frequency < 863000000)) + else if ((c->frequency >= 824000000) && (c->frequency < 863000000)) buf[3] = 0x8C; else return -EINVAL; @@ -513,31 +518,31 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) return 0; } -static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) { u32 div; - struct dvb_ofdm_parameters *op = ¶ms->u.ofdm; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; if (buf_len < 5) return -EINVAL; - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; pllbuf[0] = 0x61; pllbuf[1] = (div >> 8) & 0x7F; pllbuf[2] = div & 0xFF; pllbuf[3] = 0x85; - dprintk("frequency %u, div %u\n", params->frequency, div); + dprintk("frequency %u, div %u\n", c->frequency, div); - if (params->frequency < 470000000) + if (c->frequency < 470000000) pllbuf[4] = 0x02; - else if (params->frequency > 823000000) + else if (c->frequency > 823000000) pllbuf[4] = 0x88; else pllbuf[4] = 0x08; - if (op->bandwidth == 8) + if (c->bandwidth_hz == 8000000) pllbuf[4] |= 0x04; return 5; @@ -663,7 +668,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) /* DST is not a frontend driver !!! */ state = kmalloc(sizeof (struct dst_state), GFP_KERNEL); if (!state) { - printk("dvb_bt8xx: No memory\n"); + pr_err("No memory\n"); break; } /* Setup the Card */ @@ -673,7 +678,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) state->dst_ca = NULL; /* DST is not a frontend, attaching the ASIC */ if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { - printk("%s: Could not find a Twinhan DST.\n", __func__); + pr_err("%s: Could not find a Twinhan DST\n", __func__); break; } /* Attach other DST peripherals if any */ @@ -702,14 +707,14 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) } if (card->fe == NULL) - printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", card->bt->dev->vendor, card->bt->dev->device, card->bt->dev->subsystem_vendor, card->bt->dev->subsystem_device); else if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { - printk("dvb-bt8xx: Frontend registration failed!\n"); + pr_err("Frontend registration failed!\n"); dvb_frontend_detach(card->fe); card->fe = NULL; } @@ -723,7 +728,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) THIS_MODULE, &card->bt->dev->dev, adapter_nr); if (result < 0) { - printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result); + pr_err("dvb_register_adapter failed (errno = %d)\n", result); return result; } card->dvb_adapter.priv = card; @@ -741,66 +746,69 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) card->demux.stop_feed = dvb_bt8xx_stop_feed; card->demux.write_to_decoder = NULL; - if ((result = dvb_dmx_init(&card->demux)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = dvb_dmx_init(&card->demux); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_unregister_adaptor; } card->dmxdev.filternum = 256; card->dmxdev.demux = &card->demux.dmx; card->dmxdev.capabilities = 0; - if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) { - printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result); - - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter); + if (result < 0) { + pr_err("dvb_dmxdev_init failed (errno = %d)\n", result); + goto err_dmx_release; } card->fe_hw.source = DMX_FRONTEND_0; - if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_dmxdev_release; } card->fe_mem.source = DMX_MEMORY_FE; - if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_remove_hw_frontend; } - if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_remove_mem_frontend; } - dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); + result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); + if (result < 0) { + pr_err("dvb_net_init failed (errno = %d)\n", result); + goto err_disconnect_frontend; + } tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); frontend_init(card, type); return 0; + +err_disconnect_frontend: + card->demux.dmx.disconnect_frontend(&card->demux.dmx); +err_remove_mem_frontend: + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); +err_remove_hw_frontend: + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); +err_dmxdev_release: + dvb_dmxdev_release(&card->dmxdev); +err_dmx_release: + dvb_dmx_release(&card->demux); +err_unregister_adaptor: + dvb_unregister_adapter(&card->dvb_adapter); + return result; } static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) @@ -881,8 +889,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) break; default: - printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n", - sub->core->type); + pr_err("Unknown bttv card type: %d\n", sub->core->type); kfree(card); return -ENODEV; } @@ -890,16 +897,14 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name); if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { - printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr); + pr_err("no pci device for card %d\n", card->bttv_nr); kfree(card); return -ENODEV; } if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { - printk("dvb_bt8xx: unable to determine DMA core of card %d,\n", - card->bttv_nr); - printk("dvb_bt8xx: if you have the ALSA bt87x audio driver " - "installed, try removing it.\n"); + pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr); + pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n"); kfree(card); return -ENODEV; diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c index d1e91bc80e78..ce4f85849e7b 100644 --- a/drivers/media/dvb/ddbridge/ddbridge-core.c +++ b/drivers/media/dvb/ddbridge/ddbridge-core.c @@ -580,7 +580,7 @@ static int demod_attach_drxk(struct ddb_input *input) memset(&config, 0, sizeof(config)); config.adr = 0x29 + (input->nr & 1); - fe = input->fe = dvb_attach(drxk_attach, &config, i2c, &input->fe2); + fe = input->fe = dvb_attach(drxk_attach, &config, i2c); if (!input->fe) { printk(KERN_ERR "No DRXK found!\n"); return -ENODEV; diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 55e6533f15e9..a609b3a9b146 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -1115,11 +1115,14 @@ static int __devinit dm1105_probe(struct pci_dev *pdev, if (ret < 0) goto err_remove_mem_frontend; - ret = frontend_init(dev); + ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx); if (ret < 0) goto err_disconnect_frontend; - dvb_net_init(dvb_adapter, &dev->dvbnet, dmx); + ret = frontend_init(dev); + if (ret < 0) + goto err_dvb_net; + dm1105_ir_init(dev); INIT_WORK(&dev->work, dm1105_dmx_buffer); diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 7ea517b7e186..9be65a3b931f 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1306,6 +1306,10 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, /* fragment the packets & store in the buffer */ while (fragpos < count) { fraglen = ca->slot_info[slot].link_buf_size - 2; + if (fraglen < 0) + break; + if (fraglen > HOST_LINK_BUF_SIZE - 2) + fraglen = HOST_LINK_BUF_SIZE - 2; if ((count - fragpos) < fraglen) fraglen = count - fragpos; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2c0acdb4d811..fbbe545a74cb 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -25,6 +25,9 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ +/* Enables DVBv3 compatibility bits at the headers */ +#define __DVB_CORE__ + #include <linux/string.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -105,7 +108,6 @@ struct dvb_frontend_private { /* thread/frontend values */ struct dvb_device *dvbdev; - struct dvb_frontend_parameters parameters_in; struct dvb_frontend_parameters parameters_out; struct dvb_fe_events events; struct semaphore sem; @@ -139,6 +141,62 @@ struct dvb_frontend_private { }; static void dvb_frontend_wakeup(struct dvb_frontend *fe); +static int dtv_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p_out); + +static bool has_get_frontend(struct dvb_frontend *fe) +{ + return fe->ops.get_frontend; +} + +/* + * Due to DVBv3 API calls, a delivery system should be mapped into one of + * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC), + * otherwise, a DVBv3 call will fail. + */ +enum dvbv3_emulation_type { + DVBV3_UNKNOWN, + DVBV3_QPSK, + DVBV3_QAM, + DVBV3_OFDM, + DVBV3_ATSC, +}; + +static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system) +{ + switch (delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + return DVBV3_QAM; + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_ISDBS: + case SYS_DSS: + return DVBV3_QPSK; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_ISDBT: + case SYS_DMBTH: + return DVBV3_OFDM; + case SYS_ATSC: + case SYS_DVBC_ANNEX_B: + return DVBV3_ATSC; + case SYS_UNDEFINED: + case SYS_ISDBC: + case SYS_DVBH: + case SYS_DAB: + case SYS_ATSCMH: + default: + /* + * Doesn't know how to emulate those types and/or + * there's no frontend driver from this type yet + * with some emulation code, so, we're not sure yet how + * to handle them, or they're not compatible with a DVBv3 call. + */ + return DVBV3_UNKNOWN; + } +} static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) { @@ -149,8 +207,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) dprintk ("%s\n", __func__); - if ((status & FE_HAS_LOCK) && fe->ops.get_frontend) - fe->ops.get_frontend(fe, &fepriv->parameters_out); + if ((status & FE_HAS_LOCK) && has_get_frontend(fe)) + dtv_get_frontend(fe, &fepriv->parameters_out); mutex_lock(&events->mtx); @@ -277,12 +335,13 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra int ready = 0; int fe_set_err = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; - int original_inversion = fepriv->parameters_in.inversion; - u32 original_frequency = fepriv->parameters_in.frequency; + struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; + int original_inversion = c->inversion; + u32 original_frequency = c->frequency; /* are we using autoinversion? */ autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters_in.inversion == INVERSION_AUTO)); + (c->inversion == INVERSION_AUTO)); /* setup parameters correctly */ while(!ready) { @@ -348,19 +407,20 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step); /* set the frontend itself */ - fepriv->parameters_in.frequency += fepriv->lnb_drift; + c->frequency += fepriv->lnb_drift; if (autoinversion) - fepriv->parameters_in.inversion = fepriv->inversion; + c->inversion = fepriv->inversion; + tmp = *c; if (fe->ops.set_frontend) - fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in); - fepriv->parameters_out = fepriv->parameters_in; + fe_set_err = fe->ops.set_frontend(fe); + *c = tmp; if (fe_set_err < 0) { fepriv->state = FESTATE_ERROR; return fe_set_err; } - fepriv->parameters_in.frequency = original_frequency; - fepriv->parameters_in.inversion = original_inversion; + c->frequency = original_frequency; + c->inversion = original_inversion; fepriv->auto_sub_step++; return 0; @@ -371,6 +431,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) fe_status_t s = 0; int retval = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; /* if we've got no parameters, just keep idling */ if (fepriv->state & FESTATE_IDLE) { @@ -382,10 +443,10 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* in SCAN mode, we just set the frontend when asked and leave it alone */ if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { if (fepriv->state & FESTATE_RETUNE) { + tmp = *c; if (fe->ops.set_frontend) - retval = fe->ops.set_frontend(fe, - &fepriv->parameters_in); - fepriv->parameters_out = fepriv->parameters_in; + retval = fe->ops.set_frontend(fe); + *c = tmp; if (retval < 0) fepriv->state = FESTATE_ERROR; else @@ -415,8 +476,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* if we're tuned, then we have determined the correct inversion */ if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters_in.inversion == INVERSION_AUTO)) { - fepriv->parameters_in.inversion = fepriv->inversion; + (c->inversion == INVERSION_AUTO)) { + c->inversion = fepriv->inversion; } return; } @@ -507,7 +568,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe) return 1; if (fepriv->dvbdev->writers == 1) - if (time_after(jiffies, fepriv->release_jiffies + + if (time_after_eq(jiffies, fepriv->release_jiffies + dvb_shutdown_timeout * HZ)) return 1; @@ -540,7 +601,7 @@ static int dvb_frontend_thread(void *data) fe_status_t s; enum dvbfe_algo algo; - struct dvb_frontend_parameters *params; + bool re_tune = false; dprintk("%s\n", __func__); @@ -589,18 +650,15 @@ restart: switch (algo) { case DVBFE_ALGO_HW: dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); - params = NULL; /* have we been asked to RETUNE ? */ if (fepriv->state & FESTATE_RETUNE) { dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); - params = &fepriv->parameters_in; + re_tune = true; fepriv->state = FESTATE_TUNED; } if (fe->ops.tune) - fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); - if (params) - fepriv->parameters_out = *params; + fe->ops.tune(fe, re_tune, fepriv->tune_mode_flags, &fepriv->delay, &s); if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) { dprintk("%s: state changed, adding current state\n", __func__); @@ -624,7 +682,7 @@ restart: */ if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { if (fe->ops.search) { - fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in); + fepriv->algo_status = fe->ops.search(fe); /* We did do a search as was requested, the flags are * now unset as well and has the flags wrt to search. */ @@ -633,14 +691,10 @@ restart: } } /* Track the carrier if the search was successful */ - if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { - if (fe->ops.track) - fe->ops.track(fe, &fepriv->parameters_in); - } else { + if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) { fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; fepriv->delay = HZ / 2; } - fepriv->parameters_out = fepriv->parameters_in; fe->ops.read_status(fe, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); /* update event list */ @@ -807,52 +861,40 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, fe->dvb->num,fe->id); } -static int dvb_frontend_check_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *parms) +static int dvb_frontend_check_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 freq_min; u32 freq_max; /* range check: frequency */ dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max); - if ((freq_min && parms->frequency < freq_min) || - (freq_max && parms->frequency > freq_max)) { + if ((freq_min && c->frequency < freq_min) || + (freq_max && c->frequency > freq_max)) { printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max); + fe->dvb->num, fe->id, c->frequency, freq_min, freq_max); return -EINVAL; } /* range check: symbol rate */ - if (fe->ops.info.type == FE_QPSK) { + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: if ((fe->ops.info.symbol_rate_min && - parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || + c->symbol_rate < fe->ops.info.symbol_rate_min) || (fe->ops.info.symbol_rate_max && - parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { + c->symbol_rate > fe->ops.info.symbol_rate_max)) { printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate, - fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + fe->dvb->num, fe->id, c->symbol_rate, + fe->ops.info.symbol_rate_min, + fe->ops.info.symbol_rate_max); return -EINVAL; } - - } else if (fe->ops.info.type == FE_QAM) { - if ((fe->ops.info.symbol_rate_min && - parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || - (fe->ops.info.symbol_rate_max && - parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { - printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->u.qam.symbol_rate, - fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); - return -EINVAL; - } - } - - /* check for supported modulation */ - if (fe->ops.info.type == FE_QAM && - (parms->u.qam.modulation > QAM_AUTO || - !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) { - printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n", - fe->dvb->num, fe->id, parms->u.qam.modulation); - return -EINVAL; + default: + break; } return 0; @@ -862,32 +904,59 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; int i; + u32 delsys; + delsys = c->delivery_system; memset(c, 0, sizeof(struct dtv_frontend_properties)); + c->delivery_system = delsys; c->state = DTV_CLEAR; - c->delivery_system = SYS_UNDEFINED; - c->inversion = INVERSION_AUTO; - c->fec_inner = FEC_AUTO; + + dprintk("%s() Clearing cache for delivery system %d\n", __func__, + c->delivery_system); + c->transmission_mode = TRANSMISSION_MODE_AUTO; - c->bandwidth_hz = BANDWIDTH_AUTO; + c->bandwidth_hz = 0; /* AUTO */ c->guard_interval = GUARD_INTERVAL_AUTO; c->hierarchy = HIERARCHY_AUTO; - c->symbol_rate = QAM_AUTO; + c->symbol_rate = 0; c->code_rate_HP = FEC_AUTO; c->code_rate_LP = FEC_AUTO; - - c->isdbt_partial_reception = -1; - c->isdbt_sb_mode = -1; - c->isdbt_sb_subchannel = -1; - c->isdbt_sb_segment_idx = -1; - c->isdbt_sb_segment_count = -1; - c->isdbt_layer_enabled = 0x7; + c->fec_inner = FEC_AUTO; + c->rolloff = ROLLOFF_AUTO; + c->voltage = SEC_VOLTAGE_OFF; + c->sectone = SEC_TONE_OFF; + c->pilot = PILOT_AUTO; + + c->isdbt_partial_reception = 0; + c->isdbt_sb_mode = 0; + c->isdbt_sb_subchannel = 0; + c->isdbt_sb_segment_idx = 0; + c->isdbt_sb_segment_count = 0; + c->isdbt_layer_enabled = 0; for (i = 0; i < 3; i++) { c->layer[i].fec = FEC_AUTO; c->layer[i].modulation = QAM_AUTO; - c->layer[i].interleaving = -1; - c->layer[i].segment_count = -1; + c->layer[i].interleaving = 0; + c->layer[i].segment_count = 0; + } + + c->isdbs_ts_id = 0; + c->dvbt2_plp_id = 0; + + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + c->modulation = QPSK; /* implied for DVB-S in legacy API */ + c->rolloff = ROLLOFF_35;/* implied for DVB-S */ + break; + case SYS_ATSC: + c->modulation = VSB_8; + break; + default: + c->modulation = QAM_AUTO; + break; } return 0; @@ -943,25 +1012,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0), _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0), - _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0), - _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0), - _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0), - _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0), - _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0), - _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0), _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0), @@ -973,6 +1023,8 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0), _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0), _DTV_CMD(DTV_HIERARCHY, 0, 0), + + _DTV_CMD(DTV_ENUM_DELSYS, 0, 0), }; static void dtv_property_dump(struct dtv_property *tvp) @@ -1006,70 +1058,54 @@ static void dtv_property_dump(struct dtv_property *tvp) dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data); } -static int is_legacy_delivery_system(fe_delivery_system_t s) -{ - if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || - (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || - (s == SYS_ATSC)) - return 1; - - return 0; -} - -/* Initialize the cache with some default values derived from the - * legacy frontend_info structure. - */ -static void dtv_property_cache_init(struct dvb_frontend *fe, - struct dtv_frontend_properties *c) -{ - switch (fe->ops.info.type) { - case FE_QPSK: - c->modulation = QPSK; /* implied for DVB-S in legacy API */ - c->rolloff = ROLLOFF_35;/* implied for DVB-S */ - c->delivery_system = SYS_DVBS; - break; - case FE_QAM: - c->delivery_system = SYS_DVBC_ANNEX_AC; - break; - case FE_OFDM: - c->delivery_system = SYS_DVBT; - break; - case FE_ATSC: - break; - } -} - /* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. */ -static void dtv_property_cache_sync(struct dvb_frontend *fe, - struct dtv_frontend_properties *c, - const struct dvb_frontend_parameters *p) +static int dtv_property_cache_sync(struct dvb_frontend *fe, + struct dtv_frontend_properties *c, + const struct dvb_frontend_parameters *p) { c->frequency = p->frequency; c->inversion = p->inversion; - switch (fe->ops.info.type) { - case FE_QPSK: + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_QPSK: + dprintk("%s() Preparing QPSK req\n", __func__); c->symbol_rate = p->u.qpsk.symbol_rate; c->fec_inner = p->u.qpsk.fec_inner; break; - case FE_QAM: + case DVBV3_QAM: + dprintk("%s() Preparing QAM req\n", __func__); c->symbol_rate = p->u.qam.symbol_rate; c->fec_inner = p->u.qam.fec_inner; c->modulation = p->u.qam.modulation; break; - case FE_OFDM: - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) - c->bandwidth_hz = 6000000; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) - c->bandwidth_hz = 7000000; - else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + case DVBV3_OFDM: + dprintk("%s() Preparing OFDM req\n", __func__); + switch (p->u.ofdm.bandwidth) { + case BANDWIDTH_10_MHZ: + c->bandwidth_hz = 10000000; + break; + case BANDWIDTH_8_MHZ: c->bandwidth_hz = 8000000; - else - /* Including BANDWIDTH_AUTO */ + break; + case BANDWIDTH_7_MHZ: + c->bandwidth_hz = 7000000; + break; + case BANDWIDTH_6_MHZ: + c->bandwidth_hz = 6000000; + break; + case BANDWIDTH_5_MHZ: + c->bandwidth_hz = 5000000; + break; + case BANDWIDTH_1_712_MHZ: + c->bandwidth_hz = 1712000; + break; + case BANDWIDTH_AUTO: c->bandwidth_hz = 0; + } + c->code_rate_HP = p->u.ofdm.code_rate_HP; c->code_rate_LP = p->u.ofdm.code_rate_LP; c->modulation = p->u.ofdm.constellation; @@ -1077,50 +1113,78 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe, c->guard_interval = p->u.ofdm.guard_interval; c->hierarchy = p->u.ofdm.hierarchy_information; break; - case FE_ATSC: + case DVBV3_ATSC: + dprintk("%s() Preparing ATSC req\n", __func__); c->modulation = p->u.vsb.modulation; if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) c->delivery_system = SYS_ATSC; else c->delivery_system = SYS_DVBC_ANNEX_B; break; + case DVBV3_UNKNOWN: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + return -EINVAL; } + + return 0; } /* Ensure the cached values are set correctly in the frontend * legacy tuning structures, for the advanced tuning API. */ -static void dtv_property_legacy_params_sync(struct dvb_frontend *fe) +static int dtv_property_legacy_params_sync(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_frontend_parameters *p = &fepriv->parameters_in; p->frequency = c->frequency; p->inversion = c->inversion; - switch (fe->ops.info.type) { - case FE_QPSK: + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_UNKNOWN: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + return -EINVAL; + case DVBV3_QPSK: dprintk("%s() Preparing QPSK req\n", __func__); p->u.qpsk.symbol_rate = c->symbol_rate; p->u.qpsk.fec_inner = c->fec_inner; break; - case FE_QAM: + case DVBV3_QAM: dprintk("%s() Preparing QAM req\n", __func__); p->u.qam.symbol_rate = c->symbol_rate; p->u.qam.fec_inner = c->fec_inner; p->u.qam.modulation = c->modulation; break; - case FE_OFDM: + case DVBV3_OFDM: dprintk("%s() Preparing OFDM req\n", __func__); - if (c->bandwidth_hz == 6000000) - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - else if (c->bandwidth_hz == 7000000) - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - else if (c->bandwidth_hz == 8000000) + + switch (c->bandwidth_hz) { + case 10000000: + p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ; + break; + case 8000000: p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - else + break; + case 7000000: + p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + break; + case 6000000: + p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + break; + case 5000000: + p->u.ofdm.bandwidth = BANDWIDTH_5_MHZ; + break; + case 1712000: + p->u.ofdm.bandwidth = BANDWIDTH_1_712_MHZ; + break; + case 0: + default: p->u.ofdm.bandwidth = BANDWIDTH_AUTO; + } p->u.ofdm.code_rate_HP = c->code_rate_HP; p->u.ofdm.code_rate_LP = c->code_rate_LP; p->u.ofdm.constellation = c->modulation; @@ -1128,78 +1192,40 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe) p->u.ofdm.guard_interval = c->guard_interval; p->u.ofdm.hierarchy_information = c->hierarchy; break; - case FE_ATSC: + case DVBV3_ATSC: dprintk("%s() Preparing VSB req\n", __func__); p->u.vsb.modulation = c->modulation; break; } + return 0; } -/* Ensure the cached values are set correctly in the frontend - * legacy tuning structures, for the legacy tuning API. +/** + * dtv_get_frontend - calls a callback for retrieving DTV parameters + * @fe: struct dvb_frontend pointer + * @c: struct dtv_frontend_properties pointer (DVBv5 cache) + * @p_out struct dvb_frontend_parameters pointer (DVBv3 FE struct) + * + * This routine calls either the DVBv3 or DVBv5 get_frontend call. + * If c is not null, it will update the DVBv5 cache struct pointed by it. + * If p_out is not null, it will update the DVBv3 params pointed by it. */ -static void dtv_property_adv_params_sync(struct dvb_frontend *fe) +static int dtv_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p_out) { - const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_frontend_parameters *p = &fepriv->parameters_in; - - p->frequency = c->frequency; - p->inversion = c->inversion; - - if (c->delivery_system == SYS_DSS || - c->delivery_system == SYS_DVBS || - c->delivery_system == SYS_DVBS2 || - c->delivery_system == SYS_ISDBS || - c->delivery_system == SYS_TURBO) { - p->u.qpsk.symbol_rate = c->symbol_rate; - p->u.qpsk.fec_inner = c->fec_inner; - } + int r; - /* Fake out a generic DVB-T request so we pass validation in the ioctl */ - if ((c->delivery_system == SYS_ISDBT) || - (c->delivery_system == SYS_DVBT2)) { - p->u.ofdm.constellation = QAM_AUTO; - p->u.ofdm.code_rate_HP = FEC_AUTO; - p->u.ofdm.code_rate_LP = FEC_AUTO; - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; - if (c->bandwidth_hz == 8000000) - p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - else if (c->bandwidth_hz == 7000000) - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - else if (c->bandwidth_hz == 6000000) - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - else - p->u.ofdm.bandwidth = BANDWIDTH_AUTO; + if (fe->ops.get_frontend) { + r = fe->ops.get_frontend(fe); + if (unlikely(r < 0)) + return r; + if (p_out) + dtv_property_legacy_params_sync(fe, p_out); + return 0; } -} -static void dtv_property_cache_submit(struct dvb_frontend *fe) -{ - const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - /* For legacy delivery systems we don't need the delivery_system to - * be specified, but we populate the older structures from the cache - * so we can call set_frontend on older drivers. - */ - if(is_legacy_delivery_system(c->delivery_system)) { - - dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation); - dtv_property_legacy_params_sync(fe); - - } else { - dprintk("%s() adv, modulation = %d\n", __func__, c->modulation); - - /* For advanced delivery systems / modulation types ... - * we seed the lecacy dvb_frontend_parameters structure - * so that the sanity checking code later in the IOCTL processing - * can validate our basic frequency ranges, symbolrates, modulation - * etc. - */ - dtv_property_adv_params_sync(fe); - } + /* As everything is in cache, get_frontend fops are always supported */ + return 0; } static int dvb_frontend_ioctl_legacy(struct file *file, @@ -1208,25 +1234,21 @@ static int dvb_frontend_ioctl_properties(struct file *file, unsigned int cmd, void *parg); static int dtv_property_process_get(struct dvb_frontend *fe, + const struct dtv_frontend_properties *c, struct dtv_property *tvp, struct file *file) { - const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dtv_frontend_properties cdetected; - int r; - - /* - * If the driver implements a get_frontend function, then convert - * detected parameters to S2API properties. - */ - if (fe->ops.get_frontend) { - cdetected = *c; - dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out); - c = &cdetected; - } + int r, ncaps; switch(tvp->cmd) { + case DTV_ENUM_DELSYS: + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps]; + ncaps++; + } + tvp->u.buffer.len = ncaps; + break; case DTV_FREQUENCY: tvp->u.data = c->frequency; break; @@ -1356,14 +1378,168 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return 0; } +static int dtv_set_frontend(struct dvb_frontend *fe); + +static bool is_dvbv3_delsys(u32 delsys) +{ + bool status; + + status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) || + (delsys == SYS_DVBS) || (delsys == SYS_ATSC); + + return status; +} + +static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) +{ + int ncaps, i; + u32 delsys = SYS_UNDEFINED; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + enum dvbv3_emulation_type type; + + /* + * It was reported that some old DVBv5 applications were + * filling delivery_system with SYS_UNDEFINED. If this happens, + * assume that the application wants to use the first supported + * delivery system. + */ + if (c->delivery_system == SYS_UNDEFINED) + c->delivery_system = fe->ops.delsys[0]; + + if (desired_system == SYS_UNDEFINED) { + /* + * A DVBv3 call doesn't know what's the desired system. + * Also, DVBv3 applications don't know that ops.info->type + * could be changed, and they simply dies when it doesn't + * match. + * So, don't change the current delivery system, as it + * may be trying to do the wrong thing, like setting an + * ISDB-T frontend as DVB-T. Instead, find the closest + * DVBv3 system that matches the delivery system. + */ + if (is_dvbv3_delsys(c->delivery_system)) { + dprintk("%s() Using delivery system to %d\n", + __func__, c->delivery_system); + return 0; + } + type = dvbv3_type(c->delivery_system); + switch (type) { + case DVBV3_QPSK: + desired_system = SYS_DVBS; + break; + case DVBV3_QAM: + desired_system = SYS_DVBC_ANNEX_A; + break; + case DVBV3_ATSC: + desired_system = SYS_ATSC; + break; + case DVBV3_OFDM: + desired_system = SYS_DVBT; + break; + default: + dprintk("%s(): This frontend doesn't support DVBv3 calls\n", + __func__); + return -EINVAL; + } + } else { + /* + * This is a DVBv5 call. So, it likely knows the supported + * delivery systems. + */ + + /* Check if the desired delivery system is supported */ + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + if (fe->ops.delsys[ncaps] == desired_system) { + c->delivery_system = desired_system; + dprintk("%s() Changing delivery system to %d\n", + __func__, desired_system); + return 0; + } + ncaps++; + } + type = dvbv3_type(desired_system); + + /* + * The delivery system is not supported. See if it can be + * emulated. + * The emulation only works if the desired system is one of the + * DVBv3 delivery systems + */ + if (!is_dvbv3_delsys(desired_system)) { + dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n", + __func__); + return -EINVAL; + } + + /* + * Get the last non-DVBv3 delivery system that has the same type + * of the desired system + */ + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) && + !is_dvbv3_delsys(fe->ops.delsys[ncaps])) + delsys = fe->ops.delsys[ncaps]; + ncaps++; + } + /* There's nothing compatible with the desired delivery system */ + if (delsys == SYS_UNDEFINED) { + dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n", + __func__); + return -EINVAL; + } + c->delivery_system = delsys; + } + + /* + * The DVBv3 or DVBv5 call is requesting a different system. So, + * emulation is needed. + * + * Emulate newer delivery systems like ISDBT, DVBT and DMBTH + * for older DVBv5 applications. The emulation will try to use + * the auto mode for most things, and will assume that the desired + * delivery system is the last one at the ops.delsys[] array + */ + dprintk("%s() Using delivery system %d emulated as if it were a %d\n", + __func__, delsys, desired_system); + + /* + * For now, handles ISDB-T calls. More code may be needed here for the + * other emulated stuff + */ + if (type == DVBV3_OFDM) { + if (c->delivery_system == SYS_ISDBT) { + dprintk("%s() Using defaults for SYS_ISDBT\n", + __func__); + if (!c->bandwidth_hz) + c->bandwidth_hz = 6000000; + + c->isdbt_partial_reception = 0; + c->isdbt_sb_mode = 0; + c->isdbt_sb_subchannel = 0; + c->isdbt_sb_segment_idx = 0; + c->isdbt_sb_segment_count = 0; + c->isdbt_layer_enabled = 0; + for (i = 0; i < 3; i++) { + c->layer[i].fec = FEC_AUTO; + c->layer[i].modulation = QAM_AUTO; + c->layer[i].interleaving = 0; + c->layer[i].segment_count = 0; + } + } + } + dprintk("change delivery system on cache to %d\n", c->delivery_system); + + return 0; +} + static int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, struct file *file) { int r = 0; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - dtv_property_dump(tvp); /* Allow the frontend to validate incoming properties */ if (fe->ops.set_property) { @@ -1374,11 +1550,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe, switch(tvp->cmd) { case DTV_CLEAR: - /* Reset a cache of data specific to the frontend here. This does + /* + * Reset a cache of data specific to the frontend here. This does * not effect hardware. */ dvb_frontend_clear_cache(fe); - dprintk("%s() Flushing property cache\n", __func__); break; case DTV_TUNE: /* interpret the cache of data, build either a traditional frontend @@ -1387,10 +1563,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe, */ c->state = tvp->cmd; dprintk("%s() Finalised property cache\n", __func__); - dtv_property_cache_submit(fe); - r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND, - &fepriv->parameters_in); + r = dtv_set_frontend(fe); break; case DTV_FREQUENCY: c->frequency = tvp->u.data; @@ -1417,7 +1591,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe, c->rolloff = tvp->u.data; break; case DTV_DELIVERY_SYSTEM: - c->delivery_system = tvp->u.data; + r = set_delivery_system(fe, tvp->u.data); break; case DTV_VOLTAGE: c->voltage = tvp->u.data; @@ -1551,6 +1725,7 @@ static int dvb_frontend_ioctl_properties(struct file *file, { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int err = 0; @@ -1594,7 +1769,6 @@ static int dvb_frontend_ioctl_properties(struct file *file, } else if(cmd == FE_GET_PROPERTY) { - tvps = (struct dtv_properties __user *)parg; dprintk("%s() properties.num = %d\n", __func__, tvps->num); @@ -1616,8 +1790,18 @@ static int dvb_frontend_ioctl_properties(struct file *file, goto out; } + /* + * Fills the cache out struct with the cache contents, plus + * the data retrieved from get_frontend, if the frontend + * is not idle. Otherwise, returns the cached content + */ + if (fepriv->state != FESTATE_IDLE) { + err = dtv_get_frontend(fe, NULL); + if (err < 0) + goto out; + } for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, tvp + i, file); + err = dtv_property_process_get(fe, c, tvp + i, file); if (err < 0) goto out; (tvp + i)->result = err; @@ -1636,12 +1820,121 @@ out: return err; } +static int dtv_set_frontend(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_tune_settings fetunesettings; + u32 rolloff = 0; + + if (dvb_frontend_check_parameters(fe) < 0) + return -EINVAL; + + /* + * Be sure that the bandwidth will be filled for all + * non-satellite systems, as tuners need to know what + * low pass/Nyquist half filter should be applied, in + * order to avoid inter-channel noise. + * + * ISDB-T and DVB-T/T2 already sets bandwidth. + * ATSC and DVB-C don't set, so, the core should fill it. + * + * On DVB-C Annex A and C, the bandwidth is a function of + * the roll-off and symbol rate. Annex B defines different + * roll-off factors depending on the modulation. Fortunately, + * Annex B is only used with 6MHz, so there's no need to + * calculate it. + * + * While not officially supported, a side effect of handling it at + * the cache level is that a program could retrieve the bandwidth + * via DTV_BANDWIDTH_HZ, which may be useful for test programs. + */ + switch (c->delivery_system) { + case SYS_ATSC: + case SYS_DVBC_ANNEX_B: + c->bandwidth_hz = 6000000; + break; + case SYS_DVBC_ANNEX_A: + rolloff = 115; + break; + case SYS_DVBC_ANNEX_C: + rolloff = 113; + break; + default: + break; + } + if (rolloff) + c->bandwidth_hz = (c->symbol_rate * rolloff) / 100; + + /* force auto frequency inversion if requested */ + if (dvb_force_auto_inversion) + c->inversion = INVERSION_AUTO; + + /* + * without hierarchical coding code_rate_LP is irrelevant, + * so we tolerate the otherwise invalid FEC_NONE setting + */ + if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE) + c->code_rate_LP = FEC_AUTO; + + /* get frontend-specific tuning settings */ + memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); + if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { + fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; + fepriv->max_drift = fetunesettings.max_drift; + fepriv->step_size = fetunesettings.step_size; + } else { + /* default values */ + switch (c->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + fepriv->min_delay = HZ / 20; + fepriv->step_size = c->symbol_rate / 16000; + fepriv->max_drift = c->symbol_rate / 2000; + break; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_ISDBT: + case SYS_DMBTH: + fepriv->min_delay = HZ / 20; + fepriv->step_size = fe->ops.info.frequency_stepsize * 2; + fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; + break; + default: + /* + * FIXME: This sounds wrong! if freqency_stepsize is + * defined by the frontend, why not use it??? + */ + fepriv->min_delay = HZ / 20; + fepriv->step_size = 0; /* no zigzag */ + fepriv->max_drift = 0; + break; + } + } + if (dvb_override_tune_delay > 0) + fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; + + fepriv->state = FESTATE_RETUNE; + + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + + dvb_frontend_clear_events(fe); + dvb_frontend_add_event(fe, 0); + dvb_frontend_wakeup(fe); + fepriv->status = 0; + + return 0; +} + + static int dvb_frontend_ioctl_legacy(struct file *file, unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int cb_err, err = -EOPNOTSUPP; if (fe->dvb->fe_ioctl_override) { @@ -1658,9 +1951,43 @@ static int dvb_frontend_ioctl_legacy(struct file *file, switch (cmd) { case FE_GET_INFO: { struct dvb_frontend_info* info = parg; + memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); + /* + * Associate the 4 delivery systems supported by DVBv3 + * API with their DVBv5 counterpart. For the other standards, + * use the closest type, assuming that it would hopefully + * work with a DVBv3 application. + * It should be noticed that, on multi-frontend devices with + * different types (terrestrial and cable, for example), + * a pure DVBv3 application won't be able to use all delivery + * systems. Yet, changing the DVBv5 cache to the other delivery + * system should be enough for making it work. + */ + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_QPSK: + info->type = FE_QPSK; + break; + case DVBV3_ATSC: + info->type = FE_ATSC; + break; + case DVBV3_QAM: + info->type = FE_QAM; + break; + case DVBV3_OFDM: + info->type = FE_OFDM; + break; + default: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + fe->ops.info.type = FE_OFDM; + } + dprintk("current delivery system on cache: %d, V3 type: %d\n", + c->delivery_system, fe->ops.info.type); + /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't * do it, it is done for it. */ info->caps |= FE_CAN_INVERSION_AUTO; @@ -1819,108 +2146,22 @@ static int dvb_frontend_ioctl_legacy(struct file *file, err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); break; - case FE_SET_FRONTEND: { - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_tune_settings fetunesettings; - - if (c->state == DTV_TUNE) { - if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) { - err = -EINVAL; - break; - } - } else { - if (dvb_frontend_check_parameters(fe, parg) < 0) { - err = -EINVAL; - break; - } - - memcpy (&fepriv->parameters_in, parg, - sizeof (struct dvb_frontend_parameters)); - dtv_property_cache_init(fe, c); - dtv_property_cache_sync(fe, c, &fepriv->parameters_in); - } - - /* - * Initialize output parameters to match the values given by - * the user. FE_SET_FRONTEND triggers an initial frontend event - * with status = 0, which copies output parameters to userspace. - */ - fepriv->parameters_out = fepriv->parameters_in; - - memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); - memcpy(&fetunesettings.parameters, parg, - sizeof (struct dvb_frontend_parameters)); - - /* force auto frequency inversion if requested */ - if (dvb_force_auto_inversion) { - fepriv->parameters_in.inversion = INVERSION_AUTO; - fetunesettings.parameters.inversion = INVERSION_AUTO; - } - if (fe->ops.info.type == FE_OFDM) { - /* without hierarchical coding code_rate_LP is irrelevant, - * so we tolerate the otherwise invalid FEC_NONE setting */ - if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE && - fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE) - fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO; - } - - /* get frontend-specific tuning settings */ - if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { - fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; - fepriv->max_drift = fetunesettings.max_drift; - fepriv->step_size = fetunesettings.step_size; - } else { - /* default values */ - switch(fe->ops.info.type) { - case FE_QPSK: - fepriv->min_delay = HZ/20; - fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000; - fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000; - break; - - case FE_QAM: - fepriv->min_delay = HZ/20; - fepriv->step_size = 0; /* no zigzag */ - fepriv->max_drift = 0; - break; - - case FE_OFDM: - fepriv->min_delay = HZ/20; - fepriv->step_size = fe->ops.info.frequency_stepsize * 2; - fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; - break; - case FE_ATSC: - fepriv->min_delay = HZ/20; - fepriv->step_size = 0; - fepriv->max_drift = 0; - break; - } - } - if (dvb_override_tune_delay > 0) - fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; - - fepriv->state = FESTATE_RETUNE; - - /* Request the search algorithm to search */ - fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + case FE_SET_FRONTEND: + err = set_delivery_system(fe, SYS_UNDEFINED); + if (err) + break; - dvb_frontend_clear_events(fe); - dvb_frontend_add_event(fe, 0); - dvb_frontend_wakeup(fe); - fepriv->status = 0; - err = 0; + err = dtv_property_cache_sync(fe, c, parg); + if (err) + break; + err = dtv_set_frontend(fe); break; - } - case FE_GET_EVENT: err = dvb_frontend_get_event (fe, parg, file->f_flags); break; case FE_GET_FRONTEND: - if (fe->ops.get_frontend) { - err = fe->ops.get_frontend(fe, &fepriv->parameters_out); - memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters)); - } + err = dtv_get_frontend(fe, parg); break; case FE_SET_FRONTEND_TUNE_MODE: @@ -2061,12 +2302,15 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) dprintk ("%s\n", __func__); - if ((file->f_flags & O_ACCMODE) != O_RDONLY) + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { fepriv->release_jiffies = jiffies; + mb(); + } ret = dvb_generic_release (inode, file); if (dvbdev->users == -1) { + wake_up(&fepriv->wait_queue); if (fepriv->exit != DVB_FE_NO_EXIT) { fops_put(file->f_op); file->f_op = NULL; @@ -2127,6 +2371,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb, dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND); + /* + * Initialize the cache to the proper values according with the + * first supported delivery system (ops->delsys[0]) + */ + + fe->dtv_property_cache.delivery_system = fe->ops.delsys[0]; + dvb_frontend_clear_cache(fe); + mutex_unlock(&frontend_mutex); return 0; } diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 67bbfa728016..d63a8215fe03 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -42,11 +42,16 @@ #include "dvbdev.h" +/* + * Maximum number of Delivery systems per frontend. It + * should be smaller or equal to 32 + */ +#define MAX_DELSYS 8 + struct dvb_frontend_tune_settings { int min_delay_ms; int step_size; int max_drift; - struct dvb_frontend_parameters parameters; }; struct dvb_frontend; @@ -198,11 +203,11 @@ struct dvb_tuner_ops { int (*sleep)(struct dvb_frontend *fe); /** This is for simple PLLs - set all parameters in one go. */ - int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*set_params)(struct dvb_frontend *fe); int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ - int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); + int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len); /** This is to allow setting tuner-specific configs */ int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); @@ -250,10 +255,14 @@ struct analog_demod_ops { int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); }; +struct dtv_frontend_properties; + struct dvb_frontend_ops { struct dvb_frontend_info info; + u8 delsys[MAX_DELSYS]; + void (*release)(struct dvb_frontend* fe); void (*release_sec)(struct dvb_frontend* fe); @@ -264,7 +273,7 @@ struct dvb_frontend_ops { /* if this is set, it overrides the default swzigzag */ int (*tune)(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status); @@ -272,10 +281,10 @@ struct dvb_frontend_ops { enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); /* these two are only used for the swzigzag code */ - int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*set_frontend)(struct dvb_frontend *fe); int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); - int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*get_frontend)(struct dvb_frontend *fe); int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*read_ber)(struct dvb_frontend* fe, u32* ber); @@ -297,8 +306,7 @@ struct dvb_frontend_ops { /* These callbacks are for devices that implement their own * tuning algorithms, rather than a simple swzigzag */ - enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); - int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + enum dvbfe_search (*search)(struct dvb_frontend *fe); struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; @@ -307,6 +315,7 @@ struct dvb_frontend_ops { int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); }; +#ifdef __DVB_CORE__ #define MAX_EVENT 8 struct dvb_fe_events { @@ -317,6 +326,7 @@ struct dvb_fe_events { wait_queue_head_t wait_queue; struct mutex mtx; }; +#endif struct dtv_frontend_properties { @@ -374,6 +384,7 @@ struct dvb_frontend { void *analog_demod_priv; struct dtv_frontend_properties dtv_property_cache; #define DVB_FRONTEND_COMPONENT_TUNER 0 +#define DVB_FRONTEND_COMPONENT_DEMOD 1 int (*callback)(void *adapter_priv, int component, int cmd, int arg); int id; }; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 93d9869e0f15..8766ce8c354d 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1510,9 +1510,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, for (i=0; i<DVB_NET_DEVICES_MAX; i++) dvbnet->state[i] = 0; - dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net, + return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net, dvbnet, DVB_DEVICE_NET); - - return 0; } EXPORT_SYMBOL(dvb_net_init); diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 58257165761e..9f203c6767a6 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -311,6 +311,7 @@ config DVB_USB_ANYSEE select DVB_STV0900 if !DVB_FE_CUSTOMISE select DVB_STV6110 if !DVB_FE_CUSTOMISE select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_CXD2820R if !DVB_FE_CUSTOMISE help Say Y here to support the Anysee E30, Anysee E30 Plus or Anysee E30 C Plus DVB USB2.0 receiver. @@ -340,7 +341,7 @@ config DVB_USB_AF9015 config DVB_USB_CE6230 tristate "Intel CE6230 DVB-T USB2.0 support" - depends on DVB_USB && EXPERIMENTAL + depends on DVB_USB select DVB_ZL10353 select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE help @@ -354,7 +355,7 @@ config DVB_USB_FRIIO config DVB_USB_EC168 tristate "E3C EC168 DVB-T USB2.0 support" - depends on DVB_USB && EXPERIMENTAL + depends on DVB_USB select DVB_EC100 select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE help diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c index 3263e9749d09..740f3f496f12 100644 --- a/drivers/media/dvb/dvb-usb/af9005-fe.c +++ b/drivers/media/dvb/dvb-usb/af9005-fe.c @@ -303,7 +303,7 @@ static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, return -EINVAL; } - /* read constellation mode */ + /* read modulation mode */ ret = af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, reg_tpsd_const_pos, reg_tpsd_const_len, @@ -321,7 +321,7 @@ static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, bits = 6; break; default: - err("invalid constellation mode"); + err("invalid modulation mode"); return -EINVAL; } *pre_bit_count = super_frame_count * 68 * 4 * x * bits; @@ -533,13 +533,13 @@ static int af9005_fe_read_signal_strength(struct dvb_frontend *fe, static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr) { - /* the snr can be derived from the ber and the constellation + /* the snr can be derived from the ber and the modulation but I don't think this kind of complex calculations belong in the driver. I may be wrong.... */ return -ENOSYS; } -static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) +static int af9005_fe_program_cfoe(struct dvb_usb_device *d, u32 bw) { u8 temp0, temp1, temp2, temp3, buf[4]; int ret; @@ -551,7 +551,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) u32 NS_coeff2_8k; switch (bw) { - case BANDWIDTH_6_MHZ: + case 6000000: NS_coeff1_2048Nu = 0x2ADB6DC; NS_coeff1_8191Nu = 0xAB7313; NS_coeff1_8192Nu = 0xAB6DB7; @@ -560,7 +560,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) NS_coeff2_8k = 0x55B6DC; break; - case BANDWIDTH_7_MHZ: + case 7000000: NS_coeff1_2048Nu = 0x3200001; NS_coeff1_8191Nu = 0xC80640; NS_coeff1_8192Nu = 0xC80000; @@ -569,7 +569,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) NS_coeff2_8k = 0x640000; break; - case BANDWIDTH_8_MHZ: + case 8000000: NS_coeff1_2048Nu = 0x3924926; NS_coeff1_8191Nu = 0xE4996E; NS_coeff1_8192Nu = 0xE49249; @@ -773,17 +773,17 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) } -static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw) +static int af9005_fe_select_bw(struct dvb_usb_device *d, u32 bw) { u8 temp; switch (bw) { - case BANDWIDTH_6_MHZ: + case 6000000: temp = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: temp = 1; break; - case BANDWIDTH_8_MHZ: + case 8000000: temp = 2; break; default: @@ -930,10 +930,11 @@ static int af9005_fe_init(struct dvb_frontend *fe) /* init other parameters: program cfoe and select bandwidth */ deb_info("program cfoe\n"); - if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ))) + ret = af9005_fe_program_cfoe(state->d, 6000000); + if (ret) return ret; - /* set read-update bit for constellation */ - deb_info("set read-update bit for constellation\n"); + /* set read-update bit for modulation */ + deb_info("set read-update bit for modulation\n"); if ((ret = af9005_write_register_bits(state->d, xd_p_reg_feq_read_update, reg_feq_read_update_pos, @@ -943,8 +944,8 @@ static int af9005_fe_init(struct dvb_frontend *fe) /* sample code has a set MPEG TS code here but sniffing reveals that it doesn't do it */ - /* set read-update bit to 1 for DCA constellation */ - deb_info("set read-update bit 1 for DCA constellation\n"); + /* set read-update bit to 1 for DCA modulation */ + deb_info("set read-update bit 1 for DCA modulation\n"); if ((ret = af9005_write_register_bits(state->d, xd_p_reg_dca_read_update, reg_dca_read_update_pos, @@ -1099,15 +1100,15 @@ static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) return 0; } -static int af9005_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int af9005_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct af9005_fe_state *state = fe->demodulator_priv; int ret; u8 temp, temp0, temp1, temp2; deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency, - fep->u.ofdm.bandwidth); + fep->bandwidth_hz); if (fe->ops.tuner_ops.release == NULL) { err("Tuner not attached"); return -ENODEV; @@ -1167,10 +1168,10 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe, /* select bandwidth */ deb_info("select bandwidth"); - ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth); + ret = af9005_fe_select_bw(state->d, fep->bandwidth_hz); if (ret) return ret; - ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth); + ret = af9005_fe_program_cfoe(state->d, fep->bandwidth_hz); if (ret) return ret; @@ -1189,7 +1190,7 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe, return ret; /* set tuner */ deb_info("set tuner\n"); - ret = fe->ops.tuner_ops.set_params(fe, fep); + ret = fe->ops.tuner_ops.set_params(fe); if (ret) return ret; @@ -1225,9 +1226,9 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe, return 0; } -static int af9005_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int af9005_fe_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct af9005_fe_state *state = fe->demodulator_priv; int ret; u8 temp; @@ -1239,19 +1240,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, &temp); if (ret) return ret; - deb_info("===== fe_get_frontend ==============\n"); + deb_info("===== fe_get_frontend_legacy = =============\n"); deb_info("CONSTELLATION "); switch (temp) { case 0: - fep->u.ofdm.constellation = QPSK; + fep->modulation = QPSK; deb_info("QPSK\n"); break; case 1: - fep->u.ofdm.constellation = QAM_16; + fep->modulation = QAM_16; deb_info("QAM_16\n"); break; case 2: - fep->u.ofdm.constellation = QAM_64; + fep->modulation = QAM_64; deb_info("QAM_64\n"); break; } @@ -1266,19 +1267,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("HIERARCHY "); switch (temp) { case 0: - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fep->hierarchy = HIERARCHY_NONE; deb_info("NONE\n"); break; case 1: - fep->u.ofdm.hierarchy_information = HIERARCHY_1; + fep->hierarchy = HIERARCHY_1; deb_info("1\n"); break; case 2: - fep->u.ofdm.hierarchy_information = HIERARCHY_2; + fep->hierarchy = HIERARCHY_2; deb_info("2\n"); break; case 3: - fep->u.ofdm.hierarchy_information = HIERARCHY_4; + fep->hierarchy = HIERARCHY_4; deb_info("4\n"); break; } @@ -1302,23 +1303,23 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("CODERATE HP "); switch (temp) { case 0: - fep->u.ofdm.code_rate_HP = FEC_1_2; + fep->code_rate_HP = FEC_1_2; deb_info("FEC_1_2\n"); break; case 1: - fep->u.ofdm.code_rate_HP = FEC_2_3; + fep->code_rate_HP = FEC_2_3; deb_info("FEC_2_3\n"); break; case 2: - fep->u.ofdm.code_rate_HP = FEC_3_4; + fep->code_rate_HP = FEC_3_4; deb_info("FEC_3_4\n"); break; case 3: - fep->u.ofdm.code_rate_HP = FEC_5_6; + fep->code_rate_HP = FEC_5_6; deb_info("FEC_5_6\n"); break; case 4: - fep->u.ofdm.code_rate_HP = FEC_7_8; + fep->code_rate_HP = FEC_7_8; deb_info("FEC_7_8\n"); break; } @@ -1333,23 +1334,23 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("CODERATE LP "); switch (temp) { case 0: - fep->u.ofdm.code_rate_LP = FEC_1_2; + fep->code_rate_LP = FEC_1_2; deb_info("FEC_1_2\n"); break; case 1: - fep->u.ofdm.code_rate_LP = FEC_2_3; + fep->code_rate_LP = FEC_2_3; deb_info("FEC_2_3\n"); break; case 2: - fep->u.ofdm.code_rate_LP = FEC_3_4; + fep->code_rate_LP = FEC_3_4; deb_info("FEC_3_4\n"); break; case 3: - fep->u.ofdm.code_rate_LP = FEC_5_6; + fep->code_rate_LP = FEC_5_6; deb_info("FEC_5_6\n"); break; case 4: - fep->u.ofdm.code_rate_LP = FEC_7_8; + fep->code_rate_LP = FEC_7_8; deb_info("FEC_7_8\n"); break; } @@ -1363,19 +1364,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("GUARD INTERVAL "); switch (temp) { case 0: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + fep->guard_interval = GUARD_INTERVAL_1_32; deb_info("1_32\n"); break; case 1: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + fep->guard_interval = GUARD_INTERVAL_1_16; deb_info("1_16\n"); break; case 2: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + fep->guard_interval = GUARD_INTERVAL_1_8; deb_info("1_8\n"); break; case 3: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + fep->guard_interval = GUARD_INTERVAL_1_4; deb_info("1_4\n"); break; } @@ -1390,11 +1391,11 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("TRANSMISSION MODE "); switch (temp) { case 0: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + fep->transmission_mode = TRANSMISSION_MODE_2K; deb_info("2K\n"); break; case 1: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + fep->transmission_mode = TRANSMISSION_MODE_8K; deb_info("8K\n"); break; } @@ -1406,15 +1407,15 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("BANDWIDTH "); switch (temp) { case 0: - fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + fep->bandwidth_hz = 6000000; deb_info("6\n"); break; case 1: - fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + fep->bandwidth_hz = 7000000; deb_info("7\n"); break; case 2: - fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + fep->bandwidth_hz = 8000000; deb_info("8\n"); break; } @@ -1454,9 +1455,9 @@ struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) } static struct dvb_frontend_ops af9005_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "AF9005 USB DVB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 250000, diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index bd51a764351b..af176b6ce738 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." DVB_USB_DEBUG_STATUS); /* enable obnoxious led */ -int dvb_usb_af9005_led = 1; +bool dvb_usb_af9005_led = 1; module_param_named(led, dvb_usb_af9005_led, bool, 0644); MODULE_PARM_DESC(led, "enable led (default: 1)."); @@ -977,11 +977,20 @@ static int af9005_usb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr); } +enum af9005_usb_table_entry { + AFATECH_AF9005, + TERRATEC_AF9005, + ANSONIC_AF9005, +}; + static struct usb_device_id af9005_usb_table[] = { - {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, - {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)}, - {0}, + [AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH, + USB_PID_AFATECH_AF9005)}, + [TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_USB_XE)}, + [ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC, + USB_PID_ANSONIC_DVBT_USB)}, + { } }; MODULE_DEVICE_TABLE(usb, af9005_usb_table); @@ -1041,15 +1050,15 @@ static struct dvb_usb_device_properties af9005_properties = { .num_device_descs = 3, .devices = { {.name = "Afatech DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[0], NULL}, + .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL}, .warm_ids = {NULL}, }, {.name = "TerraTec Cinergy T USB XE", - .cold_ids = {&af9005_usb_table[1], NULL}, + .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL}, .warm_ids = {NULL}, }, {.name = "Ansonic DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[2], NULL}, + .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL}, .warm_ids = {NULL}, }, {NULL}, diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h index c71c77bd7f4b..6a2bf3de8456 100644 --- a/drivers/media/dvb/dvb-usb/af9005.h +++ b/drivers/media/dvb/dvb-usb/af9005.h @@ -35,7 +35,7 @@ extern int dvb_usb_af9005_debug; #define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args) #define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args) -extern int dvb_usb_af9005_led; +extern bool dvb_usb_af9005_led; /* firmware */ #define FW_BULKOUT_SIZE 250 diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 56cbd3636c31..282a43d648df 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -50,14 +50,14 @@ static int af9015_properties_count = ARRAY_SIZE(af9015_properties); static struct af9013_config af9015_af9013_config[] = { { - .demod_address = AF9015_I2C_DEMOD, - .output_mode = AF9013_OUTPUT_MODE_USB, + .i2c_addr = AF9015_I2C_DEMOD, + .ts_mode = AF9013_TS_USB, .api_version = { 0, 1, 9, 0 }, .gpio[0] = AF9013_GPIO_HI, .gpio[3] = AF9013_GPIO_TUNER_ON, }, { - .output_mode = AF9013_OUTPUT_MODE_SERIAL, + .ts_mode = AF9013_TS_SERIAL, .api_version = { 0, 1, 9, 0 }, .gpio[0] = AF9013_GPIO_TUNER_ON, .gpio[1] = AF9013_GPIO_LO, @@ -216,8 +216,8 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, { struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - if (addr == af9015_af9013_config[0].demod_address || - addr == af9015_af9013_config[1].demod_address) + if (addr == af9015_af9013_config[0].i2c_addr || + addr == af9015_af9013_config[1].i2c_addr) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -228,8 +228,8 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, { struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - if (addr == af9015_af9013_config[0].demod_address || - addr == af9015_af9013_config[1].demod_address) + if (addr == af9015_af9013_config[0].i2c_addr || + addr == af9015_af9013_config[1].i2c_addr) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -271,8 +271,8 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. return -EAGAIN; while (i < num) { - if (msg[i].addr == af9015_af9013_config[0].demod_address || - msg[i].addr == af9015_af9013_config[1].demod_address) { + if (msg[i].addr == af9015_af9013_config[0].i2c_addr || + msg[i].addr == af9015_af9013_config[1].i2c_addr) { addr = msg[i].buf[0] << 8; addr += msg[i].buf[1]; mbox = msg[i].buf[2]; @@ -288,8 +288,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto error; } - if (msg[i].addr == - af9015_af9013_config[0].demod_address) + if (msg[i].addr == af9015_af9013_config[0].i2c_addr) req.cmd = READ_MEMORY; else req.cmd = READ_I2C; @@ -307,7 +306,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. goto error; } if (msg[i].addr == - af9015_af9013_config[0].demod_address) { + af9015_af9013_config[0].i2c_addr) { ret = -EINVAL; goto error; } @@ -325,8 +324,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto error; } - if (msg[i].addr == - af9015_af9013_config[0].demod_address) + if (msg[i].addr == af9015_af9013_config[0].i2c_addr) req.cmd = WRITE_MEMORY; else req.cmd = WRITE_I2C; @@ -508,7 +506,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) msleep(100); ret = af9015_read_reg_i2c(d, - af9015_af9013_config[1].demod_address, 0x98be, &val); + af9015_af9013_config[1].i2c_addr, 0x98be, &val); if (ret) goto error; else @@ -536,7 +534,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) goto error; /* request boot firmware */ - ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address, + ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].i2c_addr, 0xe205, 1); deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); if (ret) @@ -547,7 +545,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) /* check firmware status */ ret = af9015_read_reg_i2c(d, - af9015_af9013_config[1].demod_address, 0x98be, &val); + af9015_af9013_config[1].i2c_addr, 0x98be, &val); deb_info("%s: firmware status cmd status:%d fw status:%02x\n", __func__, ret, val); if (ret) @@ -840,7 +838,7 @@ static int af9015_read_config(struct usb_device *udev) if (ret) goto error; - deb_info("%s: IR mode:%d\n", __func__, val); + deb_info("%s: IR mode=%d\n", __func__, val); for (i = 0; i < af9015_properties_count; i++) { if (val == AF9015_IR_MODE_DISABLED) af9015_properties[i].rc.core.rc_codes = NULL; @@ -854,7 +852,7 @@ static int af9015_read_config(struct usb_device *udev) if (ret) goto error; af9015_config.dual_mode = val; - deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode); + deb_info("%s: TS mode=%d\n", __func__, af9015_config.dual_mode); /* Set adapter0 buffer size according to USB port speed, adapter1 buffer size can be static because it is enabled only USB2.0 */ @@ -878,7 +876,7 @@ static int af9015_read_config(struct usb_device *udev) ret = af9015_rw_udev(udev, &req); if (ret) goto error; - af9015_af9013_config[1].demod_address = val; + af9015_af9013_config[1].i2c_addr = val; /* enable 2nd adapter */ for (i = 0; i < af9015_properties_count; i++) @@ -900,34 +898,38 @@ static int af9015_read_config(struct usb_device *udev) goto error; switch (val) { case 0: - af9015_af9013_config[i].adc_clock = 28800; + af9015_af9013_config[i].clock = 28800000; break; case 1: - af9015_af9013_config[i].adc_clock = 20480; + af9015_af9013_config[i].clock = 20480000; break; case 2: - af9015_af9013_config[i].adc_clock = 28000; + af9015_af9013_config[i].clock = 28000000; break; case 3: - af9015_af9013_config[i].adc_clock = 25000; + af9015_af9013_config[i].clock = 25000000; break; }; - deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i, - val, af9015_af9013_config[i].adc_clock); + deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i, + val, af9015_af9013_config[i].clock); - /* tuner IF */ + /* IF frequency */ req.addr = AF9015_EEPROM_IF1H + offset; ret = af9015_rw_udev(udev, &req); if (ret) goto error; - af9015_af9013_config[i].tuner_if = val << 8; + + af9015_af9013_config[i].if_frequency = val << 8; + req.addr = AF9015_EEPROM_IF1L + offset; ret = af9015_rw_udev(udev, &req); if (ret) goto error; - af9015_af9013_config[i].tuner_if += val; - deb_info("%s: [%d] IF1:%d\n", __func__, i, - af9015_af9013_config[0].tuner_if); + + af9015_af9013_config[i].if_frequency += val; + af9015_af9013_config[i].if_frequency *= 1000; + deb_info("%s: [%d] IF frequency=%d\n", __func__, i, + af9015_af9013_config[0].if_frequency); /* MT2060 IF1 */ req.addr = AF9015_EEPROM_MT2060_IF1H + offset; @@ -940,7 +942,7 @@ static int af9015_read_config(struct usb_device *udev) if (ret) goto error; af9015_config.mt2060_if1[i] += val; - deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i, + deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i, af9015_config.mt2060_if1[i]); /* tuner */ @@ -957,30 +959,30 @@ static int af9015_read_config(struct usb_device *udev) case AF9013_TUNER_TDA18271: case AF9013_TUNER_QT1010A: case AF9013_TUNER_TDA18218: - af9015_af9013_config[i].rf_spec_inv = 1; + af9015_af9013_config[i].spec_inv = 1; break; case AF9013_TUNER_MXL5003D: case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: case AF9013_TUNER_MXL5007T: - af9015_af9013_config[i].rf_spec_inv = 0; + af9015_af9013_config[i].spec_inv = 0; break; case AF9013_TUNER_MC44S803: af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO; - af9015_af9013_config[i].rf_spec_inv = 1; + af9015_af9013_config[i].spec_inv = 1; break; default: - warn("tuner id:%d not supported, please report!", val); + warn("tuner id=%d not supported, please report!", val); return -ENODEV; }; af9015_af9013_config[i].tuner = val; - deb_info("%s: [%d] tuner id:%d\n", __func__, i, val); + deb_info("%s: [%d] tuner id=%d\n", __func__, i, val); } error: if (ret) - err("eeprom read failed:%d", ret); + err("eeprom read failed=%d", ret); /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM content :-( Override some wrong values here. Ditto for the @@ -998,7 +1000,7 @@ error: af9015_properties[i].num_adapters = 1; /* set correct IF */ - af9015_af9013_config[0].tuner_if = 4570; + af9015_af9013_config[0].if_frequency = 4570000; } return ret; @@ -1093,9 +1095,79 @@ error: return ret; } +/* override demod callbacks for resource locking */ +static int af9015_af9013_set_frontend(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *priv = adap->dev->priv; + + if (mutex_lock_interruptible(&adap->dev->usb_mutex)) + return -EAGAIN; + + ret = priv->set_frontend[adap->id](fe); + + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *priv = adap->dev->priv; + + if (mutex_lock_interruptible(&adap->dev->usb_mutex)) + return -EAGAIN; + + ret = priv->read_status[adap->id](fe, status); + + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_init(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *priv = adap->dev->priv; + + if (mutex_lock_interruptible(&adap->dev->usb_mutex)) + return -EAGAIN; + + ret = priv->init[adap->id](fe); + + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *priv = adap->dev->priv; + + if (mutex_lock_interruptible(&adap->dev->usb_mutex)) + return -EAGAIN; + + ret = priv->sleep[adap->id](fe); + + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) { int ret; + struct af9015_state *state = adap->dev->priv; if (adap->id == 1) { /* copy firmware to 2nd demodulator */ @@ -1116,6 +1188,32 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], &adap->dev->i2c_adap); + /* + * AF9015 firmware does not like if it gets interrupted by I2C adapter + * request on some critical phases. During normal operation I2C adapter + * is used only 2nd demodulator and tuner on dual tuner devices. + * Override demodulator callbacks and use mutex for limit access to + * those "critical" paths to keep AF9015 happy. + * Note: we abuse unused usb_mutex here. + */ + if (adap->fe_adap[0].fe) { + state->set_frontend[adap->id] = + adap->fe_adap[0].fe->ops.set_frontend; + adap->fe_adap[0].fe->ops.set_frontend = + af9015_af9013_set_frontend; + + state->read_status[adap->id] = + adap->fe_adap[0].fe->ops.read_status; + adap->fe_adap[0].fe->ops.read_status = + af9015_af9013_read_status; + + state->init[adap->id] = adap->fe_adap[0].fe->ops.init; + adap->fe_adap[0].fe->ops.init = af9015_af9013_init; + + state->sleep[adap->id] = adap->fe_adap[0].fe->ops.sleep; + adap->fe_adap[0].fe->ops.sleep = af9015_af9013_sleep; + } + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -1245,49 +1343,112 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) return ret; } +enum af9015_usb_table_entry { + AFATECH_9015, + AFATECH_9016, + WINFAST_DTV_GOLD, + PINNACLE_PCTV_71E, + KWORLD_PLUSTV_399U, + TINYTWIN, + AZUREWAVE_TU700, + TERRATEC_AF9015, + KWORLD_PLUSTV_PC160, + AVERTV_VOLAR_X, + XTENSIONS_380U, + MSI_DIGIVOX_DUO, + AVERTV_VOLAR_X_REV2, + TELESTAR_STARSTICK_2, + AVERMEDIA_A309_USB, + MSI_DIGIVOX_MINI_III, + KWORLD_E396, + KWORLD_E39B, + KWORLD_E395, + TREKSTOR_DVBT, + AVERTV_A850, + AVERTV_A805, + CONCEPTRONIC_CTVDIGRCU, + KWORLD_MC810, + GENIUS_TVGO_DVB_T03, + KWORLD_399U_2, + KWORLD_PC160_T, + SVEON_STV20, + TINYTWIN_2, + WINFAST_DTV2000DS, + KWORLD_UB383_T, + KWORLD_E39A, + AVERMEDIA_A815M, + CINERGY_T_STICK_RC, + CINERGY_T_DUAL_RC, + AVERTV_A850T, + TINYTWIN_3, + SVEON_STV22, +}; + static struct usb_device_id af9015_usb_table[] = { -/* 0 */{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, - {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, - {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, - {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, -/* 5 */{USB_DEVICE(USB_VID_VISIONPLUS, - USB_PID_TINYTWIN)}, - {USB_DEVICE(USB_VID_VISIONPLUS, - USB_PID_AZUREWAVE_AD_TU700)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, -/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, - {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, - {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, -/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, - {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, -/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, - {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, -/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, - {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, -/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, - {USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, -/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, - {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)}, - {0}, + [AFATECH_9015] = + {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, + [AFATECH_9016] = + {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, + [WINFAST_DTV_GOLD] = + {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, + [PINNACLE_PCTV_71E] = + {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, + [KWORLD_PLUSTV_399U] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, + [TINYTWIN] = {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)}, + [AZUREWAVE_TU700] = + {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)}, + [TERRATEC_AF9015] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, + [KWORLD_PLUSTV_PC160] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, + [AVERTV_VOLAR_X] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, + [XTENSIONS_380U] = + {USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, + [MSI_DIGIVOX_DUO] = + {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, + [AVERTV_VOLAR_X_REV2] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, + [TELESTAR_STARSTICK_2] = + {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, + [AVERMEDIA_A309_USB] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, + [MSI_DIGIVOX_MINI_III] = + {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, + [KWORLD_E396] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, + [KWORLD_E39B] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, + [KWORLD_E395] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, + [TREKSTOR_DVBT] = {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, + [AVERTV_A850] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, + [AVERTV_A805] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, + [CONCEPTRONIC_CTVDIGRCU] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, + [KWORLD_MC810] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, + [GENIUS_TVGO_DVB_T03] = + {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, + [KWORLD_399U_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, + [KWORLD_PC160_T] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, + [SVEON_STV20] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, + [TINYTWIN_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, + [WINFAST_DTV2000DS] = + {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, + [KWORLD_UB383_T] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, + [KWORLD_E39A] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, + [AVERMEDIA_A815M] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, + [CINERGY_T_STICK_RC] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, + [CINERGY_T_DUAL_RC] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, + [AVERTV_A850T] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, + [TINYTWIN_3] = {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, + [SVEON_STV22] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)}, + { } }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1362,68 +1523,104 @@ static struct dvb_usb_device_properties af9015_properties[] = { .devices = { { .name = "Afatech AF9015 DVB-T USB2.0 stick", - .cold_ids = {&af9015_usb_table[0], - &af9015_usb_table[1], NULL}, + .cold_ids = { + &af9015_usb_table[AFATECH_9015], + &af9015_usb_table[AFATECH_9016], + NULL + }, .warm_ids = {NULL}, }, { .name = "Leadtek WinFast DTV Dongle Gold", - .cold_ids = {&af9015_usb_table[2], NULL}, + .cold_ids = { + &af9015_usb_table[WINFAST_DTV_GOLD], + NULL + }, .warm_ids = {NULL}, }, { .name = "Pinnacle PCTV 71e", - .cold_ids = {&af9015_usb_table[3], NULL}, + .cold_ids = { + &af9015_usb_table[PINNACLE_PCTV_71E], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld PlusTV Dual DVB-T Stick " \ "(DVB-T 399U)", - .cold_ids = {&af9015_usb_table[4], - &af9015_usb_table[25], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_PLUSTV_399U], + &af9015_usb_table[KWORLD_399U_2], + NULL + }, .warm_ids = {NULL}, }, { .name = "DigitalNow TinyTwin DVB-T Receiver", - .cold_ids = {&af9015_usb_table[5], - &af9015_usb_table[28], - &af9015_usb_table[36], NULL}, + .cold_ids = { + &af9015_usb_table[TINYTWIN], + &af9015_usb_table[TINYTWIN_2], + &af9015_usb_table[TINYTWIN_3], + NULL + }, .warm_ids = {NULL}, }, { .name = "TwinHan AzureWave AD-TU700(704J)", - .cold_ids = {&af9015_usb_table[6], NULL}, + .cold_ids = { + &af9015_usb_table[AZUREWAVE_TU700], + NULL + }, .warm_ids = {NULL}, }, { .name = "TerraTec Cinergy T USB XE", - .cold_ids = {&af9015_usb_table[7], NULL}, + .cold_ids = { + &af9015_usb_table[TERRATEC_AF9015], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld PlusTV Dual DVB-T PCI " \ "(DVB-T PC160-2T)", - .cold_ids = {&af9015_usb_table[8], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_PLUSTV_PC160], + NULL + }, .warm_ids = {NULL}, }, { .name = "AVerMedia AVerTV DVB-T Volar X", - .cold_ids = {&af9015_usb_table[9], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_VOLAR_X], + NULL + }, .warm_ids = {NULL}, }, { .name = "TerraTec Cinergy T Stick RC", - .cold_ids = {&af9015_usb_table[33], NULL}, + .cold_ids = { + &af9015_usb_table[CINERGY_T_STICK_RC], + NULL + }, .warm_ids = {NULL}, }, { .name = "TerraTec Cinergy T Stick Dual RC", - .cold_ids = {&af9015_usb_table[34], NULL}, + .cold_ids = { + &af9015_usb_table[CINERGY_T_DUAL_RC], + NULL + }, .warm_ids = {NULL}, }, { .name = "AverMedia AVerTV Red HD+ (A850T)", - .cold_ids = {&af9015_usb_table[35], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_A850T], + NULL + }, .warm_ids = {NULL}, }, } @@ -1496,57 +1693,87 @@ static struct dvb_usb_device_properties af9015_properties[] = { .devices = { { .name = "Xtensions XD-380", - .cold_ids = {&af9015_usb_table[10], NULL}, + .cold_ids = { + &af9015_usb_table[XTENSIONS_380U], + NULL + }, .warm_ids = {NULL}, }, { .name = "MSI DIGIVOX Duo", - .cold_ids = {&af9015_usb_table[11], NULL}, + .cold_ids = { + &af9015_usb_table[MSI_DIGIVOX_DUO], + NULL + }, .warm_ids = {NULL}, }, { .name = "Fujitsu-Siemens Slim Mobile USB DVB-T", - .cold_ids = {&af9015_usb_table[12], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_VOLAR_X_REV2], + NULL + }, .warm_ids = {NULL}, }, { .name = "Telestar Starstick 2", - .cold_ids = {&af9015_usb_table[13], NULL}, + .cold_ids = { + &af9015_usb_table[TELESTAR_STARSTICK_2], + NULL + }, .warm_ids = {NULL}, }, { .name = "AVerMedia A309", - .cold_ids = {&af9015_usb_table[14], NULL}, + .cold_ids = { + &af9015_usb_table[AVERMEDIA_A309_USB], + NULL + }, .warm_ids = {NULL}, }, { .name = "MSI Digi VOX mini III", - .cold_ids = {&af9015_usb_table[15], NULL}, + .cold_ids = { + &af9015_usb_table[MSI_DIGIVOX_MINI_III], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld USB DVB-T TV Stick II " \ "(VS-DVB-T 395U)", - .cold_ids = {&af9015_usb_table[16], - &af9015_usb_table[17], - &af9015_usb_table[18], - &af9015_usb_table[31], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_E396], + &af9015_usb_table[KWORLD_E39B], + &af9015_usb_table[KWORLD_E395], + &af9015_usb_table[KWORLD_E39A], + NULL + }, .warm_ids = {NULL}, }, { .name = "TrekStor DVB-T USB Stick", - .cold_ids = {&af9015_usb_table[19], NULL}, + .cold_ids = { + &af9015_usb_table[TREKSTOR_DVBT], + NULL + }, .warm_ids = {NULL}, }, { .name = "AverMedia AVerTV Volar Black HD " \ "(A850)", - .cold_ids = {&af9015_usb_table[20], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_A850], + NULL + }, .warm_ids = {NULL}, }, { .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV", - .cold_ids = {&af9015_usb_table[37], NULL}, + .cold_ids = { + &af9015_usb_table[SVEON_STV22], + NULL + }, .warm_ids = {NULL}, }, } @@ -1619,50 +1846,77 @@ static struct dvb_usb_device_properties af9015_properties[] = { .devices = { { .name = "AverMedia AVerTV Volar GPS 805 (A805)", - .cold_ids = {&af9015_usb_table[21], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_A805], + NULL + }, .warm_ids = {NULL}, }, { .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \ "V3.0", - .cold_ids = {&af9015_usb_table[22], NULL}, + .cold_ids = { + &af9015_usb_table[CONCEPTRONIC_CTVDIGRCU], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld Digial MC-810", - .cold_ids = {&af9015_usb_table[23], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_MC810], + NULL + }, .warm_ids = {NULL}, }, { .name = "Genius TVGo DVB-T03", - .cold_ids = {&af9015_usb_table[24], NULL}, + .cold_ids = { + &af9015_usb_table[GENIUS_TVGO_DVB_T03], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld PlusTV DVB-T PCI Pro Card " \ "(DVB-T PC160-T)", - .cold_ids = {&af9015_usb_table[26], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_PC160_T], + NULL + }, .warm_ids = {NULL}, }, { .name = "Sveon STV20 Tuner USB DVB-T HDTV", - .cold_ids = {&af9015_usb_table[27], NULL}, + .cold_ids = { + &af9015_usb_table[SVEON_STV20], + NULL + }, .warm_ids = {NULL}, }, { .name = "Leadtek WinFast DTV2000DS", - .cold_ids = {&af9015_usb_table[29], NULL}, + .cold_ids = { + &af9015_usb_table[WINFAST_DTV2000DS], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld USB DVB-T Stick Mobile " \ "(UB383-T)", - .cold_ids = {&af9015_usb_table[30], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_UB383_T], + NULL + }, .warm_ids = {NULL}, }, { .name = "AverMedia AVerTV Volar M (A815Mac)", - .cold_ids = {&af9015_usb_table[32], NULL}, + .cold_ids = { + &af9015_usb_table[AVERMEDIA_A815M], + NULL + }, .warm_ids = {NULL}, }, } diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h index 6252ea6c1904..f619063fa72f 100644 --- a/drivers/media/dvb/dvb-usb/af9015.h +++ b/drivers/media/dvb/dvb-usb/af9015.h @@ -102,6 +102,12 @@ struct af9015_state { u8 rc_repeat; u32 rc_keycode; u8 rc_last[4]; + + /* for demod callback override */ + int (*set_frontend[2]) (struct dvb_frontend *fe); + int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); + int (*init[2]) (struct dvb_frontend *fe); + int (*sleep[2]) (struct dvb_frontend *fe); }; struct af9015_config { diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index b39f14f85e71..1455e2644ab5 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -41,6 +41,7 @@ #include "stv0900.h" #include "stv6110.h" #include "isl6423.h" +#include "cxd2820r.h" /* debug */ static int dvb_usb_anysee_debug; @@ -66,10 +67,12 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, if (mutex_lock_interruptible(&anysee_usb_mutex) < 0) return -EAGAIN; + deb_xfer(">>> "); + debug_dump(buf, slen, deb_xfer); + /* We need receive one message more after dvb_usb_generic_rw due to weird transaction flow, which is 1 x send + 2 x receive. */ ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); - if (!ret) { /* receive 2nd answer */ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, @@ -79,7 +82,10 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, err("%s: recv bulk message failed: %d", __func__, ret); else { deb_xfer("<<< "); - debug_dump(buf, act_len, deb_xfer); + debug_dump(buf, rlen, deb_xfer); + + if (buf[63] != 0x4f) + deb_info("%s: cmd failed\n", __func__); } } @@ -129,6 +135,29 @@ static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, return anysee_write_reg(d, reg, val); } +/* read single register with mask */ +static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val, + u8 mask) +{ + int ret, i; + u8 tmp; + + ret = anysee_read_reg(d, reg, &tmp); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) { u8 buf[] = {CMD_GET_HW_INFO}; @@ -156,22 +185,6 @@ static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); } -static int anysee_init(struct dvb_usb_device *d) -{ - int ret; - /* LED light */ - ret = anysee_led_ctrl(d, 0x01, 0x03); - if (ret) - return ret; - - /* enable IR */ - ret = anysee_ir_ctrl(d, 1); - if (ret) - return ret; - - return 0; -} - /* I2C */ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) @@ -297,7 +310,7 @@ static struct tda10023_config anysee_tda10023_tda18212_config = { .pll_m = 12, .pll_p = 3, .pll_n = 1, - .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B, .deltaf = 0xba02, }; @@ -309,6 +322,17 @@ static struct tda18212_config anysee_tda18212_config = { .if_dvbc = 5000, }; +static struct tda18212_config anysee_tda18212_config2 = { + .i2c_address = 0x60 /* (0xc0 >> 1) */, + .if_dvbt_6 = 3550, + .if_dvbt_7 = 3700, + .if_dvbt_8 = 4150, + .if_dvbt2_6 = 3250, + .if_dvbt2_7 = 4000, + .if_dvbt2_8 = 4000, + .if_dvbc = 5000, +}; + static struct cx24116_config anysee_cx24116_config = { .demod_address = (0xaa >> 1), .mpg_clk_pos_pol = 0x00, @@ -339,6 +363,11 @@ static struct isl6423_config anysee_isl6423_config = { .addr = (0x10 >> 1), }; +static struct cxd2820r_config anysee_cxd2820r_config = { + .i2c_address = 0x6d, /* (0xda >> 1) */ + .ts_mode = 0x38, +}; + /* * New USB device strings: Mfr=1, Product=2, SerialNumber=0 * Manufacturer: AMT.CO.KR @@ -421,6 +450,14 @@ static struct isl6423_config anysee_isl6423_config = { * IOA[7] TS 1=enabled * IOE[5] STV0903 1=enabled * + * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)" + * PCB: 508T2C (rev0.3) + * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] CXD2820R 1=enabled + * * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" * PCB: 508PTC (rev0.5) * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) @@ -437,7 +474,7 @@ static struct isl6423_config anysee_isl6423_config = { * IOD[6] ZL10353 1=enabled * IOE[0] IF 0=enabled * - * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" + * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" * PCB: 508PS2 (rev0.4) * parts: DNBU10512IST(STV0903, STV6110), ISL6423 * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff @@ -446,6 +483,16 @@ static struct isl6423_config anysee_isl6423_config = { * IOE[5] STV0903 1=enabled */ + +/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ +static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + /* enable / disable tuner access on IOE[4] */ + return anysee_wr_reg_mask(adap->dev, REG_IOE, (enable << 4), 0x10); +} + static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) { struct dvb_usb_adapter *adap = fe->dvb->priv; @@ -577,7 +624,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* detect hardware only once */ if (adap->fe_adap[0].fe == NULL) { /* Check which hardware we have. - * We must do this call two times to get reliable values (hw bug). + * We must do this call two times to get reliable values + * (hw/fw bug). */ ret = anysee_get_hw_info(adap->dev, hw_info); if (ret) @@ -606,14 +654,14 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) break; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(mt352_attach, &anysee_mt352_config, - &adap->dev->i2c_adap); + adap->fe_adap[0].fe = dvb_attach(mt352_attach, + &anysee_mt352_config, &adap->dev->i2c_adap); if (adap->fe_adap[0].fe) break; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &adap->dev->i2c_adap); + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, + &anysee_zl10353_config, &adap->dev->i2c_adap); break; case ANYSEE_HW_507CD: /* 6 */ @@ -665,8 +713,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(cx24116_attach, &anysee_cx24116_config, - &adap->dev->i2c_adap); + adap->fe_adap[0].fe = dvb_attach(cx24116_attach, + &anysee_cx24116_config, &adap->dev->i2c_adap); break; case ANYSEE_HW_507FA: /* 15 */ @@ -747,17 +795,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) } } + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (tmp == 0xc7) { + if (adap->fe_adap[state->fe_id].fe) + adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + } + break; case ANYSEE_HW_508TC: /* 18 */ case ANYSEE_HW_508PTC: /* 21 */ /* E7 TC */ /* E7 PTC */ - /* enable transport stream on IOA[7] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); - if (ret) - goto error; - if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { /* disable DVB-T demod on IOD[6] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), @@ -772,7 +822,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe_adap[state->fe_id].fe = dvb_attach(tda10023_attach, + adap->fe_adap[state->fe_id].fe = + dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); } else { @@ -789,11 +840,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe_adap[state->fe_id].fe = dvb_attach(zl10353_attach, + adap->fe_adap[state->fe_id].fe = + dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config, &adap->dev->i2c_adap); } + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe_adap[state->fe_id].fe) + adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + + state->has_ci = true; + break; case ANYSEE_HW_508S2: /* 19 */ case ANYSEE_HW_508PS2: /* 22 */ @@ -803,19 +862,35 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) if (state->fe_id) break; - /* enable transport stream on IOA[7] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); + /* enable DVB-S/S2 demod on IOE[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); if (ret) goto error; - /* enable DVB-S/S2 demod on IOE[5] */ + /* attach demod */ + adap->fe_adap[0].fe = dvb_attach(stv0900_attach, + &anysee_stv0900_config, &adap->dev->i2c_adap, 0); + + state->has_ci = true; + + break; + case ANYSEE_HW_508T2C: /* 20 */ + /* E7 T2C */ + + if (state->fe_id) + break; + + /* enable DVB-T/T2/C demod on IOE[5] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); if (ret) goto error; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config, - &adap->dev->i2c_adap, 0); + adap->fe_adap[state->fe_id].fe = dvb_attach(cxd2820r_attach, + &anysee_cxd2820r_config, &adap->dev->i2c_adap, + NULL); + + state->has_ci = true; break; } @@ -842,24 +917,26 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1), - NULL, DVB_PLL_THOMSON_DTT7579); + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579); break; case ANYSEE_HW_507CD: /* 6 */ /* E30 Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1), - &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579); + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + (0xc2 >> 1), &adap->dev->i2c_adap, + DVB_PLL_THOMSON_DTT7579); break; case ANYSEE_HW_507DC: /* 10 */ /* E30 C Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc0 >> 1), - &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + (0xc0 >> 1), &adap->dev->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); break; case ANYSEE_HW_507SI: /* 11 */ @@ -877,22 +954,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* Try first attach TDA18212 silicon tuner on IOE[4], if that * fails attach old simple PLL. */ - /* enable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); - if (ret) - goto error; - /* attach tuner */ fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, &adap->dev->i2c_adap, &anysee_tda18212_config); if (fe) break; - /* disable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10); - if (ret) - goto error; - /* attach tuner */ fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe, (0xc0 >> 1), &adap->dev->i2c_adap, @@ -904,11 +971,6 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 TC */ /* E7 PTC */ - /* enable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); - if (ret) - goto error; - /* attach tuner */ fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, &adap->dev->i2c_adap, &anysee_tda18212_config); @@ -930,6 +992,15 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) } break; + + case ANYSEE_HW_508T2C: /* 20 */ + /* E7 T2C */ + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, + &adap->dev->i2c_adap, &anysee_tda18212_config2); + + break; default: fe = NULL; } @@ -939,7 +1010,6 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) else ret = -ENODEV; -error: return ret; } @@ -969,6 +1039,201 @@ static int anysee_rc_query(struct dvb_usb_device *d) return 0; } +static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot, + int addr) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1}; + u8 val; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); + if (ret) + return ret; + + return val; +} + +static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, + int addr, u8 val) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, + u8 addr) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1}; + u8 val; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); + if (ret) + return ret; + + return val; +} + +static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, + u8 addr, u8 val) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + struct anysee_state *state = d->priv; + + state->ci_cam_ready = jiffies + msecs_to_jiffies(1000); + + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + return ret; + + msleep(300); + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + return ret; + + msleep(30); + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, + int open) +{ + struct dvb_usb_device *d = ci->data; + struct anysee_state *state = d->priv; + int ret; + u8 tmp; + + ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40); + if (ret) + return ret; + + if (tmp == 0) { + ret = DVB_CA_EN50221_POLL_CAM_PRESENT; + if (time_after(jiffies, state->ci_cam_ready)) + ret |= DVB_CA_EN50221_POLL_CAM_READY; + } + + return ret; +} + +static int anysee_ci_init(struct dvb_usb_device *d) +{ + struct anysee_state *state = d->priv; + int ret; + + state->ci.owner = THIS_MODULE; + state->ci.read_attribute_mem = anysee_ci_read_attribute_mem; + state->ci.write_attribute_mem = anysee_ci_write_attribute_mem; + state->ci.read_cam_control = anysee_ci_read_cam_control; + state->ci.write_cam_control = anysee_ci_write_cam_control; + state->ci.slot_reset = anysee_ci_slot_reset; + state->ci.slot_shutdown = anysee_ci_slot_shutdown; + state->ci.slot_ts_enable = anysee_ci_slot_ts_enable; + state->ci.poll_slot_status = anysee_ci_poll_slot_status; + state->ci.data = d; + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1); + if (ret) + return ret; + + return 0; +} + +static void anysee_ci_release(struct dvb_usb_device *d) +{ + struct anysee_state *state = d->priv; + + /* detach CI */ + if (state->has_ci) + dvb_ca_en50221_release(&state->ci); + + return; +} + +static int anysee_init(struct dvb_usb_device *d) +{ + struct anysee_state *state = d->priv; + int ret; + + /* LED light */ + ret = anysee_led_ctrl(d, 0x01, 0x03); + if (ret) + return ret; + + /* enable IR */ + ret = anysee_ir_ctrl(d, 1); + if (ret) + return ret; + + /* attach CI */ + if (state->has_ci) { + ret = anysee_ci_init(d); + if (ret) { + state->has_ci = false; + return ret; + } + } + + return 0; +} + /* DVB USB Driver stuff */ static struct dvb_usb_device_properties anysee_properties; @@ -1010,6 +1275,16 @@ static int anysee_probe(struct usb_interface *intf, return anysee_init(d); } +static void anysee_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + + anysee_ci_release(d); + dvb_usb_device_exit(intf); + + return; +} + static struct usb_device_id anysee_table[] = { { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, @@ -1029,7 +1304,7 @@ static struct dvb_usb_device_properties anysee_properties = { { .num_frontends = 2, .frontend_ctrl = anysee_frontend_ctrl, - .fe = {{ + .fe = { { .streaming_ctrl = anysee_streaming_ctrl, .frontend_attach = anysee_frontend_attach, .tuner_attach = anysee_tuner_attach, @@ -1057,7 +1332,7 @@ static struct dvb_usb_device_properties anysee_properties = { } } }, - }}, + } }, } }, @@ -1087,7 +1362,7 @@ static struct dvb_usb_device_properties anysee_properties = { static struct usb_driver anysee_driver = { .name = "dvb_usb_anysee", .probe = anysee_probe, - .disconnect = dvb_usb_device_exit, + .disconnect = anysee_disconnect, .id_table = anysee_table, }; diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h index 57ee500b8c0e..8ac879431540 100644 --- a/drivers/media/dvb/dvb-usb/anysee.h +++ b/drivers/media/dvb/dvb-usb/anysee.h @@ -36,6 +36,7 @@ #define DVB_USB_LOG_PREFIX "anysee" #include "dvb-usb.h" +#include "dvb_ca_en50221.h" #define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) #define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) @@ -54,12 +55,16 @@ enum cmd { CMD_GET_IR_CODE = 0x41, CMD_GET_HW_INFO = 0x19, CMD_SMARTCARD = 0x34, + CMD_CI = 0x37, }; struct anysee_state { u8 hw; /* PCB ID */ u8 seq; u8 fe_id:1; /* frondend ID */ + u8 has_ci:1; + struct dvb_ca_en50221 ci; + unsigned long ci_cam_ready; /* jiffies */ }; #define ANYSEE_HW_507T 2 /* E30 */ @@ -69,6 +74,7 @@ struct anysee_state { #define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ #define ANYSEE_HW_508TC 18 /* E7 TC */ #define ANYSEE_HW_508S2 19 /* E7 S2 */ +#define ANYSEE_HW_508T2C 20 /* E7 T2C */ #define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ #define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c index 9cd51ac12076..8a57ed8272de 100644 --- a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c +++ b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c @@ -40,9 +40,8 @@ * We replace errornous fields by default TPS fields (the ones with value 0). */ -static uint16_t compute_tps(struct dvb_frontend_parameters *p) +static uint16_t compute_tps(struct dtv_frontend_properties *op) { - struct dvb_ofdm_parameters *op = &p->u.ofdm; uint16_t tps = 0; switch (op->code_rate_HP) { @@ -83,7 +82,7 @@ static uint16_t compute_tps(struct dvb_frontend_parameters *p) /* tps |= (0 << 4) */; } - switch (op->constellation) { + switch (op->modulation) { case QAM_16: tps |= (1 << 13); break; @@ -119,7 +118,7 @@ static uint16_t compute_tps(struct dvb_frontend_parameters *p) /* tps |= (0 << 2) */; } - switch (op->hierarchy_information) { + switch (op->hierarchy) { case HIERARCHY_1: tps |= (1 << 10); break; @@ -263,9 +262,9 @@ static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, return 0; } -static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct cinergyt2_fe_state *state = fe->demodulator_priv; struct dvbt_set_parameters_msg param; char result[2]; @@ -274,9 +273,20 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; param.tps = cpu_to_le16(compute_tps(fep)); param.freq = cpu_to_le32(fep->frequency / 1000); - param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; param.flags = 0; + switch (fep->bandwidth_hz) { + case 8000000: + param.bandwidth = 0; + break; + case 7000000: + param.bandwidth = 1; + break; + case 6000000: + param.bandwidth = 2; + break; + } + err = dvb_usb_generic_rw(state->d, (char *)¶m, sizeof(param), result, sizeof(result), 0); @@ -286,12 +296,6 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, return (err < 0) ? err : 0; } -static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - return 0; -} - static void cinergyt2_fe_release(struct dvb_frontend *fe) { struct cinergyt2_fe_state *state = fe->demodulator_priv; @@ -316,9 +320,9 @@ struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) static struct dvb_frontend_ops cinergyt2_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = DRIVER_NAME, - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, @@ -341,7 +345,6 @@ static struct dvb_frontend_ops cinergyt2_fe_ops = { .sleep = cinergyt2_fe_sleep, .set_frontend = cinergyt2_fe_set_frontend, - .get_frontend = cinergyt2_fe_get_frontend, .get_tune_settings = cinergyt2_fe_get_tune_settings, .read_status = cinergyt2_fe_read_status, diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 949ea1bc0aae..3940bb0f9ef6 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -1067,18 +1067,17 @@ static struct dib0070_config dib7070p_dib0070_config = { }; struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *, - struct dvb_frontend_parameters *); + int (*set_param_save) (struct dvb_frontend *); }; -static int dib7070_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int dib7070_set_param_override(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: offset = 950; break; default: @@ -1087,7 +1086,7 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe, fep); + return state->set_param_save(fe); } static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 9bd6d51b3b93..7de125c0b36f 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -48,6 +48,8 @@ struct dib0700_state { u8 disable_streaming_master_mode; u32 fw_version; u32 nb_packet_buffer_size; + int (*read_status)(struct dvb_frontend *, fe_status_t *); + int (*sleep)(struct dvb_frontend* fe); u8 buf[255]; }; diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 206999476f02..070e82aa53f5 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -834,6 +834,7 @@ static struct usb_driver dib0700_driver = { module_usb_driver(dib0700_driver); +MODULE_FIRMWARE("dvb-usb-dib0700-1.20.fw"); MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge"); MODULE_VERSION("1.0"); diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index f313182eb9d5..f9e966aa26e7 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -30,7 +30,7 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif "if applicable for the device (default: 0=automatic/off)."); struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); + int (*set_param_save) (struct dvb_frontend *); const struct firmware *frontend_firmware; }; @@ -804,13 +804,14 @@ static struct dib0070_config dib7770p_dib0070_config = { .charge_pump = 2, }; -static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib7070_set_param_override(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: offset = 950; break; case BAND_UHF: @@ -818,17 +819,17 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_fronte } deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe, fep); + return state->set_param_save(fe); } -static int dib7770_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int dib7770_set_param_override(struct dvb_frontend *fe) { - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: dib7000p_set_gpio(fe, 0, 0, 1); @@ -842,7 +843,7 @@ static int dib7770_set_param_override(struct dvb_frontend *fe, } deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe, fep); + return state->set_param_save(fe); } static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) @@ -1205,14 +1206,14 @@ static struct dib0070_config dib807x_dib0070_config[2] = { } }; -static int dib807x_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int dib807x_set_param_override(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; u16 offset = dib0070_wbd_offset(fe); - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: offset += 750; @@ -1224,7 +1225,7 @@ static int dib807x_set_param_override(struct dvb_frontend *fe, deb_info("WBD for DiB8000: %d\n", offset); dib8000_set_wbd_ref(fe, offset); - return state->set_param_save(fe, fep); + return state->set_param_save(fe); } static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) @@ -1279,7 +1280,7 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - 0x80); + 0x80, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); @@ -1308,7 +1309,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); /* initialize IC 0 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); @@ -1319,7 +1320,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) { /* initialize IC 1 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib807x_dib8000_config[1]); @@ -1328,7 +1329,7 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) } /* STK8096GP */ -struct dibx000_agc_config dib8090_agc_config[2] = { +static struct dibx000_agc_config dib8090_agc_config[2] = { { BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, @@ -1503,22 +1504,22 @@ static struct dib0090_config dib809x_dib0090_config = { .fref_clock_ratio = 6, }; -static int dib8096_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int dib8096_set_param_override(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); u16 target; int ret = 0; enum frontend_tune_state tune_state = CT_SHUTDOWN; u16 ltgain, rf_gain_limit; - ret = state->set_param_save(fe, fep); + ret = state->set_param_save(fe); if (ret < 0) return ret; - target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; + target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2; dib8000_set_wbd_ref(fe, target); @@ -1578,7 +1579,7 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); @@ -1629,7 +1630,7 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); if (adap->fe_adap[0].fe == NULL) @@ -1641,6 +1642,261 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) return fe_slave == NULL ? -ENODEV : 0; } +/* TFE8096P */ +static struct dibx000_agc_config dib8096p_agc_config[2] = { + { + .band_caps = BAND_UHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) + | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) + | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 684, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 32767, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 105, + .agc1_slope1 = 0, + .agc1_slope2 = 156, + .agc2_pt1 = 105, + .agc2_pt2 = 255, + .agc2_slope1 = 54, + .agc2_slope2 = 0, + + .alpha_mant = 28, + .alpha_exp = 26, + .beta_mant = 31, + .beta_exp = 51, + + .perform_agc_softsplit = 0, + } , { + .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) + | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) + | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 732, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 32767, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 98, + .agc1_slope1 = 0, + .agc1_slope2 = 167, + .agc2_pt1 = 98, + .agc2_pt2 = 255, + .agc2_slope1 = 52, + .agc2_slope2 = 0, + + .alpha_mant = 28, + .alpha_exp = 26, + .beta_mant = 31, + .beta_exp = 51, + + .perform_agc_softsplit = 0, + } +}; + +static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = { + 108000, 13500, + 1, 9, 1, 0, 0, + 0, 0, 0, 0, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20199729, + 12000000, +}; + +static struct dib8000_config tfe8096p_dib8000_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib8096p_agc_config, + .pll = &dib8096p_clock_config_12_mhz, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .agc_control = NULL, + .diversity_delay = 48, + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + +static struct dib0090_wbd_slope dib8096p_wbd_table[] = { + { 380, 81, 850, 64, 540, 4}, + { 860, 51, 866, 21, 375, 4}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, +}; + +static const struct dib0090_config tfe8096p_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib8096p_tuner_sleep, + .sleep = dib8096p_tuner_sleep, + + .freq_offset_khz_uhf = -143, + .freq_offset_khz_vhf = -143, + + .get_adc_power = dib8090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 1, + + .wbd = dib8096p_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 0, +}; + +struct dibx090p_adc { + u32 freq; /* RF freq MHz */ + u32 timf; /* New Timf */ + u32 pll_loopdiv; /* New prediv */ + u32 pll_prediv; /* New loopdiv */ +}; + +struct dibx090p_adc dib8090p_adc_tab[] = { + { 50000, 17043521, 16, 3}, /* 64 MHz */ + {878000, 20199729, 9, 1}, /* 60 MHz */ + {0xffffffff, 0, 0, 0}, /* 60 MHz */ +}; + +static int dib8096p_agc_startup(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + struct dibx000_bandwidth_config pll; + u16 target; + int better_sampling_freq = 0, ret; + struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0]; + + ret = state->set_param_save(fe); + if (ret < 0) + return ret; + memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); + + dib0090_pwm_gain_reset(fe); + /* dib0090_get_wbd_target is returning any possible + temperature compensated wbd-target */ + target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; + dib8000_set_wbd_ref(fe, target); + + + while (p->frequency / 1000 > adc_table->freq) { + better_sampling_freq = 1; + adc_table++; + } + + if ((adc_table->freq != 0xffffffff) && better_sampling_freq) { + pll.pll_ratio = adc_table->pll_loopdiv; + pll.pll_prediv = adc_table->pll_prediv; + dib8000_update_pll(fe, &pll); + dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf); + } + return 0; +} + +static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1); + + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, + &adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe8096p_dib0090_config) == NULL) + return -ENODEV; + + dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup; + return 0; +} + /* STK9090M */ static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { @@ -1883,7 +2139,7 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) return -ENODEV; - dib0700_set_i2c_speed(adap->dev, 2000); + dib0700_set_i2c_speed(adap->dev, 1500); if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) return -ENODEV; release_firmware(state->frontend_firmware); @@ -1962,7 +2218,8 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) return -ENODEV; - dib0700_set_i2c_speed(adap->dev, 2000); + + dib0700_set_i2c_speed(adap->dev, 1500); if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) return -ENODEV; @@ -1975,7 +2232,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) return -ENODEV; fe_slave->dvb = adap->fe_adap[0].fe->dvb; - dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 2000); + dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 1500); if (dib9000_firmware_post_pll_init(fe_slave) < 0) return -ENODEV; } @@ -2064,7 +2321,7 @@ static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_ return 0; } -static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib7090_agc_startup(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; @@ -2073,13 +2330,13 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para struct dib7090p_best_adc adc; int ret; - ret = state->set_param_save(fe, fep); + ret = state->set_param_save(fe); if (ret < 0) return ret; memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); dib0090_pwm_gain_reset(fe); - target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2; + target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; dib7000p_set_wbd_ref(fe, target); if (dib7090p_get_best_sampling(fe, &adc) == 0) { @@ -2092,6 +2349,49 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para return 0; } +static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) +{ + deb_info("AGC restart callback: %d", restart); + if (restart == 0) /* before AGC startup */ + dib0090_set_dc_servo(fe, 1); + return 0; +} + +static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global) +{ + u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1; + s16 wbd_delta; + + if ((fe->dtv_property_cache.frequency) < 400000000) + threshold_agc1 = 25000; + else + threshold_agc1 = 30000; + + wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2; + wbd_offset = dib0090_get_wbd_offset(fe); + dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd); + wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ; + + deb_info("update lna, agc_global=%d agc1=%d agc2=%d", + agc_global, agc1, agc2); + deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d", + wbd, wbd_target, wbd_offset, wbd_delta); + + if ((agc1 < threshold_agc1) && (wbd_delta > 0)) { + dib0090_set_switch(fe, 1, 1, 1); + dib0090_set_vga(fe, 0); + dib0090_update_rframp_7090(fe, 0); + dib0090_update_tuning_table_7090(fe, 0); + } else { + dib0090_set_vga(fe, 1); + dib0090_update_rframp_7090(fe, 1); + dib0090_update_tuning_table_7090(fe, 1); + dib0090_set_switch(fe, 0, 0, 0); + } + + return 0; +} + static struct dib0090_wbd_slope dib7090_wbd_table[] = { { 380, 81, 850, 64, 540, 4}, { 860, 51, 866, 21, 375, 4}, @@ -2100,7 +2400,16 @@ static struct dib0090_wbd_slope dib7090_wbd_table[] = { { 0xFFFF, 0, 0, 0, 0, 0}, }; -struct dibx000_agc_config dib7090_agc_config[2] = { +static struct dib0090_wbd_slope dib7090e_wbd_table[] = { + { 380, 81, 850, 64, 540, 4}, + { 700, 51, 866, 21, 320, 4}, + { 860, 48, 666, 18, 330, 6}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, +}; + +static struct dibx000_agc_config dib7090_agc_config[2] = { { .band_caps = BAND_UHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, @@ -2278,6 +2587,34 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { } }; +static struct dib7000p_config tfe7090e_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = dib7090e_update_lna, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + static const struct dib0090_config nim7090_dib0090_config = { .io.clock_khz = 12000, .io.pll_bypass = 0, @@ -2312,6 +2649,107 @@ static const struct dib0090_config nim7090_dib0090_config = { .in_soc = 1, }; +static const struct dib0090_config tfe7090e_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090e_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 1, + .is_dib7090e = 1, +}; + +static struct dib7000p_config tfe7790e_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = dib7090e_update_lna, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .enMpegOutput = 1, +}; + +static const struct dib0090_config tfe7790e_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090e_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 1, + .is_dib7090e = 1, + .force_crystal_mode = 1, +}; + static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { { .io.clock_khz = 12000, @@ -2504,6 +2942,97 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) return 0; } +static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, + 1, 0x10, &tfe7090e_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80, &tfe7090e_dib7000p_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* The TFE7790E requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(20); + dib0700_ctrl_clock(adap->dev, 72, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, + 1, 0x10, &tfe7790e_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80, &tfe7790e_dib7000p_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe7790e_dib0090_config) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe7090e_dib0090_config) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + /* STK7070PD */ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { { @@ -2537,19 +3066,25 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { } }; -static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) +static void stk7070pd_init(struct dvb_usb_device *dev) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + dib0700_set_gpio(dev, GPIO6, GPIO_OUT, 1); msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + dib0700_set_gpio(dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 0); - dib0700_ctrl_clock(adap->dev, 72, 1); + dib0700_ctrl_clock(dev, 72, 1); msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + dib0700_set_gpio(dev, GPIO10, GPIO_OUT, 1); +} + +static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) +{ + stk7070pd_init(adap->dev); + msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); @@ -2570,6 +3105,77 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } +static int novatd_read_status_override(struct dvb_frontend *fe, + fe_status_t *stat) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *dev = adap->dev; + struct dib0700_state *state = dev->priv; + int ret; + + ret = state->read_status(fe, stat); + + if (!ret) + dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, + !!(*stat & FE_HAS_LOCK)); + + return ret; +} + +static int novatd_sleep_override(struct dvb_frontend* fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *dev = adap->dev; + struct dib0700_state *state = dev->priv; + + /* turn off LED */ + dib0700_set_gpio(dev, adap->id == 0 ? GPIO1 : GPIO0, GPIO_OUT, 0); + + return state->sleep(fe); +} + +/** + * novatd_frontend_attach - Nova-TD specific attach + * + * Nova-TD has GPIO0, 1 and 2 for LEDs. So do not fiddle with them except for + * information purposes. + */ +static int novatd_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *dev = adap->dev; + struct dib0700_state *st = dev->priv; + + if (adap->id == 0) { + stk7070pd_init(dev); + + /* turn the power LED on, the other two off (just in case) */ + dib0700_set_gpio(dev, GPIO0, GPIO_OUT, 0); + dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0); + dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18, + stk7070pd_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + } + + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap, + adap->id == 0 ? 0x80 : 0x82, + &stk7070pd_dib7000p_config[adap->id]); + + if (adap->fe_adap[0].fe == NULL) + return -ENODEV; + + st->read_status = adap->fe_adap[0].fe->ops.read_status; + adap->fe_adap[0].fe->ops.read_status = novatd_read_status_override; + st->sleep = adap->fe_adap[0].fe->ops.sleep; + adap->fe_adap[0].fe->ops.sleep = novatd_sleep_override; + + return 0; +} + /* S5H1411 */ static struct s5h1411_config pinnacle_801e_config = { .output_mode = S5H1411_PARALLEL_OUTPUT, @@ -2960,6 +3566,9 @@ struct usb_device_id dib0700_usb_id_table[] = { /* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) }, +/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -3338,6 +3947,57 @@ struct dvb_usb_device_properties dib0700_devices[] = { .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = novatd_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + }, { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = novatd_frontend_attach, + .tuner_attach = dib7070p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + }}, + .size_of_priv = sizeof(struct dib0700_adapter_state), + } + }, + + .num_device_descs = 1, + .devices = { + { "Hauppauge Nova-TD Stick (52009)", + { &dib0700_usb_id_table[35], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7070pd_frontend_attach0, .tuner_attach = dib7070p_tuner_attach, @@ -3360,7 +4020,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 6, + .num_device_descs = 5, .devices = { { "DiBcom STK7070PD reference design", { &dib0700_usb_id_table[17], NULL }, @@ -3370,10 +4030,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[18], NULL }, { NULL }, }, - { "Hauppauge Nova-TD Stick (52009)", - { &dib0700_usb_id_table[35], NULL }, - { NULL }, - }, { "Hauppauge Nova-TD-500 (84xxx)", { &dib0700_usb_id_table[36], NULL }, { NULL }, @@ -4025,6 +4681,127 @@ struct dvb_usb_device_properties dib0700_devices[] = { RC_TYPE_NEC, .change_protocol = dib0700_change_protocol, }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090e_frontend_attach, + .tuner_attach = tfe7090e_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7090E reference design", + { &dib0700_usb_id_table[78], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7790e_frontend_attach, + .tuner_attach = tfe7790e_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7790E reference design", + { &dib0700_usb_id_table[79], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = tfe8096p_frontend_attach, + .tuner_attach = tfe8096p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE8096P reference design", + { &dib0700_usb_id_table[80], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, }, }; diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 0a9a79820f26..ff34419a4c88 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -118,12 +118,12 @@ static struct mt352_config digitv_mt352_config = { .demod_init = digitv_mt352_demod_init, }; -static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; u8 b[5]; - fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b)); + fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b)); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index 17413adec7a1..3d81daa49172 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -16,7 +16,7 @@ struct dtt200u_fe_state { fe_status_t stat; - struct dvb_frontend_parameters fep; + struct dtv_frontend_properties fep; struct dvb_frontend frontend; }; @@ -100,22 +100,27 @@ static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron return 0; } -static int dtt200u_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dtt200u_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dtt200u_fe_state *state = fe->demodulator_priv; int i; fe_status_t st; u16 freq = fep->frequency / 250000; u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 }; - switch (fep->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break; - case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break; - case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break; - case BANDWIDTH_AUTO: return -EOPNOTSUPP; - default: - return -EINVAL; + switch (fep->bandwidth_hz) { + case 8000000: + bwbuf[1] = 8; + break; + case 7000000: + bwbuf[1] = 7; + break; + case 6000000: + bwbuf[1] = 6; + break; + default: + return -EINVAL; } dvb_usb_generic_write(state->d,bwbuf,2); @@ -134,11 +139,11 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend* fe, return 0; } -static int dtt200u_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dtt200u_fe_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dtt200u_fe_state *state = fe->demodulator_priv; - memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters)); + memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties)); return 0; } @@ -172,9 +177,9 @@ error: } static struct dvb_frontend_ops dtt200u_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "WideView USB DVB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 250000, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index ba4a7517354f..ddf282f355b3 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -141,11 +141,17 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) goto err_dmx_dev; } - dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, + &adap->demux.dmx)) < 0) { + err("dvb_net_init failed: error %d",ret); + goto err_net_init; + } adap->state |= DVB_USB_ADAP_STATE_DVB; return 0; +err_net_init: + dvb_dmxdev_release(&adap->dmxdev); err_dmx_dev: dvb_dmx_release(&adap->demux); err_dmx: diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2d08c9b5128a..d390ddaa5a53 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -109,10 +109,13 @@ #define USB_PID_DIBCOM_STK807XPVR 0x1f98 #define USB_PID_DIBCOM_STK8096GP 0x1fa0 #define USB_PID_DIBCOM_NIM8096MD 0x1fa8 +#define USB_PID_DIBCOM_TFE8096P 0x1f9C #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DIBCOM_STK7770P 0x1e80 #define USB_PID_DIBCOM_NIM7090 0x1bb2 #define USB_PID_DIBCOM_TFE7090PVR 0x1bb4 +#define USB_PID_DIBCOM_TFE7090E 0x1bb7 +#define USB_PID_DIBCOM_TFE7790E 0x1e6e #define USB_PID_DIBCOM_NIM9090M 0x2383 #define USB_PID_DIBCOM_NIM9090MD 0x2384 #define USB_PID_DPOSH_M9206_COLD 0x9206 @@ -128,6 +131,8 @@ #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_INTEL_CE9500 0x9500 #define USB_PID_ITETECH_IT9135 0x9135 +#define USB_PID_ITETECH_IT9135_9005 0x9005 +#define USB_PID_ITETECH_IT9135_9006 0x9006 #define USB_PID_KWORLD_399U 0xe399 #define USB_PID_KWORLD_399U_2 0xe400 #define USB_PID_KWORLD_395U 0xe396 @@ -322,6 +327,7 @@ #define USB_PID_TVWAY_PLUS 0x0002 #define USB_PID_SVEON_STV20 0xe39d #define USB_PID_SVEON_STV22 0xe401 +#define USB_PID_SVEON_STV22_IT9137 0xe411 #define USB_PID_AZUREWAVE_AZ6027 0x3275 #define USB_PID_TERRATEC_DVBS2CI_V1 0x10a4 #define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index ff941d20e6b7..451c5a7adfb2 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1435,22 +1435,40 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } +enum dw2102_table_entry { + CYPRESS_DW2102, + CYPRESS_DW2101, + CYPRESS_DW2104, + TEVII_S650, + TERRATEC_CINERGY_S, + CYPRESS_DW3101, + TEVII_S630, + PROF_1100, + TEVII_S660, + PROF_7500, + GENIATECH_SU3000, + TERRATEC_CINERGY_S2, + TEVII_S480_1, + TEVII_S480_2, + X3M_SPC1400HD, +}; + static struct usb_device_id dw2102_table[] = { - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, - {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, - {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, - {USB_DEVICE(0x3034, 0x7500)}, - {USB_DEVICE(0x1f4d, 0x3000)}, - {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, - {USB_DEVICE(0x1f4d, 0x3100)}, + [CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, + [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, + [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, + [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, + [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, + [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, + [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, + [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, + [TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, + [PROF_7500] = {USB_DEVICE(0x3034, 0x7500)}, + [GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)}, + [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, + [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, + [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, + [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, { } }; @@ -1610,15 +1628,15 @@ static struct dvb_usb_device_properties dw2102_properties = { .num_device_descs = 3, .devices = { {"DVBWorld DVB-S 2102 USB2.0", - {&dw2102_table[0], NULL}, + {&dw2102_table[CYPRESS_DW2102], NULL}, {NULL}, }, {"DVBWorld DVB-S 2101 USB2.0", - {&dw2102_table[1], NULL}, + {&dw2102_table[CYPRESS_DW2101], NULL}, {NULL}, }, {"TerraTec Cinergy S USB", - {&dw2102_table[4], NULL}, + {&dw2102_table[TERRATEC_CINERGY_S], NULL}, {NULL}, }, } @@ -1664,11 +1682,11 @@ static struct dvb_usb_device_properties dw2104_properties = { .num_device_descs = 2, .devices = { { "DVBWorld DW2104 USB2.0", - {&dw2102_table[2], NULL}, + {&dw2102_table[CYPRESS_DW2104], NULL}, {NULL}, }, { "TeVii S650 USB2.0", - {&dw2102_table[3], NULL}, + {&dw2102_table[TEVII_S650], NULL}, {NULL}, }, } @@ -1715,7 +1733,7 @@ static struct dvb_usb_device_properties dw3101_properties = { .num_device_descs = 1, .devices = { { "DVBWorld DVB-C 3101 USB2.0", - {&dw2102_table[5], NULL}, + {&dw2102_table[CYPRESS_DW3101], NULL}, {NULL}, }, } @@ -1761,7 +1779,7 @@ static struct dvb_usb_device_properties s6x0_properties = { .num_device_descs = 1, .devices = { {"TeVii S630 USB", - {&dw2102_table[6], NULL}, + {&dw2102_table[TEVII_S630], NULL}, {NULL}, }, } @@ -1770,33 +1788,33 @@ static struct dvb_usb_device_properties s6x0_properties = { struct dvb_usb_device_properties *p1100; static struct dvb_usb_device_description d1100 = { "Prof 1100 USB ", - {&dw2102_table[7], NULL}, + {&dw2102_table[PROF_1100], NULL}, {NULL}, }; struct dvb_usb_device_properties *s660; static struct dvb_usb_device_description d660 = { "TeVii S660 USB", - {&dw2102_table[8], NULL}, + {&dw2102_table[TEVII_S660], NULL}, {NULL}, }; static struct dvb_usb_device_description d480_1 = { "TeVii S480.1 USB", - {&dw2102_table[12], NULL}, + {&dw2102_table[TEVII_S480_1], NULL}, {NULL}, }; static struct dvb_usb_device_description d480_2 = { "TeVii S480.2 USB", - {&dw2102_table[13], NULL}, + {&dw2102_table[TEVII_S480_2], NULL}, {NULL}, }; struct dvb_usb_device_properties *p7500; static struct dvb_usb_device_description d7500 = { "Prof 7500 USB DVB-S2", - {&dw2102_table[9], NULL}, + {&dw2102_table[PROF_7500], NULL}, {NULL}, }; @@ -1842,15 +1860,15 @@ static struct dvb_usb_device_properties su3000_properties = { .num_device_descs = 3, .devices = { { "SU3000HD DVB-S USB2.0", - { &dw2102_table[10], NULL }, + { &dw2102_table[GENIATECH_SU3000], NULL }, { NULL }, }, { "Terratec Cinergy S2 USB HD", - { &dw2102_table[11], NULL }, + { &dw2102_table[TERRATEC_CINERGY_S2], NULL }, { NULL }, }, { "X3M TV SPC1400HD PCI", - { &dw2102_table[14], NULL }, + { &dw2102_table[X3M_SPC1400HD], NULL }, { NULL }, }, } @@ -1859,12 +1877,11 @@ static struct dvb_usb_device_properties su3000_properties = { static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { - p1100 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + p1100 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!p1100) return -ENOMEM; /* copy default structure */ - memcpy(p1100, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); /* fill only different fields */ p1100->firmware = "dvb-usb-p1100.fw"; p1100->devices[0] = d1100; @@ -1872,13 +1889,12 @@ static int dw2102_probe(struct usb_interface *intf, p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; - s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + s660 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!s660) { kfree(p1100); return -ENOMEM; } - memcpy(s660, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); s660->firmware = "dvb-usb-s660.fw"; s660->num_device_descs = 3; s660->devices[0] = d660; @@ -1886,14 +1902,13 @@ static int dw2102_probe(struct usb_interface *intf, s660->devices[2] = d480_2; s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach; - p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + p7500 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!p7500) { kfree(p1100); kfree(s660); return -ENOMEM; } - memcpy(p7500, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); p7500->firmware = "dvb-usb-p7500.fw"; p7500->devices[0] = d7500; p7500->rc.legacy.rc_map_table = rc_map_tbs_table; diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c index 015b4e8af1a5..90a70c66a96e 100644 --- a/drivers/media/dvb/dvb-usb/friio-fe.c +++ b/drivers/media/dvb/dvb-usb/friio-fe.c @@ -282,23 +282,24 @@ static int jdvbt90502_set_property(struct dvb_frontend *fe, return r; } -static int jdvbt90502_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int jdvbt90502_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; p->inversion = INVERSION_AUTO; - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - p->u.ofdm.code_rate_HP = FEC_AUTO; - p->u.ofdm.code_rate_LP = FEC_AUTO; - p->u.ofdm.constellation = QAM_64; - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; + p->bandwidth_hz = 6000000; + p->code_rate_HP = FEC_AUTO; + p->code_rate_LP = FEC_AUTO; + p->modulation = QAM_64; + p->transmission_mode = TRANSMISSION_MODE_AUTO; + p->guard_interval = GUARD_INTERVAL_AUTO; + p->hierarchy = HIERARCHY_AUTO; return 0; } -static int jdvbt90502_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int jdvbt90502_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + /** * NOTE: ignore all the parameters except frequency. * others should be fixed to the proper value for ISDB-T, @@ -438,14 +439,12 @@ error: } static struct dvb_frontend_ops jdvbt90502_ops = { - + .delsys = { SYS_ISDBT }, .info = { .name = "Comtech JDVBT90502 ISDB-T", - .type = FE_OFDM, .frequency_min = 473000000, /* UHF 13ch, center */ .frequency_max = 767142857, /* UHF 62ch, center */ - .frequency_stepsize = JDVBT90502_PLL_CLK / - JDVBT90502_PLL_DIVIDER, + .frequency_stepsize = JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER, .frequency_tolerance = 0, /* NOTE: this driver ignores all parameters but frequency. */ diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 5426267980c7..67957dd99ede 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -113,28 +113,12 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front return 0; } -static int gp8psk_fe_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - deb_fe("%s(..)\n", __func__); - return 0; -} - -static int gp8psk_fe_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - deb_fe("%s(..)\n", __func__); - return 0; -} - - -static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) { struct gp8psk_fe_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; u8 cmd[10]; - u32 freq = fep->frequency * 1000; + u32 freq = c->frequency * 1000; int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); deb_fe("%s()\n", __func__); @@ -342,9 +326,9 @@ success: static struct dvb_frontend_ops gp8psk_fe_ops = { + .delsys = { SYS_DVBS }, .info = { .name = "Genpix DVB-S", - .type = FE_QPSK, .frequency_min = 800000, .frequency_max = 2250000, .frequency_stepsize = 100, @@ -366,8 +350,6 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .init = NULL, .sleep = NULL, - .set_property = gp8psk_fe_set_property, - .get_property = gp8psk_fe_get_property, .set_frontend = gp8psk_fe_set_frontend, .get_tune_settings = gp8psk_fe_get_tune_settings, diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index 67094b879bb4..9f01cd7a6e3f 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -52,42 +52,59 @@ static int pid_filter; module_param_named(pid, pid_filter, int, 0644); MODULE_PARM_DESC(pid, "set default 0=on 1=off"); +static int dvb_usb_it913x_firmware; +module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644); +MODULE_PARM_DESC(firmware, "set firmware 0=auto 1=IT9137 2=IT9135V1"); + + int cmd_counter; DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); struct it913x_state { u8 id; -}; - -struct ite_config { - u8 chip_ver; - u16 chip_type; - u32 firmware; - u8 tuner_id_0; - u8 tuner_id_1; - u8 dual_mode; + struct ite_config it913x_config; }; struct ite_config it913x_config; +#define IT913X_RETRY 10 +#define IT913X_SND_TIMEOUT 100 +#define IT913X_RCV_TIMEOUT 200 + static int it913x_bulk_write(struct usb_device *dev, u8 *snd, int len, u8 pipe) { - int ret, actual_l; + int ret, actual_l, i; + + for (i = 0; i < IT913X_RETRY; i++) { + ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), + snd, len , &actual_l, IT913X_SND_TIMEOUT); + if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT) + break; + } + + if (len != actual_l && ret == 0) + ret = -EAGAIN; - ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), - snd, len , &actual_l, 100); return ret; } static int it913x_bulk_read(struct usb_device *dev, u8 *rev, int len, u8 pipe) { - int ret, actual_l; + int ret, actual_l, i; + + for (i = 0; i < IT913X_RETRY; i++) { + ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), + rev, len , &actual_l, IT913X_RCV_TIMEOUT); + if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT) + break; + } + + if (len != actual_l && ret == 0) + ret = -EAGAIN; - ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), - rev, len , &actual_l, 200); return ret; } @@ -100,7 +117,7 @@ static u16 check_sum(u8 *p, u8 len) return ~sum; } -static int it913x_io(struct usb_device *udev, u8 mode, u8 pro, +static int it913x_usb_talk(struct usb_device *udev, u8 mode, u8 pro, u8 cmd, u32 reg, u8 addr, u8 *data, u8 len) { int ret = 0, i, buf_size = 1; @@ -159,22 +176,41 @@ static int it913x_io(struct usb_device *udev, u8 mode, u8 pro, buff[buf_size++] = (chk_sum & 0xff); ret = it913x_bulk_write(udev, buff, buf_size , 0x02); + if (ret < 0) + goto error; - ret |= it913x_bulk_read(udev, buff, (mode & 1) ? + ret = it913x_bulk_read(udev, buff, (mode & 1) ? 5 : len + 5 , 0x01); + if (ret < 0) + goto error; rlen = (mode & 0x1) ? 0x1 : len; if (mode & 1) - ret |= buff[2]; + ret = buff[2]; else memcpy(data, &buff[3], rlen); cmd_counter++; - kfree(buff); +error: kfree(buff); - return (ret < 0) ? -ENODEV : 0; + return ret; +} + +static int it913x_io(struct usb_device *udev, u8 mode, u8 pro, + u8 cmd, u32 reg, u8 addr, u8 *data, u8 len) +{ + int ret, i; + + for (i = 0; i < IT913X_RETRY; i++) { + ret = it913x_usb_talk(udev, mode, pro, + cmd, reg, addr, data, len); + if (ret != -EAGAIN) + break; + } + + return ret; } static int it913x_wr_reg(struct usb_device *udev, u8 pro, u32 reg , u8 data) @@ -223,15 +259,15 @@ static u32 it913x_query(struct usb_device *udev, u8 pro) static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - int ret = 0; + struct usb_device *udev = adap->dev->udev; + int ret; u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) return -EAGAIN; deb_info(1, "PID_C (%02x)", onoff); - if (!onoff) - ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1); + ret = it913x_wr_reg(udev, pro, PID_EN, onoff); mutex_unlock(&adap->dev->i2c_mutex); return ret; @@ -241,27 +277,20 @@ static int it913x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { struct usb_device *udev = adap->dev->udev; - int ret = 0; + int ret; u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - if (pid_filter > 0) - return 0; - if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) return -EAGAIN; deb_info(1, "PID_F (%02x)", onoff); - if (onoff) { - ret = it913x_wr_reg(udev, pro, PID_EN, 0x1); - - ret |= it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); - ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8)); + ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); - ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff); + ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8)); - ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); + ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff); - } + ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); mutex_unlock(&adap->dev->i2c_mutex); return 0; @@ -337,15 +366,73 @@ static int it913x_rc_query(struct dvb_usb_device *d) if ((ibuf[2] + ibuf[3]) == 0xff) { key = ibuf[2]; - key += ibuf[0] << 8; - deb_info(1, "INT Key =%08x", key); + key += ibuf[0] << 16; + key += ibuf[1] << 8; + deb_info(1, "NEC Extended Key =%08x", key); if (d->rc_dev != NULL) rc_keydown(d->rc_dev, key, 0); } + mutex_unlock(&d->i2c_mutex); return ret; } + +/* Firmware sets raw */ +const char fw_it9135_v1[] = "dvb-usb-it9135-01.fw"; +const char fw_it9135_v2[] = "dvb-usb-it9135-02.fw"; +const char fw_it9137[] = "dvb-usb-it9137-01.fw"; + +static int ite_firmware_select(struct usb_device *udev, + struct dvb_usb_device_properties *props) +{ + int sw; + /* auto switch */ + if (le16_to_cpu(udev->descriptor.idProduct) == + USB_PID_ITETECH_IT9135) + sw = IT9135_V1_FW; + else if (le16_to_cpu(udev->descriptor.idProduct) == + USB_PID_ITETECH_IT9135_9005) + sw = IT9135_V1_FW; + else if (le16_to_cpu(udev->descriptor.idProduct) == + USB_PID_ITETECH_IT9135_9006) { + sw = IT9135_V2_FW; + if (it913x_config.tuner_id_0 == 0) + it913x_config.tuner_id_0 = IT9135_60; + } else + sw = IT9137_FW; + + /* force switch */ + if (dvb_usb_it913x_firmware != IT9135_AUTO) + sw = dvb_usb_it913x_firmware; + + switch (sw) { + case IT9135_V1_FW: + it913x_config.firmware_ver = 1; + it913x_config.adc_x2 = 1; + props->firmware = fw_it9135_v1; + break; + case IT9135_V2_FW: + it913x_config.firmware_ver = 1; + it913x_config.adc_x2 = 1; + props->firmware = fw_it9135_v2; + break; + case IT9137_FW: + default: + it913x_config.firmware_ver = 0; + it913x_config.adc_x2 = 0; + props->firmware = fw_it9137; + } + + return 0; +} + +#define TS_MPEG_PKT_SIZE 188 +#define EP_LOW 21 +#define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) +#define EP_HIGH 348 +#define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) + static int it913x_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, @@ -359,6 +446,19 @@ static int it913x_identify_state(struct usb_device *udev, /* checnk for dual mode */ it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); + if (udev->speed != USB_SPEED_HIGH) { + props->adapter[0].fe[0].pid_filter_count = 5; + info("USB 1 low speed mode - connect to USB 2 port"); + if (pid_filter > 0) + pid_filter = 0; + if (it913x_config.dual_mode) { + it913x_config.dual_mode = 0; + info("Dual mode not supported in USB 1"); + } + } else /* For replugging */ + if(props->adapter[0].fe[0].pid_filter_count == 5) + props->adapter[0].fe[0].pid_filter_count = 31; + /* TODO different remotes */ remote = it913x_read_reg(udev, 0x49ac); /* Remote */ if (remote == 0) @@ -370,6 +470,28 @@ static int it913x_identify_state(struct usb_device *udev, info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode , remote, it913x_config.tuner_id_0); + /* Select Stream Buffer Size and pid filter option*/ + if (pid_filter) { + props->adapter[0].fe[0].stream.u.bulk.buffersize = + TS_BUFFER_SIZE_MAX; + props->adapter[0].fe[0].caps &= + ~DVB_USB_ADAP_NEED_PID_FILTERING; + } else + props->adapter[0].fe[0].stream.u.bulk.buffersize = + TS_BUFFER_SIZE_PID; + + if (it913x_config.dual_mode) { + props->adapter[1].fe[0].stream.u.bulk.buffersize = + props->adapter[0].fe[0].stream.u.bulk.buffersize; + props->num_adapters = 2; + if (pid_filter) + props->adapter[1].fe[0].caps = + props->adapter[0].fe[0].caps; + } else + props->num_adapters = 1; + + ret = ite_firmware_select(udev, props); + if (firm_no > 0) { *cold = 0; return 0; @@ -391,18 +513,22 @@ static int it913x_identify_state(struct usb_device *udev, ret = it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); } - props->num_adapters = 2; - } else - props->num_adapters = 1; + } reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); if (it913x_config.dual_mode) { ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); - ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); + if (it913x_config.firmware_ver == 1) + ret |= it913x_wr_reg(udev, DEV_0, 0xcfff, 0x1); + else + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); } else { ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0); - ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0); + if (it913x_config.firmware_ver == 1) + ret |= it913x_wr_reg(udev, DEV_0, 0xcfff, 0x0); + else + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0); } *cold = 1; @@ -428,35 +554,45 @@ static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ret; } - static int it913x_download_firmware(struct usb_device *udev, const struct firmware *fw) { - int ret = 0, i; - u8 packet_size, dlen; + int ret = 0, i = 0, pos = 0; + u8 packet_size, min_pkt; u8 *fw_data; - packet_size = 0x29; - ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); info("FRM Starting Firmware Download"); - /* This uses scatter write firmware headers follow */ - /* 03 XX 00 XX = chip number? */ - - for (i = 0; i < fw->size; i += packet_size) { - if (i > 0) - packet_size = 0x39; - fw_data = (u8 *)(fw->data + i); - dlen = ((i + packet_size) > fw->size) - ? (fw->size - i) : packet_size; - ret |= it913x_io(udev, WRITE_DATA, DEV_0, - CMD_SCATTER_WRITE, 0, 0, fw_data, dlen); - udelay(1000); + + /* Multi firmware loader */ + /* This uses scatter write firmware headers */ + /* The firmware must start with 03 XX 00 */ + /* and be the extact firmware length */ + + if (it913x_config.chip_ver == 2) + min_pkt = 0x11; + else + min_pkt = 0x19; + + while (i <= fw->size) { + if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0)) + || (i == fw->size)) { + packet_size = i - pos; + if ((packet_size > min_pkt) || (i == fw->size)) { + fw_data = (u8 *)(fw->data + pos); + pos += packet_size; + if (packet_size > 0) + ret |= it913x_io(udev, WRITE_DATA, + DEV_0, CMD_SCATTER_WRITE, 0, + 0, fw_data, packet_size); + udelay(1000); + } + } + i++; } - ret |= it913x_io(udev, WRITE_CMD, DEV_0, - CMD_BOOT, 0, 0, NULL, 0); + ret |= it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); msleep(100); @@ -474,12 +610,17 @@ static int it913x_download_firmware(struct usb_device *udev, /* Tuner function */ if (it913x_config.dual_mode) ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); - - ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); - ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); - if (it913x_config.dual_mode) { - ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); - ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); + else + ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0x68); + + if ((it913x_config.chip_ver == 1) && + (it913x_config.chip_type == 0x9135)) { + ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); + ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); + if (it913x_config.dual_mode) { + ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); + ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); + } } return (ret < 0) ? -ENODEV : 0; @@ -500,32 +641,23 @@ static int it913x_name(struct dvb_usb_adapter *adap) static int it913x_frontend_attach(struct dvb_usb_adapter *adap) { struct usb_device *udev = adap->dev->udev; + struct it913x_state *st = adap->dev->priv; int ret = 0; - u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); - u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; - u8 tuner_id, tuner_type; + u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize / 4; + u8 pkt_size = 0x80; + + if (adap->dev->udev->speed != USB_SPEED_HIGH) + pkt_size = 0x10; + + it913x_config.adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); if (adap->id == 0) - tuner_id = it913x_config.tuner_id_0; - else - tuner_id = it913x_config.tuner_id_1; - - /* TODO we always use IT9137 possible references here*/ - /* Documentation suggests don't care */ - switch (tuner_id) { - case 0x51: - case 0x52: - case 0x60: - case 0x61: - case 0x62: - default: - case 0x38: - tuner_type = IT9137; - } + memcpy(&st->it913x_config, &it913x_config, + sizeof(struct ite_config)); adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, - &adap->dev->i2c_adap, adap_addr, adf, tuner_type); + &adap->dev->i2c_adap, adap_addr, &st->it913x_config); if (adap->id == 0 && adap->fe_adap[0].fe) { ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); @@ -536,13 +668,13 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_LSB, ep_size & 0xff); ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8); - ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, 0x80); + ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, pkt_size); } else if (adap->id == 1 && adap->fe_adap[0].fe) { ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f); ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB, ep_size & 0xff); ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8); - ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, 0x80); + ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, pkt_size); ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_EN, 0x1); ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_SERIAL, 0x1); ret = it913x_wr_reg(udev, DEV_1, TOP_HOSTB_SER_MODE, 0x1); @@ -582,6 +714,9 @@ static int it913x_probe(struct usb_interface *intf, static struct usb_device_id it913x_table[] = { { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) }, + { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137) }, + { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005) }, + { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006) }, {} /* Terminating entry */ }; @@ -614,8 +749,8 @@ static struct dvb_usb_device_properties it913x_properties = { .endpoint = 0x04, .u = {/* Keep Low if PID filter on */ .bulk = { - .buffersize = 3584, - + .buffersize = + TS_BUFFER_SIZE_PID, } } } @@ -639,8 +774,8 @@ static struct dvb_usb_device_properties it913x_properties = { .endpoint = 0x05, .u = { .bulk = { - .buffersize = 3584, - + .buffersize = + TS_BUFFER_SIZE_PID, } } } @@ -654,10 +789,10 @@ static struct dvb_usb_device_properties it913x_properties = { .rc_query = it913x_rc_query, .rc_interval = IT913X_POLL, .allowed_protos = RC_TYPE_NEC, - .rc_codes = RC_MAP_KWORLD_315U, + .rc_codes = RC_MAP_MSI_DIGIVOX_III, }, .i2c_algo = &it913x_i2c_algo, - .num_device_descs = 2, + .num_device_descs = 5, .devices = { { "Kworld UB499-2T T09(IT9137)", { &it913x_table[0], NULL }, @@ -665,6 +800,15 @@ static struct dvb_usb_device_properties it913x_properties = { { "ITE 9135 Generic", { &it913x_table[1], NULL }, }, + { "Sveon STV22 Dual DVB-T HDTV(IT9137)", + { &it913x_table[2], NULL }, + }, + { "ITE 9135(9005) Generic", + { &it913x_table[3], NULL }, + }, + { "ITE 9135(9006) Generic", + { &it913x_table[4], NULL }, + }, } }; @@ -679,5 +823,5 @@ module_usb_driver(it913x_driver); MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); MODULE_DESCRIPTION("it913x USB 2 Driver"); -MODULE_VERSION("1.07"); +MODULE_VERSION("1.22"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 1a876a65ed56..b3fe05bbffc9 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -388,8 +388,7 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__, pid, index, onoff); - if (onoff) - if (!pid_filter) { + if (onoff) { ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); if (ret < 0) return -EAGAIN; @@ -654,6 +653,9 @@ static int lme2510_identify_state(struct usb_device *udev, struct dvb_usb_device_description **desc, int *cold) { + if (pid_filter > 0) + props->adapter[0].fe[0].caps &= + ~DVB_USB_ADAP_NEED_PID_FILTERING; *cold = 0; return 0; } @@ -1293,5 +1295,5 @@ module_usb_driver(lme2510_driver); MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("1.90"); +MODULE_VERSION("1.91"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c index d1f58371c711..d83df4bb72d3 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c @@ -102,8 +102,8 @@ fail: } static -int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state, - fe_modulation_t *constellation) +int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state, + fe_modulation_t *modulation) { u8 val; int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); @@ -113,13 +113,13 @@ int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state, switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { case 0: - *constellation = QPSK; + *modulation = QPSK; break; case 1: - *constellation = QAM_16; + *modulation = QAM_16; break; case 2: - *constellation = QAM_64; + *modulation = QAM_64; break; } fail: @@ -284,8 +284,7 @@ static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) /* ------------------------------------------------------------------------ */ -static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe) { struct mxl111sf_demod_state *state = fe->demodulator_priv; int ret = 0; @@ -303,7 +302,7 @@ static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe, mxl_dbg("()"); if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe, param); + ret = fe->ops.tuner_ops.set_params(fe); if (mxl_fail(ret)) goto fail; msleep(50); @@ -481,13 +480,13 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { struct mxl111sf_demod_state *state = fe->demodulator_priv; - fe_modulation_t constellation; + fe_modulation_t modulation; u16 snr; mxl111sf_demod_calc_snr(state, &snr); - mxl1x1sf_demod_get_tps_constellation(state, &constellation); + mxl1x1sf_demod_get_tps_modulation(state, &modulation); - switch (constellation) { + switch (modulation) { case QPSK: *signal_strength = (snr >= 1300) ? min(65535, snr * 44) : snr * 38; @@ -508,9 +507,9 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, return 0; } -static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mxl111sf_demod_state *state = fe->demodulator_priv; mxl_dbg("()"); @@ -518,18 +517,18 @@ static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe, p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; #endif if (fe->ops.tuner_ops.get_bandwidth) - fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth); + fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz); if (fe->ops.tuner_ops.get_frequency) fe->ops.tuner_ops.get_frequency(fe, &p->frequency); - mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP); - mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP); - mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation); + mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP); + mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP); + mxl1x1sf_demod_get_tps_modulation(state, &p->modulation); mxl1x1sf_demod_get_tps_guard_fft_mode(state, - &p->u.ofdm.transmission_mode); + &p->transmission_mode); mxl1x1sf_demod_get_tps_guard_interval(state, - &p->u.ofdm.guard_interval); + &p->guard_interval); mxl1x1sf_demod_get_tps_hierarchy(state, - &p->u.ofdm.hierarchy_information); + &p->hierarchy); return 0; } @@ -551,10 +550,9 @@ static void mxl111sf_demod_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops mxl111sf_demod_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "MaxLinear MxL111SF DVB-T demodulator", - .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c index a6341058c4e7..72db6eef4b9c 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c @@ -38,6 +38,8 @@ struct mxl111sf_tuner_state { struct mxl111sf_tuner_config *cfg; + enum mxl_if_freq if_freq; + u32 frequency; u32 bandwidth; }; @@ -186,7 +188,10 @@ static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state) ctrl = iffcw & 0x00ff; #endif ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl); - mxl_fail(ret); + if (mxl_fail(ret)) + goto fail; + + state->if_freq = state->cfg->if_freq; fail: return ret; } @@ -267,55 +272,49 @@ static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state, /* ------------------------------------------------------------------------ */ -static int mxl111sf_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mxl111sf_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; struct mxl111sf_tuner_state *state = fe->tuner_priv; int ret; u8 bw; mxl_dbg("()"); - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - bw = 0; /* ATSC */ - break; - case QAM_64: - case QAM_256: - bw = 1; /* US CABLE */ - break; - default: - err("%s: modulation not set!", __func__); - return -EINVAL; - } - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (delsys) { + case SYS_ATSC: + bw = 0; /* ATSC */ + break; + case SYS_DVBC_ANNEX_B: + bw = 1; /* US CABLE */ + break; + case SYS_DVBT: + switch (c->bandwidth_hz) { + case 6000000: bw = 6; break; - case BANDWIDTH_7_MHZ: + case 7000000: bw = 7; break; - case BANDWIDTH_8_MHZ: + case 8000000: bw = 8; break; default: err("%s: bandwidth not set!", __func__); return -EINVAL; } - } else { + break; + default: err("%s: modulation type not supported!", __func__); return -EINVAL; } - ret = mxl1x1sf_tune_rf(fe, params->frequency, bw); + ret = mxl1x1sf_tune_rf(fe, c->frequency, bw); if (mxl_fail(ret)) goto fail; - state->frequency = params->frequency; - state->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; + state->frequency = c->frequency; + state->bandwidth = c->bandwidth_hz; fail: return ret; } @@ -407,6 +406,54 @@ static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe, + u32 *frequency) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + + *frequency = 0; + + switch (state->if_freq) { + case MXL_IF_4_0: /* 4.0 MHz */ + *frequency = 4000000; + break; + case MXL_IF_4_5: /* 4.5 MHz */ + *frequency = 4500000; + break; + case MXL_IF_4_57: /* 4.57 MHz */ + *frequency = 4570000; + break; + case MXL_IF_5_0: /* 5.0 MHz */ + *frequency = 5000000; + break; + case MXL_IF_5_38: /* 5.38 MHz */ + *frequency = 5380000; + break; + case MXL_IF_6_0: /* 6.0 MHz */ + *frequency = 6000000; + break; + case MXL_IF_6_28: /* 6.28 MHz */ + *frequency = 6280000; + break; + case MXL_IF_7_2: /* 7.2 MHz */ + *frequency = 7200000; + break; + case MXL_IF_35_25: /* 35.25 MHz */ + *frequency = 35250000; + break; + case MXL_IF_36: /* 36 MHz */ + *frequency = 36000000; + break; + case MXL_IF_36_15: /* 36.15 MHz */ + *frequency = 36150000; + break; + case MXL_IF_44: /* 44 MHz */ + *frequency = 44000000; + break; + } + return 0; +} + static int mxl111sf_tuner_release(struct dvb_frontend *fe) { struct mxl111sf_tuner_state *state = fe->tuner_priv; @@ -436,6 +483,7 @@ static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { .get_rf_strength = mxl111sf_get_rf_strength, .get_frequency = mxl111sf_tuner_get_frequency, .get_bandwidth = mxl111sf_tuner_get_bandwidth, + .get_if_frequency = mxl111sf_tuner_get_if_frequency, .release = mxl111sf_tuner_release, }; diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 825a8b242e09..38ef0253d3b5 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -758,6 +758,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); #define MXL111SF_EP4_BULK_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ .stream = { \ .type = USB_BULK, \ @@ -772,6 +773,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); /* FIXME: works for v6 but not v8 silicon */ #define MXL111SF_EP4_ISOC_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ .stream = { \ .type = USB_ISOC, \ @@ -788,6 +790,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); } #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ .stream = { \ .type = USB_BULK, \ @@ -802,6 +805,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); /* FIXME */ #define MXL111SF_EP6_ISOC_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ .stream = { \ .type = USB_ISOC, \ @@ -839,8 +843,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_frontends = 1, .fe = {{ - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_attach_demod, .tuner_attach = mxl111sf_attach_tuner, @@ -883,8 +885,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_frontends = 1, .fe = {{ - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_attach_demod, .tuner_attach = mxl111sf_attach_tuner, @@ -927,16 +927,12 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_frontends = 2, .fe = {{ - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_BULK_STREAMING_CONFIG, }, { - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_attach_demod, .tuner_attach = mxl111sf_attach_tuner, @@ -992,16 +988,12 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_frontends = 2, .fe = {{ - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_ISOC_STREAMING_CONFIG, }, { - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_attach_demod, .tuner_attach = mxl111sf_attach_tuner, diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 56acf8e55d50..e53a1061cb8e 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -75,10 +75,18 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) { struct ttusb2_state *st = d->priv; - u8 s[wlen+4],r[64] = { 0 }; + u8 *s, *r = NULL; int ret = 0; - memset(s,0,wlen+4); + s = kzalloc(wlen+4, GFP_KERNEL); + if (!s) + return -ENOMEM; + + r = kzalloc(64, GFP_KERNEL); + if (!r) { + kfree(s); + return -ENOMEM; + } s[0] = 0xaa; s[1] = ++st->id; @@ -94,12 +102,17 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, r[2] != cmd || (rlen > 0 && r[3] != rlen)) { warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); + kfree(s); + kfree(r); return -EIO; } if (rlen > 0) memcpy(rbuf, &r[4], rlen); + kfree(s); + kfree(r); + return 0; } @@ -384,7 +397,7 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num memcpy(&obuf[3], msg[i].buf, msg[i].len); - if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) { + if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) { err("i2c transfer failed."); break; } diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c index 2bb8d4cc8d88..5eab468dd904 100644 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -135,9 +135,9 @@ static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front return 0; } -static int vp702x_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int vp702x_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct vp702x_fe_state *st = fe->demodulator_priv; struct vp702x_device_state *dst = st->d->priv; u32 freq = fep->frequency/1000; @@ -155,14 +155,14 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe, cmd[1] = freq & 0xff; cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ - sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20; + sr = (u64) (fep->symbol_rate/1000) << 20; do_div(sr,88000); cmd[3] = (sr >> 12) & 0xff; cmd[4] = (sr >> 4) & 0xff; cmd[5] = (sr << 4) & 0xf0; deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", - fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, + fep->frequency, freq, freq, fep->symbol_rate, (unsigned long) sr, (unsigned long) sr); /* if (fep->inversion == INVERSION_ON) @@ -171,7 +171,7 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe, if (st->voltage == SEC_VOLTAGE_18) cmd[6] |= 0x40; -/* if (fep->u.qpsk.symbol_rate > 8000000) +/* if (fep->symbol_rate > 8000000) cmd[6] |= 0x20; if (fep->frequency < 1531000) @@ -211,13 +211,6 @@ static int vp702x_fe_sleep(struct dvb_frontend *fe) return 0; } -static int vp702x_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - deb_fe("%s\n",__func__); - return 0; -} - static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *m) { @@ -350,9 +343,9 @@ error: static struct dvb_frontend_ops vp702x_fe_ops = { + .delsys = { SYS_DVBS }, .info = { .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1000, /* kHz for QPSK frontends */ @@ -371,7 +364,6 @@ static struct dvb_frontend_ops vp702x_fe_ops = { .sleep = vp702x_fe_sleep, .set_frontend = vp702x_fe_set_frontend, - .get_frontend = vp702x_fe_get_frontend, .get_tune_settings = vp702x_fe_get_tune_settings, .read_status = vp702x_fe_read_status, diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c index 8452eef90322..b8825b18c003 100644 --- a/drivers/media/dvb/dvb-usb/vp7045-fe.c +++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c @@ -103,9 +103,9 @@ static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front return 0; } -static int vp7045_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int vp7045_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct vp7045_fe_state *state = fe->demodulator_priv; u8 buf[5]; u32 freq = fep->frequency / 1000; @@ -115,25 +115,24 @@ static int vp7045_fe_set_frontend(struct dvb_frontend* fe, buf[2] = freq & 0xff; buf[3] = 0; - switch (fep->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: buf[4] = 8; break; - case BANDWIDTH_7_MHZ: buf[4] = 7; break; - case BANDWIDTH_6_MHZ: buf[4] = 6; break; - case BANDWIDTH_AUTO: return -EOPNOTSUPP; - default: - return -EINVAL; + switch (fep->bandwidth_hz) { + case 8000000: + buf[4] = 8; + break; + case 7000000: + buf[4] = 7; + break; + case 6000000: + buf[4] = 6; + break; + default: + return -EINVAL; } vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200); return 0; } -static int vp7045_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - return 0; -} - static void vp7045_fe_release(struct dvb_frontend* fe) { struct vp7045_fe_state *state = fe->demodulator_priv; @@ -159,9 +158,9 @@ error: static struct dvb_frontend_ops vp7045_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Twinhan VP7045/46 USB DVB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 1000, @@ -181,7 +180,6 @@ static struct dvb_frontend_ops vp7045_fe_ops = { .sleep = vp7045_fe_sleep, .set_frontend = vp7045_fe_set_frontend, - .get_frontend = vp7045_fe_get_frontend, .get_tune_settings = vp7045_fe_get_tune_settings, .read_status = vp7045_fe_read_status, diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c index 489ae8245867..d1a1a1324ef8 100644 --- a/drivers/media/dvb/firewire/firedtv-avc.c +++ b/drivers/media/dvb/firewire/firedtv-avc.c @@ -335,7 +335,7 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand) * (not supported by the AVC standard) */ static int avc_tuner_tuneqpsk(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *p) { struct avc_command_frame *c = (void *)fdtv->avc_data; @@ -349,15 +349,15 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv, else c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; - c->operand[4] = (params->frequency >> 24) & 0xff; - c->operand[5] = (params->frequency >> 16) & 0xff; - c->operand[6] = (params->frequency >> 8) & 0xff; - c->operand[7] = params->frequency & 0xff; + c->operand[4] = (p->frequency >> 24) & 0xff; + c->operand[5] = (p->frequency >> 16) & 0xff; + c->operand[6] = (p->frequency >> 8) & 0xff; + c->operand[7] = p->frequency & 0xff; - c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; - c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; + c->operand[8] = ((p->symbol_rate / 1000) >> 8) & 0xff; + c->operand[9] = (p->symbol_rate / 1000) & 0xff; - switch (params->u.qpsk.fec_inner) { + switch (p->fec_inner) { case FEC_1_2: c->operand[10] = 0x1; break; case FEC_2_3: c->operand[10] = 0x2; break; case FEC_3_4: c->operand[10] = 0x3; break; @@ -392,10 +392,11 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv, default: c->operand[13] = 0x2; break; } switch (fdtv->fe.dtv_property_cache.rolloff) { - case ROLLOFF_AUTO: c->operand[14] = 0x2; break; case ROLLOFF_35: c->operand[14] = 0x2; break; case ROLLOFF_20: c->operand[14] = 0x0; break; case ROLLOFF_25: c->operand[14] = 0x1; break; + case ROLLOFF_AUTO: + default: c->operand[14] = 0x2; break; /* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */ } switch (fdtv->fe.dtv_property_cache.pilot) { @@ -415,7 +416,7 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv, } static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *p) { struct avc_command_frame *c = (void *)fdtv->avc_data; @@ -434,8 +435,8 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, | 1 << 4 /* Frequency */ | 1 << 3 /* Symbol_Rate */ | 0 << 2 /* FEC_outer */ - | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0) - | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0); + | (p->fec_inner != FEC_AUTO ? 1 << 1 : 0) + | (p->modulation != QAM_AUTO ? 1 << 0 : 0); /* multiplex_valid_flags, low byte */ c->operand[6] = 0 << 7 /* NetworkID */ @@ -446,15 +447,15 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, c->operand[9] = 0x00; c->operand[10] = 0x00; - c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); - c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff; - c->operand[13] = (params->frequency / 4000) & 0xff; - c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; - c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; - c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; + c->operand[11] = (((p->frequency / 4000) >> 16) & 0xff) | (2 << 6); + c->operand[12] = ((p->frequency / 4000) >> 8) & 0xff; + c->operand[13] = (p->frequency / 4000) & 0xff; + c->operand[14] = ((p->symbol_rate / 1000) >> 12) & 0xff; + c->operand[15] = ((p->symbol_rate / 1000) >> 4) & 0xff; + c->operand[16] = ((p->symbol_rate / 1000) << 4) & 0xf0; c->operand[17] = 0x00; - switch (params->u.qpsk.fec_inner) { + switch (p->fec_inner) { case FEC_1_2: c->operand[18] = 0x1; break; case FEC_2_3: c->operand[18] = 0x2; break; case FEC_3_4: c->operand[18] = 0x3; break; @@ -466,7 +467,7 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, default: c->operand[18] = 0x0; } - switch (params->u.qam.modulation) { + switch (p->modulation) { case QAM_16: c->operand[19] = 0x08; break; case QAM_32: c->operand[19] = 0x10; break; case QAM_64: c->operand[19] = 0x18; break; @@ -483,9 +484,8 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, } static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *p) { - struct dvb_ofdm_parameters *ofdm = ¶ms->u.ofdm; struct avc_command_frame *c = (void *)fdtv->avc_data; c->opcode = AVC_OPCODE_DSD; @@ -500,42 +500,42 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, c->operand[5] = 0 << 7 /* reserved */ | 1 << 6 /* CenterFrequency */ - | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0) - | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0) - | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0) - | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0) - | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0) - | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0); + | (p->bandwidth_hz != 0 ? 1 << 5 : 0) + | (p->modulation != QAM_AUTO ? 1 << 4 : 0) + | (p->hierarchy != HIERARCHY_AUTO ? 1 << 3 : 0) + | (p->code_rate_HP != FEC_AUTO ? 1 << 2 : 0) + | (p->code_rate_LP != FEC_AUTO ? 1 << 1 : 0) + | (p->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0); /* multiplex_valid_flags, low byte */ c->operand[6] = 0 << 7 /* NetworkID */ - | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0) + | (p->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0) | 0 << 5 /* OtherFrequencyFlag */ | 0 << 0 /* reserved */ ; c->operand[7] = 0x0; - c->operand[8] = (params->frequency / 10) >> 24; - c->operand[9] = ((params->frequency / 10) >> 16) & 0xff; - c->operand[10] = ((params->frequency / 10) >> 8) & 0xff; - c->operand[11] = (params->frequency / 10) & 0xff; - - switch (ofdm->bandwidth) { - case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break; - case BANDWIDTH_8_MHZ: - case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ - case BANDWIDTH_AUTO: + c->operand[8] = (p->frequency / 10) >> 24; + c->operand[9] = ((p->frequency / 10) >> 16) & 0xff; + c->operand[10] = ((p->frequency / 10) >> 8) & 0xff; + c->operand[11] = (p->frequency / 10) & 0xff; + + switch (p->bandwidth_hz) { + case 7000000: c->operand[12] = 0x20; break; + case 8000000: + case 6000000: /* not defined by AVC spec */ + case 0: default: c->operand[12] = 0x00; } - switch (ofdm->constellation) { + switch (p->modulation) { case QAM_16: c->operand[13] = 1 << 6; break; case QAM_64: c->operand[13] = 2 << 6; break; case QPSK: default: c->operand[13] = 0x00; } - switch (ofdm->hierarchy_information) { + switch (p->hierarchy) { case HIERARCHY_1: c->operand[13] |= 1 << 3; break; case HIERARCHY_2: c->operand[13] |= 2 << 3; break; case HIERARCHY_4: c->operand[13] |= 3 << 3; break; @@ -544,7 +544,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, default: break; } - switch (ofdm->code_rate_HP) { + switch (p->code_rate_HP) { case FEC_2_3: c->operand[13] |= 1; break; case FEC_3_4: c->operand[13] |= 2; break; case FEC_5_6: c->operand[13] |= 3; break; @@ -553,7 +553,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, default: break; } - switch (ofdm->code_rate_LP) { + switch (p->code_rate_LP) { case FEC_2_3: c->operand[14] = 1 << 5; break; case FEC_3_4: c->operand[14] = 2 << 5; break; case FEC_5_6: c->operand[14] = 3 << 5; break; @@ -562,7 +562,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, default: c->operand[14] = 0x00; break; } - switch (ofdm->guard_interval) { + switch (p->guard_interval) { case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break; case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break; case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break; @@ -571,7 +571,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, default: break; } - switch (ofdm->transmission_mode) { + switch (p->transmission_mode) { case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break; case TRANSMISSION_MODE_2K: case TRANSMISSION_MODE_AUTO: @@ -585,7 +585,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, } int avc_tuner_dsd(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *p) { struct avc_command_frame *c = (void *)fdtv->avc_data; int pos, ret; @@ -597,9 +597,9 @@ int avc_tuner_dsd(struct firedtv *fdtv, switch (fdtv->type) { case FIREDTV_DVB_S: - case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break; - case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break; - case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break; + case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, p); break; + case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, p); break; + case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break; default: BUG(); } diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c index fd8bbbfa5c59..eb7496eab130 100644 --- a/drivers/media/dvb/firewire/firedtv-dvb.c +++ b/drivers/media/dvb/firewire/firedtv-dvb.c @@ -203,7 +203,9 @@ int fdtv_dvb_register(struct firedtv *fdtv, const char *name) if (err) goto fail_rem_frontend; - dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); + err = dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); + if (err) + goto fail_disconnect_frontend; fdtv_frontend_init(fdtv, name); err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe); @@ -218,6 +220,7 @@ int fdtv_dvb_register(struct firedtv *fdtv, const char *name) fail_net_release: dvb_net_release(&fdtv->dvbnet); +fail_disconnect_frontend: fdtv->demux.dmx.close(&fdtv->demux.dmx); fail_rem_frontend: fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c index 8748a61be73d..6fe9793b98b3 100644 --- a/drivers/media/dvb/firewire/firedtv-fe.c +++ b/drivers/media/dvb/firewire/firedtv-fe.c @@ -141,28 +141,12 @@ static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) return -EOPNOTSUPP; } -static int fdtv_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int fdtv_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct firedtv *fdtv = fe->sec_priv; - return avc_tuner_dsd(fdtv, params); -} - -static int fdtv_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - return -EOPNOTSUPP; -} - -static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp) -{ - return 0; -} - -static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp) -{ - return 0; + return avc_tuner_dsd(fdtv, p); } void fdtv_frontend_init(struct firedtv *fdtv, const char *name) @@ -174,10 +158,6 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) ops->sleep = fdtv_sleep; ops->set_frontend = fdtv_set_frontend; - ops->get_frontend = fdtv_get_frontend; - - ops->get_property = fdtv_get_property; - ops->set_property = fdtv_set_property; ops->read_status = fdtv_read_status; ops->read_ber = fdtv_read_ber; @@ -192,7 +172,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) switch (fdtv->type) { case FIREDTV_DVB_S: - fi->type = FE_QPSK; + ops->delsys[0] = SYS_DVBS; fi->frequency_min = 950000; fi->frequency_max = 2150000; @@ -211,7 +191,8 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) break; case FIREDTV_DVB_S2: - fi->type = FE_QPSK; + ops->delsys[0] = SYS_DVBS; + ops->delsys[1] = SYS_DVBS2; fi->frequency_min = 950000; fi->frequency_max = 2150000; @@ -231,7 +212,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) break; case FIREDTV_DVB_C: - fi->type = FE_QAM; + ops->delsys[0] = SYS_DVBC_ANNEX_A; fi->frequency_min = 47000000; fi->frequency_max = 866000000; @@ -249,7 +230,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) break; case FIREDTV_DVB_T: - fi->type = FE_OFDM; + ops->delsys[0] = SYS_DVBT; fi->frequency_min = 49000000; fi->frequency_max = 861000000; diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h index bd00b04e079d..4fdcd8cb7530 100644 --- a/drivers/media/dvb/firewire/firedtv.h +++ b/drivers/media/dvb/firewire/firedtv.h @@ -112,8 +112,8 @@ struct firedtv { /* firedtv-avc.c */ int avc_recv(struct firedtv *fdtv, void *data, size_t length); int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat); -struct dvb_frontend_parameters; -int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params); +struct dtv_frontend_properties; +int avc_tuner_dsd(struct firedtv *fdtv, struct dtv_frontend_properties *params); int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]); int avc_tuner_get_ts(struct firedtv *fdtv); int avc_identify_subunit(struct firedtv *fdtv); diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 4a2d2e6c91ab..ebb5ed7a7783 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -404,6 +404,13 @@ config DVB_EC100 help Say Y when you want to support this frontend. +config DVB_HD29L2 + tristate "HDIC HD29L2" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y when you want to support this frontend. + config DVB_STV0367 tristate "ST STV0367 based" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index f639f6781551..00a20636df62 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_DVB_STV090x) += stv090x.o obj-$(CONFIG_DVB_STV6110x) += stv6110x.o obj-$(CONFIG_DVB_ISL6423) += isl6423.o obj-$(CONFIG_DVB_EC100) += ec100.o +obj-$(CONFIG_DVB_HD29L2) += hd29l2.o obj-$(CONFIG_DVB_DS3000) += ds3000.o obj-$(CONFIG_DVB_MB86A16) += mb86a16.o obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 345311c33383..6bcbcf543b38 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -2,6 +2,7 @@ * Afatech AF9013 demodulator driver * * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> * * Thanks to Afatech who kindly provided information. * @@ -21,25 +22,15 @@ * */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/firmware.h> - -#include "dvb_frontend.h" #include "af9013_priv.h" -#include "af9013.h" int af9013_debug; +module_param_named(debug, af9013_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); struct af9013_state { struct i2c_adapter *i2c; - struct dvb_frontend frontend; - + struct dvb_frontend fe; struct af9013_config config; /* tuner/demod RF and IF AGC limits used for signal strength calc */ @@ -48,107 +39,178 @@ struct af9013_state { u32 ber; u32 ucblocks; u16 snr; - u32 frequency; - unsigned long next_statistics_check; + u32 bandwidth_hz; + fe_status_t fe_status; + unsigned long set_frontend_jiffies; + unsigned long read_status_jiffies; + bool first_tune; + bool i2c_gate_state; + unsigned int statistics_step:3; + struct delayed_work statistics_work; }; -static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; - -static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg, - u8 *val, u8 len) +/* write multiple registers */ +static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, + const u8 *val, int len) { + int ret; u8 buf[3+len]; - struct i2c_msg msg = { - .addr = state->config.demod_address, - .flags = 0, - .len = sizeof(buf), - .buf = buf }; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; + struct i2c_msg msg[1] = { + { + .addr = priv->config.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = (reg >> 8) & 0xff; + buf[1] = (reg >> 0) & 0xff; buf[2] = mbox; memcpy(&buf[3], val, len); - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - warn("I2C write failed reg:%04x len:%d", reg, len); - return -EREMOTEIO; + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed=%d reg=%04x len=%d", ret, reg, len); + ret = -EREMOTEIO; } - return 0; + return ret; } -static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val, - u8 len) +/* read multiple registers */ +static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, + u8 *val, int len) { - u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7); - return af9013_write_regs(state, mbox, reg, val, len); + int ret; + u8 buf[3]; + struct i2c_msg msg[2] = { + { + .addr = priv->config.i2c_addr, + .flags = 0, + .len = 3, + .buf = buf, + }, { + .addr = priv->config.i2c_addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + + buf[0] = (reg >> 8) & 0xff; + buf[1] = (reg >> 0) & 0xff; + buf[2] = mbox; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + ret = 0; + } else { + warn("i2c rd failed=%d reg=%04x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + return ret; } -static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, - u8 len) +/* write multiple registers */ +static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val, + int len) +{ + int ret, i; + u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); + + if ((priv->config.ts_mode == AF9013_TS_USB) && + ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { + mbox |= ((len - 1) << 2); + ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len); + } else { + for (i = 0; i < len; i++) { + ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1); + if (ret) + goto err; + } + } + +err: + return 0; +} + +/* read multiple registers */ +static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len) { - u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7); - return af9013_write_regs(state, mbox, reg, val, len); + int ret, i; + u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0); + + if ((priv->config.ts_mode == AF9013_TS_USB) && + ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { + mbox |= ((len - 1) << 2); + ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len); + } else { + for (i = 0; i < len; i++) { + ret = af9013_rd_regs_i2c(priv, mbox, reg+i, val+i, 1); + if (ret) + goto err; + } + } + +err: + return 0; } /* write single register */ -static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val) +static int af9013_wr_reg(struct af9013_state *priv, u16 reg, u8 val) { - return af9013_write_ofdm_regs(state, reg, &val, 1); + return af9013_wr_regs(priv, reg, &val, 1); } /* read single register */ -static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val) +static int af9013_rd_reg(struct af9013_state *priv, u16 reg, u8 *val) { - u8 obuf[3] = { reg >> 8, reg & 0xff, 0 }; - u8 ibuf[1]; - struct i2c_msg msg[2] = { - { - .addr = state->config.demod_address, - .flags = 0, - .len = sizeof(obuf), - .buf = obuf - }, { - .addr = state->config.demod_address, - .flags = I2C_M_RD, - .len = sizeof(ibuf), - .buf = ibuf - } - }; + return af9013_rd_regs(priv, reg, val, 1); +} - if (i2c_transfer(state->i2c, msg, 2) != 2) { - warn("I2C read failed reg:%04x", reg); - return -EREMOTEIO; - } - *val = ibuf[0]; - return 0; +static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, + u8 len) +{ + u8 mbox = (1 << 7)|(1 << 6)|((len - 1) << 2)|(1 << 1)|(1 << 0); + return af9013_wr_regs_i2c(state, mbox, reg, val, len); } -static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos, - u8 len, u8 val) +static int af9013_wr_reg_bits(struct af9013_state *state, u16 reg, int pos, + int len, u8 val) { int ret; u8 tmp, mask; - ret = af9013_read_reg(state, reg, &tmp); - if (ret) - return ret; + /* no need for read if whole reg is written */ + if (len != 8) { + ret = af9013_rd_reg(state, reg, &tmp); + if (ret) + return ret; - mask = regmask[len - 1] << pos; - tmp = (tmp & ~mask) | ((val << pos) & mask); + mask = (0xff >> (8 - len)) << pos; + val <<= pos; + tmp &= ~mask; + val |= tmp; + } - return af9013_write_reg(state, reg, tmp); + return af9013_wr_reg(state, reg, val); } -static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos, - u8 len, u8 *val) +static int af9013_rd_reg_bits(struct af9013_state *state, u16 reg, int pos, + int len, u8 *val) { int ret; u8 tmp; - ret = af9013_read_reg(state, reg, &tmp); + ret = af9013_rd_reg(state, reg, &tmp); if (ret) return ret; - *val = (tmp >> pos) & regmask[len - 1]; + + *val = (tmp >> pos); + *val &= (0xff >> (8 - len)); + return 0; } @@ -157,10 +219,13 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) int ret; u8 pos; u16 addr; - deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval); -/* GPIO0 & GPIO1 0xd735 - GPIO2 & GPIO3 0xd736 */ + dbg("%s: gpio=%d gpioval=%02x", __func__, gpio, gpioval); + + /* + * GPIO0 & GPIO1 0xd735 + * GPIO2 & GPIO3 0xd736 + */ switch (gpio) { case 0: @@ -175,7 +240,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) default: err("invalid gpio:%d\n", gpio); ret = -EINVAL; - goto error; + goto err; }; switch (gpio) { @@ -190,16 +255,21 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) break; }; - ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval); + ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval); + if (ret) + goto err; -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } static u32 af913_div(u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; - deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x); + + dbg("%s: a=%d b=%d x=%d", __func__, a, b, x); if (a > b) { c = a / b; @@ -216,205 +286,407 @@ static u32 af913_div(u32 a, u32 b, u32 x) } r = (c << (u32)x) + r; - deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r); + dbg("%s: a=%d b=%d x=%d r=%x", __func__, a, b, x, r); return r; } -static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw) +static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) { - int ret, i, j, found; - deb_info("%s: adc_clock:%d bw:%d\n", __func__, - state->config.adc_clock, bw); - - /* lookup coeff from table */ - for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) { - if (coeff_table[i].adc_clock == state->config.adc_clock && - coeff_table[i].bw == bw) { - found = 1; - break; - } - } + int ret, i; + u8 tmp; - if (!found) { - err("invalid bw or clock"); - ret = -EINVAL; - goto error; + dbg("%s: onoff=%d", __func__, onoff); + + /* enable reset */ + ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 1); + if (ret) + goto err; + + /* start reset mechanism */ + ret = af9013_wr_reg(state, 0xaeff, 1); + if (ret) + goto err; + + /* wait reset performs */ + for (i = 0; i < 150; i++) { + ret = af9013_rd_reg_bits(state, 0xd417, 1, 1, &tmp); + if (ret) + goto err; + + if (tmp) + break; /* reset done */ + + usleep_range(5000, 25000); } - deb_info("%s: coeff: ", __func__); - debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info); + if (!tmp) + return -ETIMEDOUT; - /* program */ - for (j = 0; j < sizeof(coeff_table[i].val); j++) { - ret = af9013_write_reg(state, 0xae00 + j, - coeff_table[i].val[j]); + if (onoff) { + /* clear reset */ + ret = af9013_wr_reg_bits(state, 0xd417, 1, 1, 0); if (ret) - break; + goto err; + + /* disable reset */ + ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 0); + + /* power on */ + ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 0); + } else { + /* power off */ + ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 1); } -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + + dbg("%s", __func__); + + /* reset and start BER counter */ + ret = af9013_wr_reg_bits(state, 0xd391, 4, 1, 1); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } -static int af9013_set_adc_ctrl(struct af9013_state *state) +static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe) { + struct af9013_state *state = fe->demodulator_priv; int ret; - u8 buf[3], tmp, i; - u32 adc_cw; + u8 buf[5]; - deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock); + dbg("%s", __func__); - /* adc frequency type */ - switch (state->config.adc_clock) { - case 28800: /* 28.800 MHz */ - tmp = 0; - break; - case 20480: /* 20.480 MHz */ - tmp = 1; + /* check if error bit count is ready */ + ret = af9013_rd_reg_bits(state, 0xd391, 4, 1, &buf[0]); + if (ret) + goto err; + + if (!buf[0]) { + dbg("%s: not ready", __func__); + return 0; + } + + ret = af9013_rd_regs(state, 0xd387, buf, 5); + if (ret) + goto err; + + state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + state->ucblocks += (buf[4] << 8) | buf[3]; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_statistics_snr_start(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + + dbg("%s", __func__); + + /* start SNR meas */ + ret = af9013_wr_reg_bits(state, 0xd2e1, 3, 1, 1); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_statistics_snr_result(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret, i, len; + u8 buf[3], tmp; + u32 snr_val; + const struct af9013_snr *uninitialized_var(snr_lut); + + dbg("%s", __func__); + + /* check if SNR ready */ + ret = af9013_rd_reg_bits(state, 0xd2e1, 3, 1, &tmp); + if (ret) + goto err; + + if (!tmp) { + dbg("%s: not ready", __func__); + return 0; + } + + /* read value */ + ret = af9013_rd_regs(state, 0xd2e3, buf, 3); + if (ret) + goto err; + + snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + /* read current modulation */ + ret = af9013_rd_reg(state, 0xd3c1, &tmp); + if (ret) + goto err; + + switch ((tmp >> 6) & 3) { + case 0: + len = ARRAY_SIZE(qpsk_snr_lut); + snr_lut = qpsk_snr_lut; break; - case 28000: /* 28.000 MHz */ - tmp = 2; + case 1: + len = ARRAY_SIZE(qam16_snr_lut); + snr_lut = qam16_snr_lut; break; - case 25000: /* 25.000 MHz */ - tmp = 3; + case 2: + len = ARRAY_SIZE(qam64_snr_lut); + snr_lut = qam64_snr_lut; break; default: - err("invalid xtal"); - return -EINVAL; + goto err; + break; } - adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul); + for (i = 0; i < len; i++) { + tmp = snr_lut[i].snr; - buf[0] = (u8) ((adc_cw & 0x000000ff)); - buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8); - buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16); + if (snr_val < snr_lut[i].val) + break; + } + state->snr = tmp * 10; /* dB/10 */ - deb_info("%s: adc_cw:", __func__); - debug_dump(buf, sizeof(buf), deb_info); + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_statistics_signal_strength(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret = 0; + u8 buf[2], rf_gain, if_gain; + int signal_strength; + + dbg("%s", __func__); + + if (!state->signal_strength_en) + return 0; + + ret = af9013_rd_regs(state, 0xd07c, buf, 2); + if (ret) + goto err; + + rf_gain = buf[0]; + if_gain = buf[1]; + + signal_strength = (0xffff / \ + (9 * (state->rf_50 + state->if_50) - \ + 11 * (state->rf_80 + state->if_80))) * \ + (10 * (rf_gain + if_gain) - \ + 11 * (state->rf_80 + state->if_80)); + if (signal_strength < 0) + signal_strength = 0; + else if (signal_strength > 0xffff) + signal_strength = 0xffff; + + state->signal_strength = signal_strength; - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, 0xd180 + i, buf[i]); - if (ret) - goto error; - } - ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp); -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } -static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw) +static void af9013_statistics_work(struct work_struct *work) { int ret; - u16 addr; - u8 buf[3], i, j; - u32 adc_freq, freq_cw; - s8 bfs_spec_inv; - int if_sample_freq; - - for (j = 0; j < 3; j++) { - if (j == 0) { - addr = 0xd140; /* fcw normal */ - bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; - } else if (j == 1) { - addr = 0x9be7; /* fcw dummy ram */ - bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; - } else { - addr = 0x9bea; /* fcw inverted */ - bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1; - } + struct af9013_state *state = container_of(work, + struct af9013_state, statistics_work.work); + unsigned int next_msec; + + /* update only signal strength when demod is not locked */ + if (!(state->fe_status & FE_HAS_LOCK)) { + state->statistics_step = 0; + state->ber = 0; + state->snr = 0; + } + + switch (state->statistics_step) { + default: + state->statistics_step = 0; + case 0: + ret = af9013_statistics_signal_strength(&state->fe); + state->statistics_step++; + next_msec = 300; + break; + case 1: + ret = af9013_statistics_snr_start(&state->fe); + state->statistics_step++; + next_msec = 200; + break; + case 2: + ret = af9013_statistics_ber_unc_start(&state->fe); + state->statistics_step++; + next_msec = 1000; + break; + case 3: + ret = af9013_statistics_snr_result(&state->fe); + state->statistics_step++; + next_msec = 400; + break; + case 4: + ret = af9013_statistics_ber_unc_result(&state->fe); + state->statistics_step++; + next_msec = 100; + break; + } - adc_freq = state->config.adc_clock * 1000; - if_sample_freq = state->config.tuner_if * 1000; + schedule_delayed_work(&state->statistics_work, + msecs_to_jiffies(next_msec)); - /* TDA18271 uses different sampling freq for every bw */ - if (state->config.tuner == AF9013_TUNER_TDA18271) { - switch (bw) { - case BANDWIDTH_6_MHZ: - if_sample_freq = 3300000; /* 3.3 MHz */ - break; - case BANDWIDTH_7_MHZ: - if_sample_freq = 3500000; /* 3.5 MHz */ - break; - case BANDWIDTH_8_MHZ: - default: - if_sample_freq = 4000000; /* 4.0 MHz */ - break; - } - } else if (state->config.tuner == AF9013_TUNER_TDA18218) { - switch (bw) { - case BANDWIDTH_6_MHZ: - if_sample_freq = 3000000; /* 3 MHz */ - break; - case BANDWIDTH_7_MHZ: - if_sample_freq = 3500000; /* 3.5 MHz */ - break; - case BANDWIDTH_8_MHZ: - default: - if_sample_freq = 4000000; /* 4 MHz */ + return; +} + +static int af9013_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 800; + fesettings->step_size = 0; + fesettings->max_drift = 0; + + return 0; +} + +static int af9013_set_frontend(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i, sampling_freq; + bool auto_mode, spec_inv; + u8 buf[6]; + u32 if_frequency, freq_cw; + + dbg("%s: frequency=%d bandwidth_hz=%d", __func__, + c->frequency, c->bandwidth_hz); + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + + /* program CFOE coefficients */ + if (c->bandwidth_hz != state->bandwidth_hz) { + for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { + if (coeff_lut[i].clock == state->config.clock && + coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { break; } } - while (if_sample_freq > (adc_freq / 2)) - if_sample_freq = if_sample_freq - adc_freq; + ret = af9013_wr_regs(state, 0xae00, coeff_lut[i].val, + sizeof(coeff_lut[i].val)); + } - if (if_sample_freq >= 0) - bfs_spec_inv = bfs_spec_inv * (-1); + /* program frequency control */ + if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) { + /* get used IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) + fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); else - if_sample_freq = if_sample_freq * (-1); + if_frequency = state->config.if_frequency; + + sampling_freq = if_frequency; - freq_cw = af913_div(if_sample_freq, adc_freq, 23ul); + while (sampling_freq > (state->config.clock / 2)) + sampling_freq -= state->config.clock; - if (bfs_spec_inv == -1) - freq_cw = 0x00800000 - freq_cw; + if (sampling_freq < 0) { + sampling_freq *= -1; + spec_inv = state->config.spec_inv; + } else { + spec_inv = !state->config.spec_inv; + } - buf[0] = (u8) ((freq_cw & 0x000000ff)); - buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8); - buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16); + freq_cw = af913_div(sampling_freq, state->config.clock, 23); + if (spec_inv) + freq_cw = 0x800000 - freq_cw; - deb_info("%s: freq_cw:", __func__); - debug_dump(buf, sizeof(buf), deb_info); + buf[0] = (freq_cw >> 0) & 0xff; + buf[1] = (freq_cw >> 8) & 0xff; + buf[2] = (freq_cw >> 16) & 0x7f; - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, addr++, buf[i]); - if (ret) - goto error; - } + freq_cw = 0x800000 - freq_cw; + + buf[3] = (freq_cw >> 0) & 0xff; + buf[4] = (freq_cw >> 8) & 0xff; + buf[5] = (freq_cw >> 16) & 0x7f; + + ret = af9013_wr_regs(state, 0xd140, buf, 3); + if (ret) + goto err; + + ret = af9013_wr_regs(state, 0x9be7, buf, 6); + if (ret) + goto err; } -error: - return ret; -} -static int af9013_set_ofdm_params(struct af9013_state *state, - struct dvb_ofdm_parameters *params, u8 *auto_mode) -{ - int ret; - u8 i, buf[3] = {0, 0, 0}; - *auto_mode = 0; /* set if parameters are requested to auto set */ + /* clear TPS lock flag */ + ret = af9013_wr_reg_bits(state, 0xd330, 3, 1, 1); + if (ret) + goto err; + + /* clear MPEG2 lock flag */ + ret = af9013_wr_reg_bits(state, 0xd507, 6, 1, 0); + if (ret) + goto err; + + /* empty channel function */ + ret = af9013_wr_reg_bits(state, 0x9bfe, 0, 1, 0); + if (ret) + goto err; - /* Try auto-detect transmission parameters in case of AUTO requested or - garbage parameters given by application for compatibility. - MPlayer seems to provide garbage parameters currently. */ + /* empty DVB-T channel function */ + ret = af9013_wr_reg_bits(state, 0x9bc2, 0, 1, 0); + if (ret) + goto err; + + /* transmission parameters */ + auto_mode = false; + memset(buf, 0, 3); - switch (params->transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case TRANSMISSION_MODE_2K: break; case TRANSMISSION_MODE_8K: buf[0] |= (1 << 0); break; default: - deb_info("%s: invalid transmission_mode\n", __func__); - *auto_mode = 1; + dbg("%s: invalid transmission_mode", __func__); + auto_mode = 1; } - switch (params->guard_interval) { + switch (c->guard_interval) { case GUARD_INTERVAL_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case GUARD_INTERVAL_1_32: break; case GUARD_INTERVAL_1_16: @@ -427,13 +699,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (3 << 2); break; default: - deb_info("%s: invalid guard_interval\n", __func__); - *auto_mode = 1; + dbg("%s: invalid guard_interval", __func__); + auto_mode = 1; } - switch (params->hierarchy_information) { + switch (c->hierarchy) { case HIERARCHY_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case HIERARCHY_NONE: break; case HIERARCHY_1: @@ -446,13 +719,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (3 << 4); break; default: - deb_info("%s: invalid hierarchy_information\n", __func__); - *auto_mode = 1; + dbg("%s: invalid hierarchy", __func__); + auto_mode = 1; }; - switch (params->constellation) { + switch (c->modulation) { case QAM_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case QPSK: break; case QAM_16: @@ -462,16 +736,17 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[1] |= (2 << 6); break; default: - deb_info("%s: invalid constellation\n", __func__); - *auto_mode = 1; + dbg("%s: invalid modulation", __func__); + auto_mode = 1; } /* Use HP. How and which case we can switch to LP? */ buf[1] |= (1 << 4); - switch (params->code_rate_HP) { + switch (c->code_rate_HP) { case FEC_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case FEC_1_2: break; case FEC_2_3: @@ -487,16 +762,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[2] |= (4 << 0); break; default: - deb_info("%s: invalid code_rate_HP\n", __func__); - *auto_mode = 1; + dbg("%s: invalid code_rate_HP", __func__); + auto_mode = 1; } - switch (params->code_rate_LP) { + switch (c->code_rate_LP) { case FEC_AUTO: - /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO - by dvb_frontend.c for compatibility */ - if (params->hierarchy_information != HIERARCHY_NONE) - *auto_mode = 1; + auto_mode = 1; + break; case FEC_1_2: break; case FEC_2_3: @@ -512,709 +785,373 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[2] |= (4 << 3); break; case FEC_NONE: - if (params->hierarchy_information == HIERARCHY_AUTO) - break; + break; default: - deb_info("%s: invalid code_rate_LP\n", __func__); - *auto_mode = 1; + dbg("%s: invalid code_rate_LP", __func__); + auto_mode = 1; } - switch (params->bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: break; - case BANDWIDTH_7_MHZ: + case 7000000: buf[1] |= (1 << 2); break; - case BANDWIDTH_8_MHZ: + case 8000000: buf[1] |= (2 << 2); break; default: - deb_info("%s: invalid bandwidth\n", __func__); - buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */ - } - - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]); - if (ret) - break; + dbg("%s: invalid bandwidth_hz", __func__); + ret = -EINVAL; + goto err; } - return ret; -} - -static int af9013_reset(struct af9013_state *state, u8 sleep) -{ - int ret; - u8 tmp, i; - deb_info("%s\n", __func__); - - /* enable OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1); - if (ret) - goto error; - - /* start reset mechanism */ - ret = af9013_write_reg(state, 0xaeff, 1); + ret = af9013_wr_regs(state, 0xd3c0, buf, 3); if (ret) - goto error; + goto err; - /* reset is done when bit 1 is set */ - for (i = 0; i < 150; i++) { - ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp); - if (ret) - goto error; - if (tmp) - break; /* reset done */ - msleep(10); - } - if (!tmp) - return -ETIMEDOUT; - - /* don't clear reset when going to sleep */ - if (!sleep) { - /* clear OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); + if (auto_mode) { + /* clear easy mode flag */ + ret = af9013_wr_reg(state, 0xaefd, 0); if (ret) - goto error; - - /* disable OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); - } -error: - return ret; -} - -static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) -{ - int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); + goto err; - if (onoff) { - /* power on */ - ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0); - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); + dbg("%s: auto params", __func__); } else { - /* power off */ - ret = af9013_reset(state, 1); + /* set easy mode flag */ + ret = af9013_wr_reg(state, 0xaefd, 1); if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1); - } -error: - return ret; -} - -static int af9013_lock_led(struct af9013_state *state, u8 onoff) -{ - deb_info("%s: onoff:%d\n", __func__, onoff); - - return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff); -} - -static int af9013_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - u8 auto_mode; /* auto set TPS */ + goto err; - deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, - params->u.ofdm.bandwidth); - - state->frequency = params->frequency; - - /* program tuner */ - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); - - /* program CFOE coefficients */ - ret = af9013_set_coeff(state, params->u.ofdm.bandwidth); - if (ret) - goto error; - - /* program frequency control */ - ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth); - if (ret) - goto error; - - /* clear TPS lock flag (inverted flag) */ - ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1); - if (ret) - goto error; - - /* clear MPEG2 lock flag */ - ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0); - if (ret) - goto error; - - /* empty channel function */ - ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0); - if (ret) - goto error; - - /* empty DVB-T channel function */ - ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0); - if (ret) - goto error; - - /* program TPS and bandwidth, check if auto mode needed */ - ret = af9013_set_ofdm_params(state, ¶ms->u.ofdm, &auto_mode); - if (ret) - goto error; - - if (auto_mode) { - /* clear easy mode flag */ - ret = af9013_write_reg(state, 0xaefd, 0); - deb_info("%s: auto TPS\n", __func__); - } else { - /* set easy mode flag */ - ret = af9013_write_reg(state, 0xaefd, 1); + ret = af9013_wr_reg(state, 0xaefe, 0); if (ret) - goto error; - ret = af9013_write_reg(state, 0xaefe, 0); - deb_info("%s: manual TPS\n", __func__); + goto err; + + dbg("%s: manual params", __func__); } - if (ret) - goto error; - /* everything is set, lets try to receive channel - OFSM GO! */ - ret = af9013_write_reg(state, 0xffff, 0); + /* tune */ + ret = af9013_wr_reg(state, 0xffff, 0); if (ret) - goto error; + goto err; + + state->bandwidth_hz = c->bandwidth_hz; + state->set_frontend_jiffies = jiffies; + state->first_tune = false; -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } -static int af9013_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int af9013_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct af9013_state *state = fe->demodulator_priv; int ret; - u8 i, buf[3]; - deb_info("%s\n", __func__); + u8 buf[3]; - /* read TPS registers */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]); - if (ret) - goto error; - } + dbg("%s", __func__); + + ret = af9013_rd_regs(state, 0xd3c0, buf, 3); + if (ret) + goto err; switch ((buf[1] >> 6) & 3) { case 0: - p->u.ofdm.constellation = QPSK; + c->modulation = QPSK; break; case 1: - p->u.ofdm.constellation = QAM_16; + c->modulation = QAM_16; break; case 2: - p->u.ofdm.constellation = QAM_64; + c->modulation = QAM_64; break; } switch ((buf[0] >> 0) & 3) { case 0: - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + c->transmission_mode = TRANSMISSION_MODE_2K; break; case 1: - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + c->transmission_mode = TRANSMISSION_MODE_8K; } switch ((buf[0] >> 2) & 3) { case 0: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + c->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + c->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + c->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + c->guard_interval = GUARD_INTERVAL_1_4; break; } switch ((buf[0] >> 4) & 7) { case 0: - p->u.ofdm.hierarchy_information = HIERARCHY_NONE; + c->hierarchy = HIERARCHY_NONE; break; case 1: - p->u.ofdm.hierarchy_information = HIERARCHY_1; + c->hierarchy = HIERARCHY_1; break; case 2: - p->u.ofdm.hierarchy_information = HIERARCHY_2; + c->hierarchy = HIERARCHY_2; break; case 3: - p->u.ofdm.hierarchy_information = HIERARCHY_4; + c->hierarchy = HIERARCHY_4; break; } switch ((buf[2] >> 0) & 7) { case 0: - p->u.ofdm.code_rate_HP = FEC_1_2; + c->code_rate_HP = FEC_1_2; break; case 1: - p->u.ofdm.code_rate_HP = FEC_2_3; + c->code_rate_HP = FEC_2_3; break; case 2: - p->u.ofdm.code_rate_HP = FEC_3_4; + c->code_rate_HP = FEC_3_4; break; case 3: - p->u.ofdm.code_rate_HP = FEC_5_6; + c->code_rate_HP = FEC_5_6; break; case 4: - p->u.ofdm.code_rate_HP = FEC_7_8; + c->code_rate_HP = FEC_7_8; break; } switch ((buf[2] >> 3) & 7) { case 0: - p->u.ofdm.code_rate_LP = FEC_1_2; + c->code_rate_LP = FEC_1_2; break; case 1: - p->u.ofdm.code_rate_LP = FEC_2_3; + c->code_rate_LP = FEC_2_3; break; case 2: - p->u.ofdm.code_rate_LP = FEC_3_4; + c->code_rate_LP = FEC_3_4; break; case 3: - p->u.ofdm.code_rate_LP = FEC_5_6; + c->code_rate_LP = FEC_5_6; break; case 4: - p->u.ofdm.code_rate_LP = FEC_7_8; + c->code_rate_LP = FEC_7_8; break; } switch ((buf[1] >> 2) & 3) { case 0: - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + c->bandwidth_hz = 6000000; break; case 1: - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + c->bandwidth_hz = 7000000; break; case 2: - p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + c->bandwidth_hz = 8000000; break; } - p->inversion = INVERSION_AUTO; - p->frequency = state->frequency; - -error: return ret; -} - -static int af9013_update_ber_unc(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - u8 buf[3], i; - u32 error_bit_count = 0; - u32 total_bit_count = 0; - u32 abort_packet_count = 0; - - state->ber = 0; - - /* check if error bit count is ready */ - ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]); - if (ret) - goto error; - if (!buf[0]) - goto exit; - - /* get RSD packet abort count */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0xd38a + i, &buf[i]); - if (ret) - goto error; - } - abort_packet_count = (buf[1] << 8) + buf[0]; - - /* get error bit count */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd387 + i, &buf[i]); - if (ret) - goto error; - } - error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0]; - error_bit_count = error_bit_count - abort_packet_count * 8 * 8; - - /* get used RSD counting period (10000 RSD packets used) */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0xd385 + i, &buf[i]); - if (ret) - goto error; - } - total_bit_count = (buf[1] << 8) + buf[0]; - total_bit_count = total_bit_count - abort_packet_count; - total_bit_count = total_bit_count * 204 * 8; - - if (total_bit_count) - state->ber = error_bit_count * 1000000000 / total_bit_count; - - state->ucblocks += abort_packet_count; - - deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__, - error_bit_count, total_bit_count, abort_packet_count); - - /* set BER counting range */ - ret = af9013_write_reg(state, 0xd385, 10000 & 0xff); - if (ret) - goto error; - ret = af9013_write_reg(state, 0xd386, 10000 >> 8); - if (ret) - goto error; - /* reset and start BER counter */ - ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1); - if (ret) - goto error; - -exit: -error: +err: + dbg("%s: failed=%d", __func__, ret); return ret; } -static int af9013_update_snr(struct dvb_frontend *fe) +static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct af9013_state *state = fe->demodulator_priv; int ret; - u8 buf[3], i, len; - u32 quant = 0; - struct snr_table *uninitialized_var(snr_table); - - /* check if quantizer ready (for snr) */ - ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]); - if (ret) - goto error; - if (buf[0]) { - /* quantizer ready - read it */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]); - if (ret) - goto error; - } - quant = (buf[2] << 16) + (buf[1] << 8) + buf[0]; - - /* read current constellation */ - ret = af9013_read_reg(state, 0xd3c1, &buf[0]); - if (ret) - goto error; - - switch ((buf[0] >> 6) & 3) { - case 0: - len = ARRAY_SIZE(qpsk_snr_table); - snr_table = qpsk_snr_table; - break; - case 1: - len = ARRAY_SIZE(qam16_snr_table); - snr_table = qam16_snr_table; - break; - case 2: - len = ARRAY_SIZE(qam64_snr_table); - snr_table = qam64_snr_table; - break; - default: - len = 0; - break; - } - - if (len) { - for (i = 0; i < len; i++) { - if (quant < snr_table[i].val) { - state->snr = snr_table[i].snr * 10; - break; - } - } - } - - /* set quantizer super frame count */ - ret = af9013_write_reg(state, 0xd2e2, 1); - if (ret) - goto error; - - /* check quantizer availability */ - for (i = 0; i < 10; i++) { - msleep(10); - ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1, - &buf[0]); - if (ret) - goto error; - if (!buf[0]) - break; - } - - /* reset quantizer */ - ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1); - if (ret) - goto error; - } - -error: - return ret; -} - -static int af9013_update_signal_strength(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret = 0; - u8 rf_gain, if_gain; - int signal_strength; - - deb_info("%s\n", __func__); + u8 tmp; - if (state->signal_strength_en) { - ret = af9013_read_reg(state, 0xd07c, &rf_gain); - if (ret) - goto error; - ret = af9013_read_reg(state, 0xd07d, &if_gain); - if (ret) - goto error; - signal_strength = (0xffff / \ - (9 * (state->rf_50 + state->if_50) - \ - 11 * (state->rf_80 + state->if_80))) * \ - (10 * (rf_gain + if_gain) - \ - 11 * (state->rf_80 + state->if_80)); - if (signal_strength < 0) - signal_strength = 0; - else if (signal_strength > 0xffff) - signal_strength = 0xffff; - - state->signal_strength = signal_strength; + /* + * Return status from the cache if it is younger than 2000ms with the + * exception of last tune is done during 4000ms. + */ + if (time_is_after_jiffies( + state->read_status_jiffies + msecs_to_jiffies(2000)) && + time_is_before_jiffies( + state->set_frontend_jiffies + msecs_to_jiffies(4000)) + ) { + *status = state->fe_status; + return 0; } else { - state->signal_strength = 0; + *status = 0; } -error: - return ret; -} - -static int af9013_update_statistics(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - - if (time_before(jiffies, state->next_statistics_check)) - return 0; - - /* set minimum statistic update interval */ - state->next_statistics_check = jiffies + msecs_to_jiffies(1200); - - ret = af9013_update_signal_strength(fe); - if (ret) - goto error; - ret = af9013_update_snr(fe); - if (ret) - goto error; - ret = af9013_update_ber_unc(fe); - if (ret) - goto error; - -error: - return ret; -} - -static int af9013_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) -{ - fesettings->min_delay_ms = 800; - fesettings->step_size = 0; - fesettings->max_drift = 0; - - return 0; -} - -static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret = 0; - u8 tmp; - *status = 0; - /* MPEG2 lock */ - ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp); + ret = af9013_rd_reg_bits(state, 0xd507, 6, 1, &tmp); if (ret) - goto error; + goto err; + if (tmp) *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; if (!*status) { /* TPS lock */ - ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp); + ret = af9013_rd_reg_bits(state, 0xd330, 3, 1, &tmp); if (ret) - goto error; + goto err; + if (tmp) *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI; } - if (!*status) { - /* CFO lock */ - ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - } - - if (!*status) { - /* SFOE lock */ - ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - } + state->fe_status = *status; + state->read_status_jiffies = jiffies; - if (!*status) { - /* AGC lock */ - ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL; - } - - ret = af9013_update_statistics(fe); - -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } - -static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) +static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) { struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); - *ber = state->ber; - return ret; + *snr = state->snr; + return 0; } static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); *strength = state->signal_strength; - return ret; + return 0; } -static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) +static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) { struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); - *snr = state->snr; - return ret; + *ber = state->ber; + return 0; } static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); *ucblocks = state->ucblocks; - return ret; -} - -static int af9013_sleep(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - deb_info("%s\n", __func__); - - ret = af9013_lock_led(state, 0); - if (ret) - goto error; - - ret = af9013_power_ctrl(state, 0); -error: - return ret; + return 0; } static int af9013_init(struct dvb_frontend *fe) { struct af9013_state *state = fe->demodulator_priv; int ret, i, len; - u8 tmp0, tmp1; - struct regdesc *init; - deb_info("%s\n", __func__); + u8 buf[3], tmp; + u32 adc_cw; + const struct af9013_reg_bit *init; - /* reset OFDM */ - ret = af9013_reset(state, 0); - if (ret) - goto error; + dbg("%s", __func__); /* power on */ ret = af9013_power_ctrl(state, 1); if (ret) - goto error; + goto err; /* enable ADC */ - ret = af9013_write_reg(state, 0xd73a, 0xa4); + ret = af9013_wr_reg(state, 0xd73a, 0xa4); if (ret) - goto error; + goto err; /* write API version to firmware */ - for (i = 0; i < sizeof(state->config.api_version); i++) { - ret = af9013_write_reg(state, 0x9bf2 + i, - state->config.api_version[i]); - if (ret) - goto error; - } + ret = af9013_wr_regs(state, 0x9bf2, state->config.api_version, 4); + if (ret) + goto err; /* program ADC control */ - ret = af9013_set_adc_ctrl(state); + switch (state->config.clock) { + case 28800000: /* 28.800 MHz */ + tmp = 0; + break; + case 20480000: /* 20.480 MHz */ + tmp = 1; + break; + case 28000000: /* 28.000 MHz */ + tmp = 2; + break; + case 25000000: /* 25.000 MHz */ + tmp = 3; + break; + default: + err("invalid clock"); + return -EINVAL; + } + + adc_cw = af913_div(state->config.clock, 1000000ul, 19); + buf[0] = (adc_cw >> 0) & 0xff; + buf[1] = (adc_cw >> 8) & 0xff; + buf[2] = (adc_cw >> 16) & 0xff; + + ret = af9013_wr_regs(state, 0xd180, buf, 3); + if (ret) + goto err; + + ret = af9013_wr_reg_bits(state, 0x9bd2, 0, 4, tmp); if (ret) - goto error; + goto err; /* set I2C master clock */ - ret = af9013_write_reg(state, 0xd416, 0x14); + ret = af9013_wr_reg(state, 0xd416, 0x14); if (ret) - goto error; + goto err; /* set 16 embx */ - ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1); + ret = af9013_wr_reg_bits(state, 0xd700, 1, 1, 1); if (ret) - goto error; + goto err; /* set no trigger */ - ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0); + ret = af9013_wr_reg_bits(state, 0xd700, 2, 1, 0); if (ret) - goto error; + goto err; /* set read-update bit for constellation */ - ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1); + ret = af9013_wr_reg_bits(state, 0xd371, 1, 1, 1); if (ret) - goto error; + goto err; - /* enable FEC monitor */ - ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1); + /* settings for mp2if */ + if (state->config.ts_mode == AF9013_TS_USB) { + /* AF9015 split PSB to 1.5k + 0.5k */ + ret = af9013_wr_reg_bits(state, 0xd50b, 2, 1, 1); + if (ret) + goto err; + } else { + /* AF9013 change the output bit to data7 */ + ret = af9013_wr_reg_bits(state, 0xd500, 3, 1, 1); + if (ret) + goto err; + + /* AF9013 set mpeg to full speed */ + ret = af9013_wr_reg_bits(state, 0xd502, 4, 1, 1); + if (ret) + goto err; + } + + ret = af9013_wr_reg_bits(state, 0xd520, 4, 1, 1); if (ret) - goto error; + goto err; /* load OFSM settings */ - deb_info("%s: load ofsm settings\n", __func__); + dbg("%s: load ofsm settings", __func__); len = ARRAY_SIZE(ofsm_init); init = ofsm_init; for (i = 0; i < len; i++) { - ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, + ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos, init[i].len, init[i].val); if (ret) - goto error; + goto err; } /* load tuner specific settings */ - deb_info("%s: load tuner specific settings\n", __func__); + dbg("%s: load tuner specific settings", __func__); switch (state->config.tuner) { case AF9013_TUNER_MXL5003D: len = ARRAY_SIZE(tuner_init_mxl5003d); @@ -1260,65 +1197,133 @@ static int af9013_init(struct dvb_frontend *fe) } for (i = 0; i < len; i++) { - ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, + ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos, init[i].len, init[i].val); if (ret) - goto error; + goto err; } - /* set TS mode */ - deb_info("%s: setting ts mode\n", __func__); - tmp0 = 0; /* parallel mode */ - tmp1 = 0; /* serial mode */ - switch (state->config.output_mode) { - case AF9013_OUTPUT_MODE_PARALLEL: - tmp0 = 1; - break; - case AF9013_OUTPUT_MODE_SERIAL: - tmp1 = 1; - break; - case AF9013_OUTPUT_MODE_USB: - /* usb mode for AF9015 */ - default: - break; - } - ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */ + /* TS mode */ + ret = af9013_wr_reg_bits(state, 0xd500, 1, 2, state->config.ts_mode); if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */ - if (ret) - goto error; + goto err; /* enable lock led */ - ret = af9013_lock_led(state, 1); + ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 1); if (ret) - goto error; + goto err; - /* read values needed for signal strength calculation */ - ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, - &state->signal_strength_en); - if (ret) - goto error; + /* check if we support signal strength */ + if (!state->signal_strength_en) { + ret = af9013_rd_reg_bits(state, 0x9bee, 0, 1, + &state->signal_strength_en); + if (ret) + goto err; + } - if (state->signal_strength_en) { - ret = af9013_read_reg(state, 0x9bbd, &state->rf_50); + /* read values needed for signal strength calculation */ + if (state->signal_strength_en && !state->rf_50) { + ret = af9013_rd_reg(state, 0x9bbd, &state->rf_50); if (ret) - goto error; - ret = af9013_read_reg(state, 0x9bd0, &state->rf_80); + goto err; + + ret = af9013_rd_reg(state, 0x9bd0, &state->rf_80); if (ret) - goto error; - ret = af9013_read_reg(state, 0x9be2, &state->if_50); + goto err; + + ret = af9013_rd_reg(state, 0x9be2, &state->if_50); if (ret) - goto error; - ret = af9013_read_reg(state, 0x9be4, &state->if_80); + goto err; + + ret = af9013_rd_reg(state, 0x9be4, &state->if_80); if (ret) - goto error; + goto err; } -error: + /* SNR */ + ret = af9013_wr_reg(state, 0xd2e2, 1); + if (ret) + goto err; + + /* BER / UCB */ + buf[0] = (10000 >> 0) & 0xff; + buf[1] = (10000 >> 8) & 0xff; + ret = af9013_wr_regs(state, 0xd385, buf, 2); + if (ret) + goto err; + + /* enable FEC monitor */ + ret = af9013_wr_reg_bits(state, 0xd392, 1, 1, 1); + if (ret) + goto err; + + state->first_tune = true; + schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400)); + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } +static int af9013_sleep(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + + dbg("%s", __func__); + + /* stop statistics polling */ + cancel_delayed_work_sync(&state->statistics_work); + + /* disable lock led */ + ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 0); + if (ret) + goto err; + + /* power off */ + ret = af9013_power_ctrl(state, 0); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int ret; + struct af9013_state *state = fe->demodulator_priv; + + dbg("%s: enable=%d", __func__, enable); + + /* gate already open or close */ + if (state->i2c_gate_state == enable) + return 0; + + if (state->config.ts_mode == AF9013_TS_USB) + ret = af9013_wr_reg_bits(state, 0xd417, 3, 1, enable); + else + ret = af9013_wr_reg_bits(state, 0xd607, 2, 1, enable); + if (ret) + goto err; + + state->i2c_gate_state = enable; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static void af9013_release(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + kfree(state); +} + static struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) @@ -1332,11 +1337,11 @@ static int af9013_download_firmware(struct af9013_state *state) msleep(100); /* check whether firmware is already running */ - ret = af9013_read_reg(state, 0x98be, &val); + ret = af9013_rd_reg(state, 0x98be, &val); if (ret) - goto error; + goto err; else - deb_info("%s: firmware status:%02x\n", __func__, val); + dbg("%s: firmware status=%02x", __func__, val); if (val == 0x0c) /* fw is running, no need for download */ goto exit; @@ -1351,7 +1356,7 @@ static int af9013_download_firmware(struct af9013_state *state) "Please see linux/Documentation/dvb/ for more details" \ " on firmware-problems. (%d)", fw_file, ret); - goto error; + goto err; } info("downloading firmware from file '%s'", fw_file); @@ -1369,7 +1374,7 @@ static int af9013_download_firmware(struct af9013_state *state) ret = af9013_write_ofsm_regs(state, 0x50fc, fw_params, sizeof(fw_params)); if (ret) - goto error_release; + goto err_release; #define FW_ADDR 0x5100 /* firmware start address */ #define LEN_MAX 16 /* max packet size */ @@ -1383,24 +1388,24 @@ static int af9013_download_firmware(struct af9013_state *state) (u8 *) &fw->data[fw->size - remaining], len); if (ret) { err("firmware download failed:%d", ret); - goto error_release; + goto err_release; } } /* request boot firmware */ - ret = af9013_write_reg(state, 0xe205, 1); + ret = af9013_wr_reg(state, 0xe205, 1); if (ret) - goto error_release; + goto err_release; for (i = 0; i < 15; i++) { msleep(100); /* check firmware status */ - ret = af9013_read_reg(state, 0x98be, &val); + ret = af9013_rd_reg(state, 0x98be, &val); if (ret) - goto error_release; + goto err_release; - deb_info("%s: firmware status:%02x\n", __func__, val); + dbg("%s: firmware status=%02x", __func__, val); if (val == 0x0c || val == 0x04) /* success or fail */ break; @@ -1408,43 +1413,21 @@ static int af9013_download_firmware(struct af9013_state *state) if (val == 0x04) { err("firmware did not run"); - ret = -1; + ret = -ENODEV; } else if (val != 0x0c) { err("firmware boot timeout"); - ret = -1; + ret = -ENODEV; } -error_release: +err_release: release_firmware(fw); -error: +err: exit: if (!ret) info("found a '%s' in warm state.", af9013_ops.info.name); return ret; } -static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - int ret; - struct af9013_state *state = fe->demodulator_priv; - deb_info("%s: enable:%d\n", __func__, enable); - - if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) - ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable); - else - ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable); - - return ret; -} - -static void af9013_release(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops af9013_ops; - struct dvb_frontend *af9013_attach(const struct af9013_config *config, struct i2c_adapter *i2c) { @@ -1455,91 +1438,65 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL); if (state == NULL) - goto error; + goto err; /* setup the state */ state->i2c = i2c; memcpy(&state->config, config, sizeof(struct af9013_config)); /* download firmware */ - if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) { + if (state->config.ts_mode != AF9013_TS_USB) { ret = af9013_download_firmware(state); if (ret) - goto error; + goto err; } /* firmware version */ - for (i = 0; i < 4; i++) { - ret = af9013_read_reg(state, 0x5103 + i, &buf[i]); - if (ret) - goto error; - } - info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]); - - /* chip version */ - ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); + ret = af9013_rd_regs(state, 0x5103, buf, 4); if (ret) - goto error; + goto err; - /* ROM version */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0x116b + i, &buf[i]); - if (ret) - goto error; - } - deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, - buf[2], buf[0], buf[1]); - - /* settings for mp2if */ - if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) { - /* AF9015 split PSB to 1.5k + 0.5k */ - ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1); - } else { - /* AF9013 change the output bit to data7 */ - ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1); - if (ret) - goto error; - /* AF9013 set mpeg to full speed */ - ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1); - } - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1); - if (ret) - goto error; + info("firmware version %d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]); /* set GPIOs */ for (i = 0; i < sizeof(state->config.gpio); i++) { ret = af9013_set_gpio(state, i, state->config.gpio[i]); if (ret) - goto error; + goto err; } /* create dvb_frontend */ - memcpy(&state->frontend.ops, &af9013_ops, + memcpy(&state->fe.ops, &af9013_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; + state->fe.demodulator_priv = state; + + INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work); - return &state->frontend; -error: + return &state->fe; +err: kfree(state); return NULL; } EXPORT_SYMBOL(af9013_attach); static struct dvb_frontend_ops af9013_ops = { + .delsys = { SYS_DVBT }, .info = { - .name = "Afatech AF9013 DVB-T", - .type = FE_OFDM, + .name = "Afatech AF9013", .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 250000, .frequency_tolerance = 0, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | - FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + .caps = FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | @@ -1548,24 +1505,22 @@ static struct dvb_frontend_ops af9013_ops = { }, .release = af9013_release, + .init = af9013_init, .sleep = af9013_sleep, - .i2c_gate_ctrl = af9013_i2c_gate_ctrl, + .get_tune_settings = af9013_get_tune_settings, .set_frontend = af9013_set_frontend, .get_frontend = af9013_get_frontend, - .get_tune_settings = af9013_get_tune_settings, - .read_status = af9013_read_status, - .read_ber = af9013_read_ber, - .read_signal_strength = af9013_read_signal_strength, .read_snr = af9013_read_snr, + .read_signal_strength = af9013_read_signal_strength, + .read_ber = af9013_read_ber, .read_ucblocks = af9013_read_ucblocks, -}; -module_param_named(debug, af9013_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + .i2c_gate_ctrl = af9013_i2c_gate_ctrl, +}; MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver"); diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h index e53d873f7555..b973fc5a0384 100644 --- a/drivers/media/dvb/frontends/af9013.h +++ b/drivers/media/dvb/frontends/af9013.h @@ -2,6 +2,7 @@ * Afatech AF9013 demodulator driver * * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> * * Thanks to Afatech who kindly provided information. * @@ -21,33 +22,11 @@ * */ -#ifndef _AF9013_H_ -#define _AF9013_H_ +#ifndef AF9013_H +#define AF9013_H #include <linux/dvb/frontend.h> -enum af9013_ts_mode { - AF9013_OUTPUT_MODE_PARALLEL, - AF9013_OUTPUT_MODE_SERIAL, - AF9013_OUTPUT_MODE_USB, /* only for AF9015 */ -}; - -enum af9013_tuner { - AF9013_TUNER_MXL5003D = 3, /* MaxLinear */ - AF9013_TUNER_MXL5005D = 13, /* MaxLinear */ - AF9013_TUNER_MXL5005R = 30, /* MaxLinear */ - AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */ - AF9013_TUNER_MT2060 = 130, /* Microtune */ - AF9013_TUNER_MC44S803 = 133, /* Freescale */ - AF9013_TUNER_QT1010 = 134, /* Quantek */ - AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */ - AF9013_TUNER_MT2060_2 = 147, /* Microtune */ - AF9013_TUNER_TDA18271 = 156, /* NXP */ - AF9013_TUNER_QT1010A = 162, /* Quantek */ - AF9013_TUNER_MXL5007T = 177, /* MaxLinear */ - AF9013_TUNER_TDA18218 = 179, /* NXP */ -}; - /* AF9013/5 GPIOs (mostly guessed) demod#1-gpio#0 - set demod#2 i2c-addr for dual devices demod#1-gpio#1 - xtal setting (?) @@ -55,44 +34,74 @@ enum af9013_tuner { demod#2-gpio#0 - tuner#2 demod#2-gpio#1 - xtal setting (?) */ + +struct af9013_config { + /* + * I2C address + */ + u8 i2c_addr; + + /* + * clock + * 20480000, 25000000, 28000000, 28800000 + */ + u32 clock; + + /* + * tuner + */ +#define AF9013_TUNER_MXL5003D 3 /* MaxLinear */ +#define AF9013_TUNER_MXL5005D 13 /* MaxLinear */ +#define AF9013_TUNER_MXL5005R 30 /* MaxLinear */ +#define AF9013_TUNER_ENV77H11D5 129 /* Panasonic */ +#define AF9013_TUNER_MT2060 130 /* Microtune */ +#define AF9013_TUNER_MC44S803 133 /* Freescale */ +#define AF9013_TUNER_QT1010 134 /* Quantek */ +#define AF9013_TUNER_UNKNOWN 140 /* for can tuners ? */ +#define AF9013_TUNER_MT2060_2 147 /* Microtune */ +#define AF9013_TUNER_TDA18271 156 /* NXP */ +#define AF9013_TUNER_QT1010A 162 /* Quantek */ +#define AF9013_TUNER_MXL5007T 177 /* MaxLinear */ +#define AF9013_TUNER_TDA18218 179 /* NXP */ + u8 tuner; + + /* + * IF frequency + */ + u32 if_frequency; + + /* + * TS settings + */ +#define AF9013_TS_USB 0 +#define AF9013_TS_PARALLEL 1 +#define AF9013_TS_SERIAL 2 + u8 ts_mode:2; + + /* + * input spectrum inversion + */ + bool spec_inv; + + /* + * firmware API version + */ + u8 api_version[4]; + + /* + * GPIOs + */ #define AF9013_GPIO_ON (1 << 0) #define AF9013_GPIO_EN (1 << 1) #define AF9013_GPIO_O (1 << 2) #define AF9013_GPIO_I (1 << 3) - #define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN) #define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) - #define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN) #define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) - -struct af9013_config { - /* demodulator's I2C address */ - u8 demod_address; - - /* frequencies in kHz */ - u32 adc_clock; - - /* tuner ID */ - u8 tuner; - - /* tuner IF */ - u16 tuner_if; - - /* TS data output mode */ - u8 output_mode:2; - - /* RF spectrum inversion */ - u8 rf_spec_inv:1; - - /* API version */ - u8 api_version[4]; - - /* GPIOs */ u8 gpio[4]; }; - #if defined(CONFIG_DVB_AF9013) || \ (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE)) extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, @@ -106,4 +115,4 @@ const struct af9013_config *config, struct i2c_adapter *i2c) } #endif /* CONFIG_DVB_AF9013 */ -#endif /* _AF9013_H_ */ +#endif /* AF9013_H */ diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h index e00b2a4a2db6..fa848af6e9b4 100644 --- a/drivers/media/dvb/frontends/af9013_priv.h +++ b/drivers/media/dvb/frontends/af9013_priv.h @@ -2,6 +2,7 @@ * Afatech AF9013 demodulator driver * * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> * * Thanks to Afatech who kindly provided information. * @@ -21,24 +22,19 @@ * */ -#ifndef _AF9013_PRIV_ -#define _AF9013_PRIV_ +#ifndef AF9013_PRIV_H +#define AF9013_PRIV_H -#define LOG_PREFIX "af9013" -extern int af9013_debug; - -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) +#include "dvb_frontend.h" +#include "af9013.h" +#include <linux/firmware.h> -#define debug_dump(b, l, func) {\ - int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ -} - -#define deb_info(args...) dprintk(af9013_debug, 0x01, args) +#define LOG_PREFIX "af9013" +#undef dbg +#define dbg(f, arg...) \ + if (af9013_debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) #undef err #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) #undef info @@ -48,70 +44,71 @@ extern int af9013_debug; #define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw" -struct regdesc { +struct af9013_reg_bit { u16 addr; u8 pos:4; u8 len:4; u8 val; }; -struct snr_table { +struct af9013_snr { u32 val; u8 snr; }; -struct coeff { - u32 adc_clock; - fe_bandwidth_t bw; +struct af9013_coeff { + u32 clock; + u32 bandwidth_hz; u8 val[24]; }; /* pre-calculated coeff lookup table */ -static struct coeff coeff_table[] = { +static const struct af9013_coeff coeff_lut[] = { /* 28.800 MHz */ - { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14, + { 28800000, 8000000, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14, 0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a, 0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } }, - { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71, + { 28800000, 7000000, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71, 0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38, 0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } }, - { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf, + { 28800000, 6000000, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf, 0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7, 0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } }, /* 20.480 MHz */ - { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24, + { 20480000, 8000000, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24, 0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92, 0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } }, - { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40, + { 20480000, 7000000, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40, 0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } }, - { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b, + { 20480000, 6000000, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b, 0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d, 0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } }, /* 28.000 MHz */ - { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39, + { 28000000, 8000000, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39, 0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f, 0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } }, - { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92, + { 28000000, 7000000, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92, 0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49, 0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } }, - { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb, + { 28000000, 6000000, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb, 0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63, 0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } }, /* 25.000 MHz */ - { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9, + { 25000000, 8000000, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9, 0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e, 0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } }, - { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e, + { 25000000, 7000000, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e, 0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7, 0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } }, - { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63, + { 25000000, 6000000, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63, 0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f, 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } }, }; /* QPSK SNR lookup table */ -static struct snr_table qpsk_snr_table[] = { +static const struct af9013_snr qpsk_snr_lut[] = { + { 0x000000, 0 }, { 0x0b4771, 0 }, { 0x0c1aed, 1 }, { 0x0d0d27, 2 }, @@ -131,7 +128,8 @@ static struct snr_table qpsk_snr_table[] = { }; /* QAM16 SNR lookup table */ -static struct snr_table qam16_snr_table[] = { +static const struct af9013_snr qam16_snr_lut[] = { + { 0x000000, 0 }, { 0x05eb62, 5 }, { 0x05fecf, 6 }, { 0x060b80, 7 }, @@ -151,7 +149,8 @@ static struct snr_table qam16_snr_table[] = { }; /* QAM64 SNR lookup table */ -static struct snr_table qam64_snr_table[] = { +static const struct af9013_snr qam64_snr_lut[] = { + { 0x000000, 0 }, { 0x03109b, 12 }, { 0x0310d4, 13 }, { 0x031920, 14 }, @@ -170,7 +169,7 @@ static struct snr_table qam64_snr_table[] = { { 0xffffff, 27 }, }; -static struct regdesc ofsm_init[] = { +static const struct af9013_reg_bit ofsm_init[] = { { 0xd73a, 0, 8, 0xa1 }, { 0xd73b, 0, 8, 0x1f }, { 0xd73c, 4, 4, 0x0a }, @@ -252,7 +251,7 @@ static struct regdesc ofsm_init[] = { /* Panasonic ENV77H11D5 tuner init AF9013_TUNER_ENV77H11D5 = 129 */ -static struct regdesc tuner_init_env77h11d5[] = { +static const struct af9013_reg_bit tuner_init_env77h11d5[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x03 }, { 0x9bbe, 0, 8, 0x01 }, @@ -318,7 +317,7 @@ static struct regdesc tuner_init_env77h11d5[] = { /* Microtune MT2060 tuner init AF9013_TUNER_MT2060 = 130 */ -static struct regdesc tuner_init_mt2060[] = { +static const struct af9013_reg_bit tuner_init_mt2060[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x07 }, { 0xd1a0, 1, 1, 0x01 }, @@ -395,7 +394,7 @@ static struct regdesc tuner_init_mt2060[] = { /* Microtune MT2060 tuner init AF9013_TUNER_MT2060_2 = 147 */ -static struct regdesc tuner_init_mt2060_2[] = { +static const struct af9013_reg_bit tuner_init_mt2060_2[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x06 }, { 0x9bbe, 0, 8, 0x01 }, @@ -462,7 +461,7 @@ static struct regdesc tuner_init_mt2060_2[] = { /* MaxLinear MXL5003 tuner init AF9013_TUNER_MXL5003D = 3 */ -static struct regdesc tuner_init_mxl5003d[] = { +static const struct af9013_reg_bit tuner_init_mxl5003d[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x09 }, { 0xd1a0, 1, 1, 0x01 }, @@ -534,7 +533,7 @@ static struct regdesc tuner_init_mxl5003d[] = { AF9013_TUNER_MXL5005D = 13 AF9013_TUNER_MXL5005R = 30 AF9013_TUNER_MXL5007T = 177 */ -static struct regdesc tuner_init_mxl5005[] = { +static const struct af9013_reg_bit tuner_init_mxl5005[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x07 }, { 0xd1a0, 1, 1, 0x01 }, @@ -613,7 +612,7 @@ static struct regdesc tuner_init_mxl5005[] = { /* Quantek QT1010 tuner init AF9013_TUNER_QT1010 = 134 AF9013_TUNER_QT1010A = 162 */ -static struct regdesc tuner_init_qt1010[] = { +static const struct af9013_reg_bit tuner_init_qt1010[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x09 }, { 0xd1a0, 1, 1, 0x01 }, @@ -690,7 +689,7 @@ static struct regdesc tuner_init_qt1010[] = { /* Freescale MC44S803 tuner init AF9013_TUNER_MC44S803 = 133 */ -static struct regdesc tuner_init_mc44s803[] = { +static const struct af9013_reg_bit tuner_init_mc44s803[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x06 }, { 0xd1a0, 1, 1, 0x01 }, @@ -772,7 +771,7 @@ static struct regdesc tuner_init_mc44s803[] = { /* unknown, probably for tin can tuner, tuner init AF9013_TUNER_UNKNOWN = 140 */ -static struct regdesc tuner_init_unknown[] = { +static const struct af9013_reg_bit tuner_init_unknown[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x02 }, { 0xd1a0, 1, 1, 0x01 }, @@ -845,7 +844,7 @@ static struct regdesc tuner_init_unknown[] = { /* NXP TDA18271 & TDA18218 tuner init AF9013_TUNER_TDA18271 = 156 AF9013_TUNER_TDA18218 = 179 */ -static struct regdesc tuner_init_tda18271[] = { +static const struct af9013_reg_bit tuner_init_tda18271[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x04 }, { 0xd1a0, 1, 1, 0x01 }, @@ -920,4 +919,4 @@ static struct regdesc tuner_init_tda18271[] = { { 0x9bee, 0, 1, 0x01 }, }; -#endif /* _AF9013_PRIV_ */ +#endif /* AF9013_PRIV_H */ diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c index 1539ea1f81ac..a2261ea2cf82 100644 --- a/drivers/media/dvb/frontends/atbm8830.c +++ b/drivers/media/dvb/frontends/atbm8830.c @@ -267,8 +267,7 @@ static void atbm8830_release(struct dvb_frontend *fe) kfree(state); } -static int atbm8830_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) +static int atbm8830_set_fe(struct dvb_frontend *fe) { struct atbm_state *priv = fe->demodulator_priv; int i; @@ -279,7 +278,7 @@ static int atbm8830_set_fe(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, fe_params); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -298,31 +297,31 @@ static int atbm8830_set_fe(struct dvb_frontend *fe, return 0; } -static int atbm8830_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) +static int atbm8830_get_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; dprintk("%s\n", __func__); /* TODO: get real readings from device */ /* inversion status */ - fe_params->inversion = INVERSION_OFF; + c->inversion = INVERSION_OFF; /* bandwidth */ - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + c->bandwidth_hz = 8000000; - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.code_rate_LP = FEC_AUTO; + c->code_rate_HP = FEC_AUTO; + c->code_rate_LP = FEC_AUTO; - fe_params->u.ofdm.constellation = QAM_AUTO; + c->modulation = QAM_AUTO; /* transmission mode */ - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + c->transmission_mode = TRANSMISSION_MODE_AUTO; /* guard interval */ - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + c->guard_interval = GUARD_INTERVAL_AUTO; /* hierarchy */ - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + c->hierarchy = HIERARCHY_NONE; return 0; } @@ -429,9 +428,9 @@ static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } static struct dvb_frontend_ops atbm8830_ops = { + .delsys = { SYS_DMBTH }, .info = { .name = "AltoBeam ATBM8830/8831 DMB-TH", - .type = FE_OFDM, .frequency_min = 474000000, .frequency_max = 858000000, .frequency_stepsize = 10000, diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c index 1d572940e243..c688b95df486 100644 --- a/drivers/media/dvb/frontends/au8522_dig.c +++ b/drivers/media/dvb/frontends/au8522_dig.c @@ -576,19 +576,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int au8522_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int au8522_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct au8522_state *state = fe->demodulator_priv; int ret = -EINVAL; - dprintk("%s(frequency=%d)\n", __func__, p->frequency); + dprintk("%s(frequency=%d)\n", __func__, c->frequency); - if ((state->current_frequency == p->frequency) && - (state->current_modulation == p->u.vsb.modulation)) + if ((state->current_frequency == c->frequency) && + (state->current_modulation == c->modulation)) return 0; - au8522_enable_modulation(fe, p->u.vsb.modulation); + au8522_enable_modulation(fe, c->modulation); /* Allow the demod to settle */ msleep(100); @@ -596,7 +596,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - ret = fe->ops.tuner_ops.set_params(fe, p); + ret = fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -604,7 +604,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe, if (ret < 0) return ret; - state->current_frequency = p->frequency; + state->current_frequency = c->frequency; return 0; } @@ -862,7 +862,36 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) static int au8522_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { - return au8522_read_snr(fe, signal_strength); + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + u16 snr; + u32 tmp; + int ret = au8522_read_snr(fe, &snr); + + *signal_strength = 0; + + if (0 == ret) { + /* The following calculation method was chosen + * purely for the sake of code re-use from the + * other demod drivers that use this method */ + + /* Convert from SNR in dB * 10 to 8.24 fixed-point */ + tmp = (snr * ((1 << 24) / 10)); + + /* Convert from 8.24 fixed-point to + * scale the range 0 - 35*2^24 into 0 - 65535*/ + if (tmp >= 8960 * 0x10000) + *signal_strength = 0xffff; + else + *signal_strength = tmp / 8960; + } + + return ret; } static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -882,13 +911,13 @@ static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber) return au8522_read_ucblocks(fe, ber); } -static int au8522_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int au8522_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct au8522_state *state = fe->demodulator_priv; - p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; + c->frequency = state->current_frequency; + c->modulation = state->current_modulation; return 0; } @@ -981,10 +1010,9 @@ error: EXPORT_SYMBOL(au8522_attach); static struct dvb_frontend_ops au8522_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Auvitek AU8522 QAM/8VSB Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index 8aff5868a5e1..033cd7ad3ca2 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -479,16 +479,16 @@ static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq) return -EINVAL; } -static int bcm3510_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int bcm3510_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct bcm3510_state* st = fe->demodulator_priv; struct bcm3510_hab_cmd_ext_acquire cmd; struct bcm3510_hab_cmd_bert_control bert; int ret; memset(&cmd,0,sizeof(cmd)); - switch (p->u.vsb.modulation) { + switch (c->modulation) { case QAM_256: cmd.ACQUIRE0.MODE = 0x1; cmd.ACQUIRE1.SYM_RATE = 0x1; @@ -499,7 +499,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe, cmd.ACQUIRE1.SYM_RATE = 0x2; cmd.ACQUIRE1.IF_FREQ = 0x1; break; -/* case QAM_256: +#if 0 + case QAM_256: cmd.ACQUIRE0.MODE = 0x3; break; case QAM_128: @@ -513,7 +514,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe, break; case QAM_16: cmd.ACQUIRE0.MODE = 0x7; - break;*/ + break; +#endif case VSB_8: cmd.ACQUIRE0.MODE = 0x8; cmd.ACQUIRE1.SYM_RATE = 0x0; @@ -552,7 +554,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe, bcm3510_bert_reset(st); - if ((ret = bcm3510_set_freq(st,p->frequency)) < 0) + ret = bcm3510_set_freq(st, c->frequency); + if (ret < 0) return ret; memset(&st->status1,0,sizeof(st->status1)); @@ -819,10 +822,9 @@ error: EXPORT_SYMBOL(bcm3510_attach); static struct dvb_frontend_ops bcm3510_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Broadcom BCM3510 VSB/QAM frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 803000000, /* stepsize is just a guess */ diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h index 5e431ebd089b..53e4d0dbb745 100644 --- a/drivers/media/dvb/frontends/bsbe1.h +++ b/drivers/media/dvb/frontends/bsbe1.h @@ -69,18 +69,19 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int alps_bsbe1_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int ret; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; struct i2c_adapter *i2c = fe->tuner_priv; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((p->frequency < 950000) || (p->frequency > 2150000)) return -EINVAL; - div = params->frequency / 1000; + div = p->frequency / 1000; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1; diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h index c480c839b302..c2a578e1314d 100644 --- a/drivers/media/dvb/frontends/bsru6.h +++ b/drivers/media/dvb/frontends/bsru6.h @@ -101,23 +101,24 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; struct i2c_adapter *i2c = fe->tuner_priv; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((p->frequency < 950000) || (p->frequency > 2150000)) return -EINVAL; - div = (params->frequency + (125 - 1)) / 125; // round correctly + div = (p->frequency + (125 - 1)) / 125; /* round correctly */ buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; buf[3] = 0xC4; - if (params->frequency > 1530000) + if (p->frequency > 1530000) buf[3] = 0xc0; if (fe->ops.i2c_gate_ctrl) diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index 0142214b0133..f2a90f990ce3 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -121,7 +121,8 @@ static int cx22700_set_inversion (struct cx22700_state* state, int inversion) } } -static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p) +static int cx22700_set_tps(struct cx22700_state *state, + struct dtv_frontend_properties *p) { static const u8 qam_tab [4] = { 0, 1, 0, 2 }; static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 }; @@ -146,25 +147,25 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet p->transmission_mode != TRANSMISSION_MODE_8K) return -EINVAL; - if (p->constellation != QPSK && - p->constellation != QAM_16 && - p->constellation != QAM_64) + if (p->modulation != QPSK && + p->modulation != QAM_16 && + p->modulation != QAM_64) return -EINVAL; - if (p->hierarchy_information < HIERARCHY_NONE || - p->hierarchy_information > HIERARCHY_4) + if (p->hierarchy < HIERARCHY_NONE || + p->hierarchy > HIERARCHY_4) return -EINVAL; - if (p->bandwidth < BANDWIDTH_8_MHZ || p->bandwidth > BANDWIDTH_6_MHZ) + if (p->bandwidth_hz > 8000000 || p->bandwidth_hz < 6000000) return -EINVAL; - if (p->bandwidth == BANDWIDTH_7_MHZ) + if (p->bandwidth_hz == 7000000) cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10)); else cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10)); - val = qam_tab[p->constellation - QPSK]; - val |= p->hierarchy_information - HIERARCHY_NONE; + val = qam_tab[p->modulation - QPSK]; + val |= p->hierarchy - HIERARCHY_NONE; cx22700_writereg (state, 0x04, val); @@ -184,7 +185,8 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet return 0; } -static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p) +static int cx22700_get_tps(struct cx22700_state *state, + struct dtv_frontend_properties *p) { static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, @@ -199,14 +201,14 @@ static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_paramet val = cx22700_readreg (state, 0x01); if ((val & 0x7) > 4) - p->hierarchy_information = HIERARCHY_AUTO; + p->hierarchy = HIERARCHY_AUTO; else - p->hierarchy_information = HIERARCHY_NONE + (val & 0x7); + p->hierarchy = HIERARCHY_NONE + (val & 0x7); if (((val >> 3) & 0x3) > 2) - p->constellation = QAM_AUTO; + p->modulation = QAM_AUTO; else - p->constellation = qam_tab[(val >> 3) & 0x3]; + p->modulation = qam_tab[(val >> 3) & 0x3]; val = cx22700_readreg (state, 0x02); @@ -318,33 +320,35 @@ static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx22700_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx22700_state* state = fe->demodulator_priv; cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/ cx22700_writereg (state, 0x00, 0x00); if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - cx22700_set_inversion (state, p->inversion); - cx22700_set_tps (state, &p->u.ofdm); + cx22700_set_inversion(state, c->inversion); + cx22700_set_tps(state, c); cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */ cx22700_writereg (state, 0x00, 0x01); /* restart acquire */ return 0; } -static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx22700_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx22700_state* state = fe->demodulator_priv; u8 reg09 = cx22700_readreg (state, 0x09); - p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22700_get_tps (state, &p->u.ofdm); + c->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22700_get_tps(state, c); } static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) @@ -401,10 +405,9 @@ error: } static struct dvb_frontend_ops cx22700_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Conexant CX22700 DVB-T", - .type = FE_OFDM, .frequency_min = 470000000, .frequency_max = 860000000, .frequency_stepsize = 166667, diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 3139558148ba..faba82485086 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -146,7 +146,7 @@ static int cx22702_set_inversion(struct cx22702_state *state, int inversion) /* Retrieve the demod settings */ static int cx22702_get_tps(struct cx22702_state *state, - struct dvb_ofdm_parameters *p) + struct dtv_frontend_properties *p) { u8 val; @@ -157,27 +157,27 @@ static int cx22702_get_tps(struct cx22702_state *state, val = cx22702_readreg(state, 0x01); switch ((val & 0x18) >> 3) { case 0: - p->constellation = QPSK; + p->modulation = QPSK; break; case 1: - p->constellation = QAM_16; + p->modulation = QAM_16; break; case 2: - p->constellation = QAM_64; + p->modulation = QAM_64; break; } switch (val & 0x07) { case 0: - p->hierarchy_information = HIERARCHY_NONE; + p->hierarchy = HIERARCHY_NONE; break; case 1: - p->hierarchy_information = HIERARCHY_1; + p->hierarchy = HIERARCHY_1; break; case 2: - p->hierarchy_information = HIERARCHY_2; + p->hierarchy = HIERARCHY_2; break; case 3: - p->hierarchy_information = HIERARCHY_4; + p->hierarchy = HIERARCHY_4; break; } @@ -260,14 +260,14 @@ static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int cx22702_set_tps(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx22702_set_tps(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; u8 val; struct cx22702_state *state = fe->demodulator_priv; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -277,14 +277,14 @@ static int cx22702_set_tps(struct dvb_frontend *fe, /* set bandwidth */ val = cx22702_readreg(state, 0x0C) & 0xcf; - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: val |= 0x20; break; - case BANDWIDTH_7_MHZ: + case 7000000: val |= 0x10; break; - case BANDWIDTH_8_MHZ: + case 8000000: break; default: dprintk("%s: invalid bandwidth\n", __func__); @@ -292,15 +292,15 @@ static int cx22702_set_tps(struct dvb_frontend *fe, } cx22702_writereg(state, 0x0C, val); - p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ + p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ /* use auto configuration? */ - if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) || - (p->u.ofdm.constellation == QAM_AUTO) || - (p->u.ofdm.code_rate_HP == FEC_AUTO) || - (p->u.ofdm.code_rate_LP == FEC_AUTO) || - (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) || - (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) { + if ((p->hierarchy == HIERARCHY_AUTO) || + (p->modulation == QAM_AUTO) || + (p->code_rate_HP == FEC_AUTO) || + (p->code_rate_LP == FEC_AUTO) || + (p->guard_interval == GUARD_INTERVAL_AUTO) || + (p->transmission_mode == TRANSMISSION_MODE_AUTO)) { /* TPS Source - use hardware driven values */ cx22702_writereg(state, 0x06, 0x10); @@ -316,7 +316,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, } /* manually programmed values */ - switch (p->u.ofdm.constellation) { /* mask 0x18 */ + switch (p->modulation) { /* mask 0x18 */ case QPSK: val = 0x00; break; @@ -327,10 +327,10 @@ static int cx22702_set_tps(struct dvb_frontend *fe, val = 0x10; break; default: - dprintk("%s: invalid constellation\n", __func__); + dprintk("%s: invalid modulation\n", __func__); return -EINVAL; } - switch (p->u.ofdm.hierarchy_information) { /* mask 0x07 */ + switch (p->hierarchy) { /* mask 0x07 */ case HIERARCHY_NONE: break; case HIERARCHY_1: @@ -348,7 +348,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, } cx22702_writereg(state, 0x06, val); - switch (p->u.ofdm.code_rate_HP) { /* mask 0x38 */ + switch (p->code_rate_HP) { /* mask 0x38 */ case FEC_NONE: case FEC_1_2: val = 0x00; @@ -369,7 +369,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, dprintk("%s: invalid code_rate_HP\n", __func__); return -EINVAL; } - switch (p->u.ofdm.code_rate_LP) { /* mask 0x07 */ + switch (p->code_rate_LP) { /* mask 0x07 */ case FEC_NONE: case FEC_1_2: break; @@ -391,7 +391,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, } cx22702_writereg(state, 0x07, val); - switch (p->u.ofdm.guard_interval) { /* mask 0x0c */ + switch (p->guard_interval) { /* mask 0x0c */ case GUARD_INTERVAL_1_32: val = 0x00; break; @@ -408,7 +408,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, dprintk("%s: invalid guard_interval\n", __func__); return -EINVAL; } - switch (p->u.ofdm.transmission_mode) { /* mask 0x03 */ + switch (p->transmission_mode) { /* mask 0x03 */ case TRANSMISSION_MODE_2K: break; case TRANSMISSION_MODE_8K: @@ -546,15 +546,15 @@ static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int cx22702_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx22702_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx22702_state *state = fe->demodulator_priv; u8 reg0C = cx22702_readreg(state, 0x0C); - p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22702_get_tps(state, &p->u.ofdm); + c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22702_get_tps(state, c); } static int cx22702_get_tune_settings(struct dvb_frontend *fe, @@ -603,10 +603,9 @@ error: EXPORT_SYMBOL(cx22702_attach); static const struct dvb_frontend_ops cx22702_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Conexant CX22702 DVB-T", - .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index bf9c999aa470..5101f10f2d7a 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -531,26 +531,27 @@ static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24110_set_frontend(struct dvb_frontend *fe) { struct cx24110_state *state = fe->demodulator_priv; - + struct dtv_frontend_properties *p = &fe->dtv_property_cache; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - cx24110_set_inversion (state, p->inversion); - cx24110_set_fec (state, p->u.qpsk.fec_inner); - cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate); + cx24110_set_inversion(state, p->inversion); + cx24110_set_fec(state, p->fec_inner); + cx24110_set_symbolrate(state, p->symbol_rate); cx24110_writereg(state,0x04,0x05); /* start acquisition */ return 0; } -static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24110_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx24110_state *state = fe->demodulator_priv; s32 afc; unsigned sclk; @@ -571,7 +572,7 @@ static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par p->frequency += afc; p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = cx24110_get_fec (state); + p->fec_inner = cx24110_get_fec(state); return 0; } @@ -623,10 +624,9 @@ error: } static struct dvb_frontend_ops cx24110_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Conexant CX24110 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c index c341d57d5e81..3883c3b31aef 100644 --- a/drivers/media/dvb/frontends/cx24113.c +++ b/drivers/media/dvb/frontends/cx24113.c @@ -476,21 +476,21 @@ static int cx24113_init(struct dvb_frontend *fe) return ret; } -static int cx24113_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24113_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24113_state *state = fe->tuner_priv; /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */ u32 roll_off = 675; u32 bw; - bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000; + bw = ((c->symbol_rate/100) * roll_off) / 1000; bw += (10000000/100) + 5; bw /= 10; bw += 1000; cx24113_set_bandwidth(state, bw); - cx24113_set_frequency(state, p->frequency); + cx24113_set_frequency(state, c->frequency); msleep(5); return cx24113_get_status(fe, &bw); } @@ -547,11 +547,9 @@ static const struct dvb_tuner_ops cx24113_tuner_ops = { .release = cx24113_release, .init = cx24113_init, - .sleep = NULL, .set_params = cx24113_set_params, .get_frequency = cx24113_get_frequency, - .get_bandwidth = NULL, .get_status = cx24113_get_status, }; diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index ccd05255d527..b48879186537 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -1212,25 +1212,10 @@ static int cx24116_sleep(struct dvb_frontend *fe) return 0; } -static int cx24116_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int cx24116_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - /* dvb-core told us to tune, the tv property cache will be complete, * it's safe for is to pull values and use them for tuning purposes. */ -static int cx24116_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24116_set_frontend(struct dvb_frontend *fe) { struct cx24116_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1455,12 +1440,20 @@ tuned: /* Set/Reset B/W */ return cx24116_cmd_execute(fe, &cmd); } -static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, +static int cx24116_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { + /* + * It is safe to discard "params" here, as the DVB core will sync + * fe->dtv_property_cache with fepriv->parameters_in, where the + * DVBv3 params are stored. The only practical usage for it indicate + * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is + * true. + */ + *delay = HZ / 5; - if (params) { - int ret = cx24116_set_frontend(fe, params); + if (re_tune) { + int ret = cx24116_set_frontend(fe); if (ret) return ret; } @@ -1473,10 +1466,9 @@ static int cx24116_get_algo(struct dvb_frontend *fe) } static struct dvb_frontend_ops cx24116_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2 }, .info = { .name = "Conexant CX24116/CX24118", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ @@ -1507,8 +1499,6 @@ static struct dvb_frontend_ops cx24116_ops = { .get_frontend_algo = cx24116_get_algo, .tune = cx24116_tune, - .set_property = cx24116_set_property, - .get_property = cx24116_get_property, .set_frontend = cx24116_set_frontend, }; diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index b1dd8acc607a..7e28b4ee7d4f 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -526,9 +526,9 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate) * to be configured and the correct band selected. * Calculate those values. */ -static int cx24123_pll_calculate(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24123_pll_calculate(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx24123_state *state = fe->demodulator_priv; u32 ndiv = 0, adiv = 0, vco_div = 0; int i = 0; @@ -548,8 +548,8 @@ static int cx24123_pll_calculate(struct dvb_frontend *fe, * FILTUNE programming bits */ for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) { agcv = &cx24123_AGC_vals[i]; - if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) && - (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) { + if ((agcv->symbolrate_low <= p->symbol_rate) && + (agcv->symbolrate_high >= p->symbol_rate)) { state->VCAarg = agcv->VCAprogdata; state->VGAarg = agcv->VGAprogdata; state->FILTune = agcv->FILTune; @@ -601,8 +601,7 @@ static int cx24123_pll_calculate(struct dvb_frontend *fe, * Tuner cx24109 is written through a dedicated 3wire interface * on the demod chip. */ -static int cx24123_pll_writereg(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p, u32 data) +static int cx24123_pll_writereg(struct dvb_frontend *fe, u32 data) { struct cx24123_state *state = fe->demodulator_priv; unsigned long timeout; @@ -659,26 +658,26 @@ static int cx24123_pll_writereg(struct dvb_frontend *fe, return 0; } -static int cx24123_pll_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24123_pll_tune(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx24123_state *state = fe->demodulator_priv; u8 val; dprintk("frequency=%i\n", p->frequency); - if (cx24123_pll_calculate(fe, p) != 0) { + if (cx24123_pll_calculate(fe) != 0) { err("%s: cx24123_pll_calcutate failed\n", __func__); return -EINVAL; } /* Write the new VCO/VGA */ - cx24123_pll_writereg(fe, p, state->VCAarg); - cx24123_pll_writereg(fe, p, state->VGAarg); + cx24123_pll_writereg(fe, state->VCAarg); + cx24123_pll_writereg(fe, state->VGAarg); /* Write the new bandselect and pll args */ - cx24123_pll_writereg(fe, p, state->bandselectarg); - cx24123_pll_writereg(fe, p, state->pllarg); + cx24123_pll_writereg(fe, state->bandselectarg); + cx24123_pll_writereg(fe, state->pllarg); /* set the FILTUNE voltage */ val = cx24123_readreg(state, 0x28) & ~0x3; @@ -925,10 +924,10 @@ static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; } -static int cx24123_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24123_set_frontend(struct dvb_frontend *fe) { struct cx24123_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; dprintk("\n"); @@ -936,16 +935,16 @@ static int cx24123_set_frontend(struct dvb_frontend *fe, state->config->set_ts_params(fe, 0); state->currentfreq = p->frequency; - state->currentsymbolrate = p->u.qpsk.symbol_rate; + state->currentsymbolrate = p->symbol_rate; cx24123_set_inversion(state, p->inversion); - cx24123_set_fec(state, p->u.qpsk.fec_inner); - cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate); + cx24123_set_fec(state, p->fec_inner); + cx24123_set_symbolrate(state, p->symbol_rate); if (!state->config->dont_use_pll) - cx24123_pll_tune(fe, p); + cx24123_pll_tune(fe); else if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); else err("it seems I don't have a tuner..."); @@ -960,9 +959,9 @@ static int cx24123_set_frontend(struct dvb_frontend *fe, return 0; } -static int cx24123_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24123_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx24123_state *state = fe->demodulator_priv; dprintk("\n"); @@ -971,12 +970,12 @@ static int cx24123_get_frontend(struct dvb_frontend *fe, err("%s: Failed to get inversion status\n", __func__); return -EREMOTEIO; } - if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) { + if (cx24123_get_fec(state, &p->fec_inner) != 0) { err("%s: Failed to get fec status\n", __func__); return -EREMOTEIO; } p->frequency = state->currentfreq; - p->u.qpsk.symbol_rate = state->currentsymbolrate; + p->symbol_rate = state->currentsymbolrate; return 0; } @@ -1007,15 +1006,15 @@ static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) } static int cx24123_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { int retval = 0; - if (params != NULL) - retval = cx24123_set_frontend(fe, params); + if (re_tune) + retval = cx24123_set_frontend(fe); if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) cx24123_read_status(fe, status); @@ -1126,10 +1125,9 @@ error: EXPORT_SYMBOL(cx24123_attach); static struct dvb_frontend_ops cx24123_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Conexant CX24123/CX24109", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h index 03cab7b547fb..cf0f546aa1d1 100644 --- a/drivers/media/dvb/frontends/cxd2820r.h +++ b/drivers/media/dvb/frontends/cxd2820r.h @@ -63,19 +63,6 @@ struct cxd2820r_config { */ bool spec_inv; - /* IFs for all used modes. - * Default: none, must set - * Values: <kHz> - */ - u16 if_dvbt_6; - u16 if_dvbt_7; - u16 if_dvbt_8; - u16 if_dvbt2_5; - u16 if_dvbt2_6; - u16 if_dvbt2_7; - u16 if_dvbt2_8; - u16 if_dvbc; - /* GPIOs for all used modes. * Default: none, disabled * Values: <see above> diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c index b85f5011e344..945404991529 100644 --- a/drivers/media/dvb/frontends/cxd2820r_c.c +++ b/drivers/media/dvb/frontends/cxd2820r_c.c @@ -21,13 +21,13 @@ #include "cxd2820r_priv.h" -int cxd2820r_set_frontend_c(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +int cxd2820r_set_frontend_c(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u8 buf[2]; + u32 if_freq; u16 if_ctl; u64 num; struct reg_val_mask tab[] = { @@ -56,9 +56,9 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe, /* program tuner */ if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); + fe->ops.tuner_ops.set_params(fe); - if (priv->delivery_system != SYS_DVBC_ANNEX_AC) { + if (priv->delivery_system != SYS_DVBC_ANNEX_A) { for (i = 0; i < ARRAY_SIZE(tab); i++) { ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val, tab[i].mask); @@ -67,10 +67,20 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe, } } - priv->delivery_system = SYS_DVBC_ANNEX_AC; + priv->delivery_system = SYS_DVBC_ANNEX_A; priv->ber_running = 0; /* tune stops BER counter */ - num = priv->cfg.if_dvbc; + /* program IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) { + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + if (ret) + goto error; + } else + if_freq = 0; + + dbg("%s: if_freq=%d", __func__, if_freq); + + num = if_freq / 1000; /* Hz => kHz */ num *= 0x4000; if_ctl = cxd2820r_div_u64_round_closest(num, 41000); buf[0] = (if_ctl >> 8) & 0x3f; @@ -94,8 +104,7 @@ error: return ret; } -int cxd2820r_get_frontend_c(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +int cxd2820r_get_frontend_c(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c index 036480f967b7..caae7f79c837 100644 --- a/drivers/media/dvb/frontends/cxd2820r_core.c +++ b/drivers/media/dvb/frontends/cxd2820r_core.c @@ -240,422 +240,239 @@ error: return ret; } -/* lock FE */ -static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe) -{ - int ret = 0; - dbg("%s: active_fe=%d", __func__, active_fe); - - mutex_lock(&priv->fe_lock); - - /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */ - if (priv->active_fe == active_fe) - ; - else if (priv->active_fe == -1) - priv->active_fe = active_fe; - else - ret = -EBUSY; - - mutex_unlock(&priv->fe_lock); - - return ret; -} - -/* unlock FE */ -static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe) -{ - dbg("%s: active_fe=%d", __func__, active_fe); - - mutex_lock(&priv->fe_lock); - - /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */ - if (priv->active_fe == active_fe) - priv->active_fe = -1; - - mutex_unlock(&priv->fe_lock); - - return; -} - /* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */ u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor) { return div_u64(dividend + (divisor / 2), divisor); } -static int cxd2820r_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cxd2820r_set_frontend(struct dvb_frontend *fe) { - struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (priv->delivery_system) { - case SYS_UNDEFINED: - if (c->delivery_system == SYS_DVBT) { - /* SLEEP => DVB-T */ - ret = cxd2820r_set_frontend_t(fe, p); - } else { - /* SLEEP => DVB-T2 */ - ret = cxd2820r_set_frontend_t2(fe, p); - } - break; - case SYS_DVBT: - if (c->delivery_system == SYS_DVBT) { - /* DVB-T => DVB-T */ - ret = cxd2820r_set_frontend_t(fe, p); - } else if (c->delivery_system == SYS_DVBT2) { - /* DVB-T => DVB-T2 */ - ret = cxd2820r_sleep_t(fe); - if (ret) - break; - ret = cxd2820r_set_frontend_t2(fe, p); - } - break; - case SYS_DVBT2: - if (c->delivery_system == SYS_DVBT2) { - /* DVB-T2 => DVB-T2 */ - ret = cxd2820r_set_frontend_t2(fe, p); - } else if (c->delivery_system == SYS_DVBT) { - /* DVB-T2 => DVB-T */ - ret = cxd2820r_sleep_t2(fe); - if (ret) - break; - ret = cxd2820r_set_frontend_t(fe, p); - } - break; - default: - dbg("%s: error state=%d", __func__, - priv->delivery_system); - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; - - ret = cxd2820r_set_frontend_c(fe, p); + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (c->delivery_system) { + case SYS_DVBT: + ret = cxd2820r_init_t(fe); + if (ret < 0) + goto err; + ret = cxd2820r_set_frontend_t(fe); + if (ret < 0) + goto err; + break; + case SYS_DVBT2: + ret = cxd2820r_init_t(fe); + if (ret < 0) + goto err; + ret = cxd2820r_set_frontend_t2(fe); + if (ret < 0) + goto err; + break; + case SYS_DVBC_ANNEX_A: + ret = cxd2820r_init_c(fe); + if (ret < 0) + goto err; + ret = cxd2820r_set_frontend_c(fe); + if (ret < 0) + goto err; + break; + default: + dbg("%s: error state=%d", __func__, fe->dtv_property_cache.delivery_system); + ret = -EINVAL; + break; } - +err: return ret; } - static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_status_t(fe, status); - break; - case SYS_DVBT2: - ret = cxd2820r_read_status_t2(fe, status); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_status_t(fe, status); + break; + case SYS_DVBT2: + ret = cxd2820r_read_status_t2(fe, status); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_status_c(fe, status); + break; + default: + ret = -EINVAL; + break; } - return ret; } -static int cxd2820r_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cxd2820r_get_frontend(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_get_frontend_t(fe, p); - break; - case SYS_DVBT2: - ret = cxd2820r_get_frontend_t2(fe, p); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + if (priv->delivery_system == SYS_UNDEFINED) + return 0; - ret = cxd2820r_get_frontend_c(fe, p); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_get_frontend_t(fe); + break; + case SYS_DVBT2: + ret = cxd2820r_get_frontend_t2(fe); + break; + case SYS_DVBC_ANNEX_A: + ret = cxd2820r_get_frontend_c(fe); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_ber_t(fe, ber); - break; - case SYS_DVBT2: - ret = cxd2820r_read_ber_t2(fe, ber); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_ber_t(fe, ber); + break; + case SYS_DVBT2: + ret = cxd2820r_read_ber_t2(fe, ber); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_ber_c(fe, ber); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_signal_strength_t(fe, strength); - break; - case SYS_DVBT2: - ret = cxd2820r_read_signal_strength_t2(fe, strength); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_signal_strength_t(fe, strength); + break; + case SYS_DVBT2: + ret = cxd2820r_read_signal_strength_t2(fe, strength); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_signal_strength_c(fe, strength); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_snr_t(fe, snr); - break; - case SYS_DVBT2: - ret = cxd2820r_read_snr_t2(fe, snr); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_snr_t(fe, snr); + break; + case SYS_DVBT2: + ret = cxd2820r_read_snr_t2(fe, snr); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_snr_c(fe, snr); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_ucblocks_t(fe, ucblocks); - break; - case SYS_DVBT2: - ret = cxd2820r_read_ucblocks_t2(fe, ucblocks); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_ucblocks_t(fe, ucblocks); + break; + case SYS_DVBT2: + ret = cxd2820r_read_ucblocks_t2(fe, ucblocks); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_ucblocks_c(fe, ucblocks); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_init(struct dvb_frontend *fe) { - struct cxd2820r_priv *priv = fe->demodulator_priv; - int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - priv->delivery_system = SYS_UNDEFINED; - /* delivery system is unknown at that (init) phase */ - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - ret = cxd2820r_init_t(fe); - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; - - ret = cxd2820r_init_c(fe); - } - - return ret; + return 0; } static int cxd2820r_sleep(struct dvb_frontend *fe) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_sleep_t(fe); - break; - case SYS_DVBT2: - ret = cxd2820r_sleep_t2(fe); - break; - default: - ret = -EINVAL; - } - - cxd2820r_unlock(priv, 0); - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_sleep_t(fe); + break; + case SYS_DVBT2: + ret = cxd2820r_sleep_t2(fe); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_sleep_c(fe); - - cxd2820r_unlock(priv, 1); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *s) + struct dvb_frontend_tune_settings *s) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_get_tune_settings_t(fe, s); - break; - case SYS_DVBT2: - ret = cxd2820r_get_tune_settings_t2(fe, s); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_get_tune_settings_t(fe, s); + break; + case SYS_DVBT2: + ret = cxd2820r_get_tune_settings_t2(fe, s); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_get_tune_settings_c(fe, s); + break; + default: + ret = -EINVAL; + break; } - return ret; } -static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -667,12 +484,12 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe, if (priv->last_tune_failed) { if (priv->delivery_system == SYS_DVBT) c->delivery_system = SYS_DVBT2; - else + else if (priv->delivery_system == SYS_DVBT2) c->delivery_system = SYS_DVBT; } /* set frontend */ - ret = cxd2820r_set_frontend(fe, p); + ret = cxd2820r_set_frontend(fe); if (ret) goto error; @@ -680,6 +497,7 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe, /* frontend lock wait loop count */ switch (priv->delivery_system) { case SYS_DVBT: + case SYS_DVBC_ANNEX_A: i = 20; break; case SYS_DVBT2: @@ -727,9 +545,7 @@ static void cxd2820r_release(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; dbg("%s", __func__); - if (fe->ops.info.type == FE_OFDM) - kfree(priv); - + kfree(priv); return; } @@ -742,128 +558,79 @@ static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1); } -static const struct dvb_frontend_ops cxd2820r_ops[2]; +static const struct dvb_frontend_ops cxd2820r_ops = { + .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, + /* default: DVB-T/T2 */ + .info = { + .name = "Sony CXD2820R (DVB-T/T2)", + + .caps = FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_64 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_MUTE_TS | + FE_CAN_2G_MODULATION + }, -struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, - struct i2c_adapter *i2c, struct dvb_frontend *fe) -{ - int ret; - struct cxd2820r_priv *priv = NULL; - u8 tmp; + .release = cxd2820r_release, + .init = cxd2820r_init, + .sleep = cxd2820r_sleep, - if (fe == NULL) { - /* FE0 */ - /* allocate memory for the internal priv */ - priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL); - if (priv == NULL) - goto error; + .get_tune_settings = cxd2820r_get_tune_settings, + .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl, - /* setup the priv */ - priv->i2c = i2c; - memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config)); - mutex_init(&priv->fe_lock); + .get_frontend = cxd2820r_get_frontend, - priv->active_fe = -1; /* NONE */ + .get_frontend_algo = cxd2820r_get_frontend_algo, + .search = cxd2820r_search, - /* check if the demod is there */ - priv->bank[0] = priv->bank[1] = 0xff; - ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp); - dbg("%s: chip id=%02x", __func__, tmp); - if (ret || tmp != 0xe1) - goto error; + .read_status = cxd2820r_read_status, + .read_snr = cxd2820r_read_snr, + .read_ber = cxd2820r_read_ber, + .read_ucblocks = cxd2820r_read_ucblocks, + .read_signal_strength = cxd2820r_read_signal_strength, +}; - /* create frontends */ - memcpy(&priv->fe[0].ops, &cxd2820r_ops[0], - sizeof(struct dvb_frontend_ops)); - memcpy(&priv->fe[1].ops, &cxd2820r_ops[1], - sizeof(struct dvb_frontend_ops)); +struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, + struct i2c_adapter *i2c, + struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = NULL; + int ret; + u8 tmp; - priv->fe[0].demodulator_priv = priv; - priv->fe[1].demodulator_priv = priv; + priv = kzalloc(sizeof (struct cxd2820r_priv), GFP_KERNEL); + if (!priv) + goto error; - return &priv->fe[0]; + priv->i2c = i2c; + memcpy(&priv->cfg, cfg, sizeof (struct cxd2820r_config)); - } else { - /* FE1: FE0 given as pointer, just return FE1 we have - * already created */ - priv = fe->demodulator_priv; - return &priv->fe[1]; - } + priv->bank[0] = priv->bank[1] = 0xff; + ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp); + dbg("%s: chip id=%02x", __func__, tmp); + if (ret || tmp != 0xe1) + goto error; + memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof (struct dvb_frontend_ops)); + priv->fe.demodulator_priv = priv; + return &priv->fe; error: kfree(priv); return NULL; } EXPORT_SYMBOL(cxd2820r_attach); -static const struct dvb_frontend_ops cxd2820r_ops[2] = { - { - /* DVB-T/T2 */ - .info = { - .name = "Sony CXD2820R (DVB-T/T2)", - .type = FE_OFDM, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | - FE_CAN_QAM_64 | FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | - FE_CAN_MUTE_TS | - FE_CAN_2G_MODULATION - }, - - .release = cxd2820r_release, - .init = cxd2820r_init, - .sleep = cxd2820r_sleep, - - .get_tune_settings = cxd2820r_get_tune_settings, - .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl, - - .get_frontend = cxd2820r_get_frontend, - - .get_frontend_algo = cxd2820r_get_frontend_algo, - .search = cxd2820r_search, - - .read_status = cxd2820r_read_status, - .read_snr = cxd2820r_read_snr, - .read_ber = cxd2820r_read_ber, - .read_ucblocks = cxd2820r_read_ucblocks, - .read_signal_strength = cxd2820r_read_signal_strength, - }, - { - /* DVB-C */ - .info = { - .name = "Sony CXD2820R (DVB-C)", - .type = FE_QAM, - .caps = - FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO - }, - - .release = cxd2820r_release, - .init = cxd2820r_init, - .sleep = cxd2820r_sleep, - - .get_tune_settings = cxd2820r_get_tune_settings, - .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl, - - .set_frontend = cxd2820r_set_frontend, - .get_frontend = cxd2820r_get_frontend, - - .read_status = cxd2820r_read_status, - .read_snr = cxd2820r_read_snr, - .read_ber = cxd2820r_read_ber, - .read_ucblocks = cxd2820r_read_ucblocks, - .read_signal_strength = cxd2820r_read_signal_strength, - }, -}; - - MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_DESCRIPTION("Sony CXD2820R demodulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h index 95539134efdb..9a9822cad9cd 100644 --- a/drivers/media/dvb/frontends/cxd2820r_priv.h +++ b/drivers/media/dvb/frontends/cxd2820r_priv.h @@ -48,12 +48,9 @@ struct reg_val_mask { struct cxd2820r_priv { struct i2c_adapter *i2c; - struct dvb_frontend fe[2]; + struct dvb_frontend fe; struct cxd2820r_config cfg; - struct mutex fe_lock; /* FE lock */ - int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */ - bool ber_running; u8 bank[2]; @@ -89,11 +86,9 @@ int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val); /* cxd2820r_c.c */ -int cxd2820r_get_frontend_c(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p); +int cxd2820r_get_frontend_c(struct dvb_frontend *fe); -int cxd2820r_set_frontend_c(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params); +int cxd2820r_set_frontend_c(struct dvb_frontend *fe); int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status); @@ -114,11 +109,9 @@ int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe, /* cxd2820r_t.c */ -int cxd2820r_get_frontend_t(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p); +int cxd2820r_get_frontend_t(struct dvb_frontend *fe); -int cxd2820r_set_frontend_t(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params); +int cxd2820r_set_frontend_t(struct dvb_frontend *fe); int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status); @@ -139,11 +132,9 @@ int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe, /* cxd2820r_t2.c */ -int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p); +int cxd2820r_get_frontend_t2(struct dvb_frontend *fe); -int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params); +int cxd2820r_set_frontend_t2(struct dvb_frontend *fe); int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status); diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c index a04f9c810101..1a026239cdcc 100644 --- a/drivers/media/dvb/frontends/cxd2820r_t.c +++ b/drivers/media/dvb/frontends/cxd2820r_t.c @@ -21,13 +21,12 @@ #include "cxd2820r_priv.h" -int cxd2820r_set_frontend_t(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +int cxd2820r_set_frontend_t(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; - u32 if_khz, if_ctl; + int ret, i, bw_i; + u32 if_freq, if_ctl; u64 num; u8 buf[3], bw_param; u8 bw_params1[][5] = { @@ -57,6 +56,23 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz); + switch (c->bandwidth_hz) { + case 6000000: + bw_i = 0; + bw_param = 2; + break; + case 7000000: + bw_i = 1; + bw_param = 1; + break; + case 8000000: + bw_i = 2; + bw_param = 0; + break; + default: + return -EINVAL; + } + /* update GPIOs */ ret = cxd2820r_gpio(fe); if (ret) @@ -64,7 +80,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, /* program tuner */ if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (priv->delivery_system != SYS_DVBT) { for (i = 0; i < ARRAY_SIZE(tab); i++) { @@ -78,27 +94,17 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, priv->delivery_system = SYS_DVBT; priv->ber_running = 0; /* tune stops BER counter */ - switch (c->bandwidth_hz) { - case 6000000: - if_khz = priv->cfg.if_dvbt_6; - i = 0; - bw_param = 2; - break; - case 7000000: - if_khz = priv->cfg.if_dvbt_7; - i = 1; - bw_param = 1; - break; - case 8000000: - if_khz = priv->cfg.if_dvbt_8; - i = 2; - bw_param = 0; - break; - default: - return -EINVAL; - } + /* program IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) { + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + if (ret) + goto error; + } else + if_freq = 0; + + dbg("%s: if_freq=%d", __func__, if_freq); - num = if_khz; + num = if_freq / 1000; /* Hz => kHz */ num *= 0x1000000; if_ctl = cxd2820r_div_u64_round_closest(num, 41000); buf[0] = ((if_ctl >> 16) & 0xff); @@ -109,7 +115,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, if (ret) goto error; - ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5); + ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5); if (ret) goto error; @@ -117,7 +123,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, if (ret) goto error; - ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2); + ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2); if (ret) goto error; @@ -135,8 +141,7 @@ error: return ret; } -int cxd2820r_get_frontend_t(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +int cxd2820r_get_frontend_t(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb/frontends/cxd2820r_t2.c index 6548588309f7..3a5759e0d235 100644 --- a/drivers/media/dvb/frontends/cxd2820r_t2.c +++ b/drivers/media/dvb/frontends/cxd2820r_t2.c @@ -21,13 +21,12 @@ #include "cxd2820r_priv.h" -int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; - u32 if_khz, if_ctl; + int ret, i, bw_i; + u32 if_freq, if_ctl; u64 num; u8 buf[3], bw_param; u8 bw_params1[][5] = { @@ -71,6 +70,27 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz); + switch (c->bandwidth_hz) { + case 5000000: + bw_i = 0; + bw_param = 3; + break; + case 6000000: + bw_i = 1; + bw_param = 2; + break; + case 7000000: + bw_i = 2; + bw_param = 1; + break; + case 8000000: + bw_i = 3; + bw_param = 0; + break; + default: + return -EINVAL; + } + /* update GPIOs */ ret = cxd2820r_gpio(fe); if (ret) @@ -78,7 +98,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, /* program tuner */ if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); + fe->ops.tuner_ops.set_params(fe); if (priv->delivery_system != SYS_DVBT2) { for (i = 0; i < ARRAY_SIZE(tab); i++) { @@ -91,32 +111,17 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, priv->delivery_system = SYS_DVBT2; - switch (c->bandwidth_hz) { - case 5000000: - if_khz = priv->cfg.if_dvbt2_5; - i = 0; - bw_param = 3; - break; - case 6000000: - if_khz = priv->cfg.if_dvbt2_6; - i = 1; - bw_param = 2; - break; - case 7000000: - if_khz = priv->cfg.if_dvbt2_7; - i = 2; - bw_param = 1; - break; - case 8000000: - if_khz = priv->cfg.if_dvbt2_8; - i = 3; - bw_param = 0; - break; - default: - return -EINVAL; - } + /* program IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) { + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + if (ret) + goto error; + } else + if_freq = 0; + + dbg("%s: if_freq=%d", __func__, if_freq); - num = if_khz; + num = if_freq / 1000; /* Hz => kHz */ num *= 0x1000000; if_ctl = cxd2820r_div_u64_round_closest(num, 41000); buf[0] = ((if_ctl >> 16) & 0xff); @@ -127,7 +132,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, if (ret) goto error; - ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5); + ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[bw_i], 5); if (ret) goto error; @@ -150,8 +155,7 @@ error: } -int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +int cxd2820r_get_frontend_t2(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index dc1cb17a6ea7..3b024bfe980a 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -150,7 +150,7 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) } \ } while (0) -static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +static int dib0070_set_bandwidth(struct dvb_frontend *fe) { struct dib0070_state *state = fe->tuner_priv; u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; @@ -335,7 +335,7 @@ static const struct dib0070_lna_match dib0070_lna[] = { }; #define LPF 100 -static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +static int dib0070_tune_digital(struct dvb_frontend *fe) { struct dib0070_state *state = fe->tuner_priv; @@ -507,7 +507,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par *tune_state = CT_TUNER_STEP_5; } else if (*tune_state == CT_TUNER_STEP_5) { - dib0070_set_bandwidth(fe, ch); + dib0070_set_bandwidth(fe); *tune_state = CT_TUNER_STOP; } else { ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ @@ -516,7 +516,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par } -static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dib0070_tune(struct dvb_frontend *fe) { struct dib0070_state *state = fe->tuner_priv; uint32_t ret; @@ -524,7 +524,7 @@ static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters state->tune_state = CT_TUNER_START; do { - ret = dib0070_tune_digital(fe, p); + ret = dib0070_tune_digital(fe); if (ret != FE_CALLBACK_TIME_NEVER) msleep(ret/10); else diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index b174d1c78583..224d81e85091 100644 --- a/drivers/media/dvb/frontends/dib0090.c +++ b/drivers/media/dvb/frontends/dib0090.c @@ -717,6 +717,34 @@ static const u16 rf_ramp_pwm_cband_7090[] = { (0 << 10) | 109, /* RF_RAMP4, LNA 4 */ }; +static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = { + 186, + 40, + 746, + (10 << 10) | 345, + (0 << 10) | 746, + (0 << 10) | 0, + (0 << 10) | 0, + (28 << 10) | 200, + (0 << 10) | 345, + (20 << 10) | 0, + (0 << 10) | 200, +}; + +static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = { + 86, + 40, + 345, + (0 << 10) | 0, + (0 << 10) | 0, + (0 << 10) | 0, + (0 << 10) | 0, + (28 << 10) | 200, + (0 << 10) | 345, + (20 << 10) | 0, + (0 << 10) | 200, +}; + static const u16 rf_ramp_pwm_cband_8090[] = { 345, /* max RF gain in 10th of dB */ 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ @@ -1076,8 +1104,16 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090); - else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090); + else if (state->identity.version == SOC_7090_P1G_11R1 + || state->identity.version == SOC_7090_P1G_21R1) { + if (state->config->is_dib7090e) { + if (state->rf_ramp == NULL) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity); + else + dib0090_set_rframp_pwm(state, state->rf_ramp); + } else + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090); + } } else { dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); @@ -1112,13 +1148,21 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) else dib0090_write_reg(state, 0x32, (0 << 11)); - dib0090_write_reg(state, 0x04, 0x01); + dib0090_write_reg(state, 0x04, 0x03); dib0090_write_reg(state, 0x39, (1 << 10)); } } EXPORT_SYMBOL(dib0090_pwm_gain_reset); +void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff) +{ + struct dib0090_state *state = fe->tuner_priv; + if (DC_servo_cutoff < 4) + dib0090_write_reg(state, 0x04, DC_servo_cutoff); +} +EXPORT_SYMBOL(dib0090_set_dc_servo); + static u32 dib0090_get_slow_adc_val(struct dib0090_state *state) { u16 adc_val = dib0090_read_reg(state, 0x1d); @@ -1305,7 +1349,7 @@ void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * EXPORT_SYMBOL(dib0090_get_current_gain); -u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) +u16 dib0090_get_wbd_target(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000; @@ -1342,9 +1386,57 @@ u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) return state->wbd_offset + wbd_tcold; } +EXPORT_SYMBOL(dib0090_get_wbd_target); +u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + return state->wbd_offset; +} EXPORT_SYMBOL(dib0090_get_wbd_offset); +int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3) +{ + struct dib0090_state *state = fe->tuner_priv; + + dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8) + | ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1)); + + return 0; +} +EXPORT_SYMBOL(dib0090_set_switch); + +int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff) +{ + struct dib0090_state *state = fe->tuner_priv; + + dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff) + | ((onoff & 1) << 15)); + return 0; +} +EXPORT_SYMBOL(dib0090_set_vga); + +int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity) +{ + struct dib0090_state *state = fe->tuner_priv; + + if ((!state->identity.p1g) || (!state->identity.in_soc) + || ((state->identity.version != SOC_7090_P1G_21R1) + && (state->identity.version != SOC_7090_P1G_11R1))) { + dprintk("%s() function can only be used for dib7090P", __func__); + return -ENODEV; + } + + if (cfg_sensitivity) + state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity; + else + state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci; + dib0090_pwm_gain_reset(fe); + + return 0; +} +EXPORT_SYMBOL(dib0090_update_rframp_7090); + static const u16 dib0090_defaults[] = { 25, 0x01, @@ -1430,7 +1522,7 @@ static void dib0090_set_default_config(struct dib0090_state *state, const u16 * #define POLY_MIN (u8) 0 #define POLY_MAX (u8) 8 -void dib0090_set_EFUSE(struct dib0090_state *state) +static void dib0090_set_EFUSE(struct dib0090_state *state) { u8 c, h, n; u16 e2, e4; @@ -1505,7 +1597,10 @@ static int dib0090_reset(struct dvb_frontend *fe) dib0090_set_EFUSE(state); /* Congigure in function of the crystal */ - if (state->config->io.clock_khz >= 24000) + if (state->config->force_crystal_mode != 0) + dib0090_write_reg(state, 0x14, + state->config->force_crystal_mode & 3); + else if (state->config->io.clock_khz >= 24000) dib0090_write_reg(state, 0x14, 1); else dib0090_write_reg(state, 0x14, 2); @@ -1951,6 +2046,52 @@ static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = { #endif }; +static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = { +#ifdef CONFIG_BAND_CBAND + { 300000, 0 , 3, 0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB }, + { 380000, 0 , 10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB }, + { 600000, 0 , 10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB }, + { 660000, 0 , 5, 0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB }, + { 720000, 0 , 5, 0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB }, + { 860000, 0 , 4, 0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB }, +#endif +}; + +int dib0090_update_tuning_table_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity) +{ + struct dib0090_state *state = fe->tuner_priv; + const struct dib0090_tuning *tune = + dib0090_tuning_table_cband_7090e_sensitivity; + const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = { + { 300000, 0 , 3, 0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB }, + { 650000, 0 , 4, 0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB }, + { 860000, 0 , 5, 0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB }, + }; + + if ((!state->identity.p1g) || (!state->identity.in_soc) + || ((state->identity.version != SOC_7090_P1G_21R1) + && (state->identity.version != SOC_7090_P1G_11R1))) { + dprintk("%s() function can only be used for dib7090", __func__); + return -ENODEV; + } + + if (cfg_sensitivity) + tune = dib0090_tuning_table_cband_7090e_sensitivity; + else + tune = dib0090_tuning_table_cband_7090e_aci; + + while (state->rf_request > tune->max_freq) + tune++; + + dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000) + | (tune->lna_bias & 0x7fff)); + dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f) + | ((tune->lna_tune << 6) & 0x07c0)); + return 0; +} +EXPORT_SYMBOL(dib0090_update_tuning_table_7090); + static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state) { int ret = 0; @@ -2199,12 +2340,18 @@ static int dib0090_tune(struct dvb_frontend *fe) if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF || state->current_band & BAND_UHF) { state->current_band = BAND_CBAND; - tune = dib0090_tuning_table_cband_7090; + if (state->config->is_dib7090e) + tune = dib0090_tuning_table_cband_7090e_sensitivity; + else + tune = dib0090_tuning_table_cband_7090; } } else { /* Use the CBAND input for all band under UHF */ if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) { state->current_band = BAND_CBAND; - tune = dib0090_tuning_table_cband_7090; + if (state->config->is_dib7090e) + tune = dib0090_tuning_table_cband_7090e_sensitivity; + else + tune = dib0090_tuning_table_cband_7090; } } } else @@ -2419,7 +2566,7 @@ static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) return 0; } -static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dib0090_set_params(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; u32 ret; diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb/frontends/dib0090.h index 13d85244ec16..781dc49de45b 100644 --- a/drivers/media/dvb/frontends/dib0090.h +++ b/drivers/media/dvb/frontends/dib0090.h @@ -71,6 +71,8 @@ struct dib0090_config { u8 fref_clock_ratio; u16 force_cband_input; struct dib0090_wbd_slope *wbd; + u8 is_dib7090e; + u8 force_crystal_mode; }; #if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE)) @@ -78,13 +80,21 @@ extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe); -extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner); +extern u16 dib0090_get_wbd_target(struct dvb_frontend *tuner); +extern u16 dib0090_get_wbd_offset(struct dvb_frontend *fe); extern int dib0090_gain_control(struct dvb_frontend *fe); extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe); extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt); +extern void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff); +extern int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3); +extern int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff); +extern int dib0090_update_rframp_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity); +extern int dib0090_update_tuning_table_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity); #else -static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) +static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; @@ -106,7 +116,13 @@ static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe) printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); } -static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) +static inline u16 dib0090_get_wbd_target(struct dvb_frontend *tuner) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return 0; @@ -134,6 +150,38 @@ static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); } + +static inline void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline int dib0090_set_switch(struct dvb_frontend *fe, + u8 sw1, u8 sw2, u8 sw3) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib0090_update_rframp_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib0090_update_tuning_table_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif #endif diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index 437904cbf3e6..af91e0c92339 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -112,39 +112,37 @@ static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */ } }; -static int dib3000mb_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep); +static int dib3000mb_get_frontend(struct dvb_frontend* fe); -static int dib3000mb_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep, int tuner) +static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner) { struct dib3000_state* state = fe->demodulator_priv; - struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; fe_code_rate_t fe_cr = FEC_NONE; int search_state, seq; if (tuner && fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fep); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); deb_setf("bandwidth: "); - switch (ofdm->bandwidth) { - case BANDWIDTH_8_MHZ: + switch (c->bandwidth_hz) { + case 8000000: deb_setf("8 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); break; - case BANDWIDTH_7_MHZ: + case 7000000: deb_setf("7 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz); break; - case BANDWIDTH_6_MHZ: + case 6000000: deb_setf("6 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz); break; - case BANDWIDTH_AUTO: + case 0: return -EOPNOTSUPP; default: err("unknown bandwidth value."); @@ -154,7 +152,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); deb_setf("transmission mode: "); - switch (ofdm->transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: deb_setf("2k\n"); wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K); @@ -171,7 +169,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, } deb_setf("guard: "); - switch (ofdm->guard_interval) { + switch (c->guard_interval) { case GUARD_INTERVAL_1_32: deb_setf("1_32\n"); wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32); @@ -196,7 +194,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, } deb_setf("inversion: "); - switch (fep->inversion) { + switch (c->inversion) { case INVERSION_OFF: deb_setf("off\n"); wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF); @@ -212,8 +210,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, return -EINVAL; } - deb_setf("constellation: "); - switch (ofdm->constellation) { + deb_setf("modulation: "); + switch (c->modulation) { case QPSK: deb_setf("qpsk\n"); wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK); @@ -232,7 +230,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, return -EINVAL; } deb_setf("hierarchy: "); - switch (ofdm->hierarchy_information) { + switch (c->hierarchy) { case HIERARCHY_NONE: deb_setf("none "); /* fall through */ @@ -256,16 +254,16 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, } deb_setf("hierarchy: "); - if (ofdm->hierarchy_information == HIERARCHY_NONE) { + if (c->hierarchy == HIERARCHY_NONE) { deb_setf("none\n"); wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF); wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP); - fe_cr = ofdm->code_rate_HP; - } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { + fe_cr = c->code_rate_HP; + } else if (c->hierarchy != HIERARCHY_AUTO) { deb_setf("on\n"); wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON); wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP); - fe_cr = ofdm->code_rate_LP; + fe_cr = c->code_rate_LP; } deb_setf("fec: "); switch (fe_cr) { @@ -300,9 +298,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, } seq = dib3000_seq - [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] - [ofdm->guard_interval == GUARD_INTERVAL_AUTO] - [fep->inversion == INVERSION_AUTO]; + [c->transmission_mode == TRANSMISSION_MODE_AUTO] + [c->guard_interval == GUARD_INTERVAL_AUTO] + [c->inversion == INVERSION_AUTO]; deb_setf("seq? %d\n", seq); @@ -310,8 +308,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE); - if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) { - if (ofdm->guard_interval == GUARD_INTERVAL_1_8) { + if (c->transmission_mode == TRANSMISSION_MODE_2K) { + if (c->guard_interval == GUARD_INTERVAL_1_8) { wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8); } else { wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT); @@ -339,10 +337,10 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low); /* something has to be auto searched */ - if (ofdm->constellation == QAM_AUTO || - ofdm->hierarchy_information == HIERARCHY_AUTO || + if (c->modulation == QAM_AUTO || + c->hierarchy == HIERARCHY_AUTO || fe_cr == FEC_AUTO || - fep->inversion == INVERSION_AUTO) { + c->inversion == INVERSION_AUTO) { int as_count=0; deb_setf("autosearch enabled.\n"); @@ -361,10 +359,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count); if (search_state == 1) { - struct dvb_frontend_parameters feps; - if (dib3000mb_get_frontend(fe, &feps) == 0) { + if (dib3000mb_get_frontend(fe) == 0) { deb_setf("reading tuning data from frontend succeeded.\n"); - return dib3000mb_set_frontend(fe, &feps, 0); + return dib3000mb_set_frontend(fe, 0); } } @@ -453,11 +450,10 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) return 0; } -static int dib3000mb_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib3000mb_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dib3000_state* state = fe->demodulator_priv; - struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t *cr; u16 tps_val; int inv_test1,inv_test2; @@ -484,25 +480,25 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, else inv_test2 = 2; - fep->inversion = + c->inversion = ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ? INVERSION_ON : INVERSION_OFF; - deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); + deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, c->inversion); switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) { case DIB3000_CONSTELLATION_QPSK: deb_getf("QPSK "); - ofdm->constellation = QPSK; + c->modulation = QPSK; break; case DIB3000_CONSTELLATION_16QAM: deb_getf("QAM16 "); - ofdm->constellation = QAM_16; + c->modulation = QAM_16; break; case DIB3000_CONSTELLATION_64QAM: deb_getf("QAM64 "); - ofdm->constellation = QAM_64; + c->modulation = QAM_64; break; default: err("Unexpected constellation returned by TPS (%d)", tps_val); @@ -512,24 +508,24 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, if (rd(DIB3000MB_REG_TPS_HRCH)) { deb_getf("HRCH ON\n"); - cr = &ofdm->code_rate_LP; - ofdm->code_rate_HP = FEC_NONE; + cr = &c->code_rate_LP; + c->code_rate_HP = FEC_NONE; switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) { case DIB3000_ALPHA_0: deb_getf("HIERARCHY_NONE "); - ofdm->hierarchy_information = HIERARCHY_NONE; + c->hierarchy = HIERARCHY_NONE; break; case DIB3000_ALPHA_1: deb_getf("HIERARCHY_1 "); - ofdm->hierarchy_information = HIERARCHY_1; + c->hierarchy = HIERARCHY_1; break; case DIB3000_ALPHA_2: deb_getf("HIERARCHY_2 "); - ofdm->hierarchy_information = HIERARCHY_2; + c->hierarchy = HIERARCHY_2; break; case DIB3000_ALPHA_4: deb_getf("HIERARCHY_4 "); - ofdm->hierarchy_information = HIERARCHY_4; + c->hierarchy = HIERARCHY_4; break; default: err("Unexpected ALPHA value returned by TPS (%d)", tps_val); @@ -540,9 +536,9 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP); } else { deb_getf("HRCH OFF\n"); - cr = &ofdm->code_rate_HP; - ofdm->code_rate_LP = FEC_NONE; - ofdm->hierarchy_information = HIERARCHY_NONE; + cr = &c->code_rate_HP; + c->code_rate_LP = FEC_NONE; + c->hierarchy = HIERARCHY_NONE; tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP); } @@ -577,19 +573,19 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) { case DIB3000_GUARD_TIME_1_32: deb_getf("GUARD_INTERVAL_1_32 "); - ofdm->guard_interval = GUARD_INTERVAL_1_32; + c->guard_interval = GUARD_INTERVAL_1_32; break; case DIB3000_GUARD_TIME_1_16: deb_getf("GUARD_INTERVAL_1_16 "); - ofdm->guard_interval = GUARD_INTERVAL_1_16; + c->guard_interval = GUARD_INTERVAL_1_16; break; case DIB3000_GUARD_TIME_1_8: deb_getf("GUARD_INTERVAL_1_8 "); - ofdm->guard_interval = GUARD_INTERVAL_1_8; + c->guard_interval = GUARD_INTERVAL_1_8; break; case DIB3000_GUARD_TIME_1_4: deb_getf("GUARD_INTERVAL_1_4 "); - ofdm->guard_interval = GUARD_INTERVAL_1_4; + c->guard_interval = GUARD_INTERVAL_1_4; break; default: err("Unexpected Guard Time returned by TPS (%d)", tps_val); @@ -600,11 +596,11 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) { case DIB3000_TRANSMISSION_MODE_2K: deb_getf("TRANSMISSION_MODE_2K "); - ofdm->transmission_mode = TRANSMISSION_MODE_2K; + c->transmission_mode = TRANSMISSION_MODE_2K; break; case DIB3000_TRANSMISSION_MODE_8K: deb_getf("TRANSMISSION_MODE_8K "); - ofdm->transmission_mode = TRANSMISSION_MODE_8K; + c->transmission_mode = TRANSMISSION_MODE_8K; break; default: err("unexpected transmission mode return by TPS (%d)", tps_val); @@ -701,9 +697,9 @@ static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe) return dib3000mb_fe_init(fe, 0); } -static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) +static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend *fe) { - return dib3000mb_set_frontend(fe, fep, 1); + return dib3000mb_set_frontend(fe, 1); } static void dib3000mb_release(struct dvb_frontend* fe) @@ -794,10 +790,9 @@ error: } static struct dvb_frontend_ops dib3000mb_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 3000M-B DVB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h index 16c526591f36..9dc235aa44b7 100644 --- a/drivers/media/dvb/frontends/dib3000mb_priv.h +++ b/drivers/media/dvb/frontends/dib3000mb_priv.h @@ -98,7 +98,7 @@ struct dib3000_state { int timing_offset; int timing_offset_comp_done; - fe_bandwidth_t last_tuned_bw; + u32 last_tuned_bw; u32 last_tuned_freq; }; diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 088e7fadbe3d..ffad181a9692 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -40,7 +40,7 @@ struct dib3000mc_state { u32 timf; - fe_bandwidth_t current_bandwidth; + u32 current_bandwidth; u16 dev_id; @@ -438,11 +438,14 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) dib3000mc_write_word(state, reg, cfg[reg - 129]); } -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) +static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, + struct dtv_frontend_properties *ch, u16 seq) { u16 value; - dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); + u32 bw = BANDWIDTH_TO_KHZ(ch->bandwidth_hz); + + dib3000mc_set_bandwidth(state, bw); + dib3000mc_set_timing(state, ch->transmission_mode, bw, 0); // if (boost) // dib3000mc_write_word(state, 100, (11 << 6) + 6); @@ -471,22 +474,22 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_ dib3000mc_write_word(state, 97,0); dib3000mc_write_word(state, 98,0); - dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); + dib3000mc_set_impulse_noise(state, 0, ch->transmission_mode); value = 0; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= (0 << 7); break; default: case TRANSMISSION_MODE_8K: value |= (1 << 7); break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_32: value |= (0 << 5); break; case GUARD_INTERVAL_1_16: value |= (1 << 5); break; case GUARD_INTERVAL_1_4: value |= (3 << 5); break; default: case GUARD_INTERVAL_1_8: value |= (2 << 5); break; } - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QPSK: value |= (0 << 3); break; case QAM_16: value |= (1 << 3); break; default: @@ -502,11 +505,11 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_ dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); value = 0; - if (ch->u.ofdm.hierarchy_information == 1) + if (ch->hierarchy == 1) value |= (1 << 4); if (1 == 1) value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { case FEC_2_3: value |= (2 << 1); break; case FEC_3_4: value |= (3 << 1); break; case FEC_5_6: value |= (5 << 1); break; @@ -517,12 +520,12 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_ dib3000mc_write_word(state, 181, value); // diversity synchro delay add 50% SFN margin - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_8K: value = 256; break; case TRANSMISSION_MODE_2K: default: value = 64; break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_16: value *= 2; break; case GUARD_INTERVAL_1_8: value *= 4; break; case GUARD_INTERVAL_1_4: value *= 8; break; @@ -540,27 +543,28 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_ msleep(30); - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); + dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->transmission_mode); } -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) +static int dib3000mc_autosearch_start(struct dvb_frontend *demod) { + struct dtv_frontend_properties *chan = &demod->dtv_property_cache; struct dib3000mc_state *state = demod->demodulator_priv; u16 reg; // u32 val; - struct dvb_frontend_parameters schan; + struct dtv_frontend_properties schan; schan = *chan; /* TODO what is that ? */ /* a channel for autosearch */ - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_2_3; - schan.u.ofdm.hierarchy_information = 0; + schan.transmission_mode = TRANSMISSION_MODE_8K; + schan.guard_interval = GUARD_INTERVAL_1_32; + schan.modulation = QAM_64; + schan.code_rate_HP = FEC_2_3; + schan.code_rate_LP = FEC_2_3; + schan.hierarchy = 0; dib3000mc_set_channel_cfg(state, &schan, 11); @@ -586,8 +590,9 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib3000mc_tune(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib3000mc_state *state = demod->demodulator_priv; // ** configure demod ** @@ -603,8 +608,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift } - dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); - if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { + dib3000mc_set_adp_cfg(state, (u8)ch->modulation); + if (ch->transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); } else { @@ -613,7 +618,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame } if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); + dib3000mc_set_timing(state, ch->transmission_mode, + BANDWIDTH_TO_KHZ(ch->bandwidth_hz), 1); return 0; } @@ -626,87 +632,87 @@ struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master); -static int dib3000mc_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib3000mc_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib3000mc_state *state = fe->demodulator_priv; u16 tps = dib3000mc_read_word(state,458); fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = state->current_bandwidth; + fep->bandwidth_hz = state->current_bandwidth; switch ((tps >> 8) & 0x1) { - case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; + case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break; + case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break; } switch (tps & 0x3) { - case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; - case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; - case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; - case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; + case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break; + case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break; + case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break; + case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break; } switch ((tps >> 13) & 0x3) { - case 0: fep->u.ofdm.constellation = QPSK; break; - case 1: fep->u.ofdm.constellation = QAM_16; break; + case 0: fep->modulation = QPSK; break; + case 1: fep->modulation = QAM_16; break; case 2: - default: fep->u.ofdm.constellation = QAM_64; break; + default: fep->modulation = QAM_64; break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */ - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fep->hierarchy = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { - case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; + case 1: fep->code_rate_HP = FEC_1_2; break; + case 2: fep->code_rate_HP = FEC_2_3; break; + case 3: fep->code_rate_HP = FEC_3_4; break; + case 5: fep->code_rate_HP = FEC_5_6; break; case 7: - default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; + default: fep->code_rate_HP = FEC_7_8; break; } switch ((tps >> 2) & 0x7) { - case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; + case 1: fep->code_rate_LP = FEC_1_2; break; + case 2: fep->code_rate_LP = FEC_2_3; break; + case 3: fep->code_rate_LP = FEC_3_4; break; + case 5: fep->code_rate_LP = FEC_5_6; break; case 7: - default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; + default: fep->code_rate_LP = FEC_7_8; break; } return 0; } -static int dib3000mc_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib3000mc_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib3000mc_state *state = fe->demodulator_priv; - int ret; + int ret; dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + state->current_bandwidth = fep->bandwidth_hz; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz)); /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fep); + fe->ops.tuner_ops.set_params(fe); msleep(100); } - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || - fep->u.ofdm.constellation == QAM_AUTO || - fep->u.ofdm.code_rate_HP == FEC_AUTO) { + if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || + fep->guard_interval == GUARD_INTERVAL_AUTO || + fep->modulation == QAM_AUTO || + fep->code_rate_HP == FEC_AUTO) { int i = 1000, found; - dib3000mc_autosearch_start(fe, fep); + dib3000mc_autosearch_start(fe); do { msleep(1); found = dib3000mc_autosearch_is_irq(fe); @@ -716,14 +722,14 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, if (found == 0 || found == 1) return 0; // no channel found - dib3000mc_get_frontend(fe, fep); + dib3000mc_get_frontend(fe); } - ret = dib3000mc_tune(fe, fep); + ret = dib3000mc_tune(fe); /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return ret; + return ret; } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -897,9 +903,9 @@ error: EXPORT_SYMBOL(dib3000mc_attach); static struct dvb_frontend_ops dib3000mc_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 3000MC/P", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index dbb76d75c932..148bf79236fb 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -38,7 +38,7 @@ struct dib7000m_state { u16 wbd_ref; u8 current_band; - fe_bandwidth_t current_bandwidth; + u32 current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; u32 timf_default; @@ -313,6 +313,9 @@ static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) { u32 timf; + if (!bw) + bw = 8000; + // store the current bandwidth for later use state->current_bandwidth = bw; @@ -742,8 +745,9 @@ static void dib7000m_update_timf(struct dib7000m_state *state) dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); } -static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000m_agc_startup(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000m_state *state = demod->demodulator_priv; u16 cfg_72 = dib7000m_read_word(state, 72); int ret = -1; @@ -832,28 +836,29 @@ static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ return ret; } -static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) +static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch, + u8 seq) { u16 value, est[4]; - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); /* nfft, guard, qam, alpha */ value = 0; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= (0 << 7); break; case TRANSMISSION_MODE_4K: value |= (2 << 7); break; default: case TRANSMISSION_MODE_8K: value |= (1 << 7); break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_32: value |= (0 << 5); break; case GUARD_INTERVAL_1_16: value |= (1 << 5); break; case GUARD_INTERVAL_1_4: value |= (3 << 5); break; default: case GUARD_INTERVAL_1_8: value |= (2 << 5); break; } - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QPSK: value |= (0 << 3); break; case QAM_16: value |= (1 << 3); break; default: @@ -872,11 +877,11 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte value = 0; if (1 != 0) value |= (1 << 6); - if (ch->u.ofdm.hierarchy_information == 1) + if (ch->hierarchy == 1) value |= (1 << 4); if (1 == 1) value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { case FEC_2_3: value |= (2 << 1); break; case FEC_3_4: value |= (3 << 1); break; case FEC_5_6: value |= (5 << 1); break; @@ -901,13 +906,13 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte dib7000m_write_word(state, 33, (0 << 4) | 0x5); /* P_dvsy_sync_wait */ - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_8K: value = 256; break; case TRANSMISSION_MODE_4K: value = 128; break; case TRANSMISSION_MODE_2K: default: value = 64; break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_16: value *= 2; break; case GUARD_INTERVAL_1_8: value *= 4; break; case GUARD_INTERVAL_1_4: value *= 8; break; @@ -925,7 +930,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte dib7000m_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ @@ -952,25 +957,26 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); } -static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000m_autosearch_start(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000m_state *state = demod->demodulator_priv; - struct dvb_frontend_parameters schan; + struct dtv_frontend_properties schan; int ret = 0; u32 value, factor; schan = *ch; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_3_4; - schan.u.ofdm.hierarchy_information = 0; + schan.modulation = QAM_64; + schan.guard_interval = GUARD_INTERVAL_1_32; + schan.transmission_mode = TRANSMISSION_MODE_8K; + schan.code_rate_HP = FEC_2_3; + schan.code_rate_LP = FEC_3_4; + schan.hierarchy = 0; dib7000m_set_channel(state, &schan, 7); - factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz); if (factor >= 5000) factor = 1; else @@ -1027,8 +1033,9 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) return dib7000m_autosearch_irq(state, 537); } -static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000m_tune(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000m_state *state = demod->demodulator_priv; int ret = 0; u16 value; @@ -1055,7 +1062,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet //dump_reg(state); /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ value = (6 << 8) | 0x80; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= (7 << 12); break; case TRANSMISSION_MODE_4K: value |= (8 << 12); break; default: @@ -1065,7 +1072,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ value = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= 0x6; break; case TRANSMISSION_MODE_4K: value |= 0x7; break; default: @@ -1075,7 +1082,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ value = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= 0x6; break; case TRANSMISSION_MODE_4K: value |= 0x7; break; default: @@ -1087,7 +1094,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet if ((dib7000m_read_word(state, 535) >> 6) & 0x1) dib7000m_update_timf(state); - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); return ret; } @@ -1147,57 +1154,57 @@ static int dib7000m_identify(struct dib7000m_state *state) } -static int dib7000m_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib7000m_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib7000m_state *state = fe->demodulator_priv; u16 tps = dib7000m_read_word(state,480); fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = state->current_bandwidth; + fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth); switch ((tps >> 8) & 0x3) { - case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; - /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ + case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break; + case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break; + /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */ } switch (tps & 0x3) { - case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; - case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; - case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; - case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; + case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break; + case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break; + case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break; + case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break; } switch ((tps >> 14) & 0x3) { - case 0: fep->u.ofdm.constellation = QPSK; break; - case 1: fep->u.ofdm.constellation = QAM_16; break; + case 0: fep->modulation = QPSK; break; + case 1: fep->modulation = QAM_16; break; case 2: - default: fep->u.ofdm.constellation = QAM_64; break; + default: fep->modulation = QAM_64; break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fep->hierarchy = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { - case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; + case 1: fep->code_rate_HP = FEC_1_2; break; + case 2: fep->code_rate_HP = FEC_2_3; break; + case 3: fep->code_rate_HP = FEC_3_4; break; + case 5: fep->code_rate_HP = FEC_5_6; break; case 7: - default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; + default: fep->code_rate_HP = FEC_7_8; break; } switch ((tps >> 2) & 0x7) { - case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; + case 1: fep->code_rate_LP = FEC_1_2; break; + case 2: fep->code_rate_LP = FEC_2_3; break; + case 3: fep->code_rate_LP = FEC_3_4; break; + case 5: fep->code_rate_LP = FEC_5_6; break; case 7: - default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; + default: fep->code_rate_LP = FEC_7_8; break; } /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */ @@ -1205,35 +1212,34 @@ static int dib7000m_get_frontend(struct dvb_frontend* fe, return 0; } -static int dib7000m_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib7000m_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib7000m_state *state = fe->demodulator_priv; int time, ret; - dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); + dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz)); if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, fep); + fe->ops.tuner_ops.set_params(fe); /* start up the AGC */ state->agc_state = 0; do { - time = dib7000m_agc_startup(fe, fep); + time = dib7000m_agc_startup(fe); if (time != -1) msleep(time); } while (time != -1); - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || - fep->u.ofdm.constellation == QAM_AUTO || - fep->u.ofdm.code_rate_HP == FEC_AUTO) { + if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || + fep->guard_interval == GUARD_INTERVAL_AUTO || + fep->modulation == QAM_AUTO || + fep->code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000m_autosearch_start(fe, fep); + dib7000m_autosearch_start(fe); do { msleep(1); found = dib7000m_autosearch_is_irq(fe); @@ -1243,10 +1249,10 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, if (found == 0 || found == 1) return 0; // no channel found - dib7000m_get_frontend(fe, fep); + dib7000m_get_frontend(fe); } - ret = dib7000m_tune(fe, fep); + ret = dib7000m_tune(fe); /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); @@ -1430,9 +1436,9 @@ error: EXPORT_SYMBOL(dib7000m_attach); static struct dvb_frontend_ops dib7000m_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 7000MA/MB/PA/PB/MC", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index ce8534ff142e..5ceadc285b3a 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -70,6 +70,8 @@ struct dib7000p_state { u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; struct mutex i2c_buffer_lock; + + u8 input_mode_mpeg; }; enum dib7000p_power_mode { @@ -78,8 +80,11 @@ enum dib7000p_power_mode { DIB7000P_POWER_INTERFACE_ONLY, }; +/* dib7090 specific fonctions */ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode); static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); +static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode); +static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode); static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) { @@ -276,17 +281,23 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p dib7000p_write_word(state, 774, reg_774); dib7000p_write_word(state, 775, reg_775); dib7000p_write_word(state, 776, reg_776); - dib7000p_write_word(state, 899, reg_899); dib7000p_write_word(state, 1280, reg_1280); + if (state->version != SOC7090) + dib7000p_write_word(state, 899, reg_899); return 0; } static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no) { - u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909); + u16 reg_908 = 0, reg_909 = 0; u16 reg; + if (state->version != SOC7090) { + reg_908 = dib7000p_read_word(state, 908); + reg_909 = dib7000p_read_word(state, 909); + } + switch (no) { case DIBX000_SLOW_ADC_ON: if (state->version == SOC7090) { @@ -342,8 +353,10 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4; reg_908 |= (state->cfg.enable_current_mirror & 1) << 7; - dib7000p_write_word(state, 908, reg_908); - dib7000p_write_word(state, 909, reg_909); + if (state->version != SOC7090) { + dib7000p_write_word(state, 908, reg_908); + dib7000p_write_word(state, 909, reg_909); + } } static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) @@ -398,6 +411,24 @@ int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) } EXPORT_SYMBOL(dib7000p_set_wbd_ref); +int dib7000p_get_agc_values(struct dvb_frontend *fe, + u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd) +{ + struct dib7000p_state *state = fe->demodulator_priv; + + if (agc_global != NULL) + *agc_global = dib7000p_read_word(state, 394); + if (agc1 != NULL) + *agc1 = dib7000p_read_word(state, 392); + if (agc2 != NULL) + *agc2 = dib7000p_read_word(state, 393); + if (wbd != NULL) + *wbd = dib7000p_read_word(state, 397); + + return 0; +} +EXPORT_SYMBOL(dib7000p_get_agc_values); + static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; @@ -519,7 +550,7 @@ static u16 dib7000p_defaults[] = { // auto search configuration 3, 2, 0x0004, - 0x1000, + (1<<3)|(1<<11)|(1<<12)|(1<<13), 0x0814, /* Equal Lock */ 12, 6, @@ -595,13 +626,6 @@ static u16 dib7000p_defaults[] = { 1, 235, 0x0062, - 2, 901, - 0x0006, - (3 << 10) | (1 << 6), - - 1, 905, - 0x2c8e, - 0, }; @@ -618,15 +642,18 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_write_word(state, 770, 0xffff); dib7000p_write_word(state, 771, 0xffff); dib7000p_write_word(state, 772, 0x001f); - dib7000p_write_word(state, 898, 0x0003); dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3))); dib7000p_write_word(state, 770, 0); dib7000p_write_word(state, 771, 0); dib7000p_write_word(state, 772, 0); - dib7000p_write_word(state, 898, 0); dib7000p_write_word(state, 1280, 0); + if (state->version != SOC7090) { + dib7000p_write_word(state, 898, 0x0003); + dib7000p_write_word(state, 898, 0); + } + /* default */ dib7000p_reset_pll(state); @@ -640,7 +667,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */ dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */ dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */ - dib7000p_write_word(state, 273, (1<<6) | 30); + dib7000p_write_word(state, 273, (0<<6) | 30); } if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) dprintk("OUTPUT_MODE could not be reset."); @@ -655,7 +682,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_set_bandwidth(state, 8000); if (state->version == SOC7090) { - dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ + dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ } else { if (state->cfg.tuner_is_baseband) dib7000p_write_word(state, 36, 0x0755); @@ -664,6 +691,11 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) } dib7000p_write_tab(state, dib7000p_defaults); + if (state->version != SOC7090) { + dib7000p_write_word(state, 901, 0x0006); + dib7000p_write_word(state, 902, (3 << 10) | (1 << 6)); + dib7000p_write_word(state, 905, 0x2c8e); + } dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); @@ -780,8 +812,9 @@ static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) } } -static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000p_agc_startup(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000p_state *state = demod->demodulator_priv; int ret = -1; u8 *agc_state = &state->agc_state; @@ -904,15 +937,16 @@ u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) } EXPORT_SYMBOL(dib7000p_ctrl_timf); -static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) +static void dib7000p_set_channel(struct dib7000p_state *state, + struct dtv_frontend_properties *ch, u8 seq) { u16 value, est[4]; - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); /* nfft, guard, qam, alpha */ value = 0; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= (0 << 7); break; @@ -924,7 +958,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte value |= (1 << 7); break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_32: value |= (0 << 5); break; @@ -939,7 +973,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte value |= (2 << 5); break; } - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QPSK: value |= (0 << 3); break; @@ -970,11 +1004,11 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte value = 0; if (1 != 0) value |= (1 << 6); - if (ch->u.ofdm.hierarchy_information == 1) + if (ch->hierarchy == 1) value |= (1 << 4); if (1 == 1) value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { case FEC_2_3: value |= (2 << 1); break; @@ -1001,7 +1035,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte dib7000p_write_word(state, 33, 0x0005); /* P_dvsy_sync_wait */ - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_8K: value = 256; break; @@ -1013,7 +1047,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte value = 64; break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_16: value *= 2; break; @@ -1034,11 +1068,11 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; /* deactive the possibility of diversity reception if extended interleaver */ - state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; + state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K; dib7000p_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ @@ -1062,27 +1096,31 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte dib7000p_write_word(state, 187 + value, est[value]); } -static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000p_autosearch_start(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000p_state *state = demod->demodulator_priv; - struct dvb_frontend_parameters schan; + struct dtv_frontend_properties schan; u32 value, factor; u32 internal = dib7000p_get_internal_freq(state); schan = *ch; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_3_4; - schan.u.ofdm.hierarchy_information = 0; + schan.modulation = QAM_64; + schan.guard_interval = GUARD_INTERVAL_1_32; + schan.transmission_mode = TRANSMISSION_MODE_8K; + schan.code_rate_HP = FEC_2_3; + schan.code_rate_LP = FEC_3_4; + schan.hierarchy = 0; dib7000p_set_channel(state, &schan, 7); - factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); - if (factor >= 5000) - factor = 1; - else + factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz); + if (factor >= 5000) { + if (state->version == SOC7090) + factor = 2; + else + factor = 1; + } else factor = 6; value = 30 * internal * factor; @@ -1205,8 +1243,9 @@ static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 dib7000p_write_word(state, 143, 0); } -static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000p_tune(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000p_state *state = demod->demodulator_priv; u16 tmp = 0; @@ -1239,7 +1278,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ tmp = (6 << 8) | 0x80; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: tmp |= (2 << 12); break; @@ -1255,7 +1294,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ tmp = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: tmp |= 0x6; break; @@ -1271,7 +1310,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ tmp = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: tmp |= 0x6; break; @@ -1303,9 +1342,9 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet } if (state->cfg.spur_protect) - dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); return 0; } @@ -1323,7 +1362,7 @@ static int dib7000p_sleep(struct dvb_frontend *demod) { struct dib7000p_state *state = demod->demodulator_priv; if (state->version == SOC7090) - return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); } @@ -1345,93 +1384,94 @@ static int dib7000p_identify(struct dib7000p_state *st) return 0; } -static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib7000p_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib7000p_state *state = fe->demodulator_priv; u16 tps = dib7000p_read_word(state, 463); fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth); + fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth); switch ((tps >> 8) & 0x3) { case 0: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + fep->transmission_mode = TRANSMISSION_MODE_2K; break; case 1: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + fep->transmission_mode = TRANSMISSION_MODE_8K; break; - /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ + /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */ } switch (tps & 0x3) { case 0: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + fep->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + fep->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + fep->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + fep->guard_interval = GUARD_INTERVAL_1_4; break; } switch ((tps >> 14) & 0x3) { case 0: - fep->u.ofdm.constellation = QPSK; + fep->modulation = QPSK; break; case 1: - fep->u.ofdm.constellation = QAM_16; + fep->modulation = QAM_16; break; case 2: default: - fep->u.ofdm.constellation = QAM_64; + fep->modulation = QAM_64; break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fep->hierarchy = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { case 1: - fep->u.ofdm.code_rate_HP = FEC_1_2; + fep->code_rate_HP = FEC_1_2; break; case 2: - fep->u.ofdm.code_rate_HP = FEC_2_3; + fep->code_rate_HP = FEC_2_3; break; case 3: - fep->u.ofdm.code_rate_HP = FEC_3_4; + fep->code_rate_HP = FEC_3_4; break; case 5: - fep->u.ofdm.code_rate_HP = FEC_5_6; + fep->code_rate_HP = FEC_5_6; break; case 7: default: - fep->u.ofdm.code_rate_HP = FEC_7_8; + fep->code_rate_HP = FEC_7_8; break; } switch ((tps >> 2) & 0x7) { case 1: - fep->u.ofdm.code_rate_LP = FEC_1_2; + fep->code_rate_LP = FEC_1_2; break; case 2: - fep->u.ofdm.code_rate_LP = FEC_2_3; + fep->code_rate_LP = FEC_2_3; break; case 3: - fep->u.ofdm.code_rate_LP = FEC_3_4; + fep->code_rate_LP = FEC_3_4; break; case 5: - fep->u.ofdm.code_rate_LP = FEC_5_6; + fep->code_rate_LP = FEC_5_6; break; case 7: default: - fep->u.ofdm.code_rate_LP = FEC_7_8; + fep->code_rate_LP = FEC_7_8; break; } @@ -1440,36 +1480,36 @@ static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa return 0; } -static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib7000p_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib7000p_state *state = fe->demodulator_priv; int time, ret; - if (state->version == SOC7090) { + if (state->version == SOC7090) dib7090_set_diversity_in(fe, 0); - dib7090_set_output_mode(fe, OUTMODE_HIGH_Z); - } else + else dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, fep); + fe->ops.tuner_ops.set_params(fe); /* start up the AGC */ state->agc_state = 0; do { - time = dib7000p_agc_startup(fe, fep); + time = dib7000p_agc_startup(fe); if (time != -1) msleep(time); } while (time != -1); - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { + if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || + fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000p_autosearch_start(fe, fep); + dib7000p_autosearch_start(fe); do { msleep(1); found = dib7000p_autosearch_is_irq(fe); @@ -1479,15 +1519,19 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa if (found == 0 || found == 1) return 0; - dib7000p_get_frontend(fe, fep); + dib7000p_get_frontend(fe); } - ret = dib7000p_tune(fe, fep); + ret = dib7000p_tune(fe); /* make this a config parameter */ - if (state->version == SOC7090) + if (state->version == SOC7090) { dib7090_set_output_mode(fe, state->cfg.output_mode); - else + if (state->cfg.enMpegOutput == 0) { + dib7090_setDibTxMux(state, MPEG_ON_DIBTX); + dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); + } + } else dib7000p_set_output_mode(state, state->cfg.output_mode); return ret; @@ -1831,7 +1875,8 @@ static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg m return num; } -int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address) +static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num, u16 apb_address) { struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); u16 word; @@ -1933,10 +1978,10 @@ static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[] apb_address = 915; break; case 0x27: - apb_address = 916; + apb_address = 917; break; case 0x28: - apb_address = 917; + apb_address = 916; break; case 0x1d: i = ((dib7000p_read_word(state, 72) >> 12) & 0x3); @@ -2031,12 +2076,7 @@ static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize) { - u8 index_buf; - u16 rx_copy_buf[22]; - dprintk("Configure DibStream Tx"); - for (index_buf = 0; index_buf < 22; index_buf++) - rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf); dib7000p_write_word(state, 1615, 1); dib7000p_write_word(state, 1603, P_Kin); @@ -2048,9 +2088,6 @@ static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout dib7000p_write_word(state, 1612, syncSize); dib7000p_write_word(state, 1615, 0); - for (index_buf = 0; index_buf < 22; index_buf++) - dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]); - return 0; } @@ -2077,109 +2114,121 @@ static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout return 0; } -static int dib7090_enDivOnHostBus(struct dib7000p_state *state) -{ - u16 reg; - - dprintk("Enable Diversity on host bus"); - reg = (1 << 8) | (1 << 5); - dib7000p_write_word(state, 1288, reg); - - return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); -} - -static int dib7090_enAdcOnHostBus(struct dib7000p_state *state) -{ - u16 reg; - - dprintk("Enable ADC on host bus"); - reg = (1 << 7) | (1 << 5); - dib7000p_write_word(state, 1288, reg); - - return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); -} - -static int dib7090_enMpegOnHostBus(struct dib7000p_state *state) +static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff) { - u16 reg; - - dprintk("Enable Mpeg on host bus"); - reg = (1 << 9) | (1 << 5); - dib7000p_write_word(state, 1288, reg); + u16 reg_1287 = dib7000p_read_word(state, 1287); - return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); -} + switch (onoff) { + case 1: + reg_1287 &= ~(1<<7); + break; + case 0: + reg_1287 |= (1<<7); + break; + } -static int dib7090_enMpegInput(struct dib7000p_state *state) -{ - dprintk("Enable Mpeg input"); - return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ + dib7000p_write_word(state, 1287, reg_1287); } -static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) +static void dib7090_configMpegMux(struct dib7000p_state *state, + u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) { - u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1); - dprintk("Enable Mpeg mux"); - dib7000p_write_word(state, 1287, reg); - reg &= ~(1 << 7); - dib7000p_write_word(state, 1287, reg); + dib7090_enMpegMux(state, 0); - reg = (1 << 4); - dib7000p_write_word(state, 1288, reg); + /* If the input mode is MPEG do not divide the serial clock */ + if ((enSerialMode == 1) && (state->input_mode_mpeg == 1)) + enSerialClkDiv2 = 0; - return 0; + dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2) + | ((enSerialMode & 0x1) << 1) + | (enSerialClkDiv2 & 0x1)); + + dib7090_enMpegMux(state, 1); } -static int dib7090_disableMpegMux(struct dib7000p_state *state) +static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode) { - u16 reg; - - dprintk("Disable Mpeg mux"); - dib7000p_write_word(state, 1288, 0); - - reg = dib7000p_read_word(state, 1287); - reg &= ~(1 << 7); - dib7000p_write_word(state, 1287, reg); + u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7); - return 0; + switch (mode) { + case MPEG_ON_DIBTX: + dprintk("SET MPEG ON DIBSTREAM TX"); + dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); + reg_1288 |= (1<<9); + break; + case DIV_ON_DIBTX: + dprintk("SET DIV_OUT ON DIBSTREAM TX"); + dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); + reg_1288 |= (1<<8); + break; + case ADC_ON_DIBTX: + dprintk("SET ADC_OUT ON DIBSTREAM TX"); + dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); + reg_1288 |= (1<<7); + break; + default: + break; + } + dib7000p_write_word(state, 1288, reg_1288); } -static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode) +static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode) { - struct dib7000p_state *state = fe->demodulator_priv; + u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4); switch (mode) { - case INPUT_MODE_DIVERSITY: - dprintk("Enable diversity INPUT"); - dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); + case DEMOUT_ON_HOSTBUS: + dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); + dib7090_enMpegMux(state, 0); + reg_1288 |= (1<<6); + break; + case DIBTX_ON_HOSTBUS: + dprintk("SET DIBSTREAM TX ON HOST BUS"); + dib7090_enMpegMux(state, 0); + reg_1288 |= (1<<5); break; - case INPUT_MODE_MPEG: - dprintk("Enable Mpeg INPUT"); - dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ + case MPEG_ON_HOSTBUS: + dprintk("SET MPEG MUX ON HOST BUS"); + reg_1288 |= (1<<4); break; - case INPUT_MODE_OFF: default: - dprintk("Disable INPUT"); - dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0); break; } - return 0; + dib7000p_write_word(state, 1288, reg_1288); } -static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) +int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) { + struct dib7000p_state *state = fe->demodulator_priv; + u16 reg_1287; + switch (onoff) { - case 0: /* only use the internal way - not the diversity input */ - dib7090_set_input_mode(fe, INPUT_MODE_MPEG); - break; - case 1: /* both ways */ - case 2: /* only the diversity input */ - dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY); - break; + case 0: /* only use the internal way - not the diversity input */ + dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__); + dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); + + /* Do not divide the serial clock of MPEG MUX */ + /* in SERIAL MODE in case input mode MPEG is used */ + reg_1287 = dib7000p_read_word(state, 1287); + /* enSerialClkDiv2 == 1 ? */ + if ((reg_1287 & 0x1) == 1) { + /* force enSerialClkDiv2 = 0 */ + reg_1287 &= ~0x1; + dib7000p_write_word(state, 1287, reg_1287); + } + state->input_mode_mpeg = 1; + break; + case 1: /* both ways */ + case 2: /* only the diversity input */ + dprintk("%s ON : Enable diversity INPUT", __func__); + dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); + state->input_mode_mpeg = 0; + break; } + dib7000p_set_diversity_in(&state->demod, onoff); return 0; } @@ -2204,69 +2253,63 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) case OUTMODE_MPEG2_SERIAL: if (prefer_mpeg_mux_use) { - dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux"); - dib7090_enMpegOnHostBus(state); - dib7090_enMpegInput(state); - if (state->cfg.enMpegOutput == 1) - dib7090_enMpegMux(state, 3, 1, 1); - - } else { /* Use Smooth block */ - dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (2 << 6) | (0 << 1); + dprintk("setting output mode TS_SERIAL using Mpeg Mux"); + dib7090_configMpegMux(state, 3, 1, 1); + dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS); + } else {/* Use Smooth block */ + dprintk("setting output mode TS_SERIAL using Smooth bloc"); + dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (2<<6) | (0 << 1); } break; case OUTMODE_MPEG2_PAR_GATED_CLK: if (prefer_mpeg_mux_use) { - dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); - dib7090_enMpegOnHostBus(state); - dib7090_enMpegInput(state); - if (state->cfg.enMpegOutput == 1) - dib7090_enMpegMux(state, 2, 0, 0); - } else { /* Use Smooth block */ - dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (0 << 6); + dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux"); + dib7090_configMpegMux(state, 2, 0, 0); + dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS); + } else { /* Use Smooth block */ + dprintk("setting output mode TS_PARALLEL_GATED using Smooth block"); + dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (0<<6); } break; case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ - dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (1 << 6); + dprintk("setting output mode TS_PARALLEL_CONT using Smooth block"); + dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (1<<6); break; case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ - dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (5 << 6); + dprintk("setting output mode TS_FIFO using Smooth block"); + dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (5<<6); smo_mode |= (3 << 1); fifo_threshold = 512; break; case OUTMODE_DIVERSITY: - dprintk("Sip 7090P setting output mode MODE_DIVERSITY"); - dib7090_disableMpegMux(state); - dib7090_enDivOnHostBus(state); + dprintk("setting output mode MODE_DIVERSITY"); + dib7090_setDibTxMux(state, DIV_ON_DIBTX); + dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); break; case OUTMODE_ANALOG_ADC: - dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC"); - dib7090_enAdcOnHostBus(state); + dprintk("setting output mode MODE_ANALOG_ADC"); + dib7090_setDibTxMux(state, ADC_ON_DIBTX); + dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); break; } + if (mode != OUTMODE_HIGH_Z) + outreg |= (1 << 10); if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5); ret |= dib7000p_write_word(state, 235, smo_mode); ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ - ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */ + ret |= dib7000p_write_word(state, 1286, outreg); return ret; } @@ -2296,13 +2339,6 @@ int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) } EXPORT_SYMBOL(dib7090_tuner_sleep); -int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) -{ - dprintk("AGC restart callback: %d", restart); - return 0; -} -EXPORT_SYMBOL(dib7090_agc_restart); - int dib7090_get_adc_power(struct dvb_frontend *fe) { return dib7000p_get_adc_power(fe); @@ -2391,9 +2427,9 @@ error: EXPORT_SYMBOL(dib7000p_attach); static struct dvb_frontend_ops dib7000p_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 7000PC", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 0179f9474bac..b61b03a6e1ed 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -56,11 +56,12 @@ extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw); extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf); -extern int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart); extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff); extern int dib7090_get_adc_power(struct dvb_frontend *fe); extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe); extern int dib7090_slave_reset(struct dvb_frontend *fe); +extern int dib7000p_get_agc_values(struct dvb_frontend *fe, + u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd); #else static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) { @@ -122,12 +123,6 @@ static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) return 0; } -static inline int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); @@ -151,6 +146,13 @@ static inline int dib7090_slave_reset(struct dvb_frontend *fe) printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } + +static inline int dib7000p_get_agc_values(struct dvb_frontend *fe, + u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif #endif diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index fe284d5292f5..9ca34f495009 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -81,11 +81,15 @@ struct dib8000_state { u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; struct mutex i2c_buffer_lock; + u8 input_mode_mpeg; + + u16 tuner_enable; + struct i2c_adapter dib8096p_tuner_adap; }; enum dib8000_power_mode { - DIB8000M_POWER_ALL = 0, - DIB8000M_POWER_INTERFACE_ONLY, + DIB8000_POWER_ALL = 0, + DIB8000_POWER_INTERFACE_ONLY, }; static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) @@ -428,20 +432,31 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow /* by default everything is going to be powered off */ u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, + reg_1280; + + if (state->revision != 0x8090) reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; + else + reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80; /* now, depending on the requested mode, we power on */ switch (mode) { /* power up everything in the demod */ - case DIB8000M_POWER_ALL: + case DIB8000_POWER_ALL: reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0000; reg_900 &= 0xfffc; - reg_1280 &= 0x00ff; + if (state->revision != 0x8090) + reg_1280 &= 0x00ff; + else + reg_1280 &= 0x707f; break; - case DIB8000M_POWER_INTERFACE_ONLY: - reg_1280 &= 0x00ff; + case DIB8000_POWER_INTERFACE_ONLY: + if (state->revision != 0x8090) + reg_1280 &= 0x00ff; + else + reg_1280 &= 0xfa7b; break; } @@ -453,19 +468,67 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow dib8000_write_word(state, 1280, reg_1280); } +static int dib8000_init_sdram(struct dib8000_state *state) +{ + u16 reg = 0; + dprintk("Init sdram"); + + reg = dib8000_read_word(state, 274)&0xfff0; + /* P_dintlv_delay_ram = 7 because of MobileSdram */ + dib8000_write_word(state, 274, reg | 0x7); + + dib8000_write_word(state, 1803, (7<<2)); + + reg = dib8000_read_word(state, 1280); + /* force restart P_restart_sdram */ + dib8000_write_word(state, 1280, reg | (1<<2)); + + /* release restart P_restart_sdram */ + dib8000_write_word(state, 1280, reg); + + return 0; +} + static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) { int ret = 0; - u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908); + u16 reg, reg_907 = dib8000_read_word(state, 907); + u16 reg_908 = dib8000_read_word(state, 908); switch (no) { case DIBX000_SLOW_ADC_ON: - reg_908 |= (1 << 1) | (1 << 0); - ret |= dib8000_write_word(state, 908, reg_908); - reg_908 &= ~(1 << 1); + if (state->revision != 0x8090) { + reg_908 |= (1 << 1) | (1 << 0); + ret |= dib8000_write_word(state, 908, reg_908); + reg_908 &= ~(1 << 1); + } else { + reg = dib8000_read_word(state, 1925); + /* en_slowAdc = 1 & reset_sladc = 1 */ + dib8000_write_word(state, 1925, reg | + (1<<4) | (1<<2)); + + /* read acces to make it works... strange ... */ + reg = dib8000_read_word(state, 1925); + msleep(20); + /* en_slowAdc = 1 & reset_sladc = 0 */ + dib8000_write_word(state, 1925, reg & ~(1<<4)); + + reg = dib8000_read_word(state, 921) & ~((0x3 << 14) + | (0x3 << 12)); + /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; + (Vin2 = Vcm) */ + dib8000_write_word(state, 921, reg | (1 << 14) + | (3 << 12)); + } break; case DIBX000_SLOW_ADC_OFF: + if (state->revision == 0x8090) { + reg = dib8000_read_word(state, 1925); + /* reset_sladc = 1 en_slowAdc = 0 */ + dib8000_write_word(state, 1925, + (reg & ~(1<<2)) | (1<<4)); + } reg_908 |= (1 << 1) | (1 << 0); break; @@ -521,7 +584,12 @@ static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) static int dib8000_sad_calib(struct dib8000_state *state) { -/* internal */ + if (state->revision == 0x8090) { + dprintk("%s: the sad calibration is not needed for the dib8096P", + __func__); + return 0; + } + /* internal */ dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096 @@ -546,48 +614,129 @@ EXPORT_SYMBOL(dib8000_set_wbd_ref); static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) { dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); - dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */ - dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff)); + if (state->revision != 0x8090) { + dib8000_write_word(state, 23, + (u16) (((bw->internal * 1000) >> 16) & 0xffff)); + dib8000_write_word(state, 24, + (u16) ((bw->internal * 1000) & 0xffff)); + } else { + dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff)); + dib8000_write_word(state, 24, + (u16) ((bw->internal / 2 * 1000) & 0xffff)); + } dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff)); dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff)); dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003)); - dib8000_write_word(state, 922, bw->sad_cfg); + if (state->revision != 0x8090) + dib8000_write_word(state, 922, bw->sad_cfg); } static void dib8000_reset_pll(struct dib8000_state *state) { const struct dibx000_bandwidth_config *pll = state->cfg.pll; - u16 clk_cfg1; - - // clk_cfg0 - dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); - - // clk_cfg1 - clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | - (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | - (pll->pll_range << 1) | (pll->pll_reset << 0); - - dib8000_write_word(state, 902, clk_cfg1); - clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); - dib8000_write_word(state, 902, clk_cfg1); - - dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */ - - /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ - if (state->cfg.pll->ADClkSrc == 0) - dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | - (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); - else if (state->cfg.refclksel != 0) - dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | - ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | - (pll->ADClkSrc << 7) | (0 << 1)); - else - dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); + u16 clk_cfg1, reg; + + if (state->revision != 0x8090) { + dib8000_write_word(state, 901, + (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); + + clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | + (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | + (1 << 3) | (pll->pll_range << 1) | + (pll->pll_reset << 0); + + dib8000_write_word(state, 902, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); + dib8000_write_word(state, 902, clk_cfg1); + + dprintk("clk_cfg1: 0x%04x", clk_cfg1); + + /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ + if (state->cfg.pll->ADClkSrc == 0) + dib8000_write_word(state, 904, + (0 << 15) | (0 << 12) | (0 << 10) | + (pll->modulo << 8) | + (pll->ADClkSrc << 7) | (0 << 1)); + else if (state->cfg.refclksel != 0) + dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | + ((state->cfg.refclksel & 0x3) << 10) | + (pll->modulo << 8) | + (pll->ADClkSrc << 7) | (0 << 1)); + else + dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | + (3 << 10) | (pll->modulo << 8) | + (pll->ADClkSrc << 7) | (0 << 1)); + } else { + dib8000_write_word(state, 1856, (!pll->pll_reset<<13) | + (pll->pll_range<<12) | (pll->pll_ratio<<6) | + (pll->pll_prediv)); + + reg = dib8000_read_word(state, 1857); + dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15)); + + reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */ + dib8000_write_word(state, 1858, reg | 1); + + dib8000_write_word(state, 904, (pll->modulo << 8)); + } dib8000_reset_pll_common(state, pll); } +int dib8000_update_pll(struct dvb_frontend *fe, + struct dibx000_bandwidth_config *pll) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856); + u8 loopdiv, prediv; + u32 internal, xtal; + + /* get back old values */ + prediv = reg_1856 & 0x3f; + loopdiv = (reg_1856 >> 6) & 0x3f; + + if ((pll != NULL) && (pll->pll_prediv != prediv || + pll->pll_ratio != loopdiv)) { + dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); + reg_1856 &= 0xf000; + reg_1857 = dib8000_read_word(state, 1857); + /* disable PLL */ + dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15)); + + dib8000_write_word(state, 1856, reg_1856 | + ((pll->pll_ratio & 0x3f) << 6) | + (pll->pll_prediv & 0x3f)); + + /* write new system clk into P_sec_len */ + internal = dib8000_read32(state, 23) / 1000; + dprintk("Old Internal = %d", internal); + xtal = 2 * (internal / loopdiv) * prediv; + internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio; + dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000); + dprintk("New Internal = %d", internal); + + dib8000_write_word(state, 23, + (u16) (((internal / 2) >> 16) & 0xffff)); + dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff)); + /* enable PLL */ + dib8000_write_word(state, 1857, reg_1857 | (1 << 15)); + + while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1) + dprintk("Waiting for PLL to lock"); + + /* verify */ + reg_1856 = dib8000_read_word(state, 1856); + dprintk("PLL Updated with prediv = %d and loopdiv = %d", + reg_1856&0x3f, (reg_1856>>6)&0x3f); + + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL(dib8000_update_pll); + + static int dib8000_reset_gpio(struct dib8000_state *st) { /* reset the GPIOs */ @@ -721,9 +870,6 @@ static const u16 dib8000_defaults[] = { (3 << 5) | /* P_ctrl_pre_freq_step=3 */ (1 << 0), /* P_pre_freq_win_len=1 */ - 1, 903, - (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW) - 0, }; @@ -740,7 +886,8 @@ static u16 dib8000_identify(struct i2c_device *client) } value = dib8000_i2c_read16(client, 897); - if (value != 0x8000 && value != 0x8001 && value != 0x8002) { + if (value != 0x8000 && value != 0x8001 && + value != 0x8002 && value != 0x8090) { dprintk("wrong Device ID (%x)", value); return 0; } @@ -755,6 +902,9 @@ static u16 dib8000_identify(struct i2c_device *client) case 0x8002: dprintk("found DiB8000C"); break; + case 0x8090: + dprintk("found DiB8096P"); + break; } return value; } @@ -763,17 +913,19 @@ static int dib8000_reset(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; - dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */ - if ((state->revision = dib8000_identify(&state->i2c)) == 0) return -EINVAL; + /* sram lead in, rdy */ + if (state->revision != 0x8090) + dib8000_write_word(state, 1287, 0x0003); + if (state->revision == 0x8000) dprintk("error : dib8000 MA not supported"); dibx000_reset_i2c_master(&state->i2c_master); - dib8000_set_power_mode(state, DIB8000M_POWER_ALL); + dib8000_set_power_mode(state, DIB8000_POWER_ALL); /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ dib8000_set_adc_state(state, DIBX000_VBG_ENABLE); @@ -782,8 +934,10 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_write_word(state, 770, 0xffff); dib8000_write_word(state, 771, 0xffff); dib8000_write_word(state, 772, 0xfffc); - dib8000_write_word(state, 898, 0x000c); // sad - dib8000_write_word(state, 1280, 0x004d); + if (state->revision == 0x8090) + dib8000_write_word(state, 1280, 0x0045); + else + dib8000_write_word(state, 1280, 0x004d); dib8000_write_word(state, 1281, 0x000c); dib8000_write_word(state, 770, 0x0000); @@ -794,19 +948,25 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_write_word(state, 1281, 0x0000); /* drives */ - if (state->cfg.drives) - dib8000_write_word(state, 906, state->cfg.drives); - else { - dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); - dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust + if (state->revision != 0x8090) { + if (state->cfg.drives) + dib8000_write_word(state, 906, state->cfg.drives); + else { + dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); + /* min drive SDRAM - not optimal - adjust */ + dib8000_write_word(state, 906, 0x2d98); + } } dib8000_reset_pll(state); + if (state->revision != 0x8090) + dib8000_write_word(state, 898, 0x0004); if (dib8000_reset_gpio(state) != 0) dprintk("GPIO reset was not successful."); - if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0) + if ((state->revision != 0x8090) && + (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)) dprintk("OUTPUT_MODE could not be resetted."); state->current_agc = NULL; @@ -832,6 +992,8 @@ static int dib8000_reset(struct dvb_frontend *fe) l = *n++; } } + if (state->revision != 0x8090) + dib8000_write_word(state, 903, (0 << 4) | 2); state->isdbt_cfg_loaded = 0; //div_cfg override for special configs @@ -844,10 +1006,12 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_set_bandwidth(fe, 6000); dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); - dib8000_sad_calib(state); - dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + if (state->revision != 0x8090) { + dib8000_sad_calib(state); + dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + } - dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); + dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); return 0; } @@ -879,6 +1043,8 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) { struct dibx000_agc_config *agc = NULL; int i; + u16 reg; + if (state->current_band == band && state->current_agc != NULL) return 0; state->current_band = band; @@ -914,6 +1080,12 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) dib8000_write_word(state, 106, state->wbd_ref); else // use default dib8000_write_word(state, 106, agc->wbd_ref); + + if (state->revision == 0x8090) { + reg = dib8000_read_word(state, 922) & (0x3 << 2); + dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2)); + } + dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); dib8000_write_word(state, 108, agc->agc1_max); dib8000_write_word(state, 109, agc->agc1_min); @@ -925,7 +1097,10 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); dib8000_write_word(state, 75, agc->agc1_pt3); - dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */ + if (state->revision != 0x8090) + dib8000_write_word(state, 923, + (dib8000_read_word(state, 923) & 0xffe3) | + (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); return 0; } @@ -968,14 +1143,30 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; enum frontend_tune_state *tune_state = &state->tune_state; - int ret = 0; + u16 reg, upd_demod_gain_period = 0x8000; switch (*tune_state) { case CT_AGC_START: // set power-up level: interf+analog+AGC - dib8000_set_adc_state(state, DIBX000_ADC_ON); + if (state->revision != 0x8090) + dib8000_set_adc_state(state, DIBX000_ADC_ON); + else { + dib8000_set_power_mode(state, DIB8000_POWER_ALL); + + reg = dib8000_read_word(state, 1947)&0xff00; + dib8000_write_word(state, 1946, + upd_demod_gain_period & 0xFFFF); + /* bit 14 = enDemodGain */ + dib8000_write_word(state, 1947, reg | (1<<14) | + ((upd_demod_gain_period >> 16) & 0xFF)); + + /* enable adc i & q */ + reg = dib8000_read_word(state, 1920); + dib8000_write_word(state, 1920, (reg | 0x3) & + (~(1 << 7))); + } if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) { *tune_state = CT_AGC_STOP; @@ -1026,6 +1217,579 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) } +static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive) +{ + u16 reg; + + drive &= 0x7; + + /* drive host bus 2, 3, 4 */ + reg = dib8000_read_word(state, 1798) & + ~(0x7 | (0x7 << 6) | (0x7 << 12)); + reg |= (drive<<12) | (drive<<6) | drive; + dib8000_write_word(state, 1798, reg); + + /* drive host bus 5,6 */ + reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); + reg |= (drive<<8) | (drive<<2); + dib8000_write_word(state, 1799, reg); + + /* drive host bus 7, 8, 9 */ + reg = dib8000_read_word(state, 1800) & + ~(0x7 | (0x7 << 6) | (0x7 << 12)); + reg |= (drive<<12) | (drive<<6) | drive; + dib8000_write_word(state, 1800, reg); + + /* drive host bus 10, 11 */ + reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); + reg |= (drive<<8) | (drive<<2); + dib8000_write_word(state, 1801, reg); + + /* drive host bus 12, 13, 14 */ + reg = dib8000_read_word(state, 1802) & + ~(0x7 | (0x7 << 6) | (0x7 << 12)); + reg |= (drive<<12) | (drive<<6) | drive; + dib8000_write_word(state, 1802, reg); +} + +static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout, + u32 insertExtSynchro, u32 syncSize) +{ + u32 quantif = 3; + u32 nom = (insertExtSynchro * P_Kin+syncSize); + u32 denom = P_Kout; + u32 syncFreq = ((nom << quantif) / denom); + + if ((syncFreq & ((1 << quantif) - 1)) != 0) + syncFreq = (syncFreq >> quantif) + 1; + else + syncFreq = (syncFreq >> quantif); + + if (syncFreq != 0) + syncFreq = syncFreq - 1; + + return syncFreq; +} + +static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin, + u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, + u32 syncWord, u32 syncSize) +{ + dprintk("Configure DibStream Tx"); + + dib8000_write_word(state, 1615, 1); + dib8000_write_word(state, 1603, P_Kin); + dib8000_write_word(state, 1605, P_Kout); + dib8000_write_word(state, 1606, insertExtSynchro); + dib8000_write_word(state, 1608, synchroMode); + dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff); + dib8000_write_word(state, 1610, syncWord & 0xffff); + dib8000_write_word(state, 1612, syncSize); + dib8000_write_word(state, 1615, 0); +} + +static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin, + u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, + u32 syncWord, u32 syncSize, u32 dataOutRate) +{ + u32 syncFreq; + + dprintk("Configure DibStream Rx synchroMode = %d", synchroMode); + + if ((P_Kin != 0) && (P_Kout != 0)) { + syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout, + insertExtSynchro, syncSize); + dib8000_write_word(state, 1542, syncFreq); + } + + dib8000_write_word(state, 1554, 1); + dib8000_write_word(state, 1536, P_Kin); + dib8000_write_word(state, 1537, P_Kout); + dib8000_write_word(state, 1539, synchroMode); + dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff); + dib8000_write_word(state, 1541, syncWord & 0xffff); + dib8000_write_word(state, 1543, syncSize); + dib8000_write_word(state, 1544, dataOutRate); + dib8000_write_word(state, 1554, 0); +} + +static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff) +{ + u16 reg_1287; + + reg_1287 = dib8000_read_word(state, 1287); + + switch (onoff) { + case 1: + reg_1287 &= ~(1 << 8); + break; + case 0: + reg_1287 |= (1 << 8); + break; + } + + dib8000_write_word(state, 1287, reg_1287); +} + +static void dib8096p_configMpegMux(struct dib8000_state *state, + u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) +{ + u16 reg_1287; + + dprintk("Enable Mpeg mux"); + + dib8096p_enMpegMux(state, 0); + + /* If the input mode is MPEG do not divide the serial clock */ + if ((enSerialMode == 1) && (state->input_mode_mpeg == 1)) + enSerialClkDiv2 = 0; + + reg_1287 = ((pulseWidth & 0x1f) << 3) | + ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1); + dib8000_write_word(state, 1287, reg_1287); + + dib8096p_enMpegMux(state, 1); +} + +static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode) +{ + u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7); + + switch (mode) { + case MPEG_ON_DIBTX: + dprintk("SET MPEG ON DIBSTREAM TX"); + dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); + reg_1288 |= (1 << 9); break; + case DIV_ON_DIBTX: + dprintk("SET DIV_OUT ON DIBSTREAM TX"); + dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); + reg_1288 |= (1 << 8); break; + case ADC_ON_DIBTX: + dprintk("SET ADC_OUT ON DIBSTREAM TX"); + dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); + reg_1288 |= (1 << 7); break; + default: + break; + } + dib8000_write_word(state, 1288, reg_1288); +} + +static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode) +{ + u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4); + + switch (mode) { + case DEMOUT_ON_HOSTBUS: + dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); + dib8096p_enMpegMux(state, 0); + reg_1288 |= (1 << 6); + break; + case DIBTX_ON_HOSTBUS: + dprintk("SET DIBSTREAM TX ON HOST BUS"); + dib8096p_enMpegMux(state, 0); + reg_1288 |= (1 << 5); + break; + case MPEG_ON_HOSTBUS: + dprintk("SET MPEG MUX ON HOST BUS"); + reg_1288 |= (1 << 4); + break; + default: + break; + } + dib8000_write_word(state, 1288, reg_1288); +} + +static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 reg_1287; + + switch (onoff) { + case 0: /* only use the internal way - not the diversity input */ + dprintk("%s mode OFF : by default Enable Mpeg INPUT", + __func__); + /* outputRate = 8 */ + dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); + + /* Do not divide the serial clock of MPEG MUX in + SERIAL MODE in case input mode MPEG is used */ + reg_1287 = dib8000_read_word(state, 1287); + /* enSerialClkDiv2 == 1 ? */ + if ((reg_1287 & 0x1) == 1) { + /* force enSerialClkDiv2 = 0 */ + reg_1287 &= ~0x1; + dib8000_write_word(state, 1287, reg_1287); + } + state->input_mode_mpeg = 1; + break; + case 1: /* both ways */ + case 2: /* only the diversity input */ + dprintk("%s ON : Enable diversity INPUT", __func__); + dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); + state->input_mode_mpeg = 0; + break; + } + + dib8000_set_diversity_in(state->fe[0], onoff); + return 0; +} + +static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 outreg, smo_mode, fifo_threshold; + u8 prefer_mpeg_mux_use = 1; + int ret = 0; + + dib8096p_host_bus_drive(state, 1); + + fifo_threshold = 1792; + smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); + outreg = dib8000_read_word(state, 1286) & + ~((1 << 10) | (0x7 << 6) | (1 << 1)); + + switch (mode) { + case OUTMODE_HIGH_Z: + outreg = 0; + break; + + case OUTMODE_MPEG2_SERIAL: + if (prefer_mpeg_mux_use) { + dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux"); + dib8096p_configMpegMux(state, 3, 1, 1); + dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); + } else {/* Use Smooth block */ + dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc"); + dib8096p_setHostBusMux(state, + DEMOUT_ON_HOSTBUS); + outreg |= (2 << 6) | (0 << 1); + } + break; + + case OUTMODE_MPEG2_PAR_GATED_CLK: + if (prefer_mpeg_mux_use) { + dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); + dib8096p_configMpegMux(state, 2, 0, 0); + dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); + } else { /* Use Smooth block */ + dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block"); + dib8096p_setHostBusMux(state, + DEMOUT_ON_HOSTBUS); + outreg |= (0 << 6); + } + break; + + case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ + dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block"); + dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (1 << 6); + break; + + case OUTMODE_MPEG2_FIFO: + /* Using Smooth block because not supported + by new Mpeg Mux bloc */ + dprintk("dib8096P setting output mode TS_FIFO using Smooth block"); + dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (5 << 6); + smo_mode |= (3 << 1); + fifo_threshold = 512; + break; + + case OUTMODE_DIVERSITY: + dprintk("dib8096P setting output mode MODE_DIVERSITY"); + dib8096p_setDibTxMux(state, DIV_ON_DIBTX); + dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); + break; + + case OUTMODE_ANALOG_ADC: + dprintk("dib8096P setting output mode MODE_ANALOG_ADC"); + dib8096p_setDibTxMux(state, ADC_ON_DIBTX); + dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); + break; + } + + if (mode != OUTMODE_HIGH_Z) + outreg |= (1<<10); + + dprintk("output_mpeg2_in_188_bytes = %d", + state->cfg.output_mpeg2_in_188_bytes); + if (state->cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5); + + ret |= dib8000_write_word(state, 299, smo_mode); + /* synchronous fread */ + ret |= dib8000_write_word(state, 299 + 1, fifo_threshold); + ret |= dib8000_write_word(state, 1286, outreg); + + return ret; +} + +static int map_addr_to_serpar_number(struct i2c_msg *msg) +{ + if (msg->buf[0] <= 15) + msg->buf[0] -= 1; + else if (msg->buf[0] == 17) + msg->buf[0] = 15; + else if (msg->buf[0] == 16) + msg->buf[0] = 17; + else if (msg->buf[0] == 19) + msg->buf[0] = 16; + else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) + msg->buf[0] -= 3; + else if (msg->buf[0] == 28) + msg->buf[0] = 23; + else if (msg->buf[0] == 99) + msg->buf[0] = 99; + else + return -EINVAL; + return 0; +} + +static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct dib8000_state *state = i2c_get_adapdata(i2c_adap); + u8 n_overflow = 1; + u16 i = 1000; + u16 serpar_num = msg[0].buf[0]; + + while (n_overflow == 1 && i) { + n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; + i--; + if (i == 0) + dprintk("Tuner ITF: write busy (overflow)"); + } + dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); + dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); + + return num; +} + +static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct dib8000_state *state = i2c_get_adapdata(i2c_adap); + u8 n_overflow = 1, n_empty = 1; + u16 i = 1000; + u16 serpar_num = msg[0].buf[0]; + u16 read_word; + + while (n_overflow == 1 && i) { + n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; + i--; + if (i == 0) + dprintk("TunerITF: read busy (overflow)"); + } + dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f)); + + i = 1000; + while (n_empty == 1 && i) { + n_empty = dib8000_read_word(state, 1984)&0x1; + i--; + if (i == 0) + dprintk("TunerITF: read busy (empty)"); + } + + read_word = dib8000_read_word(state, 1987); + msg[1].buf[0] = (read_word >> 8) & 0xff; + msg[1].buf[1] = (read_word) & 0xff; + + return num; +} + +static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + if (map_addr_to_serpar_number(&msg[0]) == 0) { + if (num == 1) /* write */ + return dib8096p_tuner_write_serpar(i2c_adap, msg, 1); + else /* read */ + return dib8096p_tuner_read_serpar(i2c_adap, msg, 2); + } + return num; +} + +static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num, u16 apb_address) +{ + struct dib8000_state *state = i2c_get_adapdata(i2c_adap); + u16 word; + + if (num == 1) { /* write */ + dib8000_write_word(state, apb_address, + ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); + } else { + word = dib8000_read_word(state, apb_address); + msg[1].buf[0] = (word >> 8) & 0xff; + msg[1].buf[1] = (word) & 0xff; + } + return num; +} + +static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct dib8000_state *state = i2c_get_adapdata(i2c_adap); + u16 apb_address = 0, word; + int i = 0; + + switch (msg[0].buf[0]) { + case 0x12: + apb_address = 1920; + break; + case 0x14: + apb_address = 1921; + break; + case 0x24: + apb_address = 1922; + break; + case 0x1a: + apb_address = 1923; + break; + case 0x22: + apb_address = 1924; + break; + case 0x33: + apb_address = 1926; + break; + case 0x34: + apb_address = 1927; + break; + case 0x35: + apb_address = 1928; + break; + case 0x36: + apb_address = 1929; + break; + case 0x37: + apb_address = 1930; + break; + case 0x38: + apb_address = 1931; + break; + case 0x39: + apb_address = 1932; + break; + case 0x2a: + apb_address = 1935; + break; + case 0x2b: + apb_address = 1936; + break; + case 0x2c: + apb_address = 1937; + break; + case 0x2d: + apb_address = 1938; + break; + case 0x2e: + apb_address = 1939; + break; + case 0x2f: + apb_address = 1940; + break; + case 0x30: + apb_address = 1941; + break; + case 0x31: + apb_address = 1942; + break; + case 0x32: + apb_address = 1943; + break; + case 0x3e: + apb_address = 1944; + break; + case 0x3f: + apb_address = 1945; + break; + case 0x40: + apb_address = 1948; + break; + case 0x25: + apb_address = 936; + break; + case 0x26: + apb_address = 937; + break; + case 0x27: + apb_address = 938; + break; + case 0x28: + apb_address = 939; + break; + case 0x1d: + /* get sad sel request */ + i = ((dib8000_read_word(state, 921) >> 12)&0x3); + word = dib8000_read_word(state, 924+i); + msg[1].buf[0] = (word >> 8) & 0xff; + msg[1].buf[1] = (word) & 0xff; + return num; + case 0x1f: + if (num == 1) { /* write */ + word = (u16) ((msg[0].buf[1] << 8) | + msg[0].buf[2]); + /* in the VGAMODE Sel are located on bit 0/1 */ + word &= 0x3; + word = (dib8000_read_word(state, 921) & + ~(3<<12)) | (word<<12); + /* Set the proper input */ + dib8000_write_word(state, 921, word); + return num; + } + } + + if (apb_address != 0) /* R/W acces via APB */ + return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address); + else /* R/W access via SERPAR */ + return dib8096p_tuner_rw_serpar(i2c_adap, msg, num); + + return 0; +} + +static u32 dib8096p_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dib8096p_tuner_xfer_algo = { + .master_xfer = dib8096p_tuner_xfer, + .functionality = dib8096p_i2c_func, +}; + +struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) +{ + struct dib8000_state *st = fe->demodulator_priv; + return &st->dib8096p_tuner_adap; +} +EXPORT_SYMBOL(dib8096p_get_i2c_tuner); + +int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 en_cur_state; + + dprintk("sleep dib8096p: %d", onoff); + + en_cur_state = dib8000_read_word(state, 1922); + + /* LNAs and MIX are ON and therefore it is a valid configuration */ + if (en_cur_state > 0xff) + state->tuner_enable = en_cur_state ; + + if (onoff) + en_cur_state &= 0x00ff; + else { + if (state->tuner_enable != 0) + en_cur_state = state->tuner_enable; + } + + dib8000_write_word(state, 1922, en_cur_state); + + return 0; +} +EXPORT_SYMBOL(dib8096p_tuner_sleep); + static const s32 lut_1000ln_mant[] = { 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 @@ -1051,6 +1815,26 @@ s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) } EXPORT_SYMBOL(dib8000_get_adc_power); +int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) +{ + struct dib8000_state *state = fe->demodulator_priv; + int val = 0; + + switch (IQ) { + case 1: + val = dib8000_read_word(state, 403); + break; + case 0: + val = dib8000_read_word(state, 404); + break; + } + if (val & 0x200) + val -= 1024; + + return val; +} +EXPORT_SYMBOL(dib8090p_get_dc_power); + static void dib8000_update_timf(struct dib8000_state *state) { u32 timf = state->timf = dib8000_read32(state, 435); @@ -1060,6 +1844,26 @@ static void dib8000_update_timf(struct dib8000_state *state) dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); } +u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf) +{ + struct dib8000_state *state = fe->demodulator_priv; + + switch (op) { + case DEMOD_TIMF_SET: + state->timf = timf; + break; + case DEMOD_TIMF_UPDATE: + dib8000_update_timf(state); + break; + case DEMOD_TIMF_GET: + break; + } + dib8000_set_bandwidth(state->fe[0], 6000); + + return state->timf; +} +EXPORT_SYMBOL(dib8000_ctrl_timf); + static const u16 adc_target_16dB[11] = { (1 << 13) - 825 - 117, (1 << 13) - 837 - 117, @@ -1086,6 +1890,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear u16 init_prbs = 0xfff; u16 ana_gain = 0; + if (state->revision == 0x8090) + dib8000_init_sdram(state); + if (state->ber_monitored_layer != LAYER_ALL) dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer); else @@ -1418,7 +2225,10 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask); state->differential_constellation = (seg_diff_mask != 0); - dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); + if (state->revision != 0x8090) + dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); + else + dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff); if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) @@ -1870,7 +2680,7 @@ static int dib8000_tune(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; int ret = 0; - u16 value, mode = fft_to_mode(state); + u16 lock, value, mode = fft_to_mode(state); // we are already tuned - just resuming from suspend if (state == NULL) @@ -1924,7 +2734,11 @@ static int dib8000_tune(struct dvb_frontend *fe) } // we achieved a coff_cpil_lock - it's time to update the timf - if ((dib8000_read_word(state, 568) >> 11) & 0x1) + if (state->revision != 0x8090) + lock = dib8000_read_word(state, 568); + else + lock = dib8000_read_word(state, 570); + if ((lock >> 11) & 0x1) dib8000_update_timf(state); //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start @@ -1946,11 +2760,14 @@ static int dib8000_wakeup(struct dvb_frontend *fe) u8 index_frontend; int ret; - dib8000_set_power_mode(state, DIB8000M_POWER_ALL); + dib8000_set_power_mode(state, DIB8000_POWER_ALL); dib8000_set_adc_state(state, DIBX000_ADC_ON); if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) dprintk("could not start Slow ADC"); + if (state->revision != 0x8090) + dib8000_sad_calib(state); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); if (ret < 0) @@ -1972,8 +2789,9 @@ static int dib8000_sleep(struct dvb_frontend *fe) return ret; } - dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); - dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); + if (state->revision != 0x8090) + dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); + dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); } @@ -1992,7 +2810,7 @@ int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tun } EXPORT_SYMBOL(dib8000_set_tune_state); -static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib8000_get_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; u16 i, val = 0; @@ -2006,7 +2824,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par if (stat&FE_HAS_SYNC) { dprintk("TMCC lock on the slave%i", index_frontend); /* synchronize the cache with the other frontends */ - state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); + state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]); for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { if (sub_index_frontend != index_frontend) { state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; @@ -2028,7 +2846,10 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; - val = dib8000_read_word(state, 570); + if (state->revision == 0x8090) + val = dib8000_read_word(state, 572); + else + val = dib8000_read_word(state, 570); fe->dtv_property_cache.inversion = (val & 0x40) >> 6; switch ((val & 0x30) >> 4) { case 1: @@ -2135,7 +2956,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par return 0; } -static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib8000_set_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; u8 nbr_pending, exit_condition, index_frontend; @@ -2158,9 +2979,14 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); - dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); + if (state->revision != 0x8090) + dib8000_set_output_mode(state->fe[index_frontend], + OUTMODE_HIGH_Z); + else + dib8096p_set_output_mode(state->fe[index_frontend], + OUTMODE_HIGH_Z); if (state->fe[index_frontend]->ops.tuner_ops.set_params) - state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep); + state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]); dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); } @@ -2215,7 +3041,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { - int i = 80000; + int i = 100; u8 found = 0; u8 tune_failed = 0; @@ -2243,6 +3069,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par default: dprintk("unhandled autosearch result"); case 1: + tune_failed |= (1 << index_frontend); dprintk("autosearch failed for the frontend%i", index_frontend); break; } @@ -2261,21 +3088,44 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par dprintk("tune success on frontend%i", index_frontend_success); - dib8000_get_frontend(fe, fep); + dib8000_get_frontend(fe); } for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) ret = dib8000_tune(state->fe[index_frontend]); /* set output mode and diversity input */ - dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); - dib8000_set_diversity_in(state->fe[index_frontend-1], 1); - } + if (state->revision != 0x8090) { + dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); + for (index_frontend = 1; + (index_frontend < MAX_NUMBER_OF_FRONTENDS) && + (state->fe[index_frontend] != NULL); + index_frontend++) { + dib8000_set_output_mode(state->fe[index_frontend], + OUTMODE_DIVERSITY); + dib8000_set_diversity_in(state->fe[index_frontend-1], 1); + } - /* turn off the diversity of the last chip */ - dib8000_set_diversity_in(state->fe[index_frontend-1], 0); + /* turn off the diversity of the last chip */ + dib8000_set_diversity_in(state->fe[index_frontend-1], 0); + } else { + dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode); + if (state->cfg.enMpegOutput == 0) { + dib8096p_setDibTxMux(state, MPEG_ON_DIBTX); + dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); + } + for (index_frontend = 1; + (index_frontend < MAX_NUMBER_OF_FRONTENDS) && + (state->fe[index_frontend] != NULL); + index_frontend++) { + dib8096p_set_output_mode(state->fe[index_frontend], + OUTMODE_DIVERSITY); + dib8096p_set_diversity_in(state->fe[index_frontend-1], 1); + } + + /* turn off the diversity of the last chip */ + dib8096p_set_diversity_in(state->fe[index_frontend-1], 0); + } return ret; } @@ -2284,15 +3134,22 @@ static u16 dib8000_read_lock(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; + if (state->revision == 0x8090) + return dib8000_read_word(state, 570); return dib8000_read_word(state, 568); } static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) { struct dib8000_state *state = fe->demodulator_priv; - u16 lock_slave = 0, lock = dib8000_read_word(state, 568); + u16 lock_slave = 0, lock; u8 index_frontend; + if (state->revision == 0x8090) + lock = dib8000_read_word(state, 570); + else + lock = dib8000_read_word(state, 568); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) lock_slave |= dib8000_read_lock(state->fe[index_frontend]); @@ -2330,14 +3187,26 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber) { struct dib8000_state *state = fe->demodulator_priv; - *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments + + /* 13 segments */ + if (state->revision == 0x8090) + *ber = (dib8000_read_word(state, 562) << 16) | + dib8000_read_word(state, 563); + else + *ber = (dib8000_read_word(state, 560) << 16) | + dib8000_read_word(state, 561); return 0; } static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) { struct dib8000_state *state = fe->demodulator_priv; - *unc = dib8000_read_word(state, 565); // packet error on 13 seg + + /* packet error on 13 seg */ + if (state->revision == 0x8090) + *unc = dib8000_read_word(state, 567); + else + *unc = dib8000_read_word(state, 565); return 0; } @@ -2370,14 +3239,20 @@ static u32 dib8000_get_snr(struct dvb_frontend *fe) u32 n, s, exp; u16 val; - val = dib8000_read_word(state, 542); + if (state->revision != 0x8090) + val = dib8000_read_word(state, 542); + else + val = dib8000_read_word(state, 544); n = (val >> 6) & 0xff; exp = (val & 0x3f); if ((exp & 0x20) != 0) exp -= 0x40; n <<= exp+16; - val = dib8000_read_word(state, 543); + if (state->revision != 0x8090) + val = dib8000_read_word(state, 543); + else + val = dib8000_read_word(state, 545); s = (val >> 6) & 0xff; exp = (val & 0x3f); if ((exp & 0x20) != 0) @@ -2401,7 +3276,7 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) snr_master += dib8000_get_snr(state->fe[index_frontend]); - if (snr_master != 0) { + if ((snr_master >> 16) != 0) { snr_master = 10*intlog10(snr_master>>16); *snr = snr_master / ((1 << 24) / 10); } @@ -2458,7 +3333,8 @@ struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int sla EXPORT_SYMBOL(dib8000_get_slave_frontend); -int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, + u8 default_addr, u8 first_addr, u8 is_dib8096p) { int k = 0, ret = 0; u8 new_addr = 0; @@ -2488,9 +3364,12 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau new_addr = first_addr + (k << 1); client.addr = new_addr; - dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ - if (dib8000_identify(&client) == 0) { + if (!is_dib8096p) dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ + if (dib8000_identify(&client) == 0) { + /* sram lead in, rdy */ + if (!is_dib8096p) + dib8000_i2c_write16(&client, 1287, 0x0003); client.addr = default_addr; if (dib8000_identify(&client) == 0) { dprintk("#%d: not identified", k); @@ -2549,6 +3428,7 @@ static void dib8000_release(struct dvb_frontend *fe) dvb_frontend_detach(st->fe[index_frontend]); dibx000_exit_i2c_master(&st->i2c_master); + i2c_del_adapter(&st->dib8096p_tuner_adap); kfree(st->fe[0]); kfree(st); } @@ -2581,9 +3461,9 @@ int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) EXPORT_SYMBOL(dib8000_pid_filter); static const struct dvb_frontend_ops dib8000_ops = { + .delsys = { SYS_ISDBT }, .info = { .name = "DiBcom 8000 ISDB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, @@ -2651,6 +3531,15 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); + /* init 8096p tuner adapter */ + strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", + sizeof(state->dib8096p_tuner_adap.name)); + state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo; + state->dib8096p_tuner_adap.algo_data = NULL; + state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent; + i2c_set_adapdata(&state->dib8096p_tuner_adap, state); + i2c_add_adapter(&state->dib8096p_tuner_adap); + dib8000_reset(fe); dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h index 617f9eba3a09..39591bb172c1 100644 --- a/drivers/media/dvb/frontends/dib8000.h +++ b/drivers/media/dvb/frontends/dib8000.h @@ -32,6 +32,7 @@ struct dib8000_config { u8 div_cfg; u8 output_mode; u8 refclksel; + u8 enMpegOutput:1; }; #define DEFAULT_DIB8000_I2C_ADDRESS 18 @@ -40,7 +41,8 @@ struct dib8000_config { extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg); extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); -extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); +extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, + u8 default_addr, u8 first_addr, u8 is_dib8096p); extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); @@ -50,6 +52,13 @@ extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_st extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe); extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); +extern struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe); +extern int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff); +extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ); +extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe, + uint8_t op, uint32_t timf); +extern int dib8000_update_pll(struct dvb_frontend *fe, + struct dibx000_bandwidth_config *pll); extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe); extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); @@ -66,7 +75,9 @@ static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe return NULL; } -static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, + int no_of_demods, u8 default_addr, u8 first_addr, + u8 is_dib8096p) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; @@ -109,11 +120,38 @@ static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); } +static inline struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return 0; } +static inline int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} +static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe, + uint8_t op, uint32_t timf) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} +static inline int dib8000_update_pll(struct dvb_frontend *fe, + struct dibx000_bandwidth_config *pll) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index 660f80661ed4..863ef3cfab9f 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -1136,7 +1136,7 @@ static int dib9000_fw_init(struct dib9000_state *state) return 0; } -static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_frontend_parameters *ch) +static void dib9000_fw_set_channel_head(struct dib9000_state *state) { u8 b[9]; u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000; @@ -1157,7 +1157,7 @@ static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_ dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b); } -static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) +static int dib9000_fw_get_channel(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; struct dibDVBTChannel { @@ -1309,7 +1309,7 @@ error: return ret; } -static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) +static int dib9000_fw_set_channel_union(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; struct dibDVBTChannel { @@ -1454,7 +1454,7 @@ static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_fron return 0; } -static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +static int dib9000_fw_tune(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN; @@ -1462,7 +1462,7 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete switch (state->tune_state) { case CT_DEMOD_START: - dib9000_fw_set_channel_head(state, ch); + dib9000_fw_set_channel_head(state); /* write the channel context - a channel is initialized to 0, so it is OK */ dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info); @@ -1471,7 +1471,7 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete if (search) dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0); else { - dib9000_fw_set_channel_union(fe, ch); + dib9000_fw_set_channel_union(fe); dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0); } state->tune_state = CT_DEMOD_STEP_1; @@ -1867,7 +1867,7 @@ static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_fron return 0; } -static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib9000_get_frontend(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend, sub_index_frontend; @@ -1883,7 +1883,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par dprintk("TPS lock on the slave%i", index_frontend); /* synchronize the cache with the other frontends */ - state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); + state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]); for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { if (sub_index_frontend != index_frontend) { @@ -1911,7 +1911,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } /* get the channel from master chip */ - ret = dib9000_fw_get_channel(fe, fep); + ret = dib9000_fw_get_channel(fe); if (ret != 0) goto return_value; @@ -1958,7 +1958,7 @@ static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_fronte return 0; } -static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib9000_set_frontend(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; int sleep_time, sleep_time_slave; @@ -1983,8 +1983,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par fe->dtv_property_cache.delivery_system = SYS_DVBT; /* set the master status */ - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO || + state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO || + state->fe[0]->dtv_property_cache.modulation == QAM_AUTO || + state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) { /* no channel specified, autosearch the channel */ state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN; } else @@ -2008,9 +2010,9 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ index_frontend_success = 0; do { - sleep_time = dib9000_fw_tune(state->fe[0], NULL); + sleep_time = dib9000_fw_tune(state->fe[0]); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); + sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]); if (sleep_time == FE_CALLBACK_TIME_NEVER) sleep_time = sleep_time_slave; else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) @@ -2052,7 +2054,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* synchronize all the channel cache */ state->get_frontend_internal = 1; - dib9000_get_frontend(state->fe[0], fep); + dib9000_get_frontend(state->fe[0]); state->get_frontend_internal = 0; /* retune the other frontends with the found channel */ @@ -2068,7 +2070,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par sleep_time = FE_CALLBACK_TIME_NEVER; for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { if (index_frontend != index_frontend_success) { - sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); + sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]); if (sleep_time == FE_CALLBACK_TIME_NEVER) sleep_time = sleep_time_slave; else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) @@ -2495,9 +2497,9 @@ error: EXPORT_SYMBOL(dib9000_attach); static struct dvb_frontend_ops dib9000_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 9000", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 5e011474be43..5f484881d7b1 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -146,14 +146,8 @@ enum dibx000_adc_states { DIBX000_VBG_DISABLE, }; -#define BANDWIDTH_TO_KHZ(v) ((v) == BANDWIDTH_8_MHZ ? 8000 : \ - (v) == BANDWIDTH_7_MHZ ? 7000 : \ - (v) == BANDWIDTH_6_MHZ ? 6000 : 8000) - -#define BANDWIDTH_TO_INDEX(v) ( \ - (v) == 8000 ? BANDWIDTH_8_MHZ : \ - (v) == 7000 ? BANDWIDTH_7_MHZ : \ - (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ ) +#define BANDWIDTH_TO_KHZ(v) ((v) / 1000) +#define BANDWIDTH_TO_HZ(v) ((v) * 1000) /* Chip output mode. */ #define OUTMODE_HIGH_Z 0 @@ -276,4 +270,11 @@ struct dibSubbandSelection { #define DEMOD_TIMF_GET 0x01 #define DEMOD_TIMF_UPDATE 0x02 +#define MPEG_ON_DIBTX 1 +#define DIV_ON_DIBTX 2 +#define ADC_ON_DIBTX 3 +#define DEMOUT_ON_HOSTBUS 4 +#define DIBTX_ON_HOSTBUS 5 +#define MPEG_ON_HOSTBUS 6 + #endif diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h index 7113535844f2..34398738f9bc 100644 --- a/drivers/media/dvb/frontends/drxd.h +++ b/drivers/media/dvb/frontends/drxd.h @@ -48,8 +48,6 @@ struct drxd_config { u8 disable_i2c_gate_ctrl; u32 IF; - int (*pll_set) (void *priv, void *priv_params, - u8 pll_addr, u8 demoda_addr, s32 *off); s16(*osc_deviation) (void *priv, s16 dev, int flag); }; diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c index 88e46f4cdbb2..7bf39cda83c5 100644 --- a/drivers/media/dvb/frontends/drxd_hard.c +++ b/drivers/media/dvb/frontends/drxd_hard.c @@ -120,7 +120,7 @@ enum EIFFilter { struct drxd_state { struct dvb_frontend frontend; struct dvb_frontend_ops ops; - struct dvb_frontend_parameters param; + struct dtv_frontend_properties props; const struct firmware *fw; struct device *dev; @@ -914,14 +914,13 @@ static int load_firmware(struct drxd_state *state, const char *fw_name) return -EIO; } - state->microcode = kmalloc(fw->size, GFP_KERNEL); + state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL); if (state->microcode == NULL) { release_firmware(fw); printk(KERN_ERR "drxd: firmware load failure: no memory\n"); return -ENOMEM; } - memcpy(state->microcode, fw->data, fw->size); state->microcode_length = fw->size; release_firmware(fw); return 0; @@ -1622,14 +1621,14 @@ static int CorrectSysClockDeviation(struct drxd_state *state) break; } - switch (state->param.u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: + switch (state->props.bandwidth_hz) { + case 8000000: bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ; break; - case BANDWIDTH_7_MHZ: + case 7000000: bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ; break; - case BANDWIDTH_6_MHZ: + case 6000000: bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ; break; default: @@ -1804,7 +1803,7 @@ static int StartDiversity(struct drxd_state *state) status = WriteTable(state, state->m_StartDiversityEnd); if (status < 0) break; - if (state->param.u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + if (state->props.bandwidth_hz == 8000000) { status = WriteTable(state, state->m_DiversityDelay8MHZ); if (status < 0) break; @@ -1906,7 +1905,7 @@ static int SetCfgNoiseCalibration(struct drxd_state *state, static int DRX_Start(struct drxd_state *state, s32 off) { - struct dvb_ofdm_parameters *p = &state->param.u.ofdm; + struct dtv_frontend_properties *p = &state->props; int status; u16 transmissionParams = 0; @@ -1971,7 +1970,7 @@ static int DRX_Start(struct drxd_state *state, s32 off) if (status < 0) break; - mirrorFreqSpect = (state->param.inversion == INVERSION_ON); + mirrorFreqSpect = (state->props.inversion == INVERSION_ON); switch (p->transmission_mode) { default: /* Not set, detect it automatically */ @@ -2021,7 +2020,7 @@ static int DRX_Start(struct drxd_state *state, s32 off) break; } - switch (p->hierarchy_information) { + switch (p->hierarchy) { case HIERARCHY_1: transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1; if (state->type_A) { @@ -2147,7 +2146,7 @@ static int DRX_Start(struct drxd_state *state, s32 off) if (status < 0) break; - switch (p->constellation) { + switch (p->modulation) { default: operationMode |= SC_RA_RAM_OP_AUTO_CONST__M; /* fall through , try first guess @@ -2331,9 +2330,11 @@ static int DRX_Start(struct drxd_state *state, s32 off) by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC functions */ - switch (p->bandwidth) { - case BANDWIDTH_AUTO: - case BANDWIDTH_8_MHZ: + switch (p->bandwidth_hz) { + case 0: + p->bandwidth_hz = 8000000; + /* fall through */ + case 8000000: /* (64/7)*(8/8)*1000000 */ bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ; @@ -2341,14 +2342,14 @@ static int DRX_Start(struct drxd_state *state, s32 off) status = Write16(state, FE_AG_REG_IND_DEL__A, 50, 0x0000); break; - case BANDWIDTH_7_MHZ: + case 7000000: /* (64/7)*(7/8)*1000000 */ bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ; bandwidthParam = 0x4807; /*binary:0100 1000 0000 0111 */ status = Write16(state, FE_AG_REG_IND_DEL__A, 59, 0x0000); break; - case BANDWIDTH_6_MHZ: + case 6000000: /* (64/7)*(6/8)*1000000 */ bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ; bandwidthParam = 0x0F07; /*binary: 0000 1111 0000 0111 */ @@ -2887,41 +2888,26 @@ static int drxd_sleep(struct dvb_frontend *fe) return 0; } -static int drxd_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - return 0; -} - static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { return drxd_config_i2c(fe, enable); } -static int drxd_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int drxd_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct drxd_state *state = fe->demodulator_priv; s32 off = 0; - state->param = *param; + state->props = *p; DRX_Stop(state); if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - /* FIXME: move PLL drivers */ - if (state->config.pll_set && - state->config.pll_set(state->priv, param, - state->config.pll_address, - state->config.demoda_address, &off) < 0) { - printk(KERN_ERR "Error in pll_set\n"); - return -1; - } - msleep(200); return DRX_Start(state, off); @@ -2935,10 +2921,9 @@ static void drxd_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops drxd_ops = { - + .delsys = { SYS_DVBT}, .info = { .name = "Micronas DRXD DVB-T", - .type = FE_OFDM, .frequency_min = 47125000, .frequency_max = 855250000, .frequency_stepsize = 166667, @@ -2958,7 +2943,6 @@ static struct dvb_frontend_ops drxd_ops = { .i2c_gate_ctrl = drxd_i2c_gate_ctrl, .set_frontend = drxd_set_frontend, - .get_frontend = drxd_get_frontend, .get_tune_settings = drxd_get_tune_settings, .read_status = drxd_read_status, diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h index 58baf419560c..020981844a86 100644 --- a/drivers/media/dvb/frontends/drxk.h +++ b/drivers/media/dvb/frontends/drxk.h @@ -8,6 +8,8 @@ * struct drxk_config - Configure the initial parameters for DRX-K * * adr: I2C Address of the DRX-K + * parallel_ts: true means that the device uses parallel TS, + * Serial otherwise. * single_master: Device is on the single master mode * no_i2c_bridge: Don't switch the I2C bridge to talk with tuner * antenna_gpio: GPIO bit used to control the antenna @@ -22,22 +24,23 @@ struct drxk_config { u8 adr; bool single_master; bool no_i2c_bridge; + bool parallel_ts; bool antenna_dvbt; u16 antenna_gpio; + int chunk_size; + const char *microcode_name; }; #if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \ && defined(MODULE)) extern struct dvb_frontend *drxk_attach(const struct drxk_config *config, - struct i2c_adapter *i2c, - struct dvb_frontend **fe_t); + struct i2c_adapter *i2c); #else static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config, - struct i2c_adapter *i2c, - struct dvb_frontend **fe_t) + struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c index f6431ef827dc..6980ed7b8786 100644 --- a/drivers/media/dvb/frontends/drxk_hard.c +++ b/drivers/media/dvb/frontends/drxk_hard.c @@ -368,10 +368,10 @@ static int i2c_read(struct i2c_adapter *adap, } if (debug > 2) { int i; - dprintk(2, ": read from "); + dprintk(2, ": read from"); for (i = 0; i < len; i++) printk(KERN_CONT " %02x", msg[i]); - printk(KERN_CONT "Value = "); + printk(KERN_CONT ", value = "); for (i = 0; i < alen; i++) printk(KERN_CONT " %02x", answ[i]); printk(KERN_CONT "\n"); @@ -660,7 +660,6 @@ static int init_state(struct drxk_state *state) /* io_pad_cfg_mode output mode is drive always */ /* io_pad_cfg_drive is set to power 2 (23 mA) */ u32 ulGPIOCfg = 0x0113; - u32 ulSerialMode = 1; u32 ulInvertTSClock = 0; u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH; u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH; @@ -681,7 +680,8 @@ static int init_state(struct drxk_state *state) state->m_hasOOB = false; state->m_hasAudio = false; - state->m_ChunkSize = 124; + if (!state->m_ChunkSize) + state->m_ChunkSize = 124; state->m_oscClockFreq = 0; state->m_smartAntInverted = false; @@ -810,8 +810,6 @@ static int init_state(struct drxk_state *state) /* MPEG output configuration */ state->m_enableMPEGOutput = true; /* If TRUE; enable MPEG ouput */ state->m_insertRSByte = false; /* If TRUE; insert RS byte */ - state->m_enableParallel = true; /* If TRUE; - parallel out otherwise serial */ state->m_invertDATA = false; /* If TRUE; invert DATA signals */ state->m_invertERR = false; /* If TRUE; invert ERR signal */ state->m_invertSTR = false; /* If TRUE; invert STR signals */ @@ -856,8 +854,6 @@ static int init_state(struct drxk_state *state) state->m_bPowerDown = false; state->m_currentPowerMode = DRX_POWER_DOWN; - state->m_enableParallel = (ulSerialMode == 0); - state->m_rfmirror = (ulRfMirror == 0); state->m_IfAgcPol = false; return 0; @@ -946,6 +942,9 @@ static int GetDeviceCapabilities(struct drxk_state *state) status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo); if (status < 0) goto error; + +printk(KERN_ERR "drxk: status = 0x%08x\n", sioTopJtagidLo); + /* driver 0.9.0 */ switch ((sioTopJtagidLo >> 29) & 0xF) { case 0: @@ -963,7 +962,8 @@ static int GetDeviceCapabilities(struct drxk_state *state) default: state->m_deviceSpin = DRXK_SPIN_UNKNOWN; status = -EINVAL; - printk(KERN_ERR "drxk: Spin unknown\n"); + printk(KERN_ERR "drxk: Spin %d unknown\n", + (sioTopJtagidLo >> 29) & 0xF); goto error2; } switch ((sioTopJtagidLo >> 12) & 0xFF) { @@ -1190,7 +1190,9 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable) u16 sioPdrMclkCfg = 0; u16 sioPdrMdxCfg = 0; - dprintk(1, "\n"); + dprintk(1, ": mpeg %s, %s mode\n", + mpegEnable ? "enable" : "disable", + state->m_enableParallel ? "parallel" : "serial"); /* stop lock indicator process */ status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); @@ -1846,6 +1848,7 @@ static int SetOperationMode(struct drxk_state *state, */ switch (oMode) { case OM_DVBT: + dprintk(1, ": DVB-T\n"); state->m_OperationMode = oMode; status = SetDVBTStandard(state, oMode); if (status < 0) @@ -1853,6 +1856,8 @@ static int SetOperationMode(struct drxk_state *state, break; case OM_QAM_ITU_A: /* fallthrough */ case OM_QAM_ITU_C: + dprintk(1, ": DVB-C Annex %c\n", + (state->m_OperationMode == OM_QAM_ITU_A) ? 'A' : 'C'); state->m_OperationMode = oMode; status = SetQAMStandard(state, oMode); if (status < 0) @@ -1881,7 +1886,7 @@ static int Start(struct drxk_state *state, s32 offsetFreq, state->m_DrxkState != DRXK_DTV_STARTED) goto error; - state->m_bMirrorFreqSpect = (state->param.inversion == INVERSION_ON); + state->m_bMirrorFreqSpect = (state->props.inversion == INVERSION_ON); if (IntermediateFrequency < 0) { state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect; @@ -2503,7 +2508,7 @@ static int GetQAMSignalToNoise(struct drxk_state *state, u16 qamSlErrPower = 0; /* accum. error between raw and sliced symbols */ u32 qamSlSigPower = 0; /* used for MER, depends of - QAM constellation */ + QAM modulation */ u32 qamSlMer = 0; /* QAM MER */ dprintk(1, "\n"); @@ -2517,7 +2522,7 @@ static int GetQAMSignalToNoise(struct drxk_state *state, return -EINVAL; } - switch (state->param.u.qam.modulation) { + switch (state->props.modulation) { case QAM_16: qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2; break; @@ -2748,7 +2753,7 @@ static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality) if (status < 0) break; - switch (state->param.u.qam.modulation) { + switch (state->props.modulation) { case QAM_16: SignalToNoiseRel = SignalToNoise - 200; break; @@ -3813,7 +3818,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, /*== Write channel settings to device =====================================*/ /* mode */ - switch (state->param.u.ofdm.transmission_mode) { + switch (state->props.transmission_mode) { case TRANSMISSION_MODE_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M; @@ -3827,7 +3832,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, } /* guard */ - switch (state->param.u.ofdm.guard_interval) { + switch (state->props.guard_interval) { default: case GUARD_INTERVAL_AUTO: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M; @@ -3847,7 +3852,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, } /* hierarchy */ - switch (state->param.u.ofdm.hierarchy_information) { + switch (state->props.hierarchy) { case HIERARCHY_AUTO: case HIERARCHY_NONE: default: @@ -3867,8 +3872,8 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, } - /* constellation */ - switch (state->param.u.ofdm.constellation) { + /* modulation */ + switch (state->props.modulation) { case QAM_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M; @@ -3911,7 +3916,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, #endif /* coderate */ - switch (state->param.u.ofdm.code_rate_HP) { + switch (state->props.code_rate_HP) { case FEC_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M; @@ -3940,9 +3945,11 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, /* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC functions */ - switch (state->param.u.ofdm.bandwidth) { - case BANDWIDTH_AUTO: - case BANDWIDTH_8_MHZ: + switch (state->props.bandwidth_hz) { + case 0: + state->props.bandwidth_hz = 8000000; + /* fall though */ + case 8000000: bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ; status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052); if (status < 0) @@ -3961,7 +3968,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, if (status < 0) goto error; break; - case BANDWIDTH_7_MHZ: + case 7000000: bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ; status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491); if (status < 0) @@ -3980,7 +3987,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, if (status < 0) goto error; break; - case BANDWIDTH_6_MHZ: + case 6000000: bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ; status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073); if (status < 0) @@ -4187,7 +4194,7 @@ error: /** * \brief Setup of the QAM Measurement intervals for signal quality * \param demod instance of demod. -* \param constellation current constellation. +* \param modulation current modulation. * \return DRXStatus_t. * * NOTE: @@ -4196,7 +4203,7 @@ error: * */ static int SetQAMMeasurement(struct drxk_state *state, - enum EDrxkConstellation constellation, + enum EDrxkConstellation modulation, u32 symbolRate) { u32 fecBitsDesired = 0; /* BER accounting period */ @@ -4210,11 +4217,11 @@ static int SetQAMMeasurement(struct drxk_state *state, fecRsPrescale = 1; /* fecBitsDesired = symbolRate [kHz] * FrameLenght [ms] * - (constellation + 1) * + (modulation + 1) * SyncLoss (== 1) * ViterbiLoss (==1) */ - switch (constellation) { + switch (modulation) { case DRX_CONSTELLATION_QAM16: fecBitsDesired = 4 * symbolRate; break; @@ -5281,12 +5288,12 @@ static int QAMSetSymbolrate(struct drxk_state *state) /* Select & calculate correct IQM rate */ adcFrequency = (state->m_sysClockFreq * 1000) / 3; ratesel = 0; - /* printk(KERN_DEBUG "drxk: SR %d\n", state->param.u.qam.symbol_rate); */ - if (state->param.u.qam.symbol_rate <= 1188750) + /* printk(KERN_DEBUG "drxk: SR %d\n", state->props.symbol_rate); */ + if (state->props.symbol_rate <= 1188750) ratesel = 3; - else if (state->param.u.qam.symbol_rate <= 2377500) + else if (state->props.symbol_rate <= 2377500) ratesel = 2; - else if (state->param.u.qam.symbol_rate <= 4755000) + else if (state->props.symbol_rate <= 4755000) ratesel = 1; status = write16(state, IQM_FD_RATESEL__A, ratesel); if (status < 0) @@ -5295,7 +5302,7 @@ static int QAMSetSymbolrate(struct drxk_state *state) /* IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23) */ - symbFreq = state->param.u.qam.symbol_rate * (1 << ratesel); + symbFreq = state->props.symbol_rate * (1 << ratesel); if (symbFreq == 0) { /* Divide by zero */ status = -EINVAL; @@ -5311,7 +5318,7 @@ static int QAMSetSymbolrate(struct drxk_state *state) /* LcSymbFreq = round (.125 * symbolrate / adcFreq * (1<<15)) */ - symbFreq = state->param.u.qam.symbol_rate; + symbFreq = state->props.symbol_rate; if (adcFrequency == 0) { /* Divide by zero */ status = -EINVAL; @@ -5412,7 +5419,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, goto error; /* Set params */ - switch (state->param.u.qam.modulation) { + switch (state->props.modulation) { case QAM_256: state->m_Constellation = DRX_CONSTELLATION_QAM256; break; @@ -5435,7 +5442,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, } if (status < 0) goto error; - setParamParameters[0] = state->m_Constellation; /* constellation */ + setParamParameters[0] = state->m_Constellation; /* modulation */ setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ if (state->m_OperationMode == OM_QAM_ITU_C) setParamParameters[2] = QAM_TOP_ANNEX_C; @@ -5457,7 +5464,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, if (status < 0) goto error; - setParamParameters[0] = state->m_Constellation; /* constellation */ + setParamParameters[0] = state->m_Constellation; /* modulation */ setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult); } @@ -5466,7 +5473,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, /* * STEP 3: enable the system in a mode where the ADC provides valid - * signal setup constellation independent registers + * signal setup modulation independent registers */ #if 0 status = SetFrequency(channel, tunerFreqOffset)); @@ -5478,7 +5485,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, goto error; /* Setup BER measurement */ - status = SetQAMMeasurement(state, state->m_Constellation, state->param.u. qam.symbol_rate); + status = SetQAMMeasurement(state, state->m_Constellation, state->props.symbol_rate); if (status < 0) goto error; @@ -5560,8 +5567,8 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, if (status < 0) goto error; - /* STEP 4: constellation specific setup */ - switch (state->param.u.qam.modulation) { + /* STEP 4: modulation specific setup */ + switch (state->props.modulation) { case QAM_16: status = SetQAM16(state); break; @@ -5591,7 +5598,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, goto error; /* Re-configure MPEG output, requires knowledge of channel bitrate */ - /* extAttr->currentChannel.constellation = channel->constellation; */ + /* extAttr->currentChannel.modulation = channel->modulation; */ /* extAttr->currentChannel.symbolrate = channel->symbolrate; */ status = MPEGTSDtoSetup(state, state->m_OperationMode); if (status < 0) @@ -6167,7 +6174,7 @@ error: return status; } -static void drxk_c_release(struct dvb_frontend *fe) +static void drxk_release(struct dvb_frontend *fe) { struct drxk_state *state = fe->demodulator_priv; @@ -6175,24 +6182,12 @@ static void drxk_c_release(struct dvb_frontend *fe) kfree(state); } -static int drxk_c_init(struct dvb_frontend *fe) -{ - struct drxk_state *state = fe->demodulator_priv; - - dprintk(1, "\n"); - if (mutex_trylock(&state->ctlock) == 0) - return -EBUSY; - SetOperationMode(state, OM_QAM_ITU_A); - return 0; -} - -static int drxk_c_sleep(struct dvb_frontend *fe) +static int drxk_sleep(struct dvb_frontend *fe) { struct drxk_state *state = fe->demodulator_priv; dprintk(1, "\n"); ShutDown(state); - mutex_unlock(&state->ctlock); return 0; } @@ -6204,9 +6199,10 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) return ConfigureI2CBridge(state, enable ? true : false); } -static int drxk_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int drxk_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 delsys = p->delivery_system, old_delsys; struct drxk_state *state = fe->demodulator_priv; u32 IF; @@ -6218,14 +6214,39 @@ static int drxk_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - state->param = *p; + + old_delsys = state->props.delivery_system; + state->props = *p; + + if (old_delsys != delsys) { + ShutDown(state); + switch (delsys) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + if (!state->m_hasDVBC) + return -EINVAL; + state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? true : false; + if (state->m_itut_annex_c) + SetOperationMode(state, OM_QAM_ITU_C); + else + SetOperationMode(state, OM_QAM_ITU_A); + break; + case SYS_DVBT: + if (!state->m_hasDVBT) + return -EINVAL; + SetOperationMode(state, OM_DVBT); + break; + default: + return -EINVAL; + } + } + fe->ops.tuner_ops.get_if_frequency(fe, &IF); Start(state, 0, IF); @@ -6234,13 +6255,6 @@ static int drxk_set_parameters(struct dvb_frontend *fe, return 0; } -static int drxk_c_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - dprintk(1, "\n"); - return 0; -} - static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct drxk_state *state = fe->demodulator_priv; @@ -6300,102 +6314,54 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int drxk_c_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings +static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *sets) { - dprintk(1, "\n"); - sets->min_delay_ms = 3000; - sets->max_drift = 0; - sets->step_size = 0; - return 0; -} - -static void drxk_t_release(struct dvb_frontend *fe) -{ - /* - * There's nothing to release here, as the state struct - * is already freed by drxk_c_release. - */ -} - -static int drxk_t_init(struct dvb_frontend *fe) -{ - struct drxk_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; dprintk(1, "\n"); - if (mutex_trylock(&state->ctlock) == 0) - return -EBUSY; - SetOperationMode(state, OM_DVBT); - return 0; -} - -static int drxk_t_sleep(struct dvb_frontend *fe) -{ - struct drxk_state *state = fe->demodulator_priv; - - dprintk(1, "\n"); - mutex_unlock(&state->ctlock); - return 0; -} - -static int drxk_t_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - dprintk(1, "\n"); - - return 0; + switch (p->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + sets->min_delay_ms = 3000; + sets->max_drift = 0; + sets->step_size = 0; + return 0; + default: + /* + * For DVB-T, let it use the default DVB core way, that is: + * fepriv->step_size = fe->ops.info.frequency_stepsize * 2 + */ + return -EINVAL; + } } -static struct dvb_frontend_ops drxk_c_ops = { +static struct dvb_frontend_ops drxk_ops = { + /* .delsys will be filled dynamically */ .info = { - .name = "DRXK DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 47000000, - .frequency_max = 862000000, - .symbol_rate_min = 870000, - .symbol_rate_max = 11700000, - .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, - .release = drxk_c_release, - .init = drxk_c_init, - .sleep = drxk_c_sleep, + .name = "DRXK", + .frequency_min = 47000000, + .frequency_max = 865000000, + /* For DVB-C */ + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000, + /* For DVB-T */ + .frequency_stepsize = 166667, + + .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_MUTE_TS | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO + }, + + .release = drxk_release, + .sleep = drxk_sleep, .i2c_gate_ctrl = drxk_gate_ctrl, .set_frontend = drxk_set_parameters, - .get_frontend = drxk_c_get_frontend, - .get_tune_settings = drxk_c_get_tune_settings, - - .read_status = drxk_read_status, - .read_ber = drxk_read_ber, - .read_signal_strength = drxk_read_signal_strength, - .read_snr = drxk_read_snr, - .read_ucblocks = drxk_read_ucblocks, -}; - -static struct dvb_frontend_ops drxk_t_ops = { - .info = { - .name = "DRXK DVB-T", - .type = FE_OFDM, - .frequency_min = 47125000, - .frequency_max = 865000000, - .frequency_stepsize = 166667, - .frequency_tolerance = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS}, - .release = drxk_t_release, - .init = drxk_t_init, - .sleep = drxk_t_sleep, - .i2c_gate_ctrl = drxk_gate_ctrl, - - .set_frontend = drxk_set_parameters, - .get_frontend = drxk_t_get_frontend, + .get_tune_settings = drxk_get_tune_settings, .read_status = drxk_read_status, .read_ber = drxk_read_ber, @@ -6405,9 +6371,10 @@ static struct dvb_frontend_ops drxk_t_ops = { }; struct dvb_frontend *drxk_attach(const struct drxk_config *config, - struct i2c_adapter *i2c, - struct dvb_frontend **fe_t) + struct i2c_adapter *i2c) { + int n; + struct drxk_state *state = NULL; u8 adr = config->adr; @@ -6423,6 +6390,12 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, state->no_i2c_bridge = config->no_i2c_bridge; state->antenna_gpio = config->antenna_gpio; state->antenna_dvbt = config->antenna_dvbt; + state->m_ChunkSize = config->chunk_size; + + if (config->parallel_ts) + state->m_enableParallel = true; + else + state->m_enableParallel = false; /* NOTE: as more UIO bits will be used, add them to the mask */ state->UIO_mask = config->antenna_gpio; @@ -6434,21 +6407,30 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, state->m_GPIO &= ~state->antenna_gpio; mutex_init(&state->mutex); - mutex_init(&state->ctlock); - memcpy(&state->c_frontend.ops, &drxk_c_ops, - sizeof(struct dvb_frontend_ops)); - memcpy(&state->t_frontend.ops, &drxk_t_ops, - sizeof(struct dvb_frontend_ops)); - state->c_frontend.demodulator_priv = state; - state->t_frontend.demodulator_priv = state; + memcpy(&state->frontend.ops, &drxk_ops, sizeof(drxk_ops)); + state->frontend.demodulator_priv = state; init_state(state); if (init_drxk(state) < 0) goto error; - *fe_t = &state->t_frontend; - return &state->c_frontend; + /* Initialize the supported delivery systems */ + n = 0; + if (state->m_hasDVBC) { + state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A; + state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C; + strlcat(state->frontend.ops.info.name, " DVB-C", + sizeof(state->frontend.ops.info.name)); + } + if (state->m_hasDVBT) { + state->frontend.ops.delsys[n++] = SYS_DVBT; + strlcat(state->frontend.ops.info.name, " DVB-T", + sizeof(state->frontend.ops.info.name)); + } + + printk(KERN_INFO "drxk: frontend initialized.\n"); + return &state->frontend; error: printk(KERN_ERR "drxk: not found\n"); diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h index a05c32eecdcc..3a58b73eb9b9 100644 --- a/drivers/media/dvb/frontends/drxk_hard.h +++ b/drivers/media/dvb/frontends/drxk_hard.h @@ -195,9 +195,8 @@ struct DRXKOfdmScCmd_t { }; struct drxk_state { - struct dvb_frontend c_frontend; - struct dvb_frontend t_frontend; - struct dvb_frontend_parameters param; + struct dvb_frontend frontend; + struct dtv_frontend_properties props; struct device *dev; struct i2c_adapter *i2c; @@ -205,7 +204,6 @@ struct drxk_state { void *priv; struct mutex mutex; - struct mutex ctlock; u32 m_Instance; /**< Channel 1,2,3 or 4 */ @@ -263,6 +261,8 @@ struct drxk_state { u8 m_TSDataStrength; u8 m_TSClockkStrength; + bool m_itut_annex_c; /* If true, uses ITU-T DVB-C Annex C, instead of Annex A */ + enum DRXMPEGStrWidth_t m_widthSTR; /**< MPEG start width */ u32 m_mpegTsStaticBitrate; /**< Maximum bitrate in b/s in case static clockrate is selected */ diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 90bf573308b0..af65d013db11 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -934,20 +934,6 @@ error2: } EXPORT_SYMBOL(ds3000_attach); -static int ds3000_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int ds3000_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - static int ds3000_set_carrier_offset(struct dvb_frontend *fe, s32 carrier_offset_khz) { @@ -967,8 +953,7 @@ static int ds3000_set_carrier_offset(struct dvb_frontend *fe, return 0; } -static int ds3000_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int ds3000_set_frontend(struct dvb_frontend *fe) { struct ds3000_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -994,15 +979,15 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, div4 = 0; /* calculate and set freq divider */ - if (p->frequency < 1146000) { + if (c->frequency < 1146000) { ds3000_tuner_writereg(state, 0x10, 0x11); div4 = 1; - ndiv = ((p->frequency * (6 + 8) * 4) + + ndiv = ((c->frequency * (6 + 8) * 4) + (DS3000_XTAL_FREQ / 2)) / DS3000_XTAL_FREQ - 1024; } else { ds3000_tuner_writereg(state, 0x10, 0x01); - ndiv = ((p->frequency * (6 + 8) * 2) + + ndiv = ((c->frequency * (6 + 8) * 2) + (DS3000_XTAL_FREQ / 2)) / DS3000_XTAL_FREQ - 1024; } @@ -1101,7 +1086,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, msleep(60); offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ - / (6 + 8) / (div4 + 1) / 2 - p->frequency; + / (6 + 8) / (div4 + 1) / 2 - c->frequency; /* ds3000 global reset */ ds3000_writereg(state, 0x07, 0x80); @@ -1210,7 +1195,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, for (i = 0; i < 30 ; i++) { ds3000_read_status(fe, &status); - if (status && FE_HAS_LOCK) + if (status & FE_HAS_LOCK) break; msleep(10); @@ -1220,13 +1205,13 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, } static int ds3000_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { - if (p) { - int ret = ds3000_set_frontend(fe, p); + if (re_tune) { + int ret = ds3000_set_frontend(fe); if (ret) return ret; } @@ -1279,10 +1264,9 @@ static int ds3000_sleep(struct dvb_frontend *fe) } static struct dvb_frontend_ops ds3000_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2}, .info = { .name = "Montage Technology DS3000/TS2020", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ @@ -1312,8 +1296,6 @@ static struct dvb_frontend_ops ds3000_ops = { .diseqc_send_burst = ds3000_diseqc_send_burst, .get_frontend_algo = ds3000_get_algo, - .set_property = ds3000_set_property, - .get_property = ds3000_get_property, .set_frontend = ds3000_set_frontend, .tune = ds3000_tune, }; diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 62a65efdf8d6..1ab34838221c 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -61,8 +61,7 @@ struct dvb_pll_desc { u32 min; u32 max; u32 iffreq; - void (*set)(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params); + void (*set)(struct dvb_frontend *fe, u8 *buf); u8 *initdata; u8 *initdata2; u8 *sleepdata; @@ -93,10 +92,10 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { }, }; -static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf) { - if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) + u32 bw = fe->dtv_property_cache.bandwidth_hz; + if (bw == 7000000) buf[3] |= 0x10; } @@ -186,10 +185,10 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = { /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void tda665x_bw(struct dvb_frontend *fe, u8 *buf) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + u32 bw = fe->dtv_property_cache.bandwidth_hz; + if (bw == 8000000) buf[3] |= 0x08; } @@ -220,10 +219,10 @@ static struct dvb_pll_desc dvb_pll_tda665x = { /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void tua6034_bw(struct dvb_frontend *fe, u8 *buf) { - if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) + u32 bw = fe->dtv_property_cache.bandwidth_hz; + if (bw == 7000000) buf[3] |= 0x08; } @@ -244,10 +243,10 @@ static struct dvb_pll_desc dvb_pll_tua6034 = { /* ALPS TDED4 * used in Nebula-Cards and USB boxes */ -static void tded4_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void tded4_bw(struct dvb_frontend *fe, u8 *buf) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + u32 bw = fe->dtv_property_cache.bandwidth_hz; + if (bw == 8000000) buf[3] |= 0x04; } @@ -319,11 +318,11 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { }, }; -static void opera1_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void opera1_bw(struct dvb_frontend *fe, u8 *buf) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_pll_priv *priv = fe->tuner_priv; - u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; + u32 b_w = (c->symbol_rate * 27) / 32000; struct i2c_msg msg = { .addr = priv->pll_i2c_address, .flags = 0, @@ -392,8 +391,7 @@ static struct dvb_pll_desc dvb_pll_opera1 = { } }; -static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf) { struct dvb_pll_priv *priv = fe->tuner_priv; struct i2c_msg msg = { @@ -537,30 +535,29 @@ static struct dvb_pll_desc *pll_list[] = { /* code */ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) + const u32 frequency) { struct dvb_pll_priv *priv = fe->tuner_priv; struct dvb_pll_desc *desc = priv->pll_desc; u32 div; int i; - if (params->frequency != 0 && (params->frequency < desc->min || - params->frequency > desc->max)) + if (frequency && (frequency < desc->min || frequency > desc->max)) return -EINVAL; for (i = 0; i < desc->count; i++) { - if (params->frequency > desc->entries[i].limit) + if (frequency > desc->entries[i].limit) continue; break; } if (debug) printk("pll: %s: freq=%d | i=%d/%d\n", desc->name, - params->frequency, i, desc->count); + frequency, i, desc->count); if (i == desc->count) return -EINVAL; - div = (params->frequency + desc->iffreq + + div = (frequency + desc->iffreq + desc->entries[i].stepsize/2) / desc->entries[i].stepsize; buf[0] = div >> 8; buf[1] = div & 0xff; @@ -568,7 +565,7 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, buf[3] = desc->entries[i].cb; if (desc->set) - desc->set(fe, buf, params); + desc->set(fe, buf); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", @@ -611,9 +608,9 @@ static int dvb_pll_sleep(struct dvb_frontend *fe) return -EINVAL; } -static int dvb_pll_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int dvb_pll_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_pll_priv *priv = fe->tuner_priv; u8 buf[4]; struct i2c_msg msg = @@ -625,7 +622,8 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, if (priv->i2c == NULL) return -EINVAL; - if ((result = dvb_pll_configure(fe, buf, params)) < 0) + result = dvb_pll_configure(fe, buf, c->frequency); + if (result < 0) return result; else frequency = result; @@ -637,15 +635,15 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, } priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->bandwidth = c->bandwidth_hz; return 0; } static int dvb_pll_calc_regs(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, u8 *buf, int buf_len) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_pll_priv *priv = fe->tuner_priv; int result; u32 frequency = 0; @@ -653,7 +651,8 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, if (buf_len < 5) return -EINVAL; - if ((result = dvb_pll_configure(fe, buf+1, params)) < 0) + result = dvb_pll_configure(fe, buf + 1, c->frequency); + if (result < 0) return result; else frequency = result; @@ -661,7 +660,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, buf[0] = priv->pll_i2c_address; priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->bandwidth = c->bandwidth_hz; return 5; } diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index a7fc7e53a551..dcfc902c8678 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -68,15 +68,18 @@ static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +/* + * Only needed if it actually reads something from the hardware + */ +static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe) { return 0; } -static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -171,10 +174,9 @@ error: } static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Dummy DVB-T", - .type = FE_OFDM, .frequency_min = 0, .frequency_max = 863250000, .frequency_stepsize = 62500, @@ -203,10 +205,9 @@ static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { }; static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { - + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "Dummy DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 51000000, .frequency_max = 858000000, @@ -233,10 +234,9 @@ static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { }; static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Dummy DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 250, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/ec100.c b/drivers/media/dvb/frontends/ec100.c index 2414dc6ee5d9..c56fddbf53b7 100644 --- a/drivers/media/dvb/frontends/ec100.c +++ b/drivers/media/dvb/frontends/ec100.c @@ -76,19 +76,19 @@ static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val) return 0; } -static int ec100_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int ec100_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct ec100_state *state = fe->demodulator_priv; int ret; u8 tmp, tmp2; - deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, - params->u.ofdm.bandwidth); + deb_info("%s: freq:%d bw:%d\n", __func__, c->frequency, + c->bandwidth_hz); /* program tuner */ if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); + fe->ops.tuner_ops.set_params(fe); ret = ec100_write_reg(state, 0x04, 0x06); if (ret) @@ -108,16 +108,16 @@ static int ec100_set_frontend(struct dvb_frontend *fe, B 0x1b | 0xb7 | 0x00 | 0x49 B 0x1c | 0x55 | 0x64 | 0x72 */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: tmp = 0xb7; tmp2 = 0x55; break; - case BANDWIDTH_7_MHZ: + case 7000000: tmp = 0x00; tmp2 = 0x64; break; - case BANDWIDTH_8_MHZ: + case 8000000: default: tmp = 0x49; tmp2 = 0x72; @@ -306,9 +306,9 @@ error: EXPORT_SYMBOL(ec100_attach); static struct dvb_frontend_ops ec100_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "E3C EC100 DVB-T", - .type = FE_OFDM, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | diff --git a/drivers/media/dvb/frontends/hd29l2.c b/drivers/media/dvb/frontends/hd29l2.c new file mode 100644 index 000000000000..a00318190837 --- /dev/null +++ b/drivers/media/dvb/frontends/hd29l2.c @@ -0,0 +1,861 @@ +/* + * HDIC HD29L2 DMB-TH demodulator driver + * + * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D + * + * Author: Antti Palosaari <crope@iki.fi> + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "hd29l2_priv.h" + +int hd29l2_debug; +module_param_named(debug, hd29l2_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +/* write multiple registers */ +static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len) +{ + int ret; + u8 buf[2 + len]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = 0x00; + buf[1] = reg; + memcpy(&buf[2], val, len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* read multiple registers */ +static int hd29l2_rd_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len) +{ + int ret; + u8 buf[2] = { 0x00, reg }; + struct i2c_msg msg[2] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = 2, + .buf = buf, + }, { + .addr = priv->cfg.i2c_addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + ret = 0; + } else { + warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* write single register */ +static int hd29l2_wr_reg(struct hd29l2_priv *priv, u8 reg, u8 val) +{ + return hd29l2_wr_regs(priv, reg, &val, 1); +} + +/* read single register */ +static int hd29l2_rd_reg(struct hd29l2_priv *priv, u8 reg, u8 *val) +{ + return hd29l2_rd_regs(priv, reg, val, 1); +} + +/* write single register with mask */ +static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = hd29l2_rd_regs(priv, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return hd29l2_wr_regs(priv, reg, &val, 1); +} + +/* read single register with mask */ +int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask) +{ + int ret, i; + u8 tmp; + + ret = hd29l2_rd_regs(priv, reg, &tmp, 1); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + +static int hd29l2_soft_reset(struct hd29l2_priv *priv) +{ + int ret; + u8 tmp; + + ret = hd29l2_rd_reg(priv, 0x26, &tmp); + if (ret) + goto err; + + ret = hd29l2_wr_reg(priv, 0x26, 0x0d); + if (ret) + goto err; + + usleep_range(10000, 20000); + + ret = hd29l2_wr_reg(priv, 0x26, tmp); + if (ret) + goto err; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int ret, i; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 tmp; + + dbg("%s: enable=%d", __func__, enable); + + /* set tuner address for demod */ + if (!priv->tuner_i2c_addr_programmed && enable) { + /* no need to set tuner address every time, once is enough */ + ret = hd29l2_wr_reg(priv, 0x9d, priv->cfg.tuner_i2c_addr << 1); + if (ret) + goto err; + + priv->tuner_i2c_addr_programmed = true; + } + + /* open / close gate */ + ret = hd29l2_wr_reg(priv, 0x9f, enable); + if (ret) + goto err; + + /* wait demod ready */ + for (i = 10; i; i--) { + ret = hd29l2_rd_reg(priv, 0x9e, &tmp); + if (ret) + goto err; + + if (tmp == enable) + break; + + usleep_range(5000, 10000); + } + + dbg("%s: loop=%d", __func__, i); + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 buf[2]; + + *status = 0; + + ret = hd29l2_rd_reg(priv, 0x05, &buf[0]); + if (ret) + goto err; + + if (buf[0] & 0x01) { + /* full lock */ + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_LOCK; + } else { + ret = hd29l2_rd_reg(priv, 0x0d, &buf[1]); + if (ret) + goto err; + + if ((buf[1] & 0xfe) == 0x78) + /* partial lock */ + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC; + } + + priv->fe_status = *status; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 buf[2]; + u16 tmp; + + if (!(priv->fe_status & FE_HAS_LOCK)) { + *snr = 0; + ret = 0; + goto err; + } + + ret = hd29l2_rd_regs(priv, 0x0b, buf, 2); + if (ret) + goto err; + + tmp = (buf[0] << 8) | buf[1]; + + /* report SNR in dB * 10 */ + #define LOG10_20736_24 72422627 /* log10(20736) << 24 */ + if (tmp) + *snr = (LOG10_20736_24 - intlog10(tmp)) / ((1 << 24) / 100); + else + *snr = 0; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 buf[2]; + u16 tmp; + + *strength = 0; + + ret = hd29l2_rd_regs(priv, 0xd5, buf, 2); + if (ret) + goto err; + + tmp = buf[0] << 8 | buf[1]; + tmp = ~tmp & 0x0fff; + + /* scale value to 0x0000-0xffff from 0x0000-0x0fff */ + *strength = tmp * 0xffff / 0x0fff; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 buf[2]; + + if (!(priv->fe_status & FE_HAS_SYNC)) { + *ber = 0; + ret = 0; + goto err; + } + + ret = hd29l2_rd_regs(priv, 0xd9, buf, 2); + if (ret) { + *ber = 0; + goto err; + } + + /* LDPC BER */ + *ber = ((buf[0] & 0x0f) << 8) | buf[1]; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + /* no way to read? */ + *ucblocks = 0; + return 0; +} + +static enum dvbfe_search hd29l2_search(struct dvb_frontend *fe) +{ + int ret, i; + struct hd29l2_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 tmp, buf[3]; + u8 modulation, carrier, guard_interval, interleave, code_rate; + u64 num64; + u32 if_freq, if_ctl; + bool auto_mode; + + dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d " \ + "modulation=%d inversion=%d fec_inner=%d guard_interval=%d", + __func__, + c->delivery_system, c->frequency, c->bandwidth_hz, + c->modulation, c->inversion, c->fec_inner, c->guard_interval); + + /* as for now we detect always params automatically */ + auto_mode = true; + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + + /* get and program IF */ + if (fe->ops.tuner_ops.get_if_frequency) + fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + else + if_freq = 0; + + if (if_freq) { + /* normal IF */ + + /* calc IF control value */ + num64 = if_freq; + num64 *= 0x800000; + num64 = div_u64(num64, HD29L2_XTAL); + num64 -= 0x800000; + if_ctl = num64; + + tmp = 0xfc; /* tuner type normal */ + } else { + /* zero IF */ + if_ctl = 0; + tmp = 0xfe; /* tuner type Zero-IF */ + } + + buf[0] = ((if_ctl >> 0) & 0xff); + buf[1] = ((if_ctl >> 8) & 0xff); + buf[2] = ((if_ctl >> 16) & 0xff); + + /* program IF control */ + ret = hd29l2_wr_regs(priv, 0x14, buf, 3); + if (ret) + goto err; + + /* program tuner type */ + ret = hd29l2_wr_reg(priv, 0xab, tmp); + if (ret) + goto err; + + dbg("%s: if_freq=%d if_ctl=%x", __func__, if_freq, if_ctl); + + if (auto_mode) { + /* + * use auto mode + */ + + /* disable quick mode */ + ret = hd29l2_wr_reg_mask(priv, 0xac, 0 << 7, 0x80); + if (ret) + goto err; + + ret = hd29l2_wr_reg_mask(priv, 0x82, 1 << 1, 0x02); + if (ret) + goto err; + + /* enable auto mode */ + ret = hd29l2_wr_reg_mask(priv, 0x7d, 1 << 6, 0x40); + if (ret) + goto err; + + ret = hd29l2_wr_reg_mask(priv, 0x81, 1 << 3, 0x08); + if (ret) + goto err; + + /* soft reset */ + ret = hd29l2_soft_reset(priv); + if (ret) + goto err; + + /* detect modulation */ + for (i = 30; i; i--) { + msleep(100); + + ret = hd29l2_rd_reg(priv, 0x0d, &tmp); + if (ret) + goto err; + + if ((((tmp & 0xf0) >= 0x10) && + ((tmp & 0x0f) == 0x08)) || (tmp >= 0x2c)) + break; + } + + dbg("%s: loop=%d", __func__, i); + + if (i == 0) + /* detection failed */ + return DVBFE_ALGO_SEARCH_FAILED; + + /* read modulation */ + ret = hd29l2_rd_reg_mask(priv, 0x7d, &modulation, 0x07); + if (ret) + goto err; + } else { + /* + * use manual mode + */ + + modulation = HD29L2_QAM64; + carrier = HD29L2_CARRIER_MULTI; + guard_interval = HD29L2_PN945; + interleave = HD29L2_INTERLEAVER_420; + code_rate = HD29L2_CODE_RATE_08; + + tmp = (code_rate << 3) | modulation; + ret = hd29l2_wr_reg_mask(priv, 0x7d, tmp, 0x5f); + if (ret) + goto err; + + tmp = (carrier << 2) | guard_interval; + ret = hd29l2_wr_reg_mask(priv, 0x81, tmp, 0x0f); + if (ret) + goto err; + + tmp = interleave; + ret = hd29l2_wr_reg_mask(priv, 0x82, tmp, 0x03); + if (ret) + goto err; + } + + /* ensure modulation validy */ + /* 0=QAM4_NR, 1=QAM4, 2=QAM16, 3=QAM32, 4=QAM64 */ + if (modulation > (ARRAY_SIZE(reg_mod_vals_tab[0].val) - 1)) { + dbg("%s: modulation=%d not valid", __func__, modulation); + goto err; + } + + /* program registers according to modulation */ + for (i = 0; i < ARRAY_SIZE(reg_mod_vals_tab); i++) { + ret = hd29l2_wr_reg(priv, reg_mod_vals_tab[i].reg, + reg_mod_vals_tab[i].val[modulation]); + if (ret) + goto err; + } + + /* read guard interval */ + ret = hd29l2_rd_reg_mask(priv, 0x81, &guard_interval, 0x03); + if (ret) + goto err; + + /* read carrier mode */ + ret = hd29l2_rd_reg_mask(priv, 0x81, &carrier, 0x04); + if (ret) + goto err; + + dbg("%s: modulation=%d guard_interval=%d carrier=%d", + __func__, modulation, guard_interval, carrier); + + if ((carrier == HD29L2_CARRIER_MULTI) && (modulation == HD29L2_QAM64) && + (guard_interval == HD29L2_PN945)) { + dbg("%s: C=3780 && QAM64 && PN945", __func__); + + ret = hd29l2_wr_reg(priv, 0x42, 0x33); + if (ret) + goto err; + + ret = hd29l2_wr_reg(priv, 0xdd, 0x01); + if (ret) + goto err; + } + + usleep_range(10000, 20000); + + /* soft reset */ + ret = hd29l2_soft_reset(priv); + if (ret) + goto err; + + /* wait demod lock */ + for (i = 30; i; i--) { + msleep(100); + + /* read lock bit */ + ret = hd29l2_rd_reg_mask(priv, 0x05, &tmp, 0x01); + if (ret) + goto err; + + if (tmp) + break; + } + + dbg("%s: loop=%d", __func__, i); + + if (i == 0) + return DVBFE_ALGO_SEARCH_AGAIN; + + return DVBFE_ALGO_SEARCH_SUCCESS; +err: + dbg("%s: failed=%d", __func__, ret); + return DVBFE_ALGO_SEARCH_ERROR; +} + +static int hd29l2_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static int hd29l2_get_frontend(struct dvb_frontend *fe) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 buf[3]; + u32 if_ctl; + char *str_constellation, *str_code_rate, *str_constellation_code_rate, + *str_guard_interval, *str_carrier, *str_guard_interval_carrier, + *str_interleave, *str_interleave_; + + ret = hd29l2_rd_reg(priv, 0x7d, &buf[0]); + if (ret) + goto err; + + ret = hd29l2_rd_regs(priv, 0x81, &buf[1], 2); + if (ret) + goto err; + + /* constellation, 0x7d[2:0] */ + switch ((buf[0] >> 0) & 0x07) { + case 0: /* QAM4NR */ + str_constellation = "QAM4NR"; + c->modulation = QAM_AUTO; /* FIXME */ + break; + case 1: /* QAM4 */ + str_constellation = "QAM4"; + c->modulation = QPSK; /* FIXME */ + break; + case 2: + str_constellation = "QAM16"; + c->modulation = QAM_16; + break; + case 3: + str_constellation = "QAM32"; + c->modulation = QAM_32; + break; + case 4: + str_constellation = "QAM64"; + c->modulation = QAM_64; + break; + default: + str_constellation = "?"; + } + + /* LDPC code rate, 0x7d[4:3] */ + switch ((buf[0] >> 3) & 0x03) { + case 0: /* 0.4 */ + str_code_rate = "0.4"; + c->fec_inner = FEC_AUTO; /* FIXME */ + break; + case 1: /* 0.6 */ + str_code_rate = "0.6"; + c->fec_inner = FEC_3_5; + break; + case 2: /* 0.8 */ + str_code_rate = "0.8"; + c->fec_inner = FEC_4_5; + break; + default: + str_code_rate = "?"; + } + + /* constellation & code rate set, 0x7d[6] */ + switch ((buf[0] >> 6) & 0x01) { + case 0: + str_constellation_code_rate = "manual"; + break; + case 1: + str_constellation_code_rate = "auto"; + break; + default: + str_constellation_code_rate = "?"; + } + + /* frame header, 0x81[1:0] */ + switch ((buf[1] >> 0) & 0x03) { + case 0: /* PN945 */ + str_guard_interval = "PN945"; + c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */ + break; + case 1: /* PN595 */ + str_guard_interval = "PN595"; + c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */ + break; + case 2: /* PN420 */ + str_guard_interval = "PN420"; + c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */ + break; + default: + str_guard_interval = "?"; + } + + /* carrier, 0x81[2] */ + switch ((buf[1] >> 2) & 0x01) { + case 0: + str_carrier = "C=1"; + break; + case 1: + str_carrier = "C=3780"; + break; + default: + str_carrier = "?"; + } + + /* frame header & carrier set, 0x81[3] */ + switch ((buf[1] >> 3) & 0x01) { + case 0: + str_guard_interval_carrier = "manual"; + break; + case 1: + str_guard_interval_carrier = "auto"; + break; + default: + str_guard_interval_carrier = "?"; + } + + /* interleave, 0x82[0] */ + switch ((buf[2] >> 0) & 0x01) { + case 0: + str_interleave = "M=720"; + break; + case 1: + str_interleave = "M=240"; + break; + default: + str_interleave = "?"; + } + + /* interleave set, 0x82[1] */ + switch ((buf[2] >> 1) & 0x01) { + case 0: + str_interleave_ = "manual"; + break; + case 1: + str_interleave_ = "auto"; + break; + default: + str_interleave_ = "?"; + } + + /* + * We can read out current detected NCO and use that value next + * time instead of calculating new value from targed IF. + * I think it will not effect receiver sensitivity but gaining lock + * after tune could be easier... + */ + ret = hd29l2_rd_regs(priv, 0xb1, &buf[0], 3); + if (ret) + goto err; + + if_ctl = (buf[0] << 16) | ((buf[1] - 7) << 8) | buf[2]; + + dbg("%s: %s %s %s | %s %s %s | %s %s | NCO=%06x", __func__, + str_constellation, str_code_rate, str_constellation_code_rate, + str_guard_interval, str_carrier, str_guard_interval_carrier, + str_interleave, str_interleave_, if_ctl); + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_init(struct dvb_frontend *fe) +{ + int ret, i; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 tmp; + static const struct reg_val tab[] = { + { 0x3a, 0x06 }, + { 0x3b, 0x03 }, + { 0x3c, 0x04 }, + { 0xaf, 0x06 }, + { 0xb0, 0x1b }, + { 0x80, 0x64 }, + { 0x10, 0x38 }, + }; + + dbg("%s:", __func__); + + /* reset demod */ + /* it is recommended to HW reset chip using RST_N pin */ + if (fe->callback) { + ret = fe->callback(fe, DVB_FRONTEND_COMPONENT_DEMOD, 0, 0); + if (ret) + goto err; + + /* reprogramming needed because HW reset clears registers */ + priv->tuner_i2c_addr_programmed = false; + } + + /* init */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = hd29l2_wr_reg(priv, tab[i].reg, tab[i].val); + if (ret) + goto err; + } + + /* TS params */ + ret = hd29l2_rd_reg(priv, 0x36, &tmp); + if (ret) + goto err; + + tmp &= 0x1b; + tmp |= priv->cfg.ts_mode; + ret = hd29l2_wr_reg(priv, 0x36, tmp); + if (ret) + goto err; + + ret = hd29l2_rd_reg(priv, 0x31, &tmp); + tmp &= 0xef; + + if (!(priv->cfg.ts_mode >> 7)) + /* set b4 for serial TS */ + tmp |= 0x10; + + ret = hd29l2_wr_reg(priv, 0x31, tmp); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static void hd29l2_release(struct dvb_frontend *fe) +{ + struct hd29l2_priv *priv = fe->demodulator_priv; + kfree(priv); +} + +static struct dvb_frontend_ops hd29l2_ops; + +struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config, + struct i2c_adapter *i2c) +{ + int ret; + struct hd29l2_priv *priv = NULL; + u8 tmp; + + /* allocate memory for the internal state */ + priv = kzalloc(sizeof(struct hd29l2_priv), GFP_KERNEL); + if (priv == NULL) + goto err; + + /* setup the state */ + priv->i2c = i2c; + memcpy(&priv->cfg, config, sizeof(struct hd29l2_config)); + + + /* check if the demod is there */ + ret = hd29l2_rd_reg(priv, 0x00, &tmp); + if (ret) + goto err; + + /* create dvb_frontend */ + memcpy(&priv->fe.ops, &hd29l2_ops, sizeof(struct dvb_frontend_ops)); + priv->fe.demodulator_priv = priv; + + return &priv->fe; +err: + kfree(priv); + return NULL; +} +EXPORT_SYMBOL(hd29l2_attach); + +static struct dvb_frontend_ops hd29l2_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "HDIC HD29L2 DMB-TH", + .frequency_min = 474000000, + .frequency_max = 858000000, + .frequency_stepsize = 10000, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_BANDWIDTH_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER + }, + + .release = hd29l2_release, + + .init = hd29l2_init, + + .get_frontend_algo = hd29l2_get_frontend_algo, + .search = hd29l2_search, + .get_frontend = hd29l2_get_frontend, + + .read_status = hd29l2_read_status, + .read_snr = hd29l2_read_snr, + .read_signal_strength = hd29l2_read_signal_strength, + .read_ber = hd29l2_read_ber, + .read_ucblocks = hd29l2_read_ucblocks, + + .i2c_gate_ctrl = hd29l2_i2c_gate_ctrl, +}; + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("HDIC HD29L2 DMB-TH demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/hd29l2.h b/drivers/media/dvb/frontends/hd29l2.h new file mode 100644 index 000000000000..a7a64431364d --- /dev/null +++ b/drivers/media/dvb/frontends/hd29l2.h @@ -0,0 +1,66 @@ +/* + * HDIC HD29L2 DMB-TH demodulator driver + * + * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D + * + * Author: Antti Palosaari <crope@iki.fi> + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HD29L2_H +#define HD29L2_H + +#include <linux/dvb/frontend.h> + +struct hd29l2_config { + /* + * demodulator I2C address + */ + u8 i2c_addr; + + /* + * tuner I2C address + * only needed when tuner is behind demod I2C-gate + */ + u8 tuner_i2c_addr; + + /* + * TS settings + */ +#define HD29L2_TS_SERIAL 0x00 +#define HD29L2_TS_PARALLEL 0x80 +#define HD29L2_TS_CLK_NORMAL 0x40 +#define HD29L2_TS_CLK_INVERTED 0x00 +#define HD29L2_TS_CLK_GATED 0x20 +#define HD29L2_TS_CLK_FREE 0x00 + u8 ts_mode; +}; + + +#if defined(CONFIG_DVB_HD29L2) || \ + (defined(CONFIG_DVB_HD29L2_MODULE) && defined(MODULE)) +extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *hd29l2_attach( +const struct hd29l2_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* HD29L2_H */ diff --git a/drivers/media/dvb/frontends/hd29l2_priv.h b/drivers/media/dvb/frontends/hd29l2_priv.h new file mode 100644 index 000000000000..ba16dc3ec2bd --- /dev/null +++ b/drivers/media/dvb/frontends/hd29l2_priv.h @@ -0,0 +1,314 @@ +/* + * HDIC HD29L2 DMB-TH demodulator driver + * + * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D + * + * Author: Antti Palosaari <crope@iki.fi> + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HD29L2_PRIV +#define HD29L2_PRIV + +#include <linux/dvb/version.h> +#include "dvb_frontend.h" +#include "dvb_math.h" +#include "hd29l2.h" + +#define LOG_PREFIX "hd29l2" + +#undef dbg +#define dbg(f, arg...) \ + if (hd29l2_debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +#define HD29L2_XTAL 30400000 /* Hz */ + + +#define HD29L2_QAM4NR 0x00 +#define HD29L2_QAM4 0x01 +#define HD29L2_QAM16 0x02 +#define HD29L2_QAM32 0x03 +#define HD29L2_QAM64 0x04 + +#define HD29L2_CODE_RATE_04 0x00 +#define HD29L2_CODE_RATE_06 0x08 +#define HD29L2_CODE_RATE_08 0x10 + +#define HD29L2_PN945 0x00 +#define HD29L2_PN595 0x01 +#define HD29L2_PN420 0x02 + +#define HD29L2_CARRIER_SINGLE 0x00 +#define HD29L2_CARRIER_MULTI 0x01 + +#define HD29L2_INTERLEAVER_720 0x00 +#define HD29L2_INTERLEAVER_420 0x01 + +struct reg_val { + u8 reg; + u8 val; +}; + +struct reg_mod_vals { + u8 reg; + u8 val[5]; +}; + +struct hd29l2_priv { + struct i2c_adapter *i2c; + struct dvb_frontend fe; + struct hd29l2_config cfg; + u8 tuner_i2c_addr_programmed:1; + + fe_status_t fe_status; +}; + +static const struct reg_mod_vals reg_mod_vals_tab[] = { + /* REG, QAM4NR, QAM4,QAM16,QAM32,QAM64 */ + { 0x01, { 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { 0x02, { 0x07, 0x07, 0x07, 0x07, 0x07 } }, + { 0x03, { 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { 0x04, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x05, { 0x61, 0x60, 0x60, 0x61, 0x60 } }, + { 0x06, { 0xff, 0xff, 0xff, 0xff, 0xff } }, + { 0x07, { 0xff, 0xff, 0xff, 0xff, 0xff } }, + { 0x08, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x09, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x0a, { 0x15, 0x15, 0x03, 0x03, 0x03 } }, + { 0x0d, { 0x78, 0x78, 0x88, 0x78, 0x78 } }, + { 0x0e, { 0xa0, 0x90, 0xa0, 0xa0, 0xa0 } }, + { 0x0f, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x10, { 0xa0, 0xa0, 0x58, 0x38, 0x38 } }, + { 0x11, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x12, { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a } }, + { 0x13, { 0xa2, 0xa2, 0xa2, 0xa2, 0xa2 } }, + { 0x17, { 0x40, 0x40, 0x40, 0x40, 0x40 } }, + { 0x18, { 0x21, 0x21, 0x42, 0x52, 0x42 } }, + { 0x19, { 0x21, 0x21, 0x62, 0x72, 0x62 } }, + { 0x1a, { 0x32, 0x43, 0xa9, 0xb9, 0xa9 } }, + { 0x1b, { 0x32, 0x43, 0xb9, 0xd8, 0xb9 } }, + { 0x1c, { 0x02, 0x02, 0x03, 0x02, 0x03 } }, + { 0x1d, { 0x0c, 0x0c, 0x01, 0x02, 0x02 } }, + { 0x1e, { 0x02, 0x02, 0x02, 0x01, 0x02 } }, + { 0x1f, { 0x02, 0x02, 0x01, 0x02, 0x04 } }, + { 0x20, { 0x01, 0x02, 0x01, 0x01, 0x01 } }, + { 0x21, { 0x08, 0x08, 0x0a, 0x0a, 0x0a } }, + { 0x22, { 0x06, 0x06, 0x04, 0x05, 0x05 } }, + { 0x23, { 0x06, 0x06, 0x05, 0x03, 0x05 } }, + { 0x24, { 0x08, 0x08, 0x05, 0x07, 0x07 } }, + { 0x25, { 0x16, 0x10, 0x10, 0x0a, 0x10 } }, + { 0x26, { 0x14, 0x14, 0x04, 0x04, 0x04 } }, + { 0x27, { 0x58, 0x58, 0x58, 0x5c, 0x58 } }, + { 0x28, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0x29, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0x2a, { 0x08, 0x0a, 0x08, 0x08, 0x08 } }, + { 0x2b, { 0x08, 0x08, 0x08, 0x08, 0x08 } }, + { 0x2c, { 0x06, 0x06, 0x06, 0x06, 0x06 } }, + { 0x2d, { 0x05, 0x06, 0x06, 0x06, 0x06 } }, + { 0x2e, { 0x21, 0x21, 0x21, 0x21, 0x21 } }, + { 0x2f, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x30, { 0x14, 0x14, 0x14, 0x14, 0x14 } }, + { 0x33, { 0xb7, 0xb7, 0xb7, 0xb7, 0xb7 } }, + { 0x34, { 0x81, 0x81, 0x81, 0x81, 0x81 } }, + { 0x35, { 0x80, 0x80, 0x80, 0x80, 0x80 } }, + { 0x37, { 0x70, 0x70, 0x70, 0x70, 0x70 } }, + { 0x38, { 0x04, 0x04, 0x02, 0x02, 0x02 } }, + { 0x39, { 0x07, 0x07, 0x05, 0x05, 0x05 } }, + { 0x3a, { 0x06, 0x06, 0x06, 0x06, 0x06 } }, + { 0x3b, { 0x03, 0x03, 0x03, 0x03, 0x03 } }, + { 0x3c, { 0x07, 0x06, 0x04, 0x04, 0x04 } }, + { 0x3d, { 0xf0, 0xf0, 0xf0, 0xf0, 0x80 } }, + { 0x3e, { 0x60, 0x60, 0x60, 0x60, 0xff } }, + { 0x3f, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x40, { 0x5b, 0x5b, 0x5b, 0x57, 0x50 } }, + { 0x41, { 0x30, 0x30, 0x30, 0x30, 0x18 } }, + { 0x42, { 0x20, 0x20, 0x20, 0x00, 0x30 } }, + { 0x43, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x44, { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f } }, + { 0x45, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x46, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0x47, { 0x00, 0x00, 0x95, 0x00, 0x95 } }, + { 0x48, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } }, + { 0x49, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } }, + { 0x4a, { 0x40, 0x40, 0x33, 0x11, 0x11 } }, + { 0x4b, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x4c, { 0x40, 0x40, 0x99, 0x11, 0x11 } }, + { 0x4d, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x4e, { 0x40, 0x40, 0x66, 0x77, 0x77 } }, + { 0x4f, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x50, { 0x40, 0x40, 0x88, 0x33, 0x11 } }, + { 0x51, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x52, { 0x40, 0x40, 0x88, 0x02, 0x02 } }, + { 0x53, { 0x40, 0x40, 0x00, 0x02, 0x02 } }, + { 0x54, { 0x00, 0x00, 0x88, 0x33, 0x33 } }, + { 0x55, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x56, { 0x00, 0x00, 0x00, 0x0b, 0x00 } }, + { 0x57, { 0x40, 0x40, 0x0a, 0x0b, 0x0a } }, + { 0x58, { 0xaa, 0x00, 0x00, 0x00, 0x00 } }, + { 0x59, { 0x7a, 0x40, 0x02, 0x02, 0x02 } }, + { 0x5a, { 0x18, 0x18, 0x01, 0x01, 0x01 } }, + { 0x5b, { 0x18, 0x18, 0x01, 0x01, 0x01 } }, + { 0x5c, { 0x18, 0x18, 0x01, 0x01, 0x01 } }, + { 0x5d, { 0x18, 0x18, 0x01, 0x01, 0x01 } }, + { 0x5e, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } }, + { 0x5f, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } }, + { 0x60, { 0x40, 0x40, 0x00, 0x30, 0x30 } }, + { 0x61, { 0x40, 0x40, 0x10, 0x30, 0x30 } }, + { 0x62, { 0x40, 0x40, 0x00, 0x30, 0x30 } }, + { 0x63, { 0x40, 0x40, 0x05, 0x30, 0x30 } }, + { 0x64, { 0x40, 0x40, 0x06, 0x00, 0x30 } }, + { 0x65, { 0x40, 0x40, 0x06, 0x08, 0x30 } }, + { 0x66, { 0x40, 0x40, 0x00, 0x00, 0x20 } }, + { 0x67, { 0x40, 0x40, 0x01, 0x04, 0x20 } }, + { 0x68, { 0x00, 0x00, 0x30, 0x00, 0x20 } }, + { 0x69, { 0xa0, 0xa0, 0x00, 0x08, 0x20 } }, + { 0x6a, { 0x00, 0x00, 0x30, 0x00, 0x25 } }, + { 0x6b, { 0xa0, 0xa0, 0x00, 0x06, 0x25 } }, + { 0x6c, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x6d, { 0xa0, 0x60, 0x0c, 0x03, 0x0c } }, + { 0x6e, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x6f, { 0xa0, 0x60, 0x04, 0x01, 0x04 } }, + { 0x70, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } }, + { 0x71, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } }, + { 0x72, { 0x58, 0x58, 0xff, 0xff, 0xff } }, + { 0x73, { 0x58, 0x58, 0xff, 0xff, 0xff } }, + { 0x74, { 0x06, 0x06, 0x09, 0x05, 0x05 } }, + { 0x75, { 0x06, 0x06, 0x0a, 0x10, 0x10 } }, + { 0x76, { 0x10, 0x10, 0x06, 0x0a, 0x0a } }, + { 0x77, { 0x12, 0x18, 0x28, 0x10, 0x28 } }, + { 0x78, { 0xf8, 0xf8, 0xf8, 0xf8, 0xf8 } }, + { 0x79, { 0x15, 0x15, 0x03, 0x03, 0x03 } }, + { 0x7a, { 0x02, 0x02, 0x01, 0x04, 0x03 } }, + { 0x7b, { 0x01, 0x02, 0x03, 0x03, 0x03 } }, + { 0x7c, { 0x28, 0x28, 0x28, 0x28, 0x28 } }, + { 0x7f, { 0x25, 0x92, 0x5f, 0x17, 0x2d } }, + { 0x80, { 0x64, 0x64, 0x64, 0x74, 0x64 } }, + { 0x83, { 0x06, 0x03, 0x04, 0x04, 0x04 } }, + { 0x84, { 0xff, 0xff, 0xff, 0xff, 0xff } }, + { 0x85, { 0x05, 0x05, 0x05, 0x05, 0x05 } }, + { 0x86, { 0x00, 0x00, 0x11, 0x11, 0x11 } }, + { 0x87, { 0x03, 0x03, 0x03, 0x03, 0x03 } }, + { 0x88, { 0x09, 0x09, 0x09, 0x09, 0x09 } }, + { 0x89, { 0x20, 0x20, 0x30, 0x20, 0x20 } }, + { 0x8a, { 0x03, 0x03, 0x02, 0x03, 0x02 } }, + { 0x8b, { 0x00, 0x07, 0x09, 0x00, 0x09 } }, + { 0x8c, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x8d, { 0x4f, 0x4f, 0x4f, 0x3f, 0x4f } }, + { 0x8e, { 0xf0, 0xf0, 0x60, 0xf0, 0xa0 } }, + { 0x8f, { 0xe8, 0xe8, 0xe8, 0xe8, 0xe8 } }, + { 0x90, { 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { 0x91, { 0x40, 0x40, 0x70, 0x70, 0x10 } }, + { 0x92, { 0x00, 0x00, 0x00, 0x00, 0x04 } }, + { 0x93, { 0x60, 0x60, 0x60, 0x60, 0x60 } }, + { 0x94, { 0x00, 0x00, 0x00, 0x00, 0x03 } }, + { 0x95, { 0x09, 0x09, 0x47, 0x47, 0x47 } }, + { 0x96, { 0x80, 0xa0, 0xa0, 0x40, 0xa0 } }, + { 0x97, { 0x60, 0x60, 0x60, 0x60, 0x60 } }, + { 0x98, { 0x50, 0x50, 0x50, 0x30, 0x50 } }, + { 0x99, { 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { 0x9a, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x9b, { 0x40, 0x40, 0x40, 0x30, 0x40 } }, + { 0x9c, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa0, { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 } }, + { 0xa1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa2, { 0x30, 0x30, 0x00, 0x30, 0x00 } }, + { 0xa3, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa4, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa5, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa6, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa7, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa8, { 0x77, 0x77, 0x77, 0x77, 0x77 } }, + { 0xa9, { 0x02, 0x02, 0x02, 0x02, 0x02 } }, + { 0xaa, { 0x40, 0x40, 0x40, 0x40, 0x40 } }, + { 0xac, { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f } }, + { 0xad, { 0x14, 0x14, 0x14, 0x14, 0x14 } }, + { 0xae, { 0x78, 0x78, 0x78, 0x78, 0x78 } }, + { 0xaf, { 0x06, 0x06, 0x06, 0x06, 0x07 } }, + { 0xb0, { 0x1b, 0x1b, 0x1b, 0x19, 0x1b } }, + { 0xb1, { 0x18, 0x17, 0x17, 0x18, 0x17 } }, + { 0xb2, { 0x35, 0x82, 0x82, 0x38, 0x82 } }, + { 0xb3, { 0xb6, 0xce, 0xc7, 0x5c, 0xb0 } }, + { 0xb4, { 0x3f, 0x3e, 0x3e, 0x3f, 0x3e } }, + { 0xb5, { 0x70, 0x58, 0x50, 0x68, 0x50 } }, + { 0xb6, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xb7, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xb8, { 0x03, 0x03, 0x01, 0x01, 0x01 } }, + { 0xb9, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xba, { 0x06, 0x06, 0x0a, 0x05, 0x0a } }, + { 0xbb, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xbc, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xbd, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xbe, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xbf, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc0, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc2, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc3, { 0x00, 0x00, 0x88, 0x66, 0x88 } }, + { 0xc4, { 0x10, 0x10, 0x00, 0x00, 0x00 } }, + { 0xc5, { 0x00, 0x00, 0x44, 0x60, 0x44 } }, + { 0xc6, { 0x10, 0x0a, 0x00, 0x00, 0x00 } }, + { 0xc7, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc8, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc9, { 0x90, 0x04, 0x00, 0x00, 0x00 } }, + { 0xca, { 0x90, 0x08, 0x01, 0x01, 0x01 } }, + { 0xcb, { 0xa0, 0x04, 0x00, 0x44, 0x00 } }, + { 0xcc, { 0xa0, 0x10, 0x03, 0x00, 0x03 } }, + { 0xcd, { 0x06, 0x06, 0x06, 0x05, 0x06 } }, + { 0xce, { 0x05, 0x05, 0x01, 0x01, 0x01 } }, + { 0xcf, { 0x40, 0x20, 0x18, 0x18, 0x18 } }, + { 0xd0, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xd1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xd2, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xd3, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xd4, { 0x05, 0x05, 0x05, 0x05, 0x05 } }, + { 0xd5, { 0x05, 0x05, 0x05, 0x03, 0x05 } }, + { 0xd6, { 0xac, 0x22, 0xca, 0x8f, 0xca } }, + { 0xd7, { 0x20, 0x20, 0x20, 0x20, 0x20 } }, + { 0xd8, { 0x01, 0x01, 0x01, 0x01, 0x01 } }, + { 0xd9, { 0x00, 0x00, 0x0f, 0x00, 0x0f } }, + { 0xda, { 0x00, 0xff, 0xff, 0x0e, 0xff } }, + { 0xdb, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0xdc, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0xdd, { 0x05, 0x05, 0x05, 0x05, 0x05 } }, + { 0xde, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0xdf, { 0x42, 0x42, 0x44, 0x44, 0x04 } }, + { 0xe0, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe2, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe3, { 0x00, 0x00, 0x26, 0x06, 0x26 } }, + { 0xe4, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe5, { 0x01, 0x0a, 0x01, 0x01, 0x01 } }, + { 0xe6, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe7, { 0x08, 0x08, 0x08, 0x08, 0x08 } }, + { 0xe8, { 0x63, 0x63, 0x63, 0x63, 0x63 } }, + { 0xe9, { 0x59, 0x59, 0x59, 0x59, 0x59 } }, + { 0xea, { 0x80, 0x80, 0x20, 0x80, 0x80 } }, + { 0xeb, { 0x37, 0x37, 0x78, 0x37, 0x77 } }, + { 0xec, { 0x1f, 0x1f, 0x25, 0x25, 0x25 } }, + { 0xed, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0xee, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xef, { 0x70, 0x70, 0x58, 0x38, 0x58 } }, + { 0xf0, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, +}; + +#endif /* HD29L2_PRIV */ diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h index 1c6fb4b66255..93b086ea7e1c 100644 --- a/drivers/media/dvb/frontends/it913x-fe-priv.h +++ b/drivers/media/dvb/frontends/it913x-fe-priv.h @@ -22,126 +22,126 @@ struct adctable { u32 adcFrequency; /* clock and coeff tables only table 3 is used with IT9137*/ /* TODO other tables relate AF9035 may be removed */ static struct adctable tab1[] = { - { 20156250, BANDWIDTH_6_MHZ, + { 20156250, 6000000, 0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a, 0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c }, - { 20156250, BANDWIDTH_7_MHZ, + { 20156250, 7000000, 0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007, 0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196 }, - { 20156250, BANDWIDTH_8_MHZ, + { 20156250, 8000000, 0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3, 0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0 }, - { 20156250, BANDWIDTH_5_MHZ, + { 20156250, 5000000, 0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e, 0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122 } }; static struct adctable tab2[] = { - { 20187500, BANDWIDTH_6_MHZ, + { 20187500, 6000000, 0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426, 0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c }, - { 20187500, BANDWIDTH_7_MHZ, + { 20187500, 7000000, 0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81, 0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196 }, - { 20187500, BANDWIDTH_8_MHZ, + { 20187500, 8000000, 0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd, 0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0 }, - { 20187500, BANDWIDTH_5_MHZ, + { 20187500, 5000000, 0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca, 0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122 } }; static struct adctable tab3[] = { - { 20250000, BANDWIDTH_6_MHZ, + { 20250000, 6000000, 0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1, 0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b }, - { 20250000, BANDWIDTH_7_MHZ, + { 20250000, 7000000, 0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36, 0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195 }, - { 20250000, BANDWIDTH_8_MHZ, + { 20250000, 8000000, 0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab, 0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce }, - { 20250000, BANDWIDTH_5_MHZ, + { 20250000, 5000000, 0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b, 0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121 } }; static struct adctable tab4[] = { - { 20583333, BANDWIDTH_6_MHZ, + { 20583333, 6000000, 0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12, 0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155 }, - { 20583333, BANDWIDTH_7_MHZ, + { 20583333, 7000000, 0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf, 0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e }, - { 20583333, BANDWIDTH_8_MHZ, + { 20583333, 8000000, 0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d, 0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7 }, - { 20583333, BANDWIDTH_5_MHZ, + { 20583333, 5000000, 0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64, 0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c } }; static struct adctable tab5[] = { - { 20416667, BANDWIDTH_6_MHZ, + { 20416667, 6000000, 0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a, 0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158 }, - { 20416667, BANDWIDTH_7_MHZ, + { 20416667, 7000000, 0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e, 0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191 }, - { 20416667, BANDWIDTH_8_MHZ, + { 20416667, 8000000, 0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2, 0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb }, - { 20416667, BANDWIDTH_5_MHZ, + { 20416667, 5000000, 0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865, 0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f } }; static struct adctable tab6[] = { - { 20480000, BANDWIDTH_6_MHZ, + { 20480000, 6000000, 0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c, 0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157 }, - { 20480000, BANDWIDTH_7_MHZ, + { 20480000, 7000000, 0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0, 0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190 }, - { 20480000, BANDWIDTH_8_MHZ, + { 20480000, 8000000, 0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25, 0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9 }, - { 20480000, BANDWIDTH_5_MHZ, + { 20480000, 5000000, 0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7, 0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e } }; static struct adctable tab7[] = { - { 20500000, BANDWIDTH_6_MHZ, + { 20500000, 6000000, 0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c, 0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157 }, - { 20500000, BANDWIDTH_7_MHZ, + { 20500000, 7000000, 0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce, 0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190 }, - { 20500000, BANDWIDTH_8_MHZ, + { 20500000, 8000000, 0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210, 0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9 }, - { 20500000, BANDWIDTH_5_MHZ, + { 20500000, 5000000, 0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a, 0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d } }; static struct adctable tab8[] = { - { 20625000, BANDWIDTH_6_MHZ, + { 20625000, 6000000, 0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de, 0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154 }, - { 20625000, BANDWIDTH_7_MHZ, + { 20625000, 7000000, 0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8, 0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d }, - { 20625000, BANDWIDTH_8_MHZ, + { 20625000, 8000000, 0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2, 0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6 }, - { 20625000, BANDWIDTH_5_MHZ, + { 20625000, 5000000, 0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3, 0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c } @@ -153,8 +153,7 @@ struct table { }; static struct table fe_clockTable[] = { - {12000000, tab3}, /* FPGA */ - {16384000, tab6}, /* 16.38MHz */ + {12000000, tab3}, /* 12.00MHz */ {20480000, tab6}, /* 20.48MHz */ {36000000, tab3}, /* 36.00MHz */ {30000000, tab1}, /* 30.00MHz */ @@ -164,7 +163,6 @@ static struct table fe_clockTable[] = { {34000000, tab2}, /* 34.00MHz */ {24000000, tab1}, /* 24.00MHz */ {22000000, tab8}, /* 22.00MHz */ - {12000000, tab3} /* 12.00MHz */ }; /* fe get */ @@ -205,6 +203,10 @@ fe_modulation_t fe_con[] = { /* Standard demodulator functions */ static struct it913xset set_solo_fe[] = { + {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, + {PRO_LINK, GPIOH5_ON, {0x01}, 0x01}, + {PRO_LINK, GPIOH5_O, {0x00}, 0x01}, + {PRO_LINK, GPIOH5_O, {0x01}, 0x01}, {PRO_LINK, DVBT_INTEN, {0x04}, 0x01}, {PRO_LINK, DVBT_ENABLE, {0x05}, 0x01}, {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01}, @@ -228,13 +230,127 @@ static struct it913xset init_1[] = { {PRO_LINK, LOCK3_OUT, {0x01}, 0x01}, {PRO_LINK, PADMISCDRSR, {0x01}, 0x01}, {PRO_LINK, PADMISCDR2, {0x00}, 0x01}, + {PRO_DMOD, 0xec57, {0x00, 0x00}, 0x02}, {PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */ {PRO_LINK, PADMISCDR8, {0x00}, 0x01}, {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ }; -/* ---------IT9137 0x38 tuner init---------- */ -static struct it913xset it9137_set[] = { + +/* Version 1 types */ +static struct it913xset it9135_v1[] = { + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a}, 0x01}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a}, 0x01}, + {PRO_DMOD, 0x008a, {0x01}, 0x01}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06}, 0x01}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009f, {0xe1}, 0x01}, + {PRO_DMOD, 0x00a0, {0xcf}, 0x01}, + {PRO_DMOD, 0x00a3, {0x01}, 0x01}, + {PRO_DMOD, 0x00a5, {0x01}, 0x01}, + {PRO_DMOD, 0x00a6, {0x01}, 0x01}, + {PRO_DMOD, 0x00a9, {0x00}, 0x01}, + {PRO_DMOD, 0x00aa, {0x01}, 0x01}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00c2, {0x05}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10}, 0x01}, + {PRO_DMOD, 0xf017, {0x04}, 0x01}, + {PRO_DMOD, 0xf018, {0x05}, 0x01}, + {PRO_DMOD, 0xf019, {0x04}, 0x01}, + {PRO_DMOD, 0xf01a, {0x05}, 0x01}, + {PRO_DMOD, 0xf021, {0x03}, 0x01}, + {PRO_DMOD, 0xf022, {0x0a}, 0x01}, + {PRO_DMOD, 0xf023, {0x0a}, 0x01}, + {PRO_DMOD, 0xf02b, {0x00}, 0x01}, + {PRO_DMOD, 0xf02c, {0x01}, 0x01}, + {PRO_DMOD, 0xf064, {0x03}, 0x01}, + {PRO_DMOD, 0xf065, {0xf9}, 0x01}, + {PRO_DMOD, 0xf066, {0x03}, 0x01}, + {PRO_DMOD, 0xf067, {0x01}, 0x01}, + {PRO_DMOD, 0xf06f, {0xe0}, 0x01}, + {PRO_DMOD, 0xf070, {0x03}, 0x01}, + {PRO_DMOD, 0xf072, {0x0f}, 0x01}, + {PRO_DMOD, 0xf073, {0x03}, 0x01}, + {PRO_DMOD, 0xf078, {0x00}, 0x01}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f}, 0x01}, + {PRO_DMOD, 0xf09c, {0x00}, 0x01}, + {PRO_DMOD, 0xf09d, {0x20}, 0x01}, + {PRO_DMOD, 0xf09e, {0x00}, 0x01}, + {PRO_DMOD, 0xf09f, {0x0c}, 0x01}, + {PRO_DMOD, 0xf0a0, {0x00}, 0x01}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00}, 0x01}, + {PRO_DMOD, 0xf14d, {0x00}, 0x01}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00}, 0x01}, + {PRO_DMOD, 0xf15b, {0x08}, 0x01}, + {PRO_DMOD, 0xf15d, {0x03}, 0x01}, + {PRO_DMOD, 0xf15e, {0x05}, 0x01}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01}, 0x01}, + {PRO_DMOD, 0xf167, {0x40}, 0x01}, + {PRO_DMOD, 0xf168, {0x0f}, 0x01}, + {PRO_DMOD, 0xf17a, {0x00}, 0x01}, + {PRO_DMOD, 0xf17b, {0x00}, 0x01}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36}, 0x01}, + {PRO_DMOD, 0xf1bd, {0x00}, 0x01}, + {PRO_DMOD, 0xf1cb, {0xa0}, 0x01}, + {PRO_DMOD, 0xf1cc, {0x01}, 0x01}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf40e, {0x0a}, 0x01}, + {PRO_DMOD, 0xf40f, {0x40}, 0x01}, + {PRO_DMOD, 0xf410, {0x08}, 0x01}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15}, 0x01}, + {PRO_DMOD, 0xf562, {0x20}, 0x01}, + {PRO_DMOD, 0xf5df, {0xfb}, 0x01}, + {PRO_DMOD, 0xf5e0, {0x00}, 0x01}, + {PRO_DMOD, 0xf5e3, {0x09}, 0x01}, + {PRO_DMOD, 0xf5e4, {0x01}, 0x01}, + {PRO_DMOD, 0xf5e5, {0x01}, 0x01}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05}, 0x01}, + {PRO_DMOD, 0xf601, {0x08}, 0x01}, + {PRO_DMOD, 0xf602, {0x0b}, 0x01}, + {PRO_DMOD, 0xf603, {0x0e}, 0x01}, + {PRO_DMOD, 0xf604, {0x11}, 0x01}, + {PRO_DMOD, 0xf605, {0x14}, 0x01}, + {PRO_DMOD, 0xf606, {0x17}, 0x01}, + {PRO_DMOD, 0xf607, {0x1f}, 0x01}, + {PRO_DMOD, 0xf60e, {0x00}, 0x01}, + {PRO_DMOD, 0xf60f, {0x04}, 0x01}, + {PRO_DMOD, 0xf610, {0x32}, 0x01}, + {PRO_DMOD, 0xf611, {0x10}, 0x01}, + {PRO_DMOD, 0xf707, {0xfc}, 0x01}, + {PRO_DMOD, 0xf708, {0x00}, 0x01}, + {PRO_DMOD, 0xf709, {0x37}, 0x01}, + {PRO_DMOD, 0xf70a, {0x00}, 0x01}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40}, 0x01}, + {PRO_DMOD, 0xf810, {0x54}, 0x01}, + {PRO_DMOD, 0xf811, {0x5a}, 0x01}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_38[] = { {PRO_DMOD, 0x0043, {0x00}, 0x01}, {PRO_DMOD, 0x0046, {0x38}, 0x01}, {PRO_DMOD, 0x0051, {0x01}, 0x01}, @@ -244,7 +360,7 @@ static struct it913xset it9137_set[] = { {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8, - 0xd0, 0xc3, 0x01 }, 0x0a}, + 0xd0, 0xc3, 0x01}, 0x0a}, {PRO_DMOD, 0x008e, {0x01}, 0x01}, {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, {PRO_DMOD, 0x0099, {0x01}, 0x01}, @@ -262,15 +378,25 @@ static struct it913xset it9137_set[] = { {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, {PRO_DMOD, 0x00fc, { 0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77, - 0x00, 0x02, 0xc8, 0x05, 0x7b }, 0x0c}, + 0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c}, {PRO_DMOD, 0x0109, {0x02}, 0x01}, - {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, - {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0xbc, 0xa0}, 0x04}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04}, {PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03}, {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, - {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8}, 0x04}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, {PRO_DMOD, 0xf130, {0x04}, 0x01}, {PRO_DMOD, 0xf132, {0x04}, 0x01}, {PRO_DMOD, 0xf144, {0x1a}, 0x01}, @@ -301,7 +427,7 @@ static struct it913xset it9137_set[] = { {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, - 0x1f }, 0x08}, + 0x1f}, 0x08}, {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, {PRO_DMOD, 0xf78b, {0x01}, 0x01}, @@ -309,21 +435,605 @@ static struct it913xset it9137_set[] = { {PRO_DMOD, 0xf905, {0x01}, 0x01}, {PRO_DMOD, 0xfb06, {0x03}, 0x01}, {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, - {PRO_LINK, GPIOH5_ON, {0x01}, 0x01}, - {PRO_LINK, GPIOH5_O, {0x00}, 0x01}, - {PRO_LINK, GPIOH5_O, {0x01}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_51[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x51}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, + {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96, + 0xcf, 0xc3, 0x01}, 0x0a}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, + {PRO_DMOD, 0x00c4, {0x00}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, + {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77, + 0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04}, + {PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03}, + {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_52[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x52}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x10}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, + {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97, + 0xc0, 0x9e, 0x01}, 0x0a}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, + {PRO_DMOD, 0x00c4, {0x00}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, + {PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77, + 0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04}, + {PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03}, + {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ }; +/* Version 2 types */ +static struct it913xset it9135_v2[] = { + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a}, 0x01}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a}, 0x01}, + {PRO_DMOD, 0x008a, {0x01}, 0x01}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06}, 0x01}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009f, {0xe1}, 0x01}, + {PRO_DMOD, 0x00a0, {0xcf}, 0x01}, + {PRO_DMOD, 0x00a3, {0x01}, 0x01}, + {PRO_DMOD, 0x00a5, {0x01}, 0x01}, + {PRO_DMOD, 0x00a6, {0x01}, 0x01}, + {PRO_DMOD, 0x00a9, {0x00}, 0x01}, + {PRO_DMOD, 0x00aa, {0x01}, 0x01}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00c2, {0x05}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf02b, {0x00}, 0x01}, + {PRO_DMOD, 0xf064, {0x03}, 0x01}, + {PRO_DMOD, 0xf065, {0xf9}, 0x01}, + {PRO_DMOD, 0xf066, {0x03}, 0x01}, + {PRO_DMOD, 0xf067, {0x01}, 0x01}, + {PRO_DMOD, 0xf06f, {0xe0}, 0x01}, + {PRO_DMOD, 0xf070, {0x03}, 0x01}, + {PRO_DMOD, 0xf072, {0x0f}, 0x01}, + {PRO_DMOD, 0xf073, {0x03}, 0x01}, + {PRO_DMOD, 0xf078, {0x00}, 0x01}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f}, 0x01}, + {PRO_DMOD, 0xf09c, {0x00}, 0x01}, + {PRO_DMOD, 0xf09d, {0x20}, 0x01}, + {PRO_DMOD, 0xf09e, {0x00}, 0x01}, + {PRO_DMOD, 0xf09f, {0x0c}, 0x01}, + {PRO_DMOD, 0xf0a0, {0x00}, 0x01}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00}, 0x01}, + {PRO_DMOD, 0xf14d, {0x00}, 0x01}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00}, 0x01}, + {PRO_DMOD, 0xf15b, {0x08}, 0x01}, + {PRO_DMOD, 0xf15d, {0x03}, 0x01}, + {PRO_DMOD, 0xf15e, {0x05}, 0x01}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01}, 0x01}, + {PRO_DMOD, 0xf167, {0x40}, 0x01}, + {PRO_DMOD, 0xf168, {0x0f}, 0x01}, + {PRO_DMOD, 0xf17a, {0x00}, 0x01}, + {PRO_DMOD, 0xf17b, {0x00}, 0x01}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36}, 0x01}, + {PRO_DMOD, 0xf1bd, {0x00}, 0x01}, + {PRO_DMOD, 0xf1cb, {0xa0}, 0x01}, + {PRO_DMOD, 0xf1cc, {0x01}, 0x01}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf40e, {0x0a}, 0x01}, + {PRO_DMOD, 0xf40f, {0x40}, 0x01}, + {PRO_DMOD, 0xf410, {0x08}, 0x01}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15}, 0x01}, + {PRO_DMOD, 0xf562, {0x20}, 0x01}, + {PRO_DMOD, 0xf5e3, {0x09}, 0x01}, + {PRO_DMOD, 0xf5e4, {0x01}, 0x01}, + {PRO_DMOD, 0xf5e5, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05}, 0x01}, + {PRO_DMOD, 0xf601, {0x08}, 0x01}, + {PRO_DMOD, 0xf602, {0x0b}, 0x01}, + {PRO_DMOD, 0xf603, {0x0e}, 0x01}, + {PRO_DMOD, 0xf604, {0x11}, 0x01}, + {PRO_DMOD, 0xf605, {0x14}, 0x01}, + {PRO_DMOD, 0xf606, {0x17}, 0x01}, + {PRO_DMOD, 0xf607, {0x1f}, 0x01}, + {PRO_DMOD, 0xf60e, {0x00}, 0x01}, + {PRO_DMOD, 0xf60f, {0x04}, 0x01}, + {PRO_DMOD, 0xf610, {0x32}, 0x01}, + {PRO_DMOD, 0xf611, {0x10}, 0x01}, + {PRO_DMOD, 0xf707, {0xfc}, 0x01}, + {PRO_DMOD, 0xf708, {0x00}, 0x01}, + {PRO_DMOD, 0xf709, {0x37}, 0x01}, + {PRO_DMOD, 0xf70a, {0x00}, 0x01}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40}, 0x01}, + {PRO_DMOD, 0xf810, {0x54}, 0x01}, + {PRO_DMOD, 0xf811, {0x5a}, 0x01}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_60[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x60}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c, + 0x00, 0x02, 0xbe, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xbe}, 0x01}, + {PRO_DMOD, 0x0124, {0xae}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x08}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c, + 0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xbc}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02}, + {PRO_DMOD, 0x0185, {0x24}, 0x01}, + {PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17 + , 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_61[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x61}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x06}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c, + 0x01, 0x02, 0xc8, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xc6}, 0x01}, + {PRO_DMOD, 0x0124, {0xa8}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x05}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c, + 0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xcc}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02}, + {PRO_DMOD, 0x0185, {0x28}, 0x01}, + {PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_62[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x62}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, { 0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01}, + 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c, + 0x02, 0x02, 0xc2, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xb8}, 0x01}, + {PRO_DMOD, 0x0124, {0xa8}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x05}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c, + 0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xb2}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02}, + {PRO_DMOD, 0x0185, {0x24}, 0x01}, + {PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +/* Tuner setting scripts (still keeping it9137) */ static struct it913xset it9137_tuner_off[] = { {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */ {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, + {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, 0x0c}, + {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04}, + {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}, 0x09}, + {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}, 0x0a}, + {PRO_DMOD, 0xec20, {0x00}, 0x01}, {PRO_DMOD, 0xec3f, {0x01}, 0x01}, {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ }; +static struct it913xset set_it9135_template[] = { + {PRO_DMOD, 0xee06, {0x00}, 0x01}, + {PRO_DMOD, 0xec56, {0x00}, 0x01}, + {PRO_DMOD, 0xec4c, {0x00}, 0x01}, + {PRO_DMOD, 0xec4d, {0x00}, 0x01}, + {PRO_DMOD, 0xec4e, {0x00}, 0x01}, + {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */ + {PRO_DMOD, 0x011f, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + static struct it913xset set_it9137_template[] = { {PRO_DMOD, 0xee06, {0x00}, 0x01}, {PRO_DMOD, 0xec56, {0x00}, 0x01}, diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c index d4bd24eb4700..ccc36bf2deb4 100644 --- a/drivers/media/dvb/frontends/it913x-fe.c +++ b/drivers/media/dvb/frontends/it913x-fe.c @@ -46,13 +46,17 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); dprintk(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ *p, *(p+1), *(p+2), *(p+3), *(p+4), \ *(p+5), *(p+6), *(p+7)); +#define info(format, arg...) \ + printk(KERN_INFO "it913x-fe: " format "\n" , ## arg) struct it913x_fe_state { struct dvb_frontend frontend; struct i2c_adapter *i2c_adap; + struct ite_config *config; u8 i2c_addr; u32 frequency; - u8 adf; + fe_modulation_t constellation; + fe_transmit_mode_t transmission_mode; u32 crystalFrequency; u32 adcFrequency; u8 tuner_type; @@ -62,6 +66,7 @@ struct it913x_fe_state { u8 tun_fdiv; u8 tun_clk_mode; u32 tun_fn_min; + u32 ucblocks; }; static int it913x_read_reg(struct it913x_fe_state *state, @@ -211,20 +216,24 @@ static int it913x_init_tuner(struct it913x_fe_state *state) state->tun_fn_min /= (state->tun_fdiv * nv_val); deb_info("Tuner fn_min %d", state->tun_fn_min); - for (i = 0; i < 50; i++) { - reg = it913x_read_reg_u8(state, 0xec82); - if (reg > 0) - break; - if (reg < 0) - return -ENODEV; - udelay(2000); + if (state->config->chip_ver > 1) + msleep(50); + else { + for (i = 0; i < 50; i++) { + reg = it913x_read_reg_u8(state, 0xec82); + if (reg > 0) + break; + if (reg < 0) + return -ENODEV; + udelay(2000); + } } return it913x_write_reg(state, PRO_DMOD, 0xed81, val); } static int it9137_set_tuner(struct it913x_fe_state *state, - enum fe_bandwidth bandwidth, u32 frequency_m) + u32 bandwidth, u32 frequency_m) { struct it913xset *set_tuner = set_it9137_template; int ret, reg; @@ -237,6 +246,11 @@ static int it9137_set_tuner(struct it913x_fe_state *state, u8 lna_band; u8 bw; + if (state->config->firmware_ver == 1) + set_tuner = set_it9135_template; + else + set_tuner = set_it9137_template; + deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth); if (frequency >= 51000 && frequency <= 440000) { @@ -273,16 +287,21 @@ static int it9137_set_tuner(struct it913x_fe_state *state, return -EINVAL; set_tuner[0].reg[0] = lna_band; - if (bandwidth == BANDWIDTH_5_MHZ) + switch (bandwidth) { + case 5000000: bw = 0; - else if (bandwidth == BANDWIDTH_6_MHZ) + break; + case 6000000: bw = 2; - else if (bandwidth == BANDWIDTH_7_MHZ) + break; + case 7000000: bw = 4; - else if (bandwidth == BANDWIDTH_8_MHZ) - bw = 6; - else + break; + default: + case 8000000: bw = 6; + break; + } set_tuner[1].reg[0] = bw; set_tuner[2].reg[0] = 0xa0 | (l_band << 3); @@ -361,7 +380,7 @@ static int it9137_set_tuner(struct it913x_fe_state *state, } static int it913x_fe_select_bw(struct it913x_fe_state *state, - enum fe_bandwidth bandwidth, u32 adcFrequency) + u32 bandwidth, u32 adcFrequency) { int ret, i; u8 buffer[256]; @@ -374,17 +393,21 @@ static int it913x_fe_select_bw(struct it913x_fe_state *state, deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency); - if (bandwidth == BANDWIDTH_5_MHZ) + switch (bandwidth) { + case 5000000: bw = 3; - else if (bandwidth == BANDWIDTH_6_MHZ) + break; + case 6000000: bw = 0; - else if (bandwidth == BANDWIDTH_7_MHZ) + break; + case 7000000: bw = 1; - else if (bandwidth == BANDWIDTH_8_MHZ) - bw = 2; - else + break; + default: + case 8000000: bw = 2; - + break; + } ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw); if (state->table == NULL) @@ -492,31 +515,79 @@ static int it913x_fe_read_signal_strength(struct dvb_frontend *fe, return 0; } -static int it913x_fe_read_snr(struct dvb_frontend *fe, u16* snr) +static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr) { struct it913x_fe_state *state = fe->demodulator_priv; - int ret = it913x_read_reg_u8(state, SIGNAL_QUALITY); - ret = (ret * 0xff) / 0x64; - ret |= (ret << 0x8); - *snr = ~ret; - return 0; + int ret; + u8 reg[3]; + u32 snr_val, snr_min, snr_max; + u32 temp; + + ret = it913x_read_reg(state, 0x2c, reg, sizeof(reg)); + + snr_val = (u32)(reg[2] << 16) | (reg[1] << 8) | reg[0]; + + ret |= it913x_read_reg(state, 0xf78b, reg, 1); + if (reg[0]) + snr_val /= reg[0]; + + if (state->transmission_mode == TRANSMISSION_MODE_2K) + snr_val *= 4; + else if (state->transmission_mode == TRANSMISSION_MODE_4K) + snr_val *= 2; + + if (state->constellation == QPSK) { + snr_min = 0xb4711; + snr_max = 0x191451; + } else if (state->constellation == QAM_16) { + snr_min = 0x4f0d5; + snr_max = 0xc7925; + } else if (state->constellation == QAM_64) { + snr_min = 0x256d0; + snr_max = 0x626be; + } else + return -EINVAL; + + if (snr_val < snr_min) + *snr = 0; + else if (snr_val < snr_max) { + temp = (snr_val - snr_min) >> 5; + temp *= 0xffff; + temp /= (snr_max - snr_min) >> 5; + *snr = (u16)temp; + } else + *snr = 0xffff; + + return (ret < 0) ? -ENODEV : 0; } static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber) { - *ber = 0; + struct it913x_fe_state *state = fe->demodulator_priv; + int ret; + u8 reg[5]; + /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */ + ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg)); + state->ucblocks += (u32)(reg[1] << 8) | reg[0]; + *ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2]; return 0; } static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - *ucblocks = 0; - return 0; + struct it913x_fe_state *state = fe->demodulator_priv; + int ret; + u8 reg[2]; + /* Aborted Packets */ + ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg)); + state->ucblocks += (u32)(reg[1] << 8) | reg[0]; + *ucblocks = state->ucblocks; + return ret; } -static int it913x_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int it913x_fe_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct it913x_fe_state *state = fe->demodulator_priv; int ret; u8 reg[8]; @@ -524,26 +595,30 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe, ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg)); if (reg[3] < 3) - p->u.ofdm.constellation = fe_con[reg[3]]; + p->modulation = fe_con[reg[3]]; if (reg[0] < 3) - p->u.ofdm.transmission_mode = fe_mode[reg[0]]; + p->transmission_mode = fe_mode[reg[0]]; if (reg[1] < 4) - p->u.ofdm.guard_interval = fe_gi[reg[1]]; + p->guard_interval = fe_gi[reg[1]]; if (reg[2] < 4) - p->u.ofdm.hierarchy_information = fe_hi[reg[2]]; + p->hierarchy = fe_hi[reg[2]]; + + p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; + p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; - p->u.ofdm.code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; - p->u.ofdm.code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; + /* Update internal state to reflect the autodetected props */ + state->constellation = p->modulation; + state->transmission_mode = p->transmission_mode; return 0; } -static int it913x_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int it913x_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct it913x_fe_state *state = fe->demodulator_priv; int ret, i; u8 empty_ch, last_ch; @@ -551,7 +626,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe, state->it913x_status = 0; /* Set bw*/ - ret = it913x_fe_select_bw(state, p->u.ofdm.bandwidth, + ret = it913x_fe_select_bw(state, p->bandwidth_hz, state->adcFrequency); /* Training Mode Off */ @@ -571,20 +646,25 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe, i = 1; else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000)) i = 2; - else - return -EOPNOTSUPP; + else + return -EOPNOTSUPP; ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i); deb_info("Frontend Set Tuner Type %02x", state->tuner_type); switch (state->tuner_type) { - case IT9137: /* Tuner type 0x38 */ + case IT9135_38: + case IT9135_51: + case IT9135_52: + case IT9135_60: + case IT9135_61: + case IT9135_62: ret = it9137_set_tuner(state, - p->u.ofdm.bandwidth, p->frequency); + p->bandwidth_hz, p->frequency); break; default: if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -678,16 +758,19 @@ static u32 compute_div(u32 a, u32 b, u32 x) static int it913x_fe_start(struct it913x_fe_state *state) { - struct it913xset *set_fe; + struct it913xset *set_lna; struct it913xset *set_mode; int ret; - u8 adf = (state->adf & 0xf); + u8 adf = (state->config->adf & 0xf); u32 adc, xtal; u8 b[4]; - ret = it913x_init_tuner(state); + if (state->config->chip_ver == 1) + ret = it913x_init_tuner(state); + + info("ADF table value :%02x", adf); - if (adf < 12) { + if (adf < 10) { state->crystalFrequency = fe_clockTable[adf].xtal ; state->table = fe_clockTable[adf].table; state->adcFrequency = state->table->adcFrequency; @@ -698,9 +781,6 @@ static int it913x_fe_start(struct it913x_fe_state *state) } else return -EINVAL; - deb_info("Xtal Freq :%d Adc Freq :%d Adc %08x Xtal %08x", - state->crystalFrequency, state->adcFrequency, adc, xtal); - /* Set LED indicator on GPIOH3 */ ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1); ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1); @@ -721,22 +801,71 @@ static int it913x_fe_start(struct it913x_fe_state *state) b[2] = (adc >> 16) & 0xff; ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3); + if (state->config->adc_x2) + ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01); + b[0] = 0; + b[1] = 0; + b[2] = 0; + ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3); + + info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x", + state->crystalFrequency, state->adcFrequency, + state->config->adc_x2); + deb_info("Xtal value :%04x Adc value :%04x", xtal, adc); + + if (ret < 0) + return -ENODEV; + + /* v1 or v2 tuner script */ + if (state->config->chip_ver > 1) + ret = it913x_fe_script_loader(state, it9135_v2); + else + ret = it913x_fe_script_loader(state, it9135_v1); + if (ret < 0) + return ret; + + /* LNA Scripts */ switch (state->tuner_type) { - case IT9137: /* Tuner type 0x38 */ - set_fe = it9137_set; + case IT9135_51: + set_lna = it9135_51; + break; + case IT9135_52: + set_lna = it9135_52; + break; + case IT9135_60: + set_lna = it9135_60; + break; + case IT9135_61: + set_lna = it9135_61; break; + case IT9135_62: + set_lna = it9135_62; + break; + case IT9135_38: default: - return -EINVAL; + set_lna = it9135_38; } + info("Tuner LNA type :%02x", state->tuner_type); + + ret = it913x_fe_script_loader(state, set_lna); + if (ret < 0) + return ret; + + if (state->config->chip_ver == 2) { + ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); + ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0); + ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0); + ret |= it913x_init_tuner(state); + } + if (ret < 0) + return -ENODEV; - /* set the demod */ - ret = it913x_fe_script_loader(state, set_fe); /* Always solo frontend */ set_mode = set_solo_fe; ret |= it913x_fe_script_loader(state, set_mode); ret |= it913x_fe_suspend(state); - return 0; + return (ret < 0) ? -ENODEV : 0; } static int it913x_fe_init(struct dvb_frontend *fe) @@ -746,17 +875,11 @@ static int it913x_fe_init(struct dvb_frontend *fe) /* Power Up Tuner - common all versions */ ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1); - ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0); - ret |= it913x_fe_script_loader(state, init_1); - switch (state->tuner_type) { - case IT9137: - ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0); - break; - default: - return -EINVAL; - } + ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0); + + ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0); return (ret < 0) ? -ENODEV : 0; } @@ -770,19 +893,34 @@ static void it913x_fe_release(struct dvb_frontend *fe) static struct dvb_frontend_ops it913x_fe_ofdm_ops; struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap, - u8 i2c_addr, u8 adf, u8 type) + u8 i2c_addr, struct ite_config *config) { struct it913x_fe_state *state = NULL; int ret; + /* allocate memory for the internal state */ state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL); if (state == NULL) + return NULL; + if (config == NULL) goto error; state->i2c_adap = i2c_adap; state->i2c_addr = i2c_addr; - state->adf = adf; - state->tuner_type = type; + state->config = config; + + switch (state->config->tuner_id_0) { + case IT9135_51: + case IT9135_52: + case IT9135_60: + case IT9135_61: + case IT9135_62: + state->tuner_type = state->config->tuner_id_0; + break; + default: + case IT9135_38: + state->tuner_type = IT9135_38; + } ret = it913x_fe_start(state); if (ret < 0) @@ -802,10 +940,9 @@ error: EXPORT_SYMBOL(it913x_fe_attach); static struct dvb_frontend_ops it913x_fe_ofdm_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "it913x-fe DVB-T", - .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 1680000000, .frequency_stepsize = 62500, @@ -835,5 +972,5 @@ static struct dvb_frontend_ops it913x_fe_ofdm_ops = { MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); -MODULE_VERSION("1.07"); +MODULE_VERSION("1.13"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/it913x-fe.h b/drivers/media/dvb/frontends/it913x-fe.h index 9d97f32e690b..c4a908e354e0 100644 --- a/drivers/media/dvb/frontends/it913x-fe.h +++ b/drivers/media/dvb/frontends/it913x-fe.h @@ -23,13 +23,27 @@ #include <linux/dvb/frontend.h> #include "dvb_frontend.h" + +struct ite_config { + u8 chip_ver; + u16 chip_type; + u32 firmware; + u8 firmware_ver; + u8 adc_x2; + u8 tuner_id_0; + u8 tuner_id_1; + u8 dual_mode; + u8 adf; +}; + #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \ defined(MODULE)) extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap, - u8 i2c_addr, u8 adf, u8 type); + u8 i2c_addr, struct ite_config *config); #else static inline struct dvb_frontend *it913x_fe_attach( - struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 adf, u8 type) + struct i2c_adapter *i2c_adap, + u8 i2c_addr, struct ite_config *config) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; @@ -134,6 +148,16 @@ static inline struct dvb_frontend *it913x_fe_attach( #define COEFF_1_2048 0x0001 #define XTAL_CLK 0x0025 #define BFS_FCW 0x0029 + +/* Error Regs */ +#define RSD_ABORT_PKT_LSB 0x0032 +#define RSD_ABORT_PKT_MSB 0x0033 +#define RSD_BIT_ERR_0_7 0x0034 +#define RSD_BIT_ERR_8_15 0x0035 +#define RSD_BIT_ERR_23_16 0x0036 +#define RSD_BIT_COUNT_LSB 0x0037 +#define RSD_BIT_COUNT_MSB 0x0038 + #define TPSD_LOCK 0x003c #define TRAINING_MODE 0x0040 #define ADC_X_2 0x0045 @@ -144,8 +168,14 @@ static inline struct dvb_frontend *it913x_fe_attach( #define EST_SIGNAL_LEVEL 0x004a #define FREE_BAND 0x004b #define SUSPEND_FLAG 0x004c -/* Build in tuners */ +/* Build in tuner types */ #define IT9137 0x38 +#define IT9135_38 0x38 +#define IT9135_51 0x51 +#define IT9135_52 0x52 +#define IT9135_60 0x60 +#define IT9135_61 0x61 +#define IT9135_62 0x62 enum { CMD_DEMOD_READ = 0, @@ -193,4 +223,11 @@ enum { WRITE_CMD, }; +enum { + IT9135_AUTO = 0, + IT9137_FW, + IT9135_V1_FW, + IT9135_V2_FW, +}; + #endif /* IT913X_FE_H */ diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c index aa9ccb821fa5..316457584fe7 100644 --- a/drivers/media/dvb/frontends/itd1000.c +++ b/drivers/media/dvb/frontends/itd1000.c @@ -250,13 +250,14 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) itd1000_set_vco(state, freq_khz); } -static int itd1000_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int itd1000_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct itd1000_state *state = fe->tuner_priv; u8 pllcon1; - itd1000_set_lo(state, p->frequency); - itd1000_set_lpf_bw(state, p->u.qpsk.symbol_rate); + itd1000_set_lo(state, c->frequency); + itd1000_set_lpf_bw(state, c->symbol_rate); pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f; itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7)); diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c index 9a517a4bf96d..bc5a82082aaa 100644 --- a/drivers/media/dvb/frontends/ix2505v.c +++ b/drivers/media/dvb/frontends/ix2505v.c @@ -129,12 +129,12 @@ static int ix2505v_release(struct dvb_frontend *fe) * 1 -> 8 -> 6 */ -static int ix2505v_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int ix2505v_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct ix2505v_state *state = fe->tuner_priv; - u32 frequency = params->frequency; - u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; + u32 frequency = c->frequency; + u32 b_w = (c->symbol_rate * 27) / 32000; u32 div_factor, N , A, x; int ret = 0, len; u8 gain, cc, ref, psc, local_osc, lpf; diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 445fa1068064..36fcf559e361 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -117,18 +117,17 @@ static int reset_and_configure (struct l64781_state* state) return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV; } -static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param) +static int apply_frontend_param(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct l64781_state* state = fe->demodulator_priv; /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; /* QPSK, QAM_16, QAM_64 */ static const u8 qam_tab [] = { 2, 4, 0, 6 }; - static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */ static const u8 guard_tab [] = { 1, 2, 4, 8 }; /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */ static const u32 ppm = 8000; - struct dvb_ofdm_parameters *p = ¶m->u.ofdm; u32 ddfs_offset_fixed; /* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */ /* bw_tab[p->bandWidth]<<10)/15625; */ @@ -137,18 +136,29 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa u8 val0x04; u8 val0x05; u8 val0x06; - int bw = p->bandwidth - BANDWIDTH_8_MHZ; + int bw; + + switch (p->bandwidth_hz) { + case 8000000: + bw = 8; + break; + case 7000000: + bw = 7; + break; + case 6000000: + bw = 6; + break; + default: + return -EINVAL; + } if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - if (param->inversion != INVERSION_ON && - param->inversion != INVERSION_OFF) - return -EINVAL; - - if (bw < 0 || bw > 2) + if (p->inversion != INVERSION_ON && + p->inversion != INVERSION_OFF) return -EINVAL; if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 && @@ -156,14 +166,14 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa p->code_rate_HP != FEC_7_8) return -EINVAL; - if (p->hierarchy_information != HIERARCHY_NONE && + if (p->hierarchy != HIERARCHY_NONE && (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 && p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 && p->code_rate_LP != FEC_7_8)) return -EINVAL; - if (p->constellation != QPSK && p->constellation != QAM_16 && - p->constellation != QAM_64) + if (p->modulation != QPSK && p->modulation != QAM_16 && + p->modulation != QAM_64) return -EINVAL; if (p->transmission_mode != TRANSMISSION_MODE_2K && @@ -174,22 +184,22 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa p->guard_interval > GUARD_INTERVAL_1_4) return -EINVAL; - if (p->hierarchy_information < HIERARCHY_NONE || - p->hierarchy_information > HIERARCHY_4) + if (p->hierarchy < HIERARCHY_NONE || + p->hierarchy > HIERARCHY_4) return -EINVAL; - ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000; + ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000; /* This works up to 20000 ppm, it overflows if too large ppm! */ init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) / - bw_tab[p->bandwidth] & 0xFFFFFF); + bw & 0xFFFFFF); /* SPI bias calculation is slightly modified to fit in 32bit */ /* will work for high ppm only... */ spi_bias = 378 * (1 << 10); spi_bias *= 16; - spi_bias *= bw_tab[p->bandwidth]; - spi_bias *= qam_tab[p->constellation]; + spi_bias *= bw; + spi_bias *= qam_tab[p->modulation]; spi_bias /= p->code_rate_HP + 1; spi_bias /= (guard_tab[p->guard_interval] + 32); spi_bias *= 1000; @@ -199,10 +209,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa val0x04 = (p->transmission_mode << 2) | p->guard_interval; val0x05 = fec_tab[p->code_rate_HP]; - if (p->hierarchy_information != HIERARCHY_NONE) + if (p->hierarchy != HIERARCHY_NONE) val0x05 |= (p->code_rate_LP - FEC_1_2) << 3; - val0x06 = (p->hierarchy_information << 2) | p->constellation; + val0x06 = (p->hierarchy << 2) | p->modulation; l64781_writereg (state, 0x04, val0x04); l64781_writereg (state, 0x05, val0x05); @@ -220,7 +230,7 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa l64781_writereg (state, 0x1b, spi_bias & 0xff); l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff); l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) | - (param->inversion == INVERSION_ON ? 0x80 : 0x00)); + (p->inversion == INVERSION_ON ? 0x80 : 0x00)); l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff); l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f); @@ -233,8 +243,9 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa return 0; } -static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param) +static int get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct l64781_state* state = fe->demodulator_priv; int tmp; @@ -242,98 +253,95 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* tmp = l64781_readreg(state, 0x04); switch(tmp & 3) { case 0: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + p->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + p->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + p->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + p->guard_interval = GUARD_INTERVAL_1_4; break; } switch((tmp >> 2) & 3) { case 0: - param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + p->transmission_mode = TRANSMISSION_MODE_2K; break; case 1: - param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + p->transmission_mode = TRANSMISSION_MODE_8K; break; default: - printk("Unexpected value for transmission_mode\n"); + printk(KERN_WARNING "Unexpected value for transmission_mode\n"); } - - tmp = l64781_readreg(state, 0x05); switch(tmp & 7) { case 0: - param->u.ofdm.code_rate_HP = FEC_1_2; + p->code_rate_HP = FEC_1_2; break; case 1: - param->u.ofdm.code_rate_HP = FEC_2_3; + p->code_rate_HP = FEC_2_3; break; case 2: - param->u.ofdm.code_rate_HP = FEC_3_4; + p->code_rate_HP = FEC_3_4; break; case 3: - param->u.ofdm.code_rate_HP = FEC_5_6; + p->code_rate_HP = FEC_5_6; break; case 4: - param->u.ofdm.code_rate_HP = FEC_7_8; + p->code_rate_HP = FEC_7_8; break; default: printk("Unexpected value for code_rate_HP\n"); } switch((tmp >> 3) & 7) { case 0: - param->u.ofdm.code_rate_LP = FEC_1_2; + p->code_rate_LP = FEC_1_2; break; case 1: - param->u.ofdm.code_rate_LP = FEC_2_3; + p->code_rate_LP = FEC_2_3; break; case 2: - param->u.ofdm.code_rate_LP = FEC_3_4; + p->code_rate_LP = FEC_3_4; break; case 3: - param->u.ofdm.code_rate_LP = FEC_5_6; + p->code_rate_LP = FEC_5_6; break; case 4: - param->u.ofdm.code_rate_LP = FEC_7_8; + p->code_rate_LP = FEC_7_8; break; default: printk("Unexpected value for code_rate_LP\n"); } - tmp = l64781_readreg(state, 0x06); switch(tmp & 3) { case 0: - param->u.ofdm.constellation = QPSK; + p->modulation = QPSK; break; case 1: - param->u.ofdm.constellation = QAM_16; + p->modulation = QAM_16; break; case 2: - param->u.ofdm.constellation = QAM_64; + p->modulation = QAM_64; break; default: - printk("Unexpected value for constellation\n"); + printk(KERN_WARNING "Unexpected value for modulation\n"); } switch((tmp >> 2) & 7) { case 0: - param->u.ofdm.hierarchy_information = HIERARCHY_NONE; + p->hierarchy = HIERARCHY_NONE; break; case 1: - param->u.ofdm.hierarchy_information = HIERARCHY_1; + p->hierarchy = HIERARCHY_1; break; case 2: - param->u.ofdm.hierarchy_information = HIERARCHY_2; + p->hierarchy = HIERARCHY_2; break; case 3: - param->u.ofdm.hierarchy_information = HIERARCHY_4; + p->hierarchy = HIERARCHY_4; break; default: printk("Unexpected value for hierarchy\n"); @@ -341,12 +349,12 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* tmp = l64781_readreg (state, 0x1d); - param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; + p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; tmp = (int) (l64781_readreg (state, 0x08) | (l64781_readreg (state, 0x09) << 8) | (l64781_readreg (state, 0x0a) << 16)); - param->frequency += tmp; + p->frequency += tmp; return 0; } @@ -564,10 +572,9 @@ error: } static struct dvb_frontend_ops l64781_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "LSI L64781 DVB-T", - .type = FE_OFDM, /* .frequency_min = ???,*/ /* .frequency_max = ???,*/ .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c index 3272881cb112..1d2c47378cf8 100644 --- a/drivers/media/dvb/frontends/lgdt3305.c +++ b/drivers/media/dvb/frontends/lgdt3305.c @@ -266,7 +266,7 @@ fail: } static int lgdt3305_set_modulation(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u8 opermode; int ret; @@ -279,7 +279,7 @@ static int lgdt3305_set_modulation(struct lgdt3305_state *state, opermode &= ~0x03; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: opermode |= 0x03; break; @@ -298,11 +298,11 @@ fail: } static int lgdt3305_set_filter_extension(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { int val; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: val = 0; break; @@ -321,11 +321,11 @@ static int lgdt3305_set_filter_extension(struct lgdt3305_state *state, /* ------------------------------------------------------------------------ */ static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u16 agc_ref; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: agc_ref = 0x32c4; break; @@ -348,11 +348,11 @@ static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state, } static int lgdt3305_rfagc_loop(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u16 ifbw, rfbw, agcdelay; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: agcdelay = 0x04c0; rfbw = 0x8000; @@ -398,11 +398,11 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state, } static int lgdt3305_agc_setup(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { int lockdten, acqen; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: lockdten = 0; acqen = 0; @@ -432,15 +432,15 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state, return -EINVAL; } - return lgdt3305_rfagc_loop(state, param); + return lgdt3305_rfagc_loop(state, p); } static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u16 usref = 0; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: if (state->cfg->usref_8vsb) usref = state->cfg->usref_8vsb; @@ -473,14 +473,14 @@ static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state, /* ------------------------------------------------------------------------ */ static int lgdt3305_spectral_inversion(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param, + struct dtv_frontend_properties *p, int inversion) { int ret; lg_dbg("(%d)\n", inversion); - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7, inversion ? 0xf9 : 0x79); @@ -497,13 +497,13 @@ static int lgdt3305_spectral_inversion(struct lgdt3305_state *state, } static int lgdt3305_set_if(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u16 if_freq_khz; u8 nco1, nco2, nco3, nco4; u64 nco; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: if_freq_khz = state->cfg->vsb_if_khz; break; @@ -517,7 +517,7 @@ static int lgdt3305_set_if(struct lgdt3305_state *state, nco = if_freq_khz / 10; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: nco <<= 24; do_div(nco, 625); @@ -677,37 +677,37 @@ fail: return ret; } -static int lgdt3304_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int lgdt3304_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgdt3305_state *state = fe->demodulator_priv; int ret; - lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); + lg_dbg("(%d, %d)\n", p->frequency, p->modulation); if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe, param); + ret = fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); if (lg_fail(ret)) goto fail; - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; } - ret = lgdt3305_set_modulation(state, param); + ret = lgdt3305_set_modulation(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_passband_digital_agc(state, param); + ret = lgdt3305_passband_digital_agc(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_agc_setup(state, param); + ret = lgdt3305_agc_setup(state, p); if (lg_fail(ret)) goto fail; /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */ - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: lgdt3305_write_reg(state, 0x030d, 0x00); lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f); @@ -718,7 +718,7 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe, case QAM_64: case QAM_256: lgdt3305_write_reg(state, 0x030d, 0x14); - ret = lgdt3305_set_if(state, param); + ret = lgdt3305_set_if(state, p); if (lg_fail(ret)) goto fail; break; @@ -727,13 +727,13 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe, } - ret = lgdt3305_spectral_inversion(state, param, + ret = lgdt3305_spectral_inversion(state, p, state->cfg->spectral_inversion ? 1 : 0); if (lg_fail(ret)) goto fail; - state->current_modulation = param->u.vsb.modulation; + state->current_modulation = p->modulation; ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); if (lg_fail(ret)) @@ -747,34 +747,34 @@ fail: return ret; } -static int lgdt3305_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int lgdt3305_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgdt3305_state *state = fe->demodulator_priv; int ret; - lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); + lg_dbg("(%d, %d)\n", p->frequency, p->modulation); if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe, param); + ret = fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); if (lg_fail(ret)) goto fail; - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; } - ret = lgdt3305_set_modulation(state, param); + ret = lgdt3305_set_modulation(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_passband_digital_agc(state, param); + ret = lgdt3305_passband_digital_agc(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_set_agc_power_ref(state, param); + ret = lgdt3305_set_agc_power_ref(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_agc_setup(state, param); + ret = lgdt3305_agc_setup(state, p); if (lg_fail(ret)) goto fail; @@ -786,20 +786,20 @@ static int lgdt3305_set_parameters(struct dvb_frontend *fe, if (lg_fail(ret)) goto fail; - ret = lgdt3305_set_if(state, param); + ret = lgdt3305_set_if(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_spectral_inversion(state, param, + ret = lgdt3305_spectral_inversion(state, p, state->cfg->spectral_inversion ? 1 : 0); if (lg_fail(ret)) goto fail; - ret = lgdt3305_set_filter_extension(state, param); + ret = lgdt3305_set_filter_extension(state, p); if (lg_fail(ret)) goto fail; - state->current_modulation = param->u.vsb.modulation; + state->current_modulation = p->modulation; ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); if (lg_fail(ret)) @@ -813,15 +813,15 @@ fail: return ret; } -static int lgdt3305_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int lgdt3305_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgdt3305_state *state = fe->demodulator_priv; lg_dbg("\n"); - param->u.vsb.modulation = state->current_modulation; - param->frequency = state->current_frequency; + p->modulation = state->current_modulation; + p->frequency = state->current_frequency; return 0; } @@ -1166,9 +1166,9 @@ fail: EXPORT_SYMBOL(lgdt3305_attach); static struct dvb_frontend_ops lgdt3304_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "LG Electronics LGDT3304 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, @@ -1188,9 +1188,9 @@ static struct dvb_frontend_ops lgdt3304_ops = { }; static struct dvb_frontend_ops lgdt3305_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "LG Electronics LGDT3305 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 43971e63baa7..c990d35a13dc 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -288,6 +288,8 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) int err; u8 buf[2]; + *ucblocks = 0; + switch (state->config->demod_chip) { case LGDT3302: err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, @@ -302,14 +304,16 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) "Only LGDT3302 and LGDT3303 are supported chips.\n"); err = -ENODEV; } + if (err < 0) + return err; *ucblocks = (buf[0] << 8) | buf[1]; return 0; } -static int lgdt330x_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int lgdt330x_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; /* * Array of byte pairs <address, value> * to initialize 8VSB for lgdt3303 chip 50 MHz IF @@ -343,10 +347,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; - int err; + int err = 0; /* Change only if we are actually changing the modulation */ - if (state->current_modulation != param->u.vsb.modulation) { - switch(param->u.vsb.modulation) { + if (state->current_modulation != p->modulation) { + switch (p->modulation) { case VSB_8: dprintk("%s: VSB_8 MODE\n", __func__); @@ -395,9 +399,14 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, } break; default: - printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, param->u.vsb.modulation); + printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, p->modulation); return -1; } + if (err < 0) + printk(KERN_WARNING "lgdt330x: %s: error blasting " + "bytes to lgdt3303 for modulation type(%d)\n", + __func__, p->modulation); + /* * select serial or parallel MPEG harware interface * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 @@ -410,29 +419,29 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, sizeof(top_ctrl_cfg)); if (state->config->set_ts_params) state->config->set_ts_params(fe, 0); - state->current_modulation = param->u.vsb.modulation; + state->current_modulation = p->modulation; } /* Tune to the specified frequency */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } /* Keep track of the new frequency */ /* FIXME this is the wrong way to do this... */ /* The tuner is shared with the video4linux analog API */ - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; lgdt330x_SwReset(state); return 0; } -static int lgdt330x_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters* param) +static int lgdt330x_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgdt330x_state *state = fe->demodulator_priv; - param->frequency = state->current_frequency; + p->frequency = state->current_frequency; return 0; } @@ -762,9 +771,9 @@ error: } static struct dvb_frontend_ops lgdt3302_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name= "LG Electronics LGDT3302 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min= 54000000, .frequency_max= 858000000, .frequency_stepsize= 62500, @@ -785,9 +794,9 @@ static struct dvb_frontend_ops lgdt3302_ops = { }; static struct dvb_frontend_ops lgdt3303_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name= "LG Electronics LGDT3303 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min= 54000000, .frequency_max= 858000000, .frequency_stepsize= 62500, diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c index bb37ed289a05..2cec8041a106 100644 --- a/drivers/media/dvb/frontends/lgs8gl5.c +++ b/drivers/media/dvb/frontends/lgs8gl5.c @@ -311,18 +311,18 @@ lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int -lgs8gl5_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +lgs8gl5_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgs8gl5_state *state = fe->demodulator_priv; dprintk("%s\n", __func__); - if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) + if (p->bandwidth_hz != 8000000) return -EINVAL; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -336,22 +336,21 @@ lgs8gl5_set_frontend(struct dvb_frontend *fe, static int -lgs8gl5_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +lgs8gl5_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgs8gl5_state *state = fe->demodulator_priv; u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); - struct dvb_ofdm_parameters *o = &p->u.ofdm; p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; - o->code_rate_HP = FEC_1_2; - o->code_rate_LP = FEC_7_8; - o->guard_interval = GUARD_INTERVAL_1_32; - o->transmission_mode = TRANSMISSION_MODE_2K; - o->constellation = QAM_64; - o->hierarchy_information = HIERARCHY_NONE; - o->bandwidth = BANDWIDTH_8_MHZ; + p->code_rate_HP = FEC_1_2; + p->code_rate_LP = FEC_7_8; + p->guard_interval = GUARD_INTERVAL_1_32; + p->transmission_mode = TRANSMISSION_MODE_2K; + p->modulation = QAM_64; + p->hierarchy = HIERARCHY_NONE; + p->bandwidth_hz = 8000000; return 0; } @@ -413,9 +412,9 @@ EXPORT_SYMBOL(lgs8gl5_attach); static struct dvb_frontend_ops lgs8gl5_ops = { + .delsys = { SYS_DMBTH }, .info = { .name = "Legend Silicon LGS-8GL5 DMB-TH", - .type = FE_OFDM, .frequency_min = 474000000, .frequency_max = 858000000, .frequency_stepsize = 10000, diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index 1172b54689f8..4de1d3520cd2 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -669,16 +669,16 @@ static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len) return lgs8gxx_write_reg(priv, buf[0], buf[1]); } -static int lgs8gxx_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) +static int lgs8gxx_set_fe(struct dvb_frontend *fe) { + struct lgs8gxx_state *priv = fe->demodulator_priv; dprintk("%s\n", __func__); /* set frequency */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -691,9 +691,9 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe, return 0; } -static int lgs8gxx_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) +static int lgs8gxx_get_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; dprintk("%s\n", __func__); /* TODO: get real readings from device */ @@ -701,21 +701,21 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe, fe_params->inversion = INVERSION_OFF; /* bandwidth */ - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + fe_params->bandwidth_hz = 8000000; - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.code_rate_LP = FEC_AUTO; + fe_params->code_rate_HP = FEC_AUTO; + fe_params->code_rate_LP = FEC_AUTO; - fe_params->u.ofdm.constellation = QAM_AUTO; + fe_params->modulation = QAM_AUTO; /* transmission mode */ - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + fe_params->transmission_mode = TRANSMISSION_MODE_AUTO; /* guard interval */ - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + fe_params->guard_interval = GUARD_INTERVAL_AUTO; /* hierarchy */ - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fe_params->hierarchy = HIERARCHY_NONE; return 0; } @@ -994,9 +994,9 @@ static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } static struct dvb_frontend_ops lgs8gxx_ops = { + .delsys = { SYS_DMBTH }, .info = { .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH", - .type = FE_OFDM, .frequency_min = 474000000, .frequency_max = 858000000, .frequency_stepsize = 10000, diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c index c283112051b1..9ae40abfd71a 100644 --- a/drivers/media/dvb/frontends/mb86a16.c +++ b/drivers/media/dvb/frontends/mb86a16.c @@ -1621,13 +1621,13 @@ err: return -EREMOTEIO; } -static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mb86a16_state *state = fe->demodulator_priv; state->frequency = p->frequency / 1000; - state->srate = p->u.qpsk.symbol_rate / 1000; + state->srate = p->symbol_rate / 1000; if (!mb86a16_set_fe(state)) { dprintk(verbose, MB86A16_ERROR, 1, "Successfully acquired LOCK"); @@ -1814,9 +1814,9 @@ static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe) } static struct dvb_frontend_ops mb86a16_ops = { + .delsys = { SYS_DVBS }, .info = { .name = "Fujitsu MB86A16 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 3000, diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c index 0f867a5055fb..fade566927c3 100644 --- a/drivers/media/dvb/frontends/mb86a20s.c +++ b/drivers/media/dvb/frontends/mb86a20s.c @@ -61,244 +61,111 @@ static struct regdata mb86a20s_init[] = { { 0x70, 0xff }, { 0x08, 0x01 }, { 0x09, 0x3e }, - { 0x50, 0xd1 }, - { 0x51, 0x22 }, + { 0x50, 0xd1 }, { 0x51, 0x22 }, { 0x39, 0x01 }, { 0x71, 0x00 }, - { 0x28, 0x2a }, - { 0x29, 0x00 }, - { 0x2a, 0xff }, - { 0x2b, 0x80 }, - { 0x28, 0x20 }, - { 0x29, 0x33 }, - { 0x2a, 0xdf }, - { 0x2b, 0xa9 }, + { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 }, + { 0x28, 0x20 }, { 0x29, 0x33 }, { 0x2a, 0xdf }, { 0x2b, 0xa9 }, + { 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 }, { 0x3b, 0x21 }, { 0x3c, 0x3a }, { 0x01, 0x0d }, - { 0x04, 0x08 }, - { 0x05, 0x05 }, - { 0x04, 0x0e }, - { 0x05, 0x00 }, - { 0x04, 0x0f }, - { 0x05, 0x14 }, - { 0x04, 0x0b }, - { 0x05, 0x8c }, - { 0x04, 0x00 }, - { 0x05, 0x00 }, - { 0x04, 0x01 }, - { 0x05, 0x07 }, - { 0x04, 0x02 }, - { 0x05, 0x0f }, - { 0x04, 0x03 }, - { 0x05, 0xa0 }, - { 0x04, 0x09 }, - { 0x05, 0x00 }, - { 0x04, 0x0a }, - { 0x05, 0xff }, - { 0x04, 0x27 }, - { 0x05, 0x64 }, - { 0x04, 0x28 }, - { 0x05, 0x00 }, - { 0x04, 0x1e }, - { 0x05, 0xff }, - { 0x04, 0x29 }, - { 0x05, 0x0a }, - { 0x04, 0x32 }, - { 0x05, 0x0a }, - { 0x04, 0x14 }, - { 0x05, 0x02 }, - { 0x04, 0x04 }, - { 0x05, 0x00 }, - { 0x04, 0x05 }, - { 0x05, 0x22 }, - { 0x04, 0x06 }, - { 0x05, 0x0e }, - { 0x04, 0x07 }, - { 0x05, 0xd8 }, - { 0x04, 0x12 }, - { 0x05, 0x00 }, - { 0x04, 0x13 }, - { 0x05, 0xff }, + { 0x04, 0x08 }, { 0x05, 0x05 }, + { 0x04, 0x0e }, { 0x05, 0x00 }, + { 0x04, 0x0f }, { 0x05, 0x14 }, + { 0x04, 0x0b }, { 0x05, 0x8c }, + { 0x04, 0x00 }, { 0x05, 0x00 }, + { 0x04, 0x01 }, { 0x05, 0x07 }, + { 0x04, 0x02 }, { 0x05, 0x0f }, + { 0x04, 0x03 }, { 0x05, 0xa0 }, + { 0x04, 0x09 }, { 0x05, 0x00 }, + { 0x04, 0x0a }, { 0x05, 0xff }, + { 0x04, 0x27 }, { 0x05, 0x64 }, + { 0x04, 0x28 }, { 0x05, 0x00 }, + { 0x04, 0x1e }, { 0x05, 0xff }, + { 0x04, 0x29 }, { 0x05, 0x0a }, + { 0x04, 0x32 }, { 0x05, 0x0a }, + { 0x04, 0x14 }, { 0x05, 0x02 }, + { 0x04, 0x04 }, { 0x05, 0x00 }, + { 0x04, 0x05 }, { 0x05, 0x22 }, + { 0x04, 0x06 }, { 0x05, 0x0e }, + { 0x04, 0x07 }, { 0x05, 0xd8 }, + { 0x04, 0x12 }, { 0x05, 0x00 }, + { 0x04, 0x13 }, { 0x05, 0xff }, + { 0x04, 0x15 }, { 0x05, 0x4e }, + { 0x04, 0x16 }, { 0x05, 0x20 }, { 0x52, 0x01 }, - { 0x50, 0xa7 }, - { 0x51, 0x00 }, - { 0x50, 0xa8 }, - { 0x51, 0xff }, - { 0x50, 0xa9 }, - { 0x51, 0xff }, - { 0x50, 0xaa }, - { 0x51, 0x00 }, - { 0x50, 0xab }, - { 0x51, 0xff }, - { 0x50, 0xac }, - { 0x51, 0xff }, - { 0x50, 0xad }, - { 0x51, 0x00 }, - { 0x50, 0xae }, - { 0x51, 0xff }, - { 0x50, 0xaf }, - { 0x51, 0xff }, + { 0x50, 0xa7 }, { 0x51, 0xff }, + { 0x50, 0xa8 }, { 0x51, 0xff }, + { 0x50, 0xa9 }, { 0x51, 0xff }, + { 0x50, 0xaa }, { 0x51, 0xff }, + { 0x50, 0xab }, { 0x51, 0xff }, + { 0x50, 0xac }, { 0x51, 0xff }, + { 0x50, 0xad }, { 0x51, 0xff }, + { 0x50, 0xae }, { 0x51, 0xff }, + { 0x50, 0xaf }, { 0x51, 0xff }, { 0x5e, 0x07 }, - { 0x50, 0xdc }, - { 0x51, 0x01 }, - { 0x50, 0xdd }, - { 0x51, 0xf4 }, - { 0x50, 0xde }, - { 0x51, 0x01 }, - { 0x50, 0xdf }, - { 0x51, 0xf4 }, - { 0x50, 0xe0 }, - { 0x51, 0x01 }, - { 0x50, 0xe1 }, - { 0x51, 0xf4 }, - { 0x50, 0xb0 }, - { 0x51, 0x07 }, - { 0x50, 0xb2 }, - { 0x51, 0xff }, - { 0x50, 0xb3 }, - { 0x51, 0xff }, - { 0x50, 0xb4 }, - { 0x51, 0xff }, - { 0x50, 0xb5 }, - { 0x51, 0xff }, - { 0x50, 0xb6 }, - { 0x51, 0xff }, - { 0x50, 0xb7 }, - { 0x51, 0xff }, - { 0x50, 0x50 }, - { 0x51, 0x02 }, - { 0x50, 0x51 }, - { 0x51, 0x04 }, + { 0x50, 0xdc }, { 0x51, 0x01 }, + { 0x50, 0xdd }, { 0x51, 0xf4 }, + { 0x50, 0xde }, { 0x51, 0x01 }, + { 0x50, 0xdf }, { 0x51, 0xf4 }, + { 0x50, 0xe0 }, { 0x51, 0x01 }, + { 0x50, 0xe1 }, { 0x51, 0xf4 }, + { 0x50, 0xb0 }, { 0x51, 0x07 }, + { 0x50, 0xb2 }, { 0x51, 0xff }, + { 0x50, 0xb3 }, { 0x51, 0xff }, + { 0x50, 0xb4 }, { 0x51, 0xff }, + { 0x50, 0xb5 }, { 0x51, 0xff }, + { 0x50, 0xb6 }, { 0x51, 0xff }, + { 0x50, 0xb7 }, { 0x51, 0xff }, + { 0x50, 0x50 }, { 0x51, 0x02 }, + { 0x50, 0x51 }, { 0x51, 0x04 }, { 0x45, 0x04 }, { 0x48, 0x04 }, - { 0x50, 0xd5 }, - { 0x51, 0x01 }, /* Serial */ - { 0x50, 0xd6 }, - { 0x51, 0x1f }, - { 0x50, 0xd2 }, - { 0x51, 0x03 }, - { 0x50, 0xd7 }, - { 0x51, 0x3f }, + { 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */ + { 0x50, 0xd6 }, { 0x51, 0x1f }, + { 0x50, 0xd2 }, { 0x51, 0x03 }, + { 0x50, 0xd7 }, { 0x51, 0x3f }, + { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 }, + { 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c }, + { 0x04, 0x40 }, { 0x05, 0x01 }, + { 0x28, 0x00 }, { 0x29, 0x10 }, + { 0x28, 0x05 }, { 0x29, 0x02 }, { 0x1c, 0x01 }, - { 0x28, 0x06 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x03 }, - { 0x28, 0x07 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0d }, - { 0x28, 0x08 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x02 }, - { 0x28, 0x09 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x01 }, - { 0x28, 0x0a }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x21 }, - { 0x28, 0x0b }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x29 }, - { 0x28, 0x0c }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x16 }, - { 0x28, 0x0d }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x31 }, - { 0x28, 0x0e }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0e }, - { 0x28, 0x0f }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x4e }, - { 0x28, 0x10 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x46 }, - { 0x28, 0x11 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0f }, - { 0x28, 0x12 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x56 }, - { 0x28, 0x13 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x35 }, - { 0x28, 0x14 }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0xbe }, - { 0x28, 0x15 }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0x84 }, - { 0x28, 0x16 }, - { 0x29, 0x00 }, - { 0x2a, 0x03 }, - { 0x2b, 0xee }, - { 0x28, 0x17 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x98 }, - { 0x28, 0x18 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x9f }, - { 0x28, 0x19 }, - { 0x29, 0x00 }, - { 0x2a, 0x07 }, - { 0x2b, 0xb2 }, - { 0x28, 0x1a }, - { 0x29, 0x00 }, - { 0x2a, 0x06 }, - { 0x2b, 0xc2 }, - { 0x28, 0x1b }, - { 0x29, 0x00 }, - { 0x2a, 0x07 }, - { 0x2b, 0x4a }, - { 0x28, 0x1c }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0xbc }, - { 0x28, 0x1d }, - { 0x29, 0x00 }, - { 0x2a, 0x04 }, - { 0x2b, 0xba }, - { 0x28, 0x1e }, - { 0x29, 0x00 }, - { 0x2a, 0x06 }, - { 0x2b, 0x14 }, - { 0x50, 0x1e }, - { 0x51, 0x5d }, - { 0x50, 0x22 }, - { 0x51, 0x00 }, - { 0x50, 0x23 }, - { 0x51, 0xc8 }, - { 0x50, 0x24 }, - { 0x51, 0x00 }, - { 0x50, 0x25 }, - { 0x51, 0xf0 }, - { 0x50, 0x26 }, - { 0x51, 0x00 }, - { 0x50, 0x27 }, - { 0x51, 0xc3 }, - { 0x50, 0x39 }, - { 0x51, 0x02 }, - { 0x50, 0xd5 }, - { 0x51, 0x01 }, + { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 }, + { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d }, + { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 }, + { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 }, + { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 }, + { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 }, + { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 }, + { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 }, + { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e }, + { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e }, + { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 }, + { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f }, + { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 }, + { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 }, + { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe }, + { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 }, + { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee }, + { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 }, + { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f }, + { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 }, + { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 }, + { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a }, + { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc }, + { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba }, + { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 }, + { 0x50, 0x1e }, { 0x51, 0x5d }, + { 0x50, 0x22 }, { 0x51, 0x00 }, + { 0x50, 0x23 }, { 0x51, 0xc8 }, + { 0x50, 0x24 }, { 0x51, 0x00 }, + { 0x50, 0x25 }, { 0x51, 0xf0 }, + { 0x50, 0x26 }, { 0x51, 0x00 }, + { 0x50, 0x27 }, { 0x51, 0xc3 }, + { 0x50, 0x39 }, { 0x51, 0x02 }, + { 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 }, { 0xd0, 0x00 }, }; @@ -485,18 +352,23 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status) return 0; } -static int mb86a20s_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mb86a20s_set_frontend(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; int rc; +#if 0 + /* + * FIXME: Properly implement the set frontend properties + */ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; +#endif dprintk("\n"); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); dprintk("Calling tuner set parameters\n"); - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); /* * Make it more reliable: if, for some reason, the initial @@ -520,22 +392,212 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe, return rc; } -static int mb86a20s_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mb86a20s_get_modulation(struct mb86a20s_state *state, + unsigned layer) +{ + int rc; + static unsigned char reg[] = { + [0] = 0x86, /* Layer A */ + [1] = 0x8a, /* Layer B */ + [2] = 0x8e, /* Layer C */ + }; + + if (layer >= ARRAY_SIZE(reg)) + return -EINVAL; + rc = mb86a20s_writereg(state, 0x6d, reg[layer]); + if (rc < 0) + return rc; + rc = mb86a20s_readreg(state, 0x6e); + if (rc < 0) + return rc; + switch ((rc & 0x70) >> 4) { + case 0: + return DQPSK; + case 1: + return QPSK; + case 2: + return QAM_16; + case 3: + return QAM_64; + default: + return QAM_AUTO; + } +} + +static int mb86a20s_get_fec(struct mb86a20s_state *state, + unsigned layer) { + int rc; - /* FIXME: For now, it does nothing */ + static unsigned char reg[] = { + [0] = 0x87, /* Layer A */ + [1] = 0x8b, /* Layer B */ + [2] = 0x8f, /* Layer C */ + }; - fe->dtv_property_cache.bandwidth_hz = 6000000; - fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; - fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; - fe->dtv_property_cache.isdbt_partial_reception = 0; + if (layer >= ARRAY_SIZE(reg)) + return -EINVAL; + rc = mb86a20s_writereg(state, 0x6d, reg[layer]); + if (rc < 0) + return rc; + rc = mb86a20s_readreg(state, 0x6e); + if (rc < 0) + return rc; + switch (rc) { + case 0: + return FEC_1_2; + case 1: + return FEC_2_3; + case 2: + return FEC_3_4; + case 3: + return FEC_5_6; + case 4: + return FEC_7_8; + default: + return FEC_AUTO; + } +} + +static int mb86a20s_get_interleaving(struct mb86a20s_state *state, + unsigned layer) +{ + int rc; + + static unsigned char reg[] = { + [0] = 0x88, /* Layer A */ + [1] = 0x8c, /* Layer B */ + [2] = 0x90, /* Layer C */ + }; + + if (layer >= ARRAY_SIZE(reg)) + return -EINVAL; + rc = mb86a20s_writereg(state, 0x6d, reg[layer]); + if (rc < 0) + return rc; + rc = mb86a20s_readreg(state, 0x6e); + if (rc < 0) + return rc; + if (rc > 3) + return -EINVAL; /* Not used */ + return rc; +} + +static int mb86a20s_get_segment_count(struct mb86a20s_state *state, + unsigned layer) +{ + int rc, count; + + static unsigned char reg[] = { + [0] = 0x89, /* Layer A */ + [1] = 0x8d, /* Layer B */ + [2] = 0x91, /* Layer C */ + }; + + if (layer >= ARRAY_SIZE(reg)) + return -EINVAL; + rc = mb86a20s_writereg(state, 0x6d, reg[layer]); + if (rc < 0) + return rc; + rc = mb86a20s_readreg(state, 0x6e); + if (rc < 0) + return rc; + count = (rc >> 4) & 0x0f; + + return count; +} + +static int mb86a20s_get_frontend(struct dvb_frontend *fe) +{ + struct mb86a20s_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int i, rc; + + /* Fixed parameters */ + p->delivery_system = SYS_ISDBT; + p->bandwidth_hz = 6000000; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + /* Check for partial reception */ + rc = mb86a20s_writereg(state, 0x6d, 0x85); + if (rc >= 0) + rc = mb86a20s_readreg(state, 0x6e); + if (rc >= 0) + p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0; + + /* Get per-layer data */ + p->isdbt_layer_enabled = 0; + for (i = 0; i < 3; i++) { + rc = mb86a20s_get_segment_count(state, i); + if (rc >= 0 && rc < 14) + p->layer[i].segment_count = rc; + if (rc == 0x0f) + continue; + p->isdbt_layer_enabled |= 1 << i; + rc = mb86a20s_get_modulation(state, i); + if (rc >= 0) + p->layer[i].modulation = rc; + rc = mb86a20s_get_fec(state, i); + if (rc >= 0) + p->layer[i].fec = rc; + rc = mb86a20s_get_interleaving(state, i); + if (rc >= 0) + p->layer[i].interleaving = rc; + } + + p->isdbt_sb_mode = 0; + rc = mb86a20s_writereg(state, 0x6d, 0x84); + if ((rc >= 0) && ((rc & 0x60) == 0x20)) { + p->isdbt_sb_mode = 1; + /* At least, one segment should exist */ + if (!p->isdbt_sb_segment_count) + p->isdbt_sb_segment_count = 1; + } else + p->isdbt_sb_segment_count = 0; + + /* Get transmission mode and guard interval */ + p->transmission_mode = TRANSMISSION_MODE_AUTO; + p->guard_interval = GUARD_INTERVAL_AUTO; + rc = mb86a20s_readreg(state, 0x07); + if (rc >= 0) { + if ((rc & 0x60) == 0x20) { + switch (rc & 0x0c >> 2) { + case 0: + p->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + p->transmission_mode = TRANSMISSION_MODE_4K; + break; + case 2: + p->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + } + if (!(rc & 0x10)) { + switch (rc & 0x3) { + case 0: + p->guard_interval = GUARD_INTERVAL_1_4; + break; + case 1: + p->guard_interval = GUARD_INTERVAL_1_8; + break; + case 2: + p->guard_interval = GUARD_INTERVAL_1_16; + break; + } + } + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); return 0; } static int mb86a20s_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) @@ -544,8 +606,8 @@ static int mb86a20s_tune(struct dvb_frontend *fe, dprintk("\n"); - if (params != NULL) - rc = mb86a20s_set_frontend(fe, params); + if (re_tune) + rc = mb86a20s_set_frontend(fe); if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) mb86a20s_read_status(fe, status); @@ -608,10 +670,10 @@ error: EXPORT_SYMBOL(mb86a20s_attach); static struct dvb_frontend_ops mb86a20s_ops = { + .delsys = { SYS_ISDBT }, /* Use dib8000 values per default */ .info = { .name = "Fujitsu mb86A20s", - .type = FE_OFDM, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 83e6f1a1b700..e20bf13aa860 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -531,9 +531,9 @@ static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) return 0; } -static int mt312_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mt312_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[5], config_val; @@ -553,16 +553,16 @@ static int mt312_set_frontend(struct dvb_frontend *fe, || (p->inversion > INVERSION_ON)) return -EINVAL; - if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) - || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) + if ((p->symbol_rate < fe->ops.info.symbol_rate_min) + || (p->symbol_rate > fe->ops.info.symbol_rate_max)) return -EINVAL; - if ((p->u.qpsk.fec_inner < FEC_NONE) - || (p->u.qpsk.fec_inner > FEC_AUTO)) + if ((p->fec_inner < FEC_NONE) + || (p->fec_inner > FEC_AUTO)) return -EINVAL; - if ((p->u.qpsk.fec_inner == FEC_4_5) - || (p->u.qpsk.fec_inner == FEC_8_9)) + if ((p->fec_inner == FEC_4_5) + || (p->fec_inner == FEC_8_9)) return -EINVAL; switch (state->id) { @@ -574,7 +574,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe, ret = mt312_readreg(state, CONFIG, &config_val); if (ret < 0) return ret; - if (p->u.qpsk.symbol_rate >= 30000000) { + if (p->symbol_rate >= 30000000) { /* Note that 30MS/s should use 90MHz */ if (state->freq_mult == 6) { /* We are running 60MHz */ @@ -603,25 +603,25 @@ static int mt312_set_frontend(struct dvb_frontend *fe, } if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } /* sr = (u16)(sr * 256.0 / 1000000.0) */ - sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); + sr = mt312_div(p->symbol_rate * 4, 15625); /* SYM_RATE */ buf[0] = (sr >> 8) & 0x3f; buf[1] = (sr >> 0) & 0xff; /* VIT_MODE */ - buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner]; + buf[2] = inv_tab[p->inversion] | fec_tab[p->fec_inner]; /* QPSK_CTRL */ buf[3] = 0x40; /* swap I and Q before QPSK demodulation */ - if (p->u.qpsk.symbol_rate < 10000000) + if (p->symbol_rate < 10000000) buf[3] |= 0x04; /* use afc mode */ /* GO */ @@ -636,9 +636,9 @@ static int mt312_set_frontend(struct dvb_frontend *fe, return 0; } -static int mt312_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mt312_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mt312_state *state = fe->demodulator_priv; int ret; @@ -646,11 +646,11 @@ static int mt312_get_frontend(struct dvb_frontend *fe, if (ret < 0) return ret; - ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate); + ret = mt312_get_symbol_rate(state, &p->symbol_rate); if (ret < 0) return ret; - ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner); + ret = mt312_get_code_rate(state, &p->fec_inner); if (ret < 0) return ret; @@ -738,10 +738,9 @@ static void mt312_release(struct dvb_frontend *fe) #define MT312_SYS_CLK 90000000UL /* 90 MHz */ static struct dvb_frontend_ops mt312_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Zarlink ???? DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, /* FIXME: adjust freq to real used xtal */ diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 319672f8e1a7..2c3b50e828d7 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -111,20 +111,20 @@ static int mt352_sleep(struct dvb_frontend* fe) } static void mt352_calc_nominal_rate(struct mt352_state* state, - enum fe_bandwidth bandwidth, + u32 bandwidth, unsigned char *buf) { u32 adc_clock = 20480; /* 20.340 MHz */ u32 bw,value; switch (bandwidth) { - case BANDWIDTH_6_MHZ: + case 6000000: bw = 6; break; - case BANDWIDTH_7_MHZ: + case 7000000: bw = 7; break; - case BANDWIDTH_8_MHZ: + case 8000000: default: bw = 8; break; @@ -166,15 +166,14 @@ static void mt352_calc_input_freq(struct mt352_state* state, buf[1] = lsb(value); } -static int mt352_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int mt352_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *op = &fe->dtv_property_cache; struct mt352_state* state = fe->demodulator_priv; unsigned char buf[13]; static unsigned char tuner_go[] = { 0x5d, 0x01 }; static unsigned char fsm_go[] = { 0x5e, 0x01 }; unsigned int tps = 0; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; switch (op->code_rate_HP) { case FEC_2_3: @@ -213,14 +212,14 @@ static int mt352_set_parameters(struct dvb_frontend* fe, case FEC_AUTO: break; case FEC_NONE: - if (op->hierarchy_information == HIERARCHY_AUTO || - op->hierarchy_information == HIERARCHY_NONE) + if (op->hierarchy == HIERARCHY_AUTO || + op->hierarchy == HIERARCHY_NONE) break; default: return -EINVAL; } - switch (op->constellation) { + switch (op->modulation) { case QPSK: break; case QAM_AUTO: @@ -262,7 +261,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe, return -EINVAL; } - switch (op->hierarchy_information) { + switch (op->hierarchy) { case HIERARCHY_AUTO: case HIERARCHY_NONE: break; @@ -288,12 +287,12 @@ static int mt352_set_parameters(struct dvb_frontend* fe, buf[3] = 0x50; // old // buf[3] = 0xf4; // pinnacle - mt352_calc_nominal_rate(state, op->bandwidth, buf+4); + mt352_calc_nominal_rate(state, op->bandwidth_hz, buf+4); mt352_calc_input_freq(state, buf+6); if (state->config.no_tuner) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -302,7 +301,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe, _mt352_write(fe, fsm_go, 2); } else { if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5); + fe->ops.tuner_ops.calc_regs(fe, buf+8, 5); buf[8] <<= 1; _mt352_write(fe, buf, sizeof(buf)); _mt352_write(fe, tuner_go, 2); @@ -312,14 +311,13 @@ static int mt352_set_parameters(struct dvb_frontend* fe, return 0; } -static int mt352_get_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int mt352_get_parameters(struct dvb_frontend* fe) { + struct dtv_frontend_properties *op = &fe->dtv_property_cache; struct mt352_state* state = fe->demodulator_priv; u16 tps; u16 div; u8 trl; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; static const u8 tps_fec_to_api[8] = { FEC_1_2, @@ -348,16 +346,16 @@ static int mt352_get_parameters(struct dvb_frontend* fe, switch ( (tps >> 13) & 3) { case 0: - op->constellation = QPSK; + op->modulation = QPSK; break; case 1: - op->constellation = QAM_16; + op->modulation = QAM_16; break; case 2: - op->constellation = QAM_64; + op->modulation = QAM_64; break; default: - op->constellation = QAM_AUTO; + op->modulation = QAM_AUTO; break; } @@ -385,36 +383,36 @@ static int mt352_get_parameters(struct dvb_frontend* fe, switch ( (tps >> 10) & 7) { case 0: - op->hierarchy_information = HIERARCHY_NONE; + op->hierarchy = HIERARCHY_NONE; break; case 1: - op->hierarchy_information = HIERARCHY_1; + op->hierarchy = HIERARCHY_1; break; case 2: - op->hierarchy_information = HIERARCHY_2; + op->hierarchy = HIERARCHY_2; break; case 3: - op->hierarchy_information = HIERARCHY_4; + op->hierarchy = HIERARCHY_4; break; default: - op->hierarchy_information = HIERARCHY_AUTO; + op->hierarchy = HIERARCHY_AUTO; break; } - param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000; + op->frequency = (500 * (div - IF_FREQUENCYx6)) / 3 * 1000; if (trl == 0x72) - op->bandwidth = BANDWIDTH_8_MHZ; + op->bandwidth_hz = 8000000; else if (trl == 0x64) - op->bandwidth = BANDWIDTH_7_MHZ; + op->bandwidth_hz = 7000000; else - op->bandwidth = BANDWIDTH_6_MHZ; + op->bandwidth_hz = 6000000; if (mt352_read_register(state, STATUS_2) & 0x02) - param->inversion = INVERSION_OFF; + op->inversion = INVERSION_OFF; else - param->inversion = INVERSION_ON; + op->inversion = INVERSION_ON; return 0; } @@ -569,10 +567,9 @@ error: } static struct dvb_frontend_ops mt352_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Zarlink MT352 DVB-T", - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index eac20650499f..49ca78d883b1 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -528,9 +528,9 @@ static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware return 0; }; -static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct nxt200x_state* state = fe->demodulator_priv; u8 buf[5]; @@ -546,7 +546,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, } /* set additional params */ - switch (p->u.vsb.modulation) { + switch (p->modulation) { case QAM_64: case QAM_256: /* Set punctured clock for QAM */ @@ -566,7 +566,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, if (fe->ops.tuner_ops.calc_regs) { /* get tuning information */ - fe->ops.tuner_ops.calc_regs(fe, p, buf, 5); + fe->ops.tuner_ops.calc_regs(fe, buf, 5); /* write frequency information */ nxt200x_writetuner(state, buf); @@ -576,7 +576,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, nxt200x_agc_reset(state); /* set target power level */ - switch (p->u.vsb.modulation) { + switch (p->modulation) { case QAM_64: case QAM_256: buf[0] = 0x74; @@ -620,7 +620,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, } /* write sdmx input */ - switch (p->u.vsb.modulation) { + switch (p->modulation) { case QAM_64: buf[0] = 0x68; break; @@ -714,7 +714,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, } /* write agc ucgp0 */ - switch (p->u.vsb.modulation) { + switch (p->modulation) { case QAM_64: buf[0] = 0x02; break; @@ -1203,10 +1203,9 @@ error: } static struct dvb_frontend_ops nxt200x_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Nextwave NXT200X VSB/QAM frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 860000000, .frequency_stepsize = 166666, /* stepsize is just a guess */ diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index 6599b8fea9e9..90ae6c72c0e3 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -81,22 +81,21 @@ static void nxt6000_reset(struct nxt6000_state* state) nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT); } -static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth) +static int nxt6000_set_bandwidth(struct nxt6000_state *state, u32 bandwidth) { u16 nominal_rate; int result; switch (bandwidth) { - - case BANDWIDTH_6_MHZ: + case 6000000: nominal_rate = 0x55B7; break; - case BANDWIDTH_7_MHZ: + case 7000000: nominal_rate = 0x6400; break; - case BANDWIDTH_8_MHZ: + case 8000000: nominal_rate = 0x7249; break; @@ -457,23 +456,31 @@ static int nxt6000_init(struct dvb_frontend* fe) return 0; } -static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) +static int nxt6000_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct nxt6000_state* state = fe->demodulator_priv; int result; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0) + result = nxt6000_set_bandwidth(state, p->bandwidth_hz); + if (result < 0) return result; - if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0) + + result = nxt6000_set_guard_interval(state, p->guard_interval); + if (result < 0) return result; - if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0) + + result = nxt6000_set_transmission_mode(state, p->transmission_mode); + if (result < 0) return result; - if ((result = nxt6000_set_inversion(state, param->inversion)) < 0) + + result = nxt6000_set_inversion(state, p->inversion); + if (result < 0) return result; msleep(500); @@ -566,10 +573,9 @@ error: } static struct dvb_frontend_ops nxt6000_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "NxtWave NXT6000 DVB-T", - .type = FE_OFDM, .frequency_min = 0, .frequency_max = 863250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 38e67accb8c3..5ef921823c15 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -306,9 +306,9 @@ static int modulation_fw_class(fe_modulation_t modulation) } } -static int or51132_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int or51132_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int ret; struct or51132_state* state = fe->demodulator_priv; const struct firmware *fw; @@ -317,8 +317,8 @@ static int or51132_set_parameters(struct dvb_frontend* fe, /* Upload new firmware only if we need a different one */ if (modulation_fw_class(state->current_modulation) != - modulation_fw_class(param->u.vsb.modulation)) { - switch(modulation_fw_class(param->u.vsb.modulation)) { + modulation_fw_class(p->modulation)) { + switch (modulation_fw_class(p->modulation)) { case MOD_FWCLASS_VSB: dprintk("set_parameters VSB MODE\n"); fwname = OR51132_VSB_FIRMWARE; @@ -335,7 +335,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe, break; default: printk("or51132: Modulation type(%d) UNSUPPORTED\n", - param->u.vsb.modulation); + p->modulation); return -1; } printk("or51132: Waiting for firmware upload(%s)...\n", @@ -357,13 +357,13 @@ static int or51132_set_parameters(struct dvb_frontend* fe, state->config->set_ts_params(fe, clock_mode); } /* Change only if we are actually changing the modulation */ - if (state->current_modulation != param->u.vsb.modulation) { - state->current_modulation = param->u.vsb.modulation; + if (state->current_modulation != p->modulation) { + state->current_modulation = p->modulation; or51132_setmode(fe); } if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -371,13 +371,13 @@ static int or51132_set_parameters(struct dvb_frontend* fe, or51132_setmode(fe); /* Update current frequency */ - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; return 0; } -static int or51132_get_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int or51132_get_parameters(struct dvb_frontend* fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct or51132_state* state = fe->demodulator_priv; int status; int retry = 1; @@ -389,21 +389,28 @@ start: return -EREMOTEIO; } switch(status&0xff) { - case 0x06: param->u.vsb.modulation = VSB_8; break; - case 0x43: param->u.vsb.modulation = QAM_64; break; - case 0x45: param->u.vsb.modulation = QAM_256; break; - default: - if (retry--) goto start; - printk(KERN_WARNING "or51132: unknown status 0x%02x\n", - status&0xff); - return -EREMOTEIO; + case 0x06: + p->modulation = VSB_8; + break; + case 0x43: + p->modulation = QAM_64; + break; + case 0x45: + p->modulation = QAM_256; + break; + default: + if (retry--) + goto start; + printk(KERN_WARNING "or51132: unknown status 0x%02x\n", + status&0xff); + return -EREMOTEIO; } /* FIXME: Read frequency from frontend, take AFC into account */ - param->frequency = state->current_frequency; + p->frequency = state->current_frequency; /* FIXME: How to read inversion setting? Receiver 6 register? */ - param->inversion = INVERSION_AUTO; + p->inversion = INVERSION_AUTO; return 0; } @@ -579,10 +586,9 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, } static struct dvb_frontend_ops or51132_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Oren OR51132 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min = 44000000, .frequency_max = 958000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index c709ce6771c8..c625b57b4333 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -218,15 +218,15 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode) return 0; } -static int or51211_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int or51211_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct or51211_state* state = fe->demodulator_priv; /* Change only if we are actually changing the channel */ - if (state->current_frequency != param->frequency) { + if (state->current_frequency != p->frequency) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -234,7 +234,7 @@ static int or51211_set_parameters(struct dvb_frontend* fe, or51211_setmode(fe,0); /* Update current frequency */ - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; } return 0; } @@ -544,10 +544,9 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, } static struct dvb_frontend_ops or51211_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Oren OR51211 VSB Frontend", - .type = FE_ATSC, .frequency_min = 44000000, .frequency_max = 958000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 0e2f61a8978f..f71b06221e14 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -631,9 +631,9 @@ static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1409_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1409_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(frequency=%d)\n", __func__, p->frequency); @@ -642,12 +642,12 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe, state->current_frequency = p->frequency; - s5h1409_enable_modulation(fe, p->u.vsb.modulation); + s5h1409_enable_modulation(fe, p->modulation); if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -879,7 +879,36 @@ static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr) static int s5h1409_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { - return s5h1409_read_snr(fe, signal_strength); + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + u16 snr; + u32 tmp; + int ret = s5h1409_read_snr(fe, &snr); + + *signal_strength = 0; + + if (0 == ret) { + /* The following calculation method was chosen + * purely for the sake of code re-use from the + * other demod drivers that use this method */ + + /* Convert from SNR in dB * 10 to 8.24 fixed-point */ + tmp = (snr * ((1 << 24) / 10)); + + /* Convert from 8.24 fixed-point to + * scale the range 0 - 35*2^24 into 0 - 65535*/ + if (tmp >= 8960 * 0x10000) + *signal_strength = 0xffff; + else + *signal_strength = tmp / 8960; + } + + return ret; } static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -896,13 +925,13 @@ static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber) return s5h1409_read_ucblocks(fe, ber); } -static int s5h1409_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1409_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1409_state *state = fe->demodulator_priv; p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; + p->modulation = state->current_modulation; return 0; } @@ -967,10 +996,9 @@ error: EXPORT_SYMBOL(s5h1409_attach); static struct dvb_frontend_ops s5h1409_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Samsung S5H1409 QAM/8VSB Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c index d8adf1e32019..6cc4b7a9dd60 100644 --- a/drivers/media/dvb/frontends/s5h1411.c +++ b/drivers/media/dvb/frontends/s5h1411.c @@ -585,9 +585,9 @@ static int s5h1411_register_reset(struct dvb_frontend *fe) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1411_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1411_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1411_state *state = fe->demodulator_priv; dprintk("%s(frequency=%d)\n", __func__, p->frequency); @@ -596,13 +596,13 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe, state->current_frequency = p->frequency; - s5h1411_enable_modulation(fe, p->u.vsb.modulation); + s5h1411_enable_modulation(fe, p->modulation); if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -794,7 +794,36 @@ static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr) static int s5h1411_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { - return s5h1411_read_snr(fe, signal_strength); + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + u16 snr; + u32 tmp; + int ret = s5h1411_read_snr(fe, &snr); + + *signal_strength = 0; + + if (0 == ret) { + /* The following calculation method was chosen + * purely for the sake of code re-use from the + * other demod drivers that use this method */ + + /* Convert from SNR in dB * 10 to 8.24 fixed-point */ + tmp = (snr * ((1 << 24) / 10)); + + /* Convert from 8.24 fixed-point to + * scale the range 0 - 35*2^24 into 0 - 65535*/ + if (tmp >= 8960 * 0x10000) + *signal_strength = 0xffff; + else + *signal_strength = tmp / 8960; + } + + return ret; } static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -811,13 +840,13 @@ static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber) return s5h1411_read_ucblocks(fe, ber); } -static int s5h1411_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1411_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1411_state *state = fe->demodulator_priv; p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; + p->modulation = state->current_modulation; return 0; } @@ -886,10 +915,9 @@ error: EXPORT_SYMBOL(s5h1411_attach); static struct dvb_frontend_ops s5h1411_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Samsung S5H1411 QAM/8VSB Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 3879d2e378aa..2322257c69ae 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -472,15 +472,15 @@ static void s5h1420_reset(struct s5h1420_state* state) } static void s5h1420_setsymbolrate(struct s5h1420_state* state, - struct dvb_frontend_parameters *p) + struct dtv_frontend_properties *p) { u8 v; u64 val; dprintk("enter %s\n", __func__); - val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24); - if (p->u.qpsk.symbol_rate < 29000000) + val = ((u64) p->symbol_rate / 1000ULL) * (1ULL<<24); + if (p->symbol_rate < 29000000) val *= 2; do_div(val, (state->fclk / 1000)); @@ -543,7 +543,7 @@ static int s5h1420_getfreqoffset(struct s5h1420_state* state) } static void s5h1420_setfec_inversion(struct s5h1420_state* state, - struct dvb_frontend_parameters *p) + struct dtv_frontend_properties *p) { u8 inversion = 0; u8 vit08, vit09; @@ -555,11 +555,11 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state, else if (p->inversion == INVERSION_ON) inversion = state->config->invert ? 0 : 0x08; - if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { + if ((p->fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { vit08 = 0x3f; vit09 = 0; } else { - switch(p->u.qpsk.fec_inner) { + switch (p->fec_inner) { case FEC_1_2: vit08 = 0x01; vit09 = 0x10; break; @@ -628,9 +628,9 @@ static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) return INVERSION_OFF; } -static int s5h1420_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int s5h1420_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1420_state* state = fe->demodulator_priv; int frequency_delta; struct dvb_frontend_tune_settings fesettings; @@ -639,17 +639,16 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, dprintk("enter %s\n", __func__); /* check if we should do a fast-tune */ - memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); s5h1420_get_tune_settings(fe, &fesettings); frequency_delta = p->frequency - state->tunedfreq; if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) && (frequency_delta != 0) && - (state->fec_inner == p->u.qpsk.fec_inner) && - (state->symbol_rate == p->u.qpsk.symbol_rate)) { + (state->fec_inner == p->fec_inner) && + (state->symbol_rate == p->symbol_rate)) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } if (fe->ops.tuner_ops.get_frequency) { @@ -669,13 +668,13 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, s5h1420_reset(state); /* set s5h1420 fclk PLL according to desired symbol rate */ - if (p->u.qpsk.symbol_rate > 33000000) + if (p->symbol_rate > 33000000) state->fclk = 80000000; - else if (p->u.qpsk.symbol_rate > 28500000) + else if (p->symbol_rate > 28500000) state->fclk = 59000000; - else if (p->u.qpsk.symbol_rate > 25000000) + else if (p->symbol_rate > 25000000) state->fclk = 86000000; - else if (p->u.qpsk.symbol_rate > 1900000) + else if (p->symbol_rate > 1900000) state->fclk = 88000000; else state->fclk = 44000000; @@ -705,7 +704,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); /* TODO DC offset removal, config parameter ? */ - if (p->u.qpsk.symbol_rate > 29000000) + if (p->symbol_rate > 29000000) s5h1420_writereg(state, QPSK01, 0xae | 0x10); else s5h1420_writereg(state, QPSK01, 0xac | 0x10); @@ -718,15 +717,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, s5h1420_writereg(state, Loop01, 0xF0); s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */ s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */ - if (p->u.qpsk.symbol_rate > 20000000) + if (p->symbol_rate > 20000000) s5h1420_writereg(state, Loop04, 0x79); else s5h1420_writereg(state, Loop04, 0x58); s5h1420_writereg(state, Loop05, 0x6b); - if (p->u.qpsk.symbol_rate >= 8000000) + if (p->symbol_rate >= 8000000) s5h1420_writereg(state, Post01, (0 << 6) | 0x10); - else if (p->u.qpsk.symbol_rate >= 4000000) + else if (p->symbol_rate >= 4000000) s5h1420_writereg(state, Post01, (1 << 6) | 0x10); else s5h1420_writereg(state, Post01, (3 << 6) | 0x10); @@ -744,7 +743,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, /* set tuner PLL */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); s5h1420_setfreqoffset(state, 0); @@ -757,8 +756,8 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, /* start QPSK */ s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1); - state->fec_inner = p->u.qpsk.fec_inner; - state->symbol_rate = p->u.qpsk.symbol_rate; + state->fec_inner = p->fec_inner; + state->symbol_rate = p->symbol_rate; state->postlocked = 0; state->tunedfreq = p->frequency; @@ -766,15 +765,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, return 0; } -static int s5h1420_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int s5h1420_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1420_state* state = fe->demodulator_priv; p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); p->inversion = s5h1420_getinversion(state); - p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state); - p->u.qpsk.fec_inner = s5h1420_getfec(state); + p->symbol_rate = s5h1420_getsymbolrate(state); + p->fec_inner = s5h1420_getfec(state); return 0; } @@ -782,29 +781,30 @@ static int s5h1420_get_frontend(struct dvb_frontend* fe, static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + if (p->symbol_rate > 20000000) { fesettings->min_delay_ms = 50; fesettings->step_size = 2000; fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + } else if (p->symbol_rate > 12000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 1500; fesettings->max_drift = 9000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + } else if (p->symbol_rate > 8000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 1000; fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + } else if (p->symbol_rate > 4000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 500; fesettings->max_drift = 7000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + } else if (p->symbol_rate > 2000000) { fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->step_size = (p->symbol_rate / 8000); fesettings->max_drift = 14 * fesettings->step_size; } else { fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->step_size = (p->symbol_rate / 8000); fesettings->max_drift = 18 * fesettings->step_size; } @@ -937,10 +937,9 @@ error: EXPORT_SYMBOL(s5h1420_attach); static struct dvb_frontend_ops s5h1420_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Samsung S5H1420/PnpNetwork PN1010 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/s5h1432.c b/drivers/media/dvb/frontends/s5h1432.c index 0c6dcb90d168..8352ce1c9556 100644 --- a/drivers/media/dvb/frontends/s5h1432.c +++ b/drivers/media/dvb/frontends/s5h1432.c @@ -178,9 +178,9 @@ static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1432_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1432_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 dvb_bandwidth = 8; struct s5h1432_state *state = fe->demodulator_priv; @@ -188,26 +188,26 @@ static int s5h1432_set_frontend(struct dvb_frontend *fe, /*current_frequency = p->frequency; */ /*state->current_frequency = p->frequency; */ } else { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); msleep(300); s5h1432_set_channel_bandwidth(fe, dvb_bandwidth); - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: dvb_bandwidth = 6; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; - case BANDWIDTH_7_MHZ: + case 7000000: dvb_bandwidth = 7; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; - case BANDWIDTH_8_MHZ: + case 8000000: dvb_bandwidth = 8; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; default: return 0; } - /*fe->ops.tuner_ops.set_params(fe, p); */ + /*fe->ops.tuner_ops.set_params(fe); */ /*Soft Reset chip*/ msleep(30); s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); @@ -215,23 +215,23 @@ static int s5h1432_set_frontend(struct dvb_frontend *fe, s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b); s5h1432_set_channel_bandwidth(fe, dvb_bandwidth); - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: dvb_bandwidth = 6; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; - case BANDWIDTH_7_MHZ: + case 7000000: dvb_bandwidth = 7; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; - case BANDWIDTH_8_MHZ: + case 8000000: dvb_bandwidth = 8; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; default: return 0; } - /*fe->ops.tuner_ops.set_params(fe,p); */ + /*fe->ops.tuner_ops.set_params(fe); */ /*Soft Reset chip*/ msleep(30); s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); @@ -329,12 +329,6 @@ static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber) return 0; } -static int s5h1432_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - return 0; -} - static int s5h1432_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) { @@ -381,10 +375,9 @@ error: EXPORT_SYMBOL(s5h1432_attach); static struct dvb_frontend_ops s5h1432_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Samsung s5h1432 DVB-T Frontend", - .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, @@ -397,7 +390,6 @@ static struct dvb_frontend_ops s5h1432_ops = { .init = s5h1432_init, .sleep = s5h1432_sleep, .set_frontend = s5h1432_set_frontend, - .get_frontend = s5h1432_get_frontend, .get_tune_settings = s5h1432_get_tune_settings, .read_status = s5h1432_read_status, .read_ber = s5h1432_read_ber, diff --git a/drivers/media/dvb/frontends/s921.c b/drivers/media/dvb/frontends/s921.c index ca0103d5f148..cd2288c07147 100644 --- a/drivers/media/dvb/frontends/s921.c +++ b/drivers/media/dvb/frontends/s921.c @@ -262,9 +262,9 @@ static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg) s921_i2c_writeregdata(state, state->config->demod_address, \ regdata, ARRAY_SIZE(regdata)) -static int s921_pll_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s921_pll_tune(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s921_state *state = fe->demodulator_priv; int band, rc, i; unsigned long f_offset; @@ -414,9 +414,9 @@ static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return 0; } -static int s921_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s921_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s921_state *state = fe->demodulator_priv; int rc; @@ -424,7 +424,7 @@ static int s921_set_frontend(struct dvb_frontend *fe, /* FIXME: We don't know how to use non-auto mode */ - rc = s921_pll_tune(fe, p); + rc = s921_pll_tune(fe); if (rc < 0) return rc; @@ -433,19 +433,20 @@ static int s921_set_frontend(struct dvb_frontend *fe, return 0; } -static int s921_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s921_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s921_state *state = fe->demodulator_priv; /* FIXME: Probably it is possible to get it from regs f1 and f2 */ p->frequency = state->currentfreq; + p->delivery_system = SYS_ISDBT; return 0; } static int s921_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) @@ -454,8 +455,8 @@ static int s921_tune(struct dvb_frontend *fe, dprintk("\n"); - if (params != NULL) - rc = s921_set_frontend(fe, params); + if (re_tune) + rc = s921_set_frontend(fe); if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) s921_read_status(fe, status); @@ -510,10 +511,10 @@ rcor: EXPORT_SYMBOL(s921_attach); static struct dvb_frontend_ops s921_ops = { + .delsys = { SYS_ISDBT }, /* Use dib8000 values per default */ .info = { .name = "Sharp S921", - .type = FE_OFDM, .frequency_min = 470000000, /* * Max should be 770MHz instead, according with Sharp docs, diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c index 4b0c99a08a85..a68a64800df7 100644 --- a/drivers/media/dvb/frontends/si21xx.c +++ b/drivers/media/dvb/frontends/si21xx.c @@ -690,20 +690,7 @@ static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, return status; } -static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int si21xx_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *dfp) +static int si21xx_set_frontend(struct dvb_frontend *fe) { struct si21xx_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -877,10 +864,9 @@ static void si21xx_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops si21xx_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "SL SI21XX DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ @@ -908,8 +894,6 @@ static struct dvb_frontend_ops si21xx_ops = { .set_tone = si21xx_set_tone, .set_voltage = si21xx_set_voltage, - .set_property = si21xx_set_property, - .get_property = si21xx_get_property, .set_frontend = si21xx_set_frontend, }; diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index b85eb60a893e..e37274c8f14e 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -168,13 +168,13 @@ static int sp8870_read_data_valid_signal(struct sp8870_state* state) return (sp8870_readreg(state, 0x0D02) > 0); } -static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) +static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) { int known_parameters = 1; *reg0xc05 = 0x000; - switch (p->u.ofdm.constellation) { + switch (p->modulation) { case QPSK: break; case QAM_16: @@ -190,7 +190,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) return -EINVAL; }; - switch (p->u.ofdm.hierarchy_information) { + switch (p->hierarchy) { case HIERARCHY_NONE: break; case HIERARCHY_1: @@ -209,7 +209,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) return -EINVAL; }; - switch (p->u.ofdm.code_rate_HP) { + switch (p->code_rate_HP) { case FEC_1_2: break; case FEC_2_3: @@ -245,9 +245,9 @@ static int sp8870_wake_up(struct sp8870_state* state) return sp8870_writereg(state, 0xC18, 0x00D); } -static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int sp8870_set_frontend_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct sp8870_state* state = fe->demodulator_priv; int err; u16 reg0xc05; @@ -260,7 +260,7 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, // set tuner parameters if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -277,15 +277,15 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, sp8870_writereg(state, 0x030A, 0x0000); // filter for 6/7/8 Mhz channel - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + if (p->bandwidth_hz == 6000000) sp8870_writereg(state, 0x0311, 0x0002); - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + else if (p->bandwidth_hz == 7000000) sp8870_writereg(state, 0x0311, 0x0001); else sp8870_writereg(state, 0x0311, 0x0000); // scan order: 2k first = 0x0000, 8k first = 0x0001 - if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) + if (p->transmission_mode == TRANSMISSION_MODE_2K) sp8870_writereg(state, 0x0338, 0x0000); else sp8870_writereg(state, 0x0338, 0x0001); @@ -459,8 +459,9 @@ static int lockups; /* only for debugging: counter for channel switches */ static int switches; -static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int sp8870_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct sp8870_state* state = fe->demodulator_priv; /* @@ -479,7 +480,8 @@ static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_par for (trials = 1; trials <= MAXTRIALS; trials++) { - if ((err = sp8870_set_frontend_parameters(fe, p))) + err = sp8870_set_frontend_parameters(fe); + if (err) return err; for (check_count = 0; check_count < MAXCHECKS; check_count++) { @@ -579,10 +581,9 @@ error: } static struct dvb_frontend_ops sp8870_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Spase SP8870 DVB-T", - .type = FE_OFDM, .frequency_min = 470000000, .frequency_max = 860000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 4a7c3d842608..f4096ccb226e 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -209,13 +209,13 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware return 0; }; -static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) +static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) { int known_parameters = 1; *reg0xc05 = 0x000; - switch (p->u.ofdm.constellation) { + switch (p->modulation) { case QPSK: break; case QAM_16: @@ -231,7 +231,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) return -EINVAL; }; - switch (p->u.ofdm.hierarchy_information) { + switch (p->hierarchy) { case HIERARCHY_NONE: break; case HIERARCHY_1: @@ -250,7 +250,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) return -EINVAL; }; - switch (p->u.ofdm.code_rate_HP) { + switch (p->code_rate_HP) { case FEC_1_2: break; case FEC_2_3: @@ -303,17 +303,30 @@ static void divide (int n, int d, int *quotient_i, int *quotient_f) } static void sp887x_correct_offsets (struct sp887x_state* state, - struct dvb_frontend_parameters *p, + struct dtv_frontend_properties *p, int actual_freq) { static const u32 srate_correction [] = { 1879617, 4544878, 8098561 }; - int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; + int bw_index; int freq_offset = actual_freq - p->frequency; int sysclock = 61003; //[kHz] int ifreq = 36000000; int freq; int frequency_shift; + switch (p->bandwidth_hz) { + default: + case 8000000: + bw_index = 0; + break; + case 7000000: + bw_index = 1; + break; + case 6000000: + bw_index = 2; + break; + } + if (p->inversion == INVERSION_ON) freq = ifreq - freq_offset; else @@ -333,17 +346,17 @@ static void sp887x_correct_offsets (struct sp887x_state* state, sp887x_writereg(state, 0x30a, frequency_shift & 0xfff); } -static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int sp887x_setup_frontend_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct sp887x_state* state = fe->demodulator_priv; unsigned actual_freq; int err; u16 val, reg0xc05; - if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && - p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ && - p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ) + if (p->bandwidth_hz != 8000000 && + p->bandwidth_hz != 7000000 && + p->bandwidth_hz != 6000000) return -EINVAL; if ((err = configure_reg0xc05(p, ®0xc05))) @@ -353,7 +366,7 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, /* setup the PLL */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } if (fe->ops.tuner_ops.get_frequency) { @@ -369,9 +382,9 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, sp887x_correct_offsets(state, p, actual_freq); /* filter for 6/7/8 Mhz channel */ - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + if (p->bandwidth_hz == 6000000) val = 2; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + else if (p->bandwidth_hz == 7000000) val = 1; else val = 0; @@ -379,16 +392,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, sp887x_writereg(state, 0x311, val); /* scan order: 2k first = 0, 8k first = 1 */ - if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) + if (p->transmission_mode == TRANSMISSION_MODE_2K) sp887x_writereg(state, 0x338, 0x000); else sp887x_writereg(state, 0x338, 0x001); sp887x_writereg(state, 0xc05, reg0xc05); - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + if (p->bandwidth_hz == 6000000) val = 2 << 3; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + else if (p->bandwidth_hz == 7000000) val = 3 << 3; else val = 0 << 3; @@ -579,10 +592,9 @@ error: } static struct dvb_frontend_ops sp887x_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Spase SP887x DVB-T", - .type = FE_OFDM, .frequency_min = 50500000, .frequency_max = 858000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index 8408ef877b4b..38565beafe23 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -1431,7 +1431,7 @@ static void stb0899_set_iterations(struct stb0899_state *state) stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg); } -static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static enum dvbfe_search stb0899_search(struct dvb_frontend *fe) { struct stb0899_state *state = fe->demodulator_priv; struct stb0899_params *i_params = &state->params; @@ -1441,8 +1441,8 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron u32 SearchRange, gain; - i_params->freq = p->frequency; - i_params->srate = p->u.qpsk.symbol_rate; + i_params->freq = props->frequency; + i_params->srate = props->symbol_rate; state->delsys = props->delivery_system; dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys); @@ -1568,34 +1568,15 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron return DVBFE_ALGO_SEARCH_ERROR; } -/* - * stb0899_track - * periodically check the signal level against a specified - * threshold level and perform derotator centering. - * called once we have a lock from a successful search - * event. - * - * Will be called periodically called to maintain the - * lock. - * - * Will be used to get parameters as well as info from - * the decoded baseband header - * - * Once a new lock has established, the internal state - * frequency (internal->freq) is updated - */ -static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - return 0; -} -static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int stb0899_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stb0899_state *state = fe->demodulator_priv; struct stb0899_internal *internal = &state->internal; dprintk(state->verbose, FE_DEBUG, 1, "Get params"); - p->u.qpsk.symbol_rate = internal->srate; + p->symbol_rate = internal->srate; return 0; } @@ -1606,10 +1587,9 @@ static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe) } static struct dvb_frontend_ops stb0899_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STB0899 Multistandard", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 0, @@ -1632,8 +1612,7 @@ static struct dvb_frontend_ops stb0899_ops = { .get_frontend_algo = stb0899_frontend_algo, .search = stb0899_search, - .track = stb0899_track, - .get_frontend = stb0899_get_frontend, + .get_frontend = stb0899_get_frontend, .read_status = stb0899_read_status, diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c index ed699647050e..a0c3c526b132 100644 --- a/drivers/media/dvb/frontends/stb6000.c +++ b/drivers/media/dvb/frontends/stb6000.c @@ -75,9 +75,9 @@ static int stb6000_sleep(struct dvb_frontend *fe) return (ret == 1) ? 0 : ret; } -static int stb6000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int stb6000_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stb6000_priv *priv = fe->tuner_priv; unsigned int n, m; int ret; @@ -93,8 +93,8 @@ static int stb6000_set_params(struct dvb_frontend *fe, dprintk("%s:\n", __func__); - freq_mhz = params->frequency / 1000; - bandwidth = params->u.qpsk.symbol_rate / 1000000; + freq_mhz = p->frequency / 1000; + bandwidth = p->symbol_rate / 1000000; if (bandwidth > 31) bandwidth = 31; diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c index bc1a8af4f6e1..def88abb30bf 100644 --- a/drivers/media/dvb/frontends/stb6100.c +++ b/drivers/media/dvb/frontends/stb6100.c @@ -327,7 +327,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) int rc; const struct stb6100_lkup *ptr; struct stb6100_state *state = fe->tuner_priv; - struct dvb_frontend_parameters p; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 srate = 0, fvco, nint, nfrac; u8 regs[STB6100_NUMREGS]; @@ -337,9 +337,9 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) if (fe->ops.get_frontend) { dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); - fe->ops.get_frontend(fe, &p); + fe->ops.get_frontend(fe); } - srate = p.u.qpsk.symbol_rate; + srate = p->symbol_rate; /* Set up tuner cleanly, LPF calibration on */ rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK); diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c index 0aa3962ff18b..fb5548a82208 100644 --- a/drivers/media/dvb/frontends/stv0288.c +++ b/drivers/media/dvb/frontends/stv0288.c @@ -452,14 +452,7 @@ static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p) return 0; } -static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int stv0288_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *dfp) +static int stv0288_set_frontend(struct dvb_frontend *fe) { struct stv0288_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -481,10 +474,8 @@ static int stv0288_set_frontend(struct dvb_frontend *fe, state->config->set_ts_params(fe, 0); /* only frequency & symbol_rate are used for tuner*/ - dfp->frequency = c->frequency; - dfp->u.qpsk.symbol_rate = c->symbol_rate; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, dfp); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -545,10 +536,9 @@ static void stv0288_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops stv0288_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "ST STV0288 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1000, /* kHz for QPSK frontends */ @@ -578,7 +568,6 @@ static struct dvb_frontend_ops stv0288_ops = { .set_voltage = stv0288_set_voltage, .set_property = stv0288_set_property, - .get_property = stv0288_get_property, .set_frontend = stv0288_set_frontend, }; diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 84d88f33275e..85c157a1fe5e 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -404,8 +404,9 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) return 0; } -static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int stv0297_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0297_state *state = fe->demodulator_priv; int u_threshold; int initial_u; @@ -417,7 +418,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par unsigned long timeout; fe_spectral_inversion_t inversion; - switch (p->u.qam.modulation) { + switch (p->modulation) { case QAM_16: case QAM_32: case QAM_64: @@ -455,7 +456,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par stv0297_init(fe); if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -519,16 +520,16 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); /* set parameters */ - stv0297_set_qam(state, p->u.qam.modulation); - stv0297_set_symbolrate(state, p->u.qam.symbol_rate / 1000); - stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000); + stv0297_set_qam(state, p->modulation); + stv0297_set_symbolrate(state, p->symbol_rate / 1000); + stv0297_set_sweeprate(state, sweeprate, p->symbol_rate / 1000); stv0297_set_carrieroffset(state, carrieroffset); stv0297_set_inversion(state, inversion); /* kick off lock */ /* Disable corner detection for higher QAMs */ - if (p->u.qam.modulation == QAM_128 || - p->u.qam.modulation == QAM_256) + if (p->modulation == QAM_128 || + p->modulation == QAM_256) stv0297_writereg_mask(state, 0x88, 0x08, 0x00); else stv0297_writereg_mask(state, 0x88, 0x08, 0x08); @@ -613,8 +614,9 @@ timeout: return 0; } -static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int stv0297_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0297_state *state = fe->demodulator_priv; int reg_00, reg_83; @@ -625,24 +627,24 @@ static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; if (state->config->invert) p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; - p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000; - p->u.qam.fec_inner = FEC_NONE; + p->symbol_rate = stv0297_get_symbolrate(state) * 1000; + p->fec_inner = FEC_NONE; switch ((reg_00 >> 4) & 0x7) { case 0: - p->u.qam.modulation = QAM_16; + p->modulation = QAM_16; break; case 1: - p->u.qam.modulation = QAM_32; + p->modulation = QAM_32; break; case 2: - p->u.qam.modulation = QAM_128; + p->modulation = QAM_128; break; case 3: - p->u.qam.modulation = QAM_256; + p->modulation = QAM_256; break; case 4: - p->u.qam.modulation = QAM_64; + p->modulation = QAM_64; break; } @@ -688,10 +690,9 @@ error: } static struct dvb_frontend_ops stv0297_ops = { - + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "ST STV0297 DVB-C", - .type = FE_QAM, .frequency_min = 47000000, .frequency_max = 862000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 42684bec8883..057b5f8effc0 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -559,8 +559,9 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +static int stv0299_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0299_state* state = fe->demodulator_priv; int invval = 0; @@ -579,24 +580,25 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - stv0299_set_FEC (state, p->u.qpsk.fec_inner); - stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); + stv0299_set_FEC(state, p->fec_inner); + stv0299_set_symbolrate(fe, p->symbol_rate); stv0299_writeregI(state, 0x22, 0x00); stv0299_writeregI(state, 0x23, 0x00); state->tuner_frequency = p->frequency; - state->fec_inner = p->u.qpsk.fec_inner; - state->symbol_rate = p->u.qpsk.symbol_rate; + state->fec_inner = p->fec_inner; + state->symbol_rate = p->symbol_rate; return 0; } -static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +static int stv0299_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0299_state* state = fe->demodulator_priv; s32 derot_freq; int invval; @@ -614,8 +616,8 @@ static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (state->config->invert) invval = (~invval) & 1; p->inversion = invval ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = stv0299_get_fec (state); - p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state); + p->fec_inner = stv0299_get_fec(state); + p->symbol_rate = stv0299_get_symbolrate(state); return 0; } @@ -646,14 +648,15 @@ static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { struct stv0299_state* state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; fesettings->min_delay_ms = state->config->min_delay_ms; - if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; + if (p->symbol_rate < 10000000) { + fesettings->step_size = p->symbol_rate / 32000; fesettings->max_drift = 5000; } else { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; - fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; + fesettings->step_size = p->symbol_rate / 16000; + fesettings->max_drift = p->symbol_rate / 2000; } return 0; } @@ -705,10 +708,9 @@ error: } static struct dvb_frontend_ops stv0299_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "ST STV0299 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index e57ab53e2e27..fdd20c7737b5 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -1577,9 +1577,9 @@ int stv0367ter_init(struct dvb_frontend *fe) return 0; } -static int stv0367ter_algo(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367ter_algo(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; int offset = 0, tempo = 0; @@ -1591,7 +1591,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe, dprintk("%s:\n", __func__); - ter_state->frequency = param->frequency; + ter_state->frequency = p->frequency; ter_state->force = FE_TER_FORCENONE + stv0367_readbits(state, F367TER_FORCE) * 2; ter_state->if_iq_mode = state->config->if_iq_mode; @@ -1620,7 +1620,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe, usleep_range(5000, 7000); - switch (param->inversion) { + switch (p->inversion) { case INVERSION_AUTO: default: dprintk("%s: inversion AUTO\n", __func__); @@ -1636,10 +1636,10 @@ static int stv0367ter_algo(struct dvb_frontend *fe, case INVERSION_OFF: if (ter_state->if_iq_mode == FE_TER_IQ_TUNER) stv0367_writebits(state, F367TER_IQ_INVERT, - param->inversion); + p->inversion); else stv0367_writebits(state, F367TER_INV_SPECTR, - param->inversion); + p->inversion); break; } @@ -1806,10 +1806,9 @@ static int stv0367ter_algo(struct dvb_frontend *fe, return 0; } -static int stv0367ter_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367ter_set_frontend(struct dvb_frontend *fe) { - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; @@ -1822,12 +1821,12 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - switch (op->transmission_mode) { + switch (p->transmission_mode) { default: case TRANSMISSION_MODE_AUTO: case TRANSMISSION_MODE_2K: @@ -1841,34 +1840,34 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe, break; } - switch (op->guard_interval) { + switch (p->guard_interval) { default: case GUARD_INTERVAL_1_32: case GUARD_INTERVAL_1_16: case GUARD_INTERVAL_1_8: case GUARD_INTERVAL_1_4: - ter_state->guard = op->guard_interval; + ter_state->guard = p->guard_interval; break; case GUARD_INTERVAL_AUTO: ter_state->guard = GUARD_INTERVAL_1_32; break; } - switch (op->bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: ter_state->bw = FE_TER_CHAN_BW_6M; break; - case BANDWIDTH_7_MHZ: + case 7000000: ter_state->bw = FE_TER_CHAN_BW_7M; break; - case BANDWIDTH_8_MHZ: + case 8000000: default: ter_state->bw = FE_TER_CHAN_BW_8M; } ter_state->hierarchy = FE_TER_HIER_NONE; - switch (param->inversion) { + switch (p->inversion) { case INVERSION_OFF: case INVERSION_ON: num_trials = 1; @@ -1885,14 +1884,14 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe, while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) { if (!ter_state->first_lock) { - if (param->inversion == INVERSION_AUTO) + if (p->inversion == INVERSION_AUTO) ter_state->sense = SenseTrials[index]; } - stv0367ter_algo(fe,/* &pLook, result,*/ param); + stv0367ter_algo(fe); if ((ter_state->state == FE_TER_LOCKOK) && - (param->inversion == INVERSION_AUTO) && + (p->inversion == INVERSION_AUTO) && (index == 1)) { /* invert spectrum sense */ SenseTrials[index] = SenseTrials[0]; @@ -1927,50 +1926,48 @@ static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int stv0367ter_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367ter_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; int error = 0; enum stv0367_ter_mode mode; int constell = 0,/* snr = 0,*/ Data = 0; - param->frequency = stv0367_get_tuner_freq(fe); - if ((int)param->frequency < 0) - param->frequency = c->frequency; + p->frequency = stv0367_get_tuner_freq(fe); + if ((int)p->frequency < 0) + p->frequency = -p->frequency; constell = stv0367_readbits(state, F367TER_TPS_CONST); if (constell == 0) - op->constellation = QPSK; + p->modulation = QPSK; else if (constell == 1) - op->constellation = QAM_16; + p->modulation = QAM_16; else - op->constellation = QAM_64; + p->modulation = QAM_64; - param->inversion = stv0367_readbits(state, F367TER_INV_SPECTR); + p->inversion = stv0367_readbits(state, F367TER_INV_SPECTR); /* Get the Hierarchical mode */ Data = stv0367_readbits(state, F367TER_TPS_HIERMODE); switch (Data) { case 0: - op->hierarchy_information = HIERARCHY_NONE; + p->hierarchy = HIERARCHY_NONE; break; case 1: - op->hierarchy_information = HIERARCHY_1; + p->hierarchy = HIERARCHY_1; break; case 2: - op->hierarchy_information = HIERARCHY_2; + p->hierarchy = HIERARCHY_2; break; case 3: - op->hierarchy_information = HIERARCHY_4; + p->hierarchy = HIERARCHY_4; break; default: - op->hierarchy_information = HIERARCHY_AUTO; + p->hierarchy = HIERARCHY_AUTO; break; /* error */ } @@ -1982,22 +1979,22 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe, switch (Data) { case 0: - op->code_rate_HP = FEC_1_2; + p->code_rate_HP = FEC_1_2; break; case 1: - op->code_rate_HP = FEC_2_3; + p->code_rate_HP = FEC_2_3; break; case 2: - op->code_rate_HP = FEC_3_4; + p->code_rate_HP = FEC_3_4; break; case 3: - op->code_rate_HP = FEC_5_6; + p->code_rate_HP = FEC_5_6; break; case 4: - op->code_rate_HP = FEC_7_8; + p->code_rate_HP = FEC_7_8; break; default: - op->code_rate_HP = FEC_AUTO; + p->code_rate_HP = FEC_AUTO; break; /* error */ } @@ -2005,19 +2002,19 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe, switch (mode) { case FE_TER_MODE_2K: - op->transmission_mode = TRANSMISSION_MODE_2K; + p->transmission_mode = TRANSMISSION_MODE_2K; break; /* case FE_TER_MODE_4K: - op->transmission_mode = TRANSMISSION_MODE_4K; + p->transmission_mode = TRANSMISSION_MODE_4K; break;*/ case FE_TER_MODE_8K: - op->transmission_mode = TRANSMISSION_MODE_8K; + p->transmission_mode = TRANSMISSION_MODE_8K; break; default: - op->transmission_mode = TRANSMISSION_MODE_AUTO; + p->transmission_mode = TRANSMISSION_MODE_AUTO; } - op->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); + p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); return error; } @@ -2265,9 +2262,9 @@ static void stv0367_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops stv0367ter_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "ST STV0367 DVB-T", - .type = FE_OFDM, .frequency_min = 47000000, .frequency_max = 862000000, .frequency_stepsize = 15625, @@ -2822,9 +2819,8 @@ int stv0367cab_init(struct dvb_frontend *fe) } static enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { - struct dvb_qam_parameters *op = ¶m->u.qam; struct stv0367cab_state *cab_state = state->cab_state; enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC; u32 QAMFEC_Lock, QAM_Lock, u32_tmp, @@ -2839,7 +2835,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, /* A max lock time of 25 ms is allowed for delayed AGC */ AGCTimeOut = 25; /* 100000 symbols needed by the TRL as a maximum value */ - TRLTimeOut = 100000000 / op->symbol_rate; + TRLTimeOut = 100000000 / p->symbol_rate; /* CRLSymbols is the needed number of symbols to achieve a lock within [-4%, +4%] of the symbol rate. CRL timeout is calculated @@ -2849,7 +2845,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, A characterization must be performed with these echoes to get new timeout values. */ - switch (op->modulation) { + switch (p->modulation) { case QAM_16: CRLSymbols = 150000; EQLTimeOut = 100; @@ -2883,9 +2879,9 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, } else #endif CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) / - (op->symbol_rate / 1000); + (p->symbol_rate / 1000); - CRLTimeOut = (1000 * CRLTimeOut) / op->symbol_rate; + CRLTimeOut = (1000 * CRLTimeOut) / p->symbol_rate; /* Timeouts below 50ms are coerced */ if (CRLTimeOut < 50) CRLTimeOut = 50; @@ -2915,7 +2911,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, stv0367cab_set_derot_freq(state, cab_state->adc_clk, (1000 * (s32)state->config->if_khz + cab_state->derot_offset)); /* Disable the Allpass Filter when the symbol rate is out of range */ - if ((op->symbol_rate > 10800000) | (op->symbol_rate < 1800000)) { + if ((p->symbol_rate > 10800000) | (p->symbol_rate < 1800000)) { stv0367_writebits(state, F367CAB_ADJ_EN, 0); stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0); } @@ -2999,7 +2995,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, if (QAMFEC_Lock) { signalType = FE_CAB_DATAOK; - cab_state->modulation = op->modulation; + cab_state->modulation = p->modulation; cab_state->spect_inv = stv0367_readbits(state, F367CAB_QUAD_INV); #if 0 @@ -3081,20 +3077,19 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, return signalType; } -static int stv0367cab_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367cab_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367cab_state *cab_state = state->cab_state; - struct dvb_qam_parameters *op = ¶m->u.qam; enum stv0367cab_mod QAMSize = 0; dprintk("%s: freq = %d, srate = %d\n", __func__, - param->frequency, op->symbol_rate); + p->frequency, p->symbol_rate); cab_state->derot_offset = 0; - switch (op->modulation) { + switch (p->modulation) { case QAM_16: QAMSize = FE_CAB_MOD_QAM16; break; @@ -3120,77 +3115,76 @@ static int stv0367cab_set_frontend(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } stv0367cab_SetQamSize( state, - op->symbol_rate, + p->symbol_rate, QAMSize); stv0367cab_set_srate(state, cab_state->adc_clk, cab_state->mclk, - op->symbol_rate, + p->symbol_rate, QAMSize); /* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */ - cab_state->state = stv0367cab_algo(state, param); + cab_state->state = stv0367cab_algo(state, p); return 0; } -static int stv0367cab_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367cab_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367cab_state *cab_state = state->cab_state; - struct dvb_qam_parameters *op = ¶m->u.qam; enum stv0367cab_mod QAMSize; dprintk("%s:\n", __func__); - op->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk); + p->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk); QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); switch (QAMSize) { case FE_CAB_MOD_QAM16: - op->modulation = QAM_16; + p->modulation = QAM_16; break; case FE_CAB_MOD_QAM32: - op->modulation = QAM_32; + p->modulation = QAM_32; break; case FE_CAB_MOD_QAM64: - op->modulation = QAM_64; + p->modulation = QAM_64; break; case FE_CAB_MOD_QAM128: - op->modulation = QAM_128; + p->modulation = QAM_128; break; case QAM_256: - op->modulation = QAM_256; + p->modulation = QAM_256; break; default: break; } - param->frequency = stv0367_get_tuner_freq(fe); + p->frequency = stv0367_get_tuner_freq(fe); - dprintk("%s: tuner frequency = %d\n", __func__, param->frequency); + dprintk("%s: tuner frequency = %d\n", __func__, p->frequency); if (state->config->if_khz == 0) { - param->frequency += + p->frequency += (stv0367cab_get_derot_freq(state, cab_state->adc_clk) - cab_state->adc_clk / 4000); return 0; } if (state->config->if_khz > cab_state->adc_clk / 1000) - param->frequency += (state->config->if_khz + p->frequency += (state->config->if_khz - stv0367cab_get_derot_freq(state, cab_state->adc_clk) - cab_state->adc_clk / 1000); else - param->frequency += (state->config->if_khz + p->frequency += (state->config->if_khz - stv0367cab_get_derot_freq(state, cab_state->adc_clk)); return 0; @@ -3386,9 +3380,9 @@ static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks) }; static struct dvb_frontend_ops stv0367cab_ops = { + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "ST STV0367 DVB-C", - .type = FE_QAM, .frequency_min = 47000000, .frequency_max = 862000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index 0ca316d6fffa..7f1badaf0d03 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -973,22 +973,6 @@ static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe) return DVBFE_ALGO_CUSTOM; } -static int stb0900_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - - return 0; -} - -static int stb0900_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - - return 0; -} - void stv0900_start_search(struct stv0900_internal *intp, enum fe_stv0900_demod_num demod) { @@ -1574,8 +1558,7 @@ static int stv0900_status(struct stv0900_internal *intp, return locked; } -static enum dvbfe_search stv0900_search(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static enum dvbfe_search stv0900_search(struct dvb_frontend *fe) { struct stv0900_state *state = fe->demodulator_priv; struct stv0900_internal *intp = state->internal; @@ -1675,12 +1658,6 @@ static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status) return 0; } -static int stv0900_track(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - return 0; -} - static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts) { @@ -1866,24 +1843,23 @@ static int stv0900_sleep(struct dvb_frontend *fe) return 0; } -static int stv0900_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int stv0900_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0900_state *state = fe->demodulator_priv; struct stv0900_internal *intp = state->internal; enum fe_stv0900_demod_num demod = state->demod; struct stv0900_signal_info p_result = intp->result[demod]; p->frequency = p_result.locked ? p_result.frequency : 0; - p->u.qpsk.symbol_rate = p_result.locked ? p_result.symbol_rate : 0; + p->symbol_rate = p_result.locked ? p_result.symbol_rate : 0; return 0; } static struct dvb_frontend_ops stv0900_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STV0900 frontend", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, @@ -1907,10 +1883,7 @@ static struct dvb_frontend_ops stv0900_ops = { .diseqc_send_burst = stv0900_send_burst, .diseqc_recv_slave_reply = stv0900_recv_slave_reply, .set_tone = stv0900_set_tone, - .set_property = stb0900_set_property, - .get_property = stb0900_get_property, .search = stv0900_search, - .track = stv0900_track, .read_status = stv0900_read_status, .read_ber = stv0900_read_ber, .read_signal_strength = stv0900_read_signal_strength, diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index ebda41936b90..4aef1877ed42 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -3427,17 +3427,17 @@ err: return -1; } -static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static enum dvbfe_search stv090x_search(struct dvb_frontend *fe) { struct stv090x_state *state = fe->demodulator_priv; struct dtv_frontend_properties *props = &fe->dtv_property_cache; - if (p->frequency == 0) + if (props->frequency == 0) return DVBFE_ALGO_SEARCH_INVALID; state->delsys = props->delivery_system; - state->frequency = p->frequency; - state->srate = p->u.qpsk.symbol_rate; + state->frequency = props->frequency; + state->srate = props->symbol_rate; state->search_mode = STV090x_SEARCH_AUTO; state->algo = STV090x_COLD_SEARCH; state->fec = STV090x_PRERR; @@ -4712,10 +4712,9 @@ int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, EXPORT_SYMBOL(stv090x_set_gpio); static struct dvb_frontend_ops stv090x_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STV090x Multistandard", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 0, @@ -4743,7 +4742,7 @@ static struct dvb_frontend_ops stv090x_ops = { .read_status = stv090x_read_status, .read_ber = stv090x_read_per, .read_signal_strength = stv090x_read_signal_strength, - .read_snr = stv090x_read_cnr + .read_snr = stv090x_read_cnr, }; diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb/frontends/stv6110.c index 2dca7c8e5148..20b5fa92c53e 100644 --- a/drivers/media/dvb/frontends/stv6110.c +++ b/drivers/media/dvb/frontends/stv6110.c @@ -347,8 +347,7 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency) return 0; } -static int stv6110_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int stv6110_set_params(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff); diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 6ca533ea0f0e..1bff7f457e19 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -224,47 +224,86 @@ static int tda10021_init (struct dvb_frontend *fe) return 0; } -static int tda10021_set_parameters (struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +struct qam_params { + u8 conf, agcref, lthr, mseth, aref; +}; + +static int tda10021_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + unsigned qam = c->modulation; + bool is_annex_c; + u32 reg0x3d; struct tda10021_state* state = fe->demodulator_priv; + static const struct qam_params qam_params[] = { + /* Modulation Conf AGCref LTHR MSETH AREF */ + [QPSK] = { 0x14, 0x78, 0x78, 0x8c, 0x96 }, + [QAM_16] = { 0x00, 0x8c, 0x87, 0xa2, 0x91 }, + [QAM_32] = { 0x04, 0x8c, 0x64, 0x74, 0x96 }, + [QAM_64] = { 0x08, 0x6a, 0x46, 0x43, 0x6a }, + [QAM_128] = { 0x0c, 0x78, 0x36, 0x34, 0x7e }, + [QAM_256] = { 0x10, 0x5c, 0x26, 0x23, 0x6b }, + }; + + switch (delsys) { + case SYS_DVBC_ANNEX_A: + is_annex_c = false; + break; + case SYS_DVBC_ANNEX_C: + is_annex_c = true; + break; + default: + return -EINVAL; + } - //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256 - //CONF - static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 }; - //AGCREF value - static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c }; - //LTHR value - static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 }; - //MSETH - static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 }; - //AREF - static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b }; - - int qam = p->u.qam.modulation; - - if (qam < 0 || qam > 5) + /* + * gcc optimizes the code bellow the same way as it would code: + * "if (qam > 5) return -EINVAL;" + * Yet, the code is clearer, as it shows what QAM standards are + * supported by the driver, and avoids the usage of magic numbers on + * it. + */ + switch (qam) { + case QPSK: + case QAM_16: + case QAM_32: + case QAM_64: + case QAM_128: + case QAM_256: + break; + default: return -EINVAL; + } - if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF) + if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF) return -EINVAL; - //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); + /*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - tda10021_set_symbolrate (state, p->u.qam.symbol_rate); - _tda10021_writereg (state, 0x34, state->pwm); - - _tda10021_writereg (state, 0x01, reg0x01[qam]); - _tda10021_writereg (state, 0x05, reg0x05[qam]); - _tda10021_writereg (state, 0x08, reg0x08[qam]); - _tda10021_writereg (state, 0x09, reg0x09[qam]); - - tda10021_setup_reg0 (state, reg0x00[qam], p->inversion); + tda10021_set_symbolrate(state, c->symbol_rate); + _tda10021_writereg(state, 0x34, state->pwm); + + _tda10021_writereg(state, 0x01, qam_params[qam].agcref); + _tda10021_writereg(state, 0x05, qam_params[qam].lthr); + _tda10021_writereg(state, 0x08, qam_params[qam].mseth); + _tda10021_writereg(state, 0x09, qam_params[qam].aref); + + /* + * Bit 0 == 0 means roll-off = 0.15 (Annex A) + * == 1 means roll-off = 0.13 (Annex C) + */ + reg0x3d = tda10021_readreg (state, 0x3d); + if (is_annex_c) + _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d); + else + _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d); + tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion); return 0; } @@ -347,8 +386,9 @@ static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int tda10021_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda10021_state* state = fe->demodulator_priv; int sync; s8 afc = 0; @@ -360,17 +400,17 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" : "DVB: TDA10021(%d): [AFC (%d) %dHz]\n", state->frontend.dvb->num, afc, - -((s32)p->u.qam.symbol_rate * afc) >> 10); + -((s32)p->symbol_rate * afc) >> 10); } p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + p->modulation = ((state->reg0 >> 2) & 7) + QAM_16; - p->u.qam.fec_inner = FEC_NONE; + p->fec_inner = FEC_NONE; p->frequency = ((p->frequency + 31250) / 62500) * 62500; if (sync & 2) - p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; + p->frequency -= ((s32)p->symbol_rate * afc) >> 10; return 0; } @@ -444,10 +484,9 @@ error: } static struct dvb_frontend_ops tda10021_ops = { - + .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C }, .info = { .name = "Philips TDA10021 DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 47000000, .frequency_max = 862000000, diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index a3c34eecdee9..ca1e0d54b69a 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -298,42 +298,80 @@ static int tda10023_init (struct dvb_frontend *fe) return 0; } -static int tda10023_set_parameters (struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +struct qam_params { + u8 qam, lockthr, mseth, aref, agcrefnyq, eragnyq_thd; +}; + +static int tda10023_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + unsigned qam = c->modulation; + bool is_annex_c; struct tda10023_state* state = fe->demodulator_priv; - - static int qamvals[6][6] = { - // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD - { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM - { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM - { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM - { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM - { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM - { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM + static const struct qam_params qam_params[] = { + /* Modulation QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD */ + [QPSK] = { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, + [QAM_16] = { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, + [QAM_32] = { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, + [QAM_64] = { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, + [QAM_128] = { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, + [QAM_256] = { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, }; - int qam = p->u.qam.modulation; + switch (delsys) { + case SYS_DVBC_ANNEX_A: + is_annex_c = false; + break; + case SYS_DVBC_ANNEX_C: + is_annex_c = true; + break; + default: + return -EINVAL; + } - if (qam < 0 || qam > 5) + /* + * gcc optimizes the code bellow the same way as it would code: + * "if (qam > 5) return -EINVAL;" + * Yet, the code is clearer, as it shows what QAM standards are + * supported by the driver, and avoids the usage of magic numbers on + * it. + */ + switch (qam) { + case QPSK: + case QAM_16: + case QAM_32: + case QAM_64: + case QAM_128: + case QAM_256: + break; + default: return -EINVAL; + } if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - tda10023_set_symbolrate (state, p->u.qam.symbol_rate); - tda10023_writereg (state, 0x05, qamvals[qam][1]); - tda10023_writereg (state, 0x08, qamvals[qam][2]); - tda10023_writereg (state, 0x09, qamvals[qam][3]); - tda10023_writereg (state, 0xb4, qamvals[qam][4]); - tda10023_writereg (state, 0xb6, qamvals[qam][5]); - -// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32)); -// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); - tda10023_writebit (state, 0x04, 0x40, 0x40); - tda10023_setup_reg0 (state, qamvals[qam][0]); + tda10023_set_symbolrate(state, c->symbol_rate); + tda10023_writereg(state, 0x05, qam_params[qam].lockthr); + tda10023_writereg(state, 0x08, qam_params[qam].mseth); + tda10023_writereg(state, 0x09, qam_params[qam].aref); + tda10023_writereg(state, 0xb4, qam_params[qam].agcrefnyq); + tda10023_writereg(state, 0xb6, qam_params[qam].eragnyq_thd); +#if 0 + tda10023_writereg(state, 0x04, (c->inversion ? 0x12 : 0x32)); + tda10023_writebit(state, 0x04, 0x60, (c->inversion ? 0 : 0x20)); +#endif + tda10023_writebit(state, 0x04, 0x40, 0x40); + + if (is_annex_c) + tda10023_writebit(state, 0x3d, 0xfc, 0x03); + else + tda10023_writebit(state, 0x3d, 0xfc, 0x02); + + tda10023_setup_reg0(state, qam_params[qam].qam); return 0; } @@ -418,8 +456,9 @@ static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int tda10023_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda10023_state* state = fe->demodulator_priv; int sync,inv; s8 afc = 0; @@ -433,17 +472,17 @@ static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", state->frontend.dvb->num, afc, - -((s32)p->u.qam.symbol_rate * afc) >> 10); + -((s32)p->symbol_rate * afc) >> 10); } p->inversion = (inv&0x20?0:1); - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + p->modulation = ((state->reg0 >> 2) & 7) + QAM_16; - p->u.qam.fec_inner = FEC_NONE; + p->fec_inner = FEC_NONE; p->frequency = ((p->frequency + 31250) / 62500) * 62500; if (sync & 2) - p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; + p->frequency -= ((s32)p->symbol_rate * afc) >> 10; return 0; } @@ -534,10 +573,9 @@ error: } static struct dvb_frontend_ops tda10023_ops = { - + .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C }, .info = { .name = "Philips TDA10023 DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 47000000, .frequency_max = 862000000, @@ -557,7 +595,6 @@ static struct dvb_frontend_ops tda10023_ops = { .set_frontend = tda10023_set_parameters, .get_frontend = tda10023_get_frontend, - .read_status = tda10023_read_status, .read_ber = tda10023_read_ber, .read_signal_strength = tda10023_read_signal_strength, diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c index 7f105946a434..71fb63299de7 100644 --- a/drivers/media/dvb/frontends/tda10048.c +++ b/drivers/media/dvb/frontends/tda10048.c @@ -153,7 +153,7 @@ struct tda10048_state { u32 pll_pfactor; u32 sample_freq; - enum fe_bandwidth bandwidth; + u32 bandwidth; }; static struct init_tab { @@ -341,21 +341,14 @@ static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz, { struct tda10048_state *state = fe->demodulator_priv; u64 t, z; - u32 b = 8000000; dprintk(1, "%s()\n", __func__); if (sample_freq_hz == 0) return -EINVAL; - if (bw == BANDWIDTH_6_MHZ) - b = 6000000; - else - if (bw == BANDWIDTH_7_MHZ) - b = 7000000; - /* WREF = (B / (7 * fs)) * 2^31 */ - t = b * 10; + t = bw * 10; /* avoid warning: this decimal constant is unsigned only in ISO C90 */ /* t *= 2147483648 on 32bit platforms */ t *= (2048 * 1024); @@ -378,25 +371,18 @@ static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, { struct tda10048_state *state = fe->demodulator_priv; u64 t; - u32 b = 8000000; dprintk(1, "%s()\n", __func__); if (sample_freq_hz == 0) return -EINVAL; - if (bw == BANDWIDTH_6_MHZ) - b = 6000000; - else - if (bw == BANDWIDTH_7_MHZ) - b = 7000000; - /* INVWREF = ((7 * fs) / B) * 2^5 */ t = sample_freq_hz; t *= 7; t *= 32; t *= 10; - do_div(t, b); + do_div(t, bw); t += 5; do_div(t, 10); @@ -407,16 +393,16 @@ static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, } static int tda10048_set_bandwidth(struct dvb_frontend *fe, - enum fe_bandwidth bw) + u32 bw) { struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s(bw=%d)\n", __func__, bw); /* Bandwidth setting may need to be adjusted */ switch (bw) { - case BANDWIDTH_6_MHZ: - case BANDWIDTH_7_MHZ: - case BANDWIDTH_8_MHZ: + case 6000000: + case 7000000: + case 8000000: tda10048_set_wref(fe, state->sample_freq, bw); tda10048_set_invwref(fe, state->sample_freq, bw); break; @@ -430,7 +416,7 @@ static int tda10048_set_bandwidth(struct dvb_frontend *fe, return 0; } -static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) +static int tda10048_set_if(struct dvb_frontend *fe, u32 bw) { struct tda10048_state *state = fe->demodulator_priv; struct tda10048_config *config = &state->config; @@ -441,13 +427,13 @@ static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) /* based on target bandwidth and clk we calculate pll factors */ switch (bw) { - case BANDWIDTH_6_MHZ: + case 6000000: if_freq_khz = config->dtv6_if_freq_khz; break; - case BANDWIDTH_7_MHZ: + case 7000000: if_freq_khz = config->dtv7_if_freq_khz; break; - case BANDWIDTH_8_MHZ: + case 8000000: if_freq_khz = config->dtv8_if_freq_khz; break; default: @@ -601,7 +587,7 @@ static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion) /* Retrieve the demod settings */ static int tda10048_get_tps(struct tda10048_state *state, - struct dvb_ofdm_parameters *p) + struct dtv_frontend_properties *p) { u8 val; @@ -612,27 +598,27 @@ static int tda10048_get_tps(struct tda10048_state *state, val = tda10048_readreg(state, TDA10048_OUT_CONF2); switch ((val & 0x60) >> 5) { case 0: - p->constellation = QPSK; + p->modulation = QPSK; break; case 1: - p->constellation = QAM_16; + p->modulation = QAM_16; break; case 2: - p->constellation = QAM_64; + p->modulation = QAM_64; break; } switch ((val & 0x18) >> 3) { case 0: - p->hierarchy_information = HIERARCHY_NONE; + p->hierarchy = HIERARCHY_NONE; break; case 1: - p->hierarchy_information = HIERARCHY_1; + p->hierarchy = HIERARCHY_1; break; case 2: - p->hierarchy_information = HIERARCHY_2; + p->hierarchy = HIERARCHY_2; break; case 3: - p->hierarchy_information = HIERARCHY_4; + p->hierarchy = HIERARCHY_4; break; } switch (val & 0x07) { @@ -738,17 +724,17 @@ static int tda10048_output_mode(struct dvb_frontend *fe, int serial) /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ /* TODO: Support manual tuning with specific params */ -static int tda10048_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int tda10048_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); /* Update the I/F pll's if the bandwidth changes */ - if (p->u.ofdm.bandwidth != state->bandwidth) { - tda10048_set_if(fe, p->u.ofdm.bandwidth); - tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth); + if (p->bandwidth_hz != state->bandwidth) { + tda10048_set_if(fe, p->bandwidth_hz); + tda10048_set_bandwidth(fe, p->bandwidth_hz); } if (fe->ops.tuner_ops.set_params) { @@ -756,7 +742,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -797,8 +783,8 @@ static int tda10048_init(struct dvb_frontend *fe) tda10048_set_inversion(fe, config->inversion); /* Establish default RF values */ - tda10048_set_if(fe, BANDWIDTH_8_MHZ); - tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ); + tda10048_set_if(fe, 8000000); + tda10048_set_bandwidth(fe, 8000000); /* Ensure we leave the gate closed */ tda10048_i2c_gate_ctrl(fe, 0); @@ -1042,9 +1028,9 @@ static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int tda10048_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int tda10048_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s()\n", __func__); @@ -1052,7 +1038,7 @@ static int tda10048_get_frontend(struct dvb_frontend *fe, p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1) & 0x20 ? INVERSION_ON : INVERSION_OFF; - return tda10048_get_tps(state, &p->u.ofdm); + return tda10048_get_tps(state, p); } static int tda10048_get_tune_settings(struct dvb_frontend *fe, @@ -1126,7 +1112,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, memcpy(&state->config, config, sizeof(*config)); state->i2c = i2c; state->fwloaded = config->no_firmware; - state->bandwidth = BANDWIDTH_8_MHZ; + state->bandwidth = 8000000; /* check if the demod is present */ if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) @@ -1152,11 +1138,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, tda10048_establish_defaults(&state->frontend); /* Set the xtal and freq defaults */ - if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0) + if (tda10048_set_if(&state->frontend, 8000000) != 0) goto error; /* Default bandwidth */ - if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0) + if (tda10048_set_bandwidth(&state->frontend, 8000000) != 0) goto error; /* Leave the gate closed */ @@ -1171,10 +1157,9 @@ error: EXPORT_SYMBOL(tda10048_attach); static struct dvb_frontend_ops tda10048_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "NXP TDA10048HN DVB-T", - .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index ea485d923550..ae6f22aae677 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -224,22 +224,22 @@ static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state) } static int tda10045h_set_bandwidth(struct tda1004x_state *state, - fe_bandwidth_t bandwidth) + u32 bandwidth) { static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 }; switch (bandwidth) { - case BANDWIDTH_6_MHZ: + case 6000000: tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); break; - case BANDWIDTH_7_MHZ: + case 7000000: tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); break; - case BANDWIDTH_8_MHZ: + case 8000000: tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); break; @@ -253,7 +253,7 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state, } static int tda10046h_set_bandwidth(struct tda1004x_state *state, - fe_bandwidth_t bandwidth) + u32 bandwidth) { static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; @@ -270,7 +270,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, else tda10046_clk53m = 1; switch (bandwidth) { - case BANDWIDTH_6_MHZ: + case 6000000: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M, sizeof(bandwidth_6mhz_53M)); @@ -283,7 +283,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, } break; - case BANDWIDTH_7_MHZ: + case 7000000: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M, sizeof(bandwidth_7mhz_53M)); @@ -296,7 +296,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, } break; - case BANDWIDTH_8_MHZ: + case 8000000: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M, sizeof(bandwidth_8mhz_53M)); @@ -409,7 +409,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe) msleep(10); /* set parameters */ - tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); + tda10045h_set_bandwidth(state, 8000000); ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); release_firmware(fw); @@ -473,7 +473,7 @@ static void tda10046_init_plls(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f); break; } - tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz + tda10046h_set_bandwidth(state, 8000000); /* default bandwidth 8 MHz */ /* let the PLLs settle */ msleep(120); } @@ -697,9 +697,9 @@ static int tda10046_init(struct dvb_frontend* fe) return 0; } -static int tda1004x_set_fe(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fe_params) +static int tda1004x_set_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda1004x_state* state = fe->demodulator_priv; int tmp; int inversion; @@ -718,7 +718,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set frequency if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -726,37 +726,37 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // Hardcoded to use auto as much as possible on the TDA10045 as it // is very unreliable if AUTO mode is _not_ used. if (state->demod_type == TDA1004X_DEMOD_TDA10045) { - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + fe_params->code_rate_HP = FEC_AUTO; + fe_params->guard_interval = GUARD_INTERVAL_AUTO; + fe_params->transmission_mode = TRANSMISSION_MODE_AUTO; } // Set standard params.. or put them to auto - if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || - (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || - (fe_params->u.ofdm.constellation == QAM_AUTO) || - (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { + if ((fe_params->code_rate_HP == FEC_AUTO) || + (fe_params->code_rate_LP == FEC_AUTO) || + (fe_params->modulation == QAM_AUTO) || + (fe_params->hierarchy == HIERARCHY_AUTO)) { tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); /* turn off modulation bits */ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits } else { tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto // set HP FEC - tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); + tmp = tda1004x_encode_fec(fe_params->code_rate_HP); if (tmp < 0) return tmp; tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp); // set LP FEC - tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); + tmp = tda1004x_encode_fec(fe_params->code_rate_LP); if (tmp < 0) return tmp; tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); - // set constellation - switch (fe_params->u.ofdm.constellation) { + /* set modulation */ + switch (fe_params->modulation) { case QPSK: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); break; @@ -774,7 +774,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // set hierarchy - switch (fe_params->u.ofdm.hierarchy_information) { + switch (fe_params->hierarchy) { case HIERARCHY_NONE: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); break; @@ -799,11 +799,11 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set bandwidth switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: - tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); + tda10045h_set_bandwidth(state, fe_params->bandwidth_hz); break; case TDA1004X_DEMOD_TDA10046: - tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); + tda10046h_set_bandwidth(state, fe_params->bandwidth_hz); break; } @@ -825,7 +825,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // set guard interval - switch (fe_params->u.ofdm.guard_interval) { + switch (fe_params->guard_interval) { case GUARD_INTERVAL_1_32: tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); @@ -856,7 +856,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // set transmission mode - switch (fe_params->u.ofdm.transmission_mode) { + switch (fe_params->transmission_mode) { case TRANSMISSION_MODE_2K: tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4); @@ -895,8 +895,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, return 0; } -static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) +static int tda1004x_get_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __func__); @@ -913,13 +914,13 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete case TDA1004X_DEMOD_TDA10045: switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) { case 0x14: - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + fe_params->bandwidth_hz = 8000000; break; case 0xdb: - fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + fe_params->bandwidth_hz = 7000000; break; case 0x4f: - fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + fe_params->bandwidth_hz = 6000000; break; } break; @@ -927,73 +928,73 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { case 0x5c: case 0x54: - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + fe_params->bandwidth_hz = 8000000; break; case 0x6a: case 0x60: - fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + fe_params->bandwidth_hz = 7000000; break; case 0x7b: case 0x70: - fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + fe_params->bandwidth_hz = 6000000; break; } break; } // FEC - fe_params->u.ofdm.code_rate_HP = + fe_params->code_rate_HP = tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7); - fe_params->u.ofdm.code_rate_LP = + fe_params->code_rate_LP = tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7); - // constellation + /* modulation */ switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) { case 0: - fe_params->u.ofdm.constellation = QPSK; + fe_params->modulation = QPSK; break; case 1: - fe_params->u.ofdm.constellation = QAM_16; + fe_params->modulation = QAM_16; break; case 2: - fe_params->u.ofdm.constellation = QAM_64; + fe_params->modulation = QAM_64; break; } // transmission mode - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + fe_params->transmission_mode = TRANSMISSION_MODE_2K; if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + fe_params->transmission_mode = TRANSMISSION_MODE_8K; // guard interval switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { case 0: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + fe_params->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + fe_params->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + fe_params->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + fe_params->guard_interval = GUARD_INTERVAL_1_4; break; } // hierarchy switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { case 0: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fe_params->hierarchy = HIERARCHY_NONE; break; case 1: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_1; + fe_params->hierarchy = HIERARCHY_1; break; case 2: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_2; + fe_params->hierarchy = HIERARCHY_2; break; case 3: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_4; + fe_params->hierarchy = HIERARCHY_4; break; } @@ -1231,9 +1232,9 @@ static void tda1004x_release(struct dvb_frontend* fe) } static struct dvb_frontend_ops tda10045_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Philips TDA10045H DVB-T", - .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 166667, @@ -1301,9 +1302,9 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, } static struct dvb_frontend_ops tda10046_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Philips TDA10046H DVB-T", - .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 166667, diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c index 0c37434d19e2..a99205026751 100644 --- a/drivers/media/dvb/frontends/tda10071.c +++ b/drivers/media/dvb/frontends/tda10071.c @@ -636,8 +636,7 @@ error: return ret; } -static int tda10071_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda10071_set_frontend(struct dvb_frontend *fe) { struct tda10071_priv *priv = fe->demodulator_priv; struct tda10071_cmd cmd; @@ -777,8 +776,7 @@ error: return ret; } -static int tda10071_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int tda10071_get_frontend(struct dvb_frontend *fe) { struct tda10071_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1217,9 +1215,9 @@ error: EXPORT_SYMBOL(tda10071_attach); static struct dvb_frontend_ops tda10071_ops = { + .delsys = { SYS_DVBT, SYS_DVBT2 }, .info = { .name = "NXP TDA10071", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_tolerance = 5000, diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index f2c8faac6f36..fcfe2e080cb0 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -267,7 +267,7 @@ static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minic } static int tda10086_set_inversion(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) + struct dtv_frontend_properties *fe_params) { u8 invval = 0x80; @@ -292,7 +292,7 @@ static int tda10086_set_inversion(struct tda10086_state *state, } static int tda10086_set_symbol_rate(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) + struct dtv_frontend_properties *fe_params) { u8 dfn = 0; u8 afs = 0; @@ -303,7 +303,7 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state, u32 tmp; u32 bdr; u32 bdri; - u32 symbol_rate = fe_params->u.qpsk.symbol_rate; + u32 symbol_rate = fe_params->symbol_rate; dprintk ("%s %i\n", __func__, symbol_rate); @@ -367,13 +367,13 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state, } static int tda10086_set_fec(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) + struct dtv_frontend_properties *fe_params) { u8 fecval; - dprintk ("%s %i\n", __func__, fe_params->u.qpsk.fec_inner); + dprintk("%s %i\n", __func__, fe_params->fec_inner); - switch(fe_params->u.qpsk.fec_inner) { + switch (fe_params->fec_inner) { case FEC_1_2: fecval = 0x00; break; @@ -409,9 +409,9 @@ static int tda10086_set_fec(struct tda10086_state *state, return 0; } -static int tda10086_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fe_params) +static int tda10086_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda10086_state *state = fe->demodulator_priv; int ret; u32 freq = 0; @@ -425,7 +425,7 @@ static int tda10086_set_frontend(struct dvb_frontend* fe, /* set params */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -452,13 +452,14 @@ static int tda10086_set_frontend(struct dvb_frontend* fe, tda10086_write_mask(state, 0x10, 0x40, 0x40); tda10086_write_mask(state, 0x00, 0x01, 0x00); - state->symbol_rate = fe_params->u.qpsk.symbol_rate; + state->symbol_rate = fe_params->symbol_rate; state->frequency = fe_params->frequency; return 0; } -static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) +static int tda10086_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda10086_state* state = fe->demodulator_priv; u8 val; int tmp; @@ -467,7 +468,7 @@ static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa dprintk ("%s\n", __func__); /* check for invalid symbol rate */ - if (fe_params->u.qpsk.symbol_rate < 500000) + if (fe_params->symbol_rate < 500000) return -EINVAL; /* calculate the updated frequency (note: we convert from Hz->kHz) */ @@ -516,34 +517,34 @@ static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa tmp |= 0xffffff00; tmp = (tmp * 480 * (1<<1)) / 128; tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000); - fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp; + fe_params->symbol_rate = state->symbol_rate + tmp; /* the FEC */ val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4; switch(val) { case 0x00: - fe_params->u.qpsk.fec_inner = FEC_1_2; + fe_params->fec_inner = FEC_1_2; break; case 0x01: - fe_params->u.qpsk.fec_inner = FEC_2_3; + fe_params->fec_inner = FEC_2_3; break; case 0x02: - fe_params->u.qpsk.fec_inner = FEC_3_4; + fe_params->fec_inner = FEC_3_4; break; case 0x03: - fe_params->u.qpsk.fec_inner = FEC_4_5; + fe_params->fec_inner = FEC_4_5; break; case 0x04: - fe_params->u.qpsk.fec_inner = FEC_5_6; + fe_params->fec_inner = FEC_5_6; break; case 0x05: - fe_params->u.qpsk.fec_inner = FEC_6_7; + fe_params->fec_inner = FEC_6_7; break; case 0x06: - fe_params->u.qpsk.fec_inner = FEC_7_8; + fe_params->fec_inner = FEC_7_8; break; case 0x07: - fe_params->u.qpsk.fec_inner = FEC_8_9; + fe_params->fec_inner = FEC_8_9; break; } @@ -664,29 +665,31 @@ static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + + if (p->symbol_rate > 20000000) { fesettings->min_delay_ms = 50; fesettings->step_size = 2000; fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + } else if (p->symbol_rate > 12000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 1500; fesettings->max_drift = 9000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + } else if (p->symbol_rate > 8000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 1000; fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + } else if (p->symbol_rate > 4000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 500; fesettings->max_drift = 7000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + } else if (p->symbol_rate > 2000000) { fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->step_size = p->symbol_rate / 8000; fesettings->max_drift = 14 * fesettings->step_size; } else { fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->step_size = p->symbol_rate / 8000; fesettings->max_drift = 18 * fesettings->step_size; } @@ -701,10 +704,9 @@ static void tda10086_release(struct dvb_frontend* fe) } static struct dvb_frontend_ops tda10086_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Philips TDA10086 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb/frontends/tda18271c2dd.c index 1b1bf200c55c..ad7c72e8f517 100644 --- a/drivers/media/dvb/frontends/tda18271c2dd.c +++ b/drivers/media/dvb/frontends/tda18271c2dd.c @@ -29,7 +29,6 @@ #include <linux/delay.h> #include <linux/firmware.h> #include <linux/i2c.h> -#include <linux/version.h> #include <asm/div64.h> #include "dvb_frontend.h" @@ -1123,55 +1122,51 @@ static int release(struct dvb_frontend *fe) return 0; } -/* - * As defined on EN 300 429 Annex A and on ITU-T J.83 annex A, the DVB-C - * roll-off factor is 0.15. - * According with the specs, the amount of the needed bandwith is given by: - * Bw = Symbol_rate * (1 + 0.15) - * As such, the maximum symbol rate supported by 6 MHz is - * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds - *NOTE: For ITU-T J.83 Annex C, the roll-off factor is 0.13. So: - * max_symbol_rate = 6 MHz / 1.13 = 5309735 Baud - * That means that an adjustment is needed for Japan, - * but, as currently DRX-K is hardcoded to Annex A, let's stick - * with 0.15 roll-off factor. - */ -#define MAX_SYMBOL_RATE_6MHz 5217391 -static int set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int set_params(struct dvb_frontend *fe) { struct tda_state *state = fe->tuner_priv; int status = 0; int Standard; + u32 bw = fe->dtv_property_cache.bandwidth_hz; + u32 delsys = fe->dtv_property_cache.delivery_system; - state->m_Frequency = params->frequency; + state->m_Frequency = fe->dtv_property_cache.frequency; - if (fe->ops.info.type == FE_OFDM) - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (delsys) { + case SYS_DVBT: + case SYS_DVBT2: + switch (bw) { + case 6000000: Standard = HF_DVBT_6MHZ; break; - case BANDWIDTH_7_MHZ: + case 7000000: Standard = HF_DVBT_7MHZ; break; - default: - case BANDWIDTH_8_MHZ: + case 8000000: Standard = HF_DVBT_8MHZ; break; + default: + return -EINVAL; } - else if (fe->ops.info.type == FE_QAM) { - if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + if (bw <= 6000000) Standard = HF_DVBC_6MHZ; + else if (bw <= 7000000) + Standard = HF_DVBC_7MHZ; else Standard = HF_DVBC_8MHZ; - } else + break; + default: return -EINVAL; + } do { - status = RFTrackingFiltersCorrection(state, params->frequency); + status = RFTrackingFiltersCorrection(state, state->m_Frequency); if (status < 0) break; - status = ChannelConfiguration(state, params->frequency, Standard); + status = ChannelConfiguration(state, state->m_Frequency, + Standard); if (status < 0) break; diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 9369f7442f27..15912c96926a 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -315,18 +315,19 @@ static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int tda8083_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda8083_state* state = fe->demodulator_priv; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } tda8083_set_inversion (state, p->inversion); - tda8083_set_fec (state, p->u.qpsk.fec_inner); - tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate); + tda8083_set_fec(state, p->fec_inner); + tda8083_set_symbolrate(state, p->symbol_rate); tda8083_writereg (state, 0x00, 0x3c); tda8083_writereg (state, 0x00, 0x04); @@ -334,16 +335,17 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int tda8083_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda8083_state* state = fe->demodulator_priv; /* FIXME: get symbolrate & frequency offset...*/ /*p->frequency = ???;*/ p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = tda8083_get_fec (state); - /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/ + p->fec_inner = tda8083_get_fec(state); + /*p->symbol_rate = tda8083_get_symbolrate (state);*/ return 0; } @@ -438,10 +440,9 @@ error: } static struct dvb_frontend_ops tda8083_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Philips TDA8083 DVB-S", - .type = FE_QPSK, .frequency_min = 920000, /* TDA8060 */ .frequency_max = 2200000, /* TDA8060 */ .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c index 06c94800b940..04bbcc24de0a 100644 --- a/drivers/media/dvb/frontends/tda826x.c +++ b/drivers/media/dvb/frontends/tda826x.c @@ -71,8 +71,9 @@ static int tda826x_sleep(struct dvb_frontend *fe) return (ret == 1) ? 0 : ret; } -static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int tda826x_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda826x_priv *priv = fe->tuner_priv; int ret; u32 div; @@ -83,11 +84,11 @@ static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_param dprintk("%s:\n", __func__); - div = (params->frequency + (1000-1)) / 1000; + div = (p->frequency + (1000-1)) / 1000; /* BW = ((1 + RO) * SR/2 + 5) * 1.3 [SR in MSPS, BW in MHz] */ /* with R0 = 0.35 and some transformations: */ - ksyms = params->u.qpsk.symbol_rate / 1000; + ksyms = p->symbol_rate / 1000; bandwidth = (878 * ksyms + 6500000) / 1000000 + 1; if (bandwidth < 5) bandwidth = 5; diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h index 51f170678650..17750985db0c 100644 --- a/drivers/media/dvb/frontends/tdhd1.h +++ b/drivers/media/dvb/frontends/tdhd1.h @@ -40,24 +40,25 @@ static struct tda1004x_config alps_tdhd1_204a_config = { .request_firmware = alps_tdhd1_204_request_firmware }; -static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct i2c_adapter *i2c = fe->tuner_priv; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; u32 div; - div = (params->frequency + 36166666) / 166666; + div = (p->frequency + 36166666) / 166666; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x85; - if (params->frequency >= 174000000 && params->frequency <= 230000000) + if (p->frequency >= 174000000 && p->frequency <= 230000000) data[3] = 0x02; - else if (params->frequency >= 470000000 && params->frequency <= 823000000) + else if (p->frequency >= 470000000 && p->frequency <= 823000000) data[3] = 0x0C; - else if (params->frequency > 823000000 && params->frequency <= 862000000) + else if (p->frequency > 823000000 && p->frequency <= 862000000) data[3] = 0x8C; else return -EINVAL; diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c index bcb95c2ef296..029384d1fddd 100644 --- a/drivers/media/dvb/frontends/tua6100.c +++ b/drivers/media/dvb/frontends/tua6100.c @@ -67,9 +67,9 @@ static int tua6100_sleep(struct dvb_frontend *fe) return (ret == 1) ? 0 : ret; } -static int tua6100_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tua6100_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct tua6100_priv *priv = fe->tuner_priv; u32 div; u32 prediv; @@ -85,36 +85,37 @@ static int tua6100_set_params(struct dvb_frontend *fe, #define _ri 4000000 // setup register 0 - if (params->frequency < 2000000) { + if (c->frequency < 2000000) reg0[1] = 0x03; - } else { + else reg0[1] = 0x07; - } // setup register 1 - if (params->frequency < 1630000) { + if (c->frequency < 1630000) reg1[1] = 0x2c; - } else { + else reg1[1] = 0x0c; - } + if (_P == 64) reg1[1] |= 0x40; - if (params->frequency >= 1525000) + if (c->frequency >= 1525000) reg1[1] |= 0x80; // register 2 reg2[1] = (_R >> 8) & 0x03; reg2[2] = _R; - if (params->frequency < 1455000) { + if (c->frequency < 1455000) reg2[1] |= 0x1c; - } else if (params->frequency < 1630000) { + else if (c->frequency < 1630000) reg2[1] |= 0x0c; - } else { + else reg2[1] |= 0x1c; - } - // The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz) - prediv = (params->frequency * _R) / (_ri / 1000); + /* + * The N divisor ratio (note: c->frequency is in kHz, but we + * need it in Hz) + */ + prediv = (c->frequency * _R) / (_ri / 1000); div = prediv / _P; reg1[1] |= (div >> 9) & 0x03; reg1[2] = div >> 1; diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 550a07a8a997..bb42b563c42d 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -205,25 +205,26 @@ static int ves1820_init(struct dvb_frontend* fe) return 0; } -static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ves1820_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ves1820_state* state = fe->demodulator_priv; static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 }; static const u8 reg0x01[] = { 140, 140, 106, 100, 92 }; static const u8 reg0x05[] = { 135, 100, 70, 54, 38 }; static const u8 reg0x08[] = { 162, 116, 67, 52, 35 }; static const u8 reg0x09[] = { 145, 150, 106, 126, 107 }; - int real_qam = p->u.qam.modulation - QAM_16; + int real_qam = p->modulation - QAM_16; if (real_qam < 0 || real_qam > 4) return -EINVAL; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - ves1820_set_symbolrate(state, p->u.qam.symbol_rate); + ves1820_set_symbolrate(state, p->symbol_rate); ves1820_writereg(state, 0x34, state->pwm); ves1820_writereg(state, 0x01, reg0x01[real_qam]); @@ -309,8 +310,9 @@ static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ves1820_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ves1820_state* state = fe->demodulator_priv; int sync; s8 afc = 0; @@ -320,7 +322,7 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (verbose) { /* AFC only valid when carrier has been recovered */ printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" : - "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10); + "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10); } if (!state->config->invert) { @@ -329,13 +331,13 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF; } - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + p->modulation = ((state->reg0 >> 2) & 7) + QAM_16; - p->u.qam.fec_inner = FEC_NONE; + p->fec_inner = FEC_NONE; p->frequency = ((p->frequency + 31250) / 62500) * 62500; if (sync & 2) - p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10; + p->frequency -= ((s32) p->symbol_rate * afc) >> 10; return 0; } @@ -405,10 +407,9 @@ error: } static struct dvb_frontend_ops ves1820_ops = { - + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "VLSI VES1820 DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 47000000, .frequency_max = 862000000, diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c index 8d7854c2fb0c..9c17eacaec24 100644 --- a/drivers/media/dvb/frontends/ves1x93.c +++ b/drivers/media/dvb/frontends/ves1x93.c @@ -46,6 +46,7 @@ struct ves1x93_state { u8 *init_1x93_wtab; u8 tab_size; u8 demod_type; + u32 frequency; }; static int debug; @@ -384,31 +385,34 @@ static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ves1x93_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ves1x93_state* state = fe->demodulator_priv; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } ves1x93_set_inversion (state, p->inversion); - ves1x93_set_fec (state, p->u.qpsk.fec_inner); - ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate); + ves1x93_set_fec(state, p->fec_inner); + ves1x93_set_symbolrate(state, p->symbol_rate); state->inversion = p->inversion; + state->frequency = p->frequency; return 0; } -static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ves1x93_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ves1x93_state* state = fe->demodulator_priv; int afc; afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2; - afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16; + afc = (afc * (int)(p->symbol_rate/1000/8))/16; - p->frequency -= afc; + p->frequency = state->frequency - afc; /* * inversion indicator is only valid @@ -417,7 +421,7 @@ static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (state->inversion == INVERSION_AUTO) p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ? INVERSION_OFF : INVERSION_ON; - p->u.qpsk.fec_inner = ves1x93_get_fec (state); + p->fec_inner = ves1x93_get_fec(state); /* XXX FIXME: timing offset !! */ return 0; @@ -506,10 +510,9 @@ error: } static struct dvb_frontend_ops ves1x93_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "VLSI VES1x93 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c index 81aa984c551f..0903d461b8fa 100644 --- a/drivers/media/dvb/frontends/zl10036.c +++ b/drivers/media/dvb/frontends/zl10036.c @@ -305,12 +305,12 @@ static int zl10036_set_gain_params(struct zl10036_state *state, return zl10036_write(state, buf, sizeof(buf)); } -static int zl10036_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int zl10036_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct zl10036_state *state = fe->tuner_priv; int ret = 0; - u32 frequency = params->frequency; + u32 frequency = p->frequency; u32 fbw; int i; u8 c; @@ -326,7 +326,7 @@ static int zl10036_set_params(struct dvb_frontend *fe, * fBW = (alpha*symbolrate)/(2*0.8) * 1.35 / (2*0.8) = 27 / 32 */ - fbw = (27 * params->u.qpsk.symbol_rate) / 32; + fbw = (27 * p->symbol_rate) / 32; /* scale to kHz */ fbw /= 1000; @@ -353,7 +353,7 @@ static int zl10036_set_params(struct dvb_frontend *fe, if (ret < 0) goto error; - ret = zl10036_set_frequency(state, params->frequency); + ret = zl10036_set_frequency(state, p->frequency); if (ret < 0) goto error; diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb/frontends/zl10039.c index c085e58a94bf..eff9c5fde50a 100644 --- a/drivers/media/dvb/frontends/zl10039.c +++ b/drivers/media/dvb/frontends/zl10039.c @@ -176,9 +176,9 @@ static int zl10039_sleep(struct dvb_frontend *fe) return 0; } -static int zl10039_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int zl10039_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct zl10039_state *state = fe->tuner_priv; u8 buf[6]; u8 bf; @@ -188,12 +188,12 @@ static int zl10039_set_params(struct dvb_frontend *fe, dprintk("%s\n", __func__); dprintk("Set frequency = %d, symbol rate = %d\n", - params->frequency, params->u.qpsk.symbol_rate); + c->frequency, c->symbol_rate); /* Assumed 10.111 MHz crystal oscillator */ /* Cancelled num/den 80 to prevent overflow */ - div = (params->frequency * 1000) / 126387; - fbw = (params->u.qpsk.symbol_rate * 27) / 32000; + div = (c->frequency * 1000) / 126387; + fbw = (c->symbol_rate * 27) / 32000; /* Cancelled num/den 10 to prevent overflow */ bf = ((fbw * 5088) / 1011100) - 1; diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index adbbf6d3d044..ac7237891374 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -37,9 +37,9 @@ struct zl10353_state { struct zl10353_config config; - enum fe_bandwidth bandwidth; - u32 ucblocks; - u32 frequency; + u32 bandwidth; + u32 ucblocks; + u32 frequency; }; static int debug; @@ -122,30 +122,17 @@ static void zl10353_dump_regs(struct dvb_frontend *fe) } static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, - enum fe_bandwidth bandwidth, + u32 bandwidth, u16 *nominal_rate) { struct zl10353_state *state = fe->demodulator_priv; u32 adc_clock = 450560; /* 45.056 MHz */ u64 value; - u8 bw; + u8 bw = bandwidth / 1000000; if (state->config.adc_clock) adc_clock = state->config.adc_clock; - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - bw = 6; - break; - case BANDWIDTH_7_MHZ: - bw = 7; - break; - case BANDWIDTH_8_MHZ: - default: - bw = 8; - break; - } - value = (u64)10 * (1 << 23) / 7 * 125; value = (bw * value) + adc_clock / 2; do_div(value, adc_clock); @@ -192,16 +179,15 @@ static int zl10353_sleep(struct dvb_frontend *fe) return 0; } -static int zl10353_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int zl10353_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct zl10353_state *state = fe->demodulator_priv; u16 nominal_rate, input_freq; u8 pllbuf[6] = { 0x67 }, acq_ctl = 0; u16 tps = 0; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - state->frequency = param->frequency; + state->frequency = c->frequency; zl10353_single_write(fe, RESET, 0x80); udelay(200); @@ -211,42 +197,44 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, zl10353_single_write(fe, AGC_TARGET, 0x28); - if (op->transmission_mode != TRANSMISSION_MODE_AUTO) + if (c->transmission_mode != TRANSMISSION_MODE_AUTO) acq_ctl |= (1 << 0); - if (op->guard_interval != GUARD_INTERVAL_AUTO) + if (c->guard_interval != GUARD_INTERVAL_AUTO) acq_ctl |= (1 << 1); zl10353_single_write(fe, ACQ_CTL, acq_ctl); - switch (op->bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: /* These are extrapolated from the 7 and 8MHz values */ zl10353_single_write(fe, MCLK_RATIO, 0x97); zl10353_single_write(fe, 0x64, 0x34); zl10353_single_write(fe, 0xcc, 0xdd); break; - case BANDWIDTH_7_MHZ: + case 7000000: zl10353_single_write(fe, MCLK_RATIO, 0x86); zl10353_single_write(fe, 0x64, 0x35); zl10353_single_write(fe, 0xcc, 0x73); break; - case BANDWIDTH_8_MHZ: default: + c->bandwidth_hz = 8000000; + /* fall though */ + case 8000000: zl10353_single_write(fe, MCLK_RATIO, 0x75); zl10353_single_write(fe, 0x64, 0x36); zl10353_single_write(fe, 0xcc, 0x73); } - zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); + zl10353_calc_nominal_rate(fe, c->bandwidth_hz, &nominal_rate); zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); - state->bandwidth = op->bandwidth; + state->bandwidth = c->bandwidth_hz; zl10353_calc_input_freq(fe, &input_freq); zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); /* Hint at TPS settings */ - switch (op->code_rate_HP) { + switch (c->code_rate_HP) { case FEC_2_3: tps |= (1 << 7); break; @@ -266,7 +254,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - switch (op->code_rate_LP) { + switch (c->code_rate_LP) { case FEC_2_3: tps |= (1 << 4); break; @@ -283,14 +271,14 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, case FEC_AUTO: break; case FEC_NONE: - if (op->hierarchy_information == HIERARCHY_AUTO || - op->hierarchy_information == HIERARCHY_NONE) + if (c->hierarchy == HIERARCHY_AUTO || + c->hierarchy == HIERARCHY_NONE) break; default: return -EINVAL; } - switch (op->constellation) { + switch (c->modulation) { case QPSK: break; case QAM_AUTO: @@ -304,7 +292,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - switch (op->transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: case TRANSMISSION_MODE_AUTO: break; @@ -315,7 +303,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - switch (op->guard_interval) { + switch (c->guard_interval) { case GUARD_INTERVAL_1_32: case GUARD_INTERVAL_AUTO: break; @@ -332,7 +320,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - switch (op->hierarchy_information) { + switch (c->hierarchy) { case HIERARCHY_AUTO: case HIERARCHY_NONE: break; @@ -362,12 +350,12 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, */ if (state->config.no_tuner) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } } else if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5); + fe->ops.tuner_ops.calc_regs(fe, pllbuf + 1, 5); pllbuf[1] <<= 1; zl10353_write(fe, pllbuf, sizeof(pllbuf)); } @@ -383,11 +371,10 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return 0; } -static int zl10353_get_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int zl10353_get_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct zl10353_state *state = fe->demodulator_priv; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; int s6, s9; u16 tps; static const u8 tps_fec_to_api[8] = { @@ -411,66 +398,66 @@ static int zl10353_get_parameters(struct dvb_frontend *fe, tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 | zl10353_read_register(state, TPS_RECEIVED_0); - op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; - op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; + c->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; + c->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; switch ((tps >> 13) & 3) { case 0: - op->constellation = QPSK; + c->modulation = QPSK; break; case 1: - op->constellation = QAM_16; + c->modulation = QAM_16; break; case 2: - op->constellation = QAM_64; + c->modulation = QAM_64; break; default: - op->constellation = QAM_AUTO; + c->modulation = QAM_AUTO; break; } - op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : + c->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K; switch ((tps >> 2) & 3) { case 0: - op->guard_interval = GUARD_INTERVAL_1_32; + c->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - op->guard_interval = GUARD_INTERVAL_1_16; + c->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - op->guard_interval = GUARD_INTERVAL_1_8; + c->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - op->guard_interval = GUARD_INTERVAL_1_4; + c->guard_interval = GUARD_INTERVAL_1_4; break; default: - op->guard_interval = GUARD_INTERVAL_AUTO; + c->guard_interval = GUARD_INTERVAL_AUTO; break; } switch ((tps >> 10) & 7) { case 0: - op->hierarchy_information = HIERARCHY_NONE; + c->hierarchy = HIERARCHY_NONE; break; case 1: - op->hierarchy_information = HIERARCHY_1; + c->hierarchy = HIERARCHY_1; break; case 2: - op->hierarchy_information = HIERARCHY_2; + c->hierarchy = HIERARCHY_2; break; case 3: - op->hierarchy_information = HIERARCHY_4; + c->hierarchy = HIERARCHY_4; break; default: - op->hierarchy_information = HIERARCHY_AUTO; + c->hierarchy = HIERARCHY_AUTO; break; } - param->frequency = state->frequency; - op->bandwidth = state->bandwidth; - param->inversion = INVERSION_AUTO; + c->frequency = state->frequency; + c->bandwidth_hz = state->bandwidth; + c->inversion = INVERSION_AUTO; return 0; } @@ -651,10 +638,9 @@ error: } static struct dvb_frontend_ops zl10353_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Zarlink ZL10353 DVB-T", - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c index 2ae0afa7756b..ad013e93ed11 100644 --- a/drivers/media/dvb/mantis/mantis_vp1033.c +++ b/drivers/media/dvb/mantis/mantis_vp1033.c @@ -83,9 +83,9 @@ u8 lgtdqcs001f_inittab[] = { #define MANTIS_MODEL_NAME "VP-1033" #define MANTIS_DEV_TYPE "DVB-S/DSS" -int lgtdqcs001f_tuner_set(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +int lgtdqcs001f_tuner_set(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mantis_pci *mantis = fe->dvb->priv; struct i2c_adapter *adapter = &mantis->adapter; @@ -95,14 +95,14 @@ int lgtdqcs001f_tuner_set(struct dvb_frontend *fe, struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)}; - div = params->frequency / 250; + div = p->frequency / 250; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x83; buf[3] = 0xc0; - if (params->frequency < 1531000) + if (p->frequency < 1531000) buf[3] |= 0x04; else buf[3] &= ~0x04; diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c index 06da0ddf05a7..1ca6837fbe46 100644 --- a/drivers/media/dvb/mantis/mantis_vp2033.c +++ b/drivers/media/dvb/mantis/mantis_vp2033.c @@ -65,8 +65,9 @@ static u8 read_pwm(struct mantis_pci *mantis) return pwm; } -static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mantis_pci *mantis = fe->dvb->priv; struct i2c_adapter *adapter = &mantis->adapter; @@ -77,13 +78,13 @@ static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_fronten #define CU1216_IF 36125000 #define TUNER_MUL 62500 - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); + buf[3] = (p->frequency < 150000000 ? 0x01 : + p->frequency < 445000000 ? 0x02 : 0x04); buf[4] = 0xde; buf[5] = 0x20; diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c index f72b137b7652..d480741afd78 100644 --- a/drivers/media/dvb/mantis/mantis_vp2040.c +++ b/drivers/media/dvb/mantis/mantis_vp2040.c @@ -47,8 +47,9 @@ struct tda10023_config vp2040_tda10023_cu1216_config = { .invert = 1, }; -static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mantis_pci *mantis = fe->dvb->priv; struct i2c_adapter *adapter = &mantis->adapter; @@ -59,13 +60,13 @@ static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_fronten #define CU1216_IF 36125000 #define TUNER_MUL 62500 - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); + buf[3] = (p->frequency < 150000000 ? 0x01 : + p->frequency < 445000000 ? 0x02 : 0x04); buf[4] = 0xde; buf[5] = 0x20; diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 056419228363..8418c02bcefe 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -218,7 +218,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, memset(&config, 0, sizeof(config)); config.adr = 0x29 + (chan->number ^ 2); - chan->fe = dvb_attach(drxk_attach, &config, i2c, &chan->fe2); + chan->fe = dvb_attach(drxk_attach, &config, i2c); if (!chan->fe) { printk(KERN_ERR "No DRXK found!\n"); return -ENODEV; diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 80fb51004461..e1f20c236989 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -445,9 +445,9 @@ static inline u32 divide(u32 numerator, u32 denominator) } /* LG Innotek TDTE-E001P (Infineon TUA6034) */ -static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct pluto *pluto = frontend_to_pluto(fe); struct i2c_msg msg; int ret; @@ -478,7 +478,7 @@ static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe, else buf[3] = 0x04; - if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + if (p->bandwidth_hz == 8000000) buf[3] |= 0x08; if (sizeof(buf) == 6) { diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c index 451641c0c1d2..d980dfb21e5e 100644 --- a/drivers/media/dvb/pt1/va1j5jf8007s.c +++ b/drivers/media/dvb/pt1/va1j5jf8007s.c @@ -385,7 +385,7 @@ va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock) static int va1j5jf8007s_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { @@ -395,7 +395,7 @@ va1j5jf8007s_tune(struct dvb_frontend *fe, state = fe->demodulator_priv; - if (params != NULL) + if (re_tune) state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1; switch (state->tune_state) { @@ -579,9 +579,9 @@ static void va1j5jf8007s_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops va1j5jf8007s_ops = { + .delsys = { SYS_ISDBS }, .info = { .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1000, diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c index 0f085c3e571b..2db15159d514 100644 --- a/drivers/media/dvb/pt1/va1j5jf8007t.c +++ b/drivers/media/dvb/pt1/va1j5jf8007t.c @@ -264,7 +264,7 @@ static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state, static int va1j5jf8007t_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { @@ -274,7 +274,7 @@ va1j5jf8007t_tune(struct dvb_frontend *fe, state = fe->demodulator_priv; - if (params != NULL) + if (re_tune) state->tune_state = VA1J5JF8007T_SET_FREQUENCY; switch (state->tune_state) { @@ -428,9 +428,9 @@ static void va1j5jf8007t_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops va1j5jf8007t_ops = { + .delsys = { SYS_ISDBT }, .info = { .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T", - .type = FE_OFDM, .frequency_min = 90000000, .frequency_max = 770000000, .frequency_stepsize = 142857, diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 37c594f82782..654685c9303e 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -50,7 +50,7 @@ struct smsdvb_client_t { struct completion tune_done; /* todo: save freq/band instead whole struct */ - struct dvb_frontend_parameters fe_params; + struct dtv_frontend_properties fe_params; struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; int event_fe_state; @@ -591,8 +591,7 @@ static int smsdvb_get_tune_settings(struct dvb_frontend *fe, return 0; } -static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct smsdvb_client_t *client = @@ -658,8 +657,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe, &client->tune_done); } -static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct smsdvb_client_t *client = @@ -723,8 +721,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe, &client->tune_done); } -static int smsdvb_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int smsdvb_set_frontend(struct dvb_frontend *fe) { struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); @@ -733,18 +730,18 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe, switch (smscore_get_device_mode(coredev)) { case DEVICE_MODE_DVBT: case DEVICE_MODE_DVBT_BDA: - return smsdvb_dvbt_set_frontend(fe, fep); + return smsdvb_dvbt_set_frontend(fe); case DEVICE_MODE_ISDBT: case DEVICE_MODE_ISDBT_BDA: - return smsdvb_isdbt_set_frontend(fe, fep); + return smsdvb_isdbt_set_frontend(fe); default: return -EINVAL; } } -static int smsdvb_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int smsdvb_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); @@ -752,7 +749,7 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe, /* todo: */ memcpy(fep, &client->fe_params, - sizeof(struct dvb_frontend_parameters)); + sizeof(struct dtv_frontend_properties)); return 0; } @@ -789,7 +786,6 @@ static void smsdvb_release(struct dvb_frontend *fe) static struct dvb_frontend_ops smsdvb_fe_ops = { .info = { .name = "Siano Mobile Digital MDTV Receiver", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 250000, @@ -873,6 +869,17 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, memcpy(&client->frontend.ops, &smsdvb_fe_ops, sizeof(struct dvb_frontend_ops)); + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + smsdvb_fe_ops.delsys[0] = SYS_DVBT; + break; + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + smsdvb_fe_ops.delsys[0] = SYS_ISDBT; + break; + } + rc = dvb_register_frontend(&client->adapter, &client->frontend); if (rc < 0) { sms_err("frontend registration failed %d", rc); diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 3d20719fce1a..6ecbcf614878 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -991,7 +991,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) if (feed->type == DMX_TYPE_TS) { if ((feed->ts_type & TS_DECODER) && - (feed->pes_type < DMX_TS_PES_OTHER)) { + (feed->pes_type <= DMX_TS_PES_PCR)) { switch (demux->dmx.frontend->source) { case DMX_MEMORY_FE: if (feed->ts_type & TS_DECODER) @@ -1568,20 +1568,27 @@ static int get_firmware(struct av7110* av7110) return ret; } -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u8 pwr = 0; u8 buf[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; + u32 div = (p->frequency + 479500) / 125; - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; - else pwr = 2; + if (p->frequency > 2000000) + pwr = 3; + else if (p->frequency > 1800000) + pwr = 2; + else if (p->frequency > 1600000) + pwr = 1; + else if (p->frequency > 1200000) + pwr = 0; + else if (p->frequency >= 1100000) + pwr = 1; + else + pwr = 2; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; @@ -1604,19 +1611,20 @@ static struct ves1x93_config alps_bsrv2_config = { .invert_pwm = 0, }; -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (params->frequency + 35937500 + 31250) / 62500; + div = (p->frequency + 35937500 + 31250) / 62500; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1635,14 +1643,15 @@ static struct ves1820_config alps_tdbe2_config = { -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = params->frequency / 125; + div = p->frequency / 125; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x8e; @@ -1661,11 +1670,12 @@ static struct tda8083_config grundig_29504_451_config = { -static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; - u32 f = params->frequency; + u32 f = p->frequency; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; @@ -1692,16 +1702,17 @@ static struct ves1820_config philips_cd1516_config = { -static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div, pwr; u8 data[4]; struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (params->frequency + 36200000) / 166666; + div = (p->frequency + 36200000) / 166666; - if (params->frequency <= 782000000) + if (p->frequency <= 782000000) pwr = 1; else pwr = 2; @@ -1829,8 +1840,9 @@ static u8 nexusca_stv0297_inittab[] = { 0xff, 0xff, }; -static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; u8 data[4]; @@ -1838,19 +1850,19 @@ static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_ struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 }; int i; - div = (params->frequency + 36150000 + 31250) / 62500; + div = (p->frequency + 36150000 + 31250) / 62500; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0xce; - if (params->frequency < 45000000) + if (p->frequency < 45000000) return -EINVAL; - else if (params->frequency < 137000000) + else if (p->frequency < 137000000) data[3] = 0x01; - else if (params->frequency < 403000000) + else if (p->frequency < 403000000) data[3] = 0x02; - else if (params->frequency < 860000000) + else if (p->frequency < 860000000) data[3] = 0x04; else return -EINVAL; @@ -1884,27 +1896,36 @@ static struct stv0297_config nexusca_stv0297_config = { -static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; u8 cfg, cpump, band_select; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (36125000 + params->frequency) / 166666; + div = (36125000 + p->frequency) / 166666; cfg = 0x88; - if (params->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) cpump = 1; - else cpump = 3; + if (p->frequency < 175000000) + cpump = 2; + else if (p->frequency < 390000000) + cpump = 1; + else if (p->frequency < 470000000) + cpump = 2; + else if (p->frequency < 750000000) + cpump = 1; + else + cpump = 3; - if (params->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) band_select = 0x05; - else band_select = 0x03; + if (p->frequency < 175000000) + band_select = 0x0e; + else if (p->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; @@ -1964,15 +1985,14 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) return ret; } -static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int av7110_fe_set_frontend(struct dvb_frontend *fe) { struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_fe_params = *params; - ret = av7110->fe_set_frontend(fe, params); - } + if (!ret) + ret = av7110->fe_set_frontend(fe); + return ret; } @@ -2081,7 +2101,7 @@ static void dvb_s_recover(struct av7110* av7110) msleep(20); av7110_fe_set_tone(av7110->fe, av7110->saved_tone); - av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params); + av7110_fe_set_frontend(av7110->fe); } static u8 read_pwm(struct av7110* av7110) diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index d85b8512ac30..88b3b2d6cc0e 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -272,7 +272,6 @@ struct av7110 { /* crash recovery */ void (*recover)(struct av7110* av7110); - struct dvb_frontend_parameters saved_fe_params; fe_sec_voltage_t saved_voltage; fe_sec_tone_mode_t saved_tone; struct dvb_diseqc_master_cmd saved_master_cmd; @@ -286,7 +285,7 @@ struct av7110 { int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); - int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*fe_set_frontend)(struct dvb_frontend *fe); }; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 78d32f7e49fc..8b32e282bf5d 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -502,33 +502,33 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra return 0; } -static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 div; u8 buf[4]; struct budget *budget = (struct budget *) fe->dvb->priv; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((c->frequency < 950000) || (c->frequency > 2150000)) return -EINVAL; - div = (params->frequency + (125 - 1)) / 125; // round correctly + div = (c->frequency + (125 - 1)) / 125; /* round correctly */ buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; buf[3] = 0x20; - if (params->u.qpsk.symbol_rate < 4000000) + if (c->symbol_rate < 4000000) buf[3] |= 1; - if (params->frequency < 1250000) + if (c->frequency < 1250000) buf[3] |= 0; - else if (params->frequency < 1550000) + else if (c->frequency < 1550000) buf[3] |= 0x40; - else if (params->frequency < 2050000) + else if (c->frequency < 2050000) buf[3] |= 0x80; - else if (params->frequency < 2150000) + else if (c->frequency < 2150000) buf[3] |= 0xC0; if (fe->ops.i2c_gate_ctrl) @@ -617,8 +617,9 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = { .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, }; -static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget *budget = (struct budget *) fe->dvb->priv; u8 buf[6]; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -627,13 +628,13 @@ static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f #define CU1216_IF 36125000 #define TUNER_MUL 62500 - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); + buf[3] = (c->frequency < 150000000 ? 0x01 : + c->frequency < 445000000 ? 0x02 : 0x04); buf[4] = 0xde; buf[5] = 0x20; @@ -697,8 +698,9 @@ static int philips_tu1216_tuner_init(struct dvb_frontend *fe) return 0; } -static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget *budget = (struct budget *) fe->dvb->priv; u8 tuner_buf[4]; struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = @@ -707,7 +709,7 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36166000; + tuner_frequency = c->frequency + 36166000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) @@ -732,28 +734,28 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f return -EINVAL; // determine band - if (params->frequency < 49000000) + if (c->frequency < 49000000) return -EINVAL; - else if (params->frequency < 161000000) + else if (c->frequency < 161000000) band = 1; - else if (params->frequency < 444000000) + else if (c->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) + else if (c->frequency < 861000000) band = 4; else return -EINVAL; // setup PLL filter - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: filter = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: filter = 0; break; - case BANDWIDTH_8_MHZ: + case 8000000: filter = 1; break; @@ -763,7 +765,7 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f // calculate divisor // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; + tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000; // setup tuner buffer tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index ca02e9722172..98e524178765 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -193,7 +193,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) dev->input_phys = budget_ci->ir.phys; dev->input_id.bustype = BUS_PCI; dev->input_id.version = 1; - dev->scanmask = 0xff; if (saa->pci->subsystem_vendor) { dev->input_id.vendor = saa->pci->subsystem_vendor; dev->input_id.product = saa->pci->subsystem_device; @@ -234,6 +233,8 @@ static int msp430_ir_init(struct budget_ci *budget_ci) dev->map_name = RC_MAP_BUDGET_CI_OLD; break; } + if (!budget_ci->ir.full_rc5) + dev->scanmask = 0xff; error = rc_register_device(dev); if (error) { @@ -659,33 +660,33 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, return 0; } -static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u32 div; u8 buf[4]; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((p->frequency < 950000) || (p->frequency > 2150000)) return -EINVAL; - div = (params->frequency + (500 - 1)) / 500; // round correctly + div = (p->frequency + (500 - 1)) / 500; /* round correctly */ buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; buf[3] = 0x20; - if (params->u.qpsk.symbol_rate < 4000000) + if (p->symbol_rate < 4000000) buf[3] |= 1; - if (params->frequency < 1250000) + if (p->frequency < 1250000) buf[3] |= 0; - else if (params->frequency < 1550000) + else if (p->frequency < 1550000) buf[3] |= 0x40; - else if (params->frequency < 2050000) + else if (p->frequency < 2050000) buf[3] |= 0x80; - else if (params->frequency < 2150000) + else if (p->frequency < 2150000) buf[3] |= 0xC0; if (fe->ops.i2c_gate_ctrl) @@ -740,8 +741,9 @@ static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) return 0; } -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 tuner_buf[4]; struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; @@ -749,7 +751,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36130000; + tuner_frequency = p->frequency + 36130000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) @@ -774,30 +776,30 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb return -EINVAL; // determine band - if (params->frequency < 49000000) + if (p->frequency < 49000000) return -EINVAL; - else if (params->frequency < 159000000) + else if (p->frequency < 159000000) band = 1; - else if (params->frequency < 444000000) + else if (p->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) + else if (p->frequency < 861000000) band = 4; else return -EINVAL; // setup PLL filter and TDA9889 - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: tda1004x_writereg(fe, 0x0C, 0x14); filter = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: tda1004x_writereg(fe, 0x0C, 0x80); filter = 0; break; - case BANDWIDTH_8_MHZ: + case 8000000: tda1004x_writereg(fe, 0x0C, 0x14); filter = 1; break; @@ -808,7 +810,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb // calculate divisor // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; // setup tuner buffer tuner_buf[0] = tuner_frequency >> 8; @@ -855,8 +857,9 @@ static struct tda1004x_config philips_tdm1316l_config_invert = { .request_firmware = philips_tdm1316l_request_firmware, }; -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 tuner_buf[5]; struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, @@ -867,7 +870,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36125000; + tuner_frequency = p->frequency + 36125000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) { @@ -904,7 +907,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc filter = 1; // calculate divisor - tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500; + tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500; // setup tuner buffer tuner_buf[0] = tuner_frequency >> 8; diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 3395d1a90516..2cb35c23d2ac 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -261,19 +261,25 @@ static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_c return 0; } -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; u8 pwr = 0; u8 buf[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; - - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; + u32 div = (p->frequency + 479500) / 125; + + if (p->frequency > 2000000) + pwr = 3; + else if (p->frequency > 1800000) + pwr = 2; + else if (p->frequency > 1600000) + pwr = 1; + else if (p->frequency > 1200000) + pwr = 0; + else if (p->frequency >= 1100000) + pwr = 1; else pwr = 2; buf[0] = (div >> 8) & 0x7f; @@ -297,14 +303,15 @@ static struct ves1x93_config alps_bsrv2_config = { .invert_pwm = 0, }; -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = params->frequency / 125; + div = p->frequency / 125; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x8e; diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index d238fb9371a7..b21bcce66708 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -200,19 +200,25 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m return 0; } -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget* budget = (struct budget*) fe->dvb->priv; u8 pwr = 0; u8 buf[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; - - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; + u32 div = (c->frequency + 479500) / 125; + + if (c->frequency > 2000000) + pwr = 3; + else if (c->frequency > 1800000) + pwr = 2; + else if (c->frequency > 1600000) + pwr = 1; + else if (c->frequency > 1200000) + pwr = 0; + else if (c->frequency >= 1100000) + pwr = 1; else pwr = 2; buf[0] = (div >> 8) & 0x7f; @@ -236,19 +242,20 @@ static struct ves1x93_config alps_bsrv2_config = .invert_pwm = 0, }; -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (params->frequency + 35937500 + 31250) / 62500; + div = (c->frequency + 35937500 + 31250) / 62500; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -263,8 +270,9 @@ static struct ves1820_config alps_tdbe2_config = { .selagc = VES1820_SELAGC_SIGNAMPERR, }; -static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget *budget = fe->dvb->priv; u8 *tuner_addr = fe->tuner_priv; u32 div; @@ -277,19 +285,27 @@ static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dv else msg.addr = 0x61; - div = (36125000 + params->frequency) / 166666; + div = (36125000 + c->frequency) / 166666; cfg = 0x88; - if (params->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) cpump = 1; - else cpump = 3; + if (c->frequency < 175000000) + cpump = 2; + else if (c->frequency < 390000000) + cpump = 1; + else if (c->frequency < 470000000) + cpump = 2; + else if (c->frequency < 750000000) + cpump = 1; + else + cpump = 3; - if (params->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) band_select = 0x05; - else band_select = 0x03; + if (c->frequency < 175000000) + band_select = 0x0e; + else if (c->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; @@ -312,14 +328,15 @@ static struct l64781_config grundig_29504_401_config_activy = { static u8 tuner_address_grundig_29504_401_activy = 0x60; -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = params->frequency / 125; + div = c->frequency / 125; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x8e; @@ -335,14 +352,15 @@ static struct tda8083_config grundig_29504_451_config = { .demod_address = 0x68, }; -static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int s5h1420_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = params->frequency / 1000; + div = c->frequency / 1000; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0xc2; diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index e90192fdde11..5b682cc4c814 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1017,19 +1017,20 @@ static u32 functionality(struct i2c_adapter *adapter) -static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdmb7_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 data[4]; struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) }; u32 div; - div = (params->frequency + 36166667) / 166667; + div = (p->frequency + 36166667) / 166667; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = ((div >> 10) & 0x60) | 0x85; - data[3] = params->frequency < 592000000 ? 0x40 : 0x80; + data[3] = p->frequency < 592000000 ? 0x40 : 0x80; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1071,8 +1072,9 @@ static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe) return 0; } -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 tuner_buf[4]; struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; @@ -1080,7 +1082,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36130000; + tuner_frequency = p->frequency + 36130000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) cp = 3; else if (tuner_frequency < 160000000) cp = 5; @@ -1094,25 +1096,29 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb else return -EINVAL; // determine band - if (params->frequency < 49000000) return -EINVAL; - else if (params->frequency < 159000000) band = 1; - else if (params->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) band = 4; + if (p->frequency < 49000000) + return -EINVAL; + else if (p->frequency < 159000000) + band = 1; + else if (p->frequency < 444000000) + band = 2; + else if (p->frequency < 861000000) + band = 4; else return -EINVAL; // setup PLL filter - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: tda1004x_writereg(fe, 0x0C, 0); filter = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: tda1004x_writereg(fe, 0x0C, 0); filter = 0; break; - case BANDWIDTH_8_MHZ: + case 8000000: tda1004x_writereg(fe, 0x0C, 0xFF); filter = 1; break; @@ -1123,7 +1129,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb // calculate divisor // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; // setup tuner buffer tuner_buf[0] = tuner_frequency >> 8; @@ -1273,23 +1279,24 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 return 0; } -static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 buf[4]; u32 div; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((p->frequency < 950000) || (p->frequency > 2150000)) return -EINVAL; - div = (params->frequency + (125 - 1)) / 125; // round correctly + div = (p->frequency + (125 - 1)) / 125; /* round correctly */ buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; buf[3] = 0xC4; - if (params->frequency > 1530000) + if (p->frequency > 1530000) buf[3] = 0xC0; /* BSBE1 wants XCE bit set */ @@ -1316,14 +1323,15 @@ static struct stv0299_config alps_stv0299_config = { .set_symbol_rate = alps_stv0299_set_symbol_rate, }; -static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 buf[4]; u32 div; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - div = params->frequency / 125; + div = p->frequency / 125; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; @@ -1343,19 +1351,20 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = { .demod_address = 0x68, }; -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (params->frequency + 35937500 + 31250) / 62500; + div = (p->frequency + 35937500 + 31250) / 62500; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1387,8 +1396,9 @@ static u8 read_pwm(struct ttusb* ttusb) } -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv; u8 tuner_buf[5]; struct i2c_msg tuner_msg = {.addr = 0x60, @@ -1399,7 +1409,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency; + tuner_frequency = p->frequency; if (tuner_frequency < 87000000) {return -EINVAL;} else if (tuner_frequency < 130000000) {cp = 3; band = 1;} else if (tuner_frequency < 160000000) {cp = 5; band = 1;} @@ -1417,7 +1427,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc // calculate divisor // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz - tuner_frequency = ((params->frequency + 36125000) / 62500); + tuner_frequency = ((p->frequency + 36125000) / 62500); // setup tuner buffer tuner_buf[0] = tuner_frequency >> 8; @@ -1694,10 +1704,8 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i ttusb->i2c_adap.dev.parent = &udev->dev; result = i2c_add_adapter(&ttusb->i2c_adap); - if (result) { - dvb_unregister_adapter (&ttusb->adapter); - return result; - } + if (result) + goto err_unregister_adapter; memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); @@ -1714,33 +1722,29 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i ttusb->dvb_demux.stop_feed = ttusb_stop_feed; ttusb->dvb_demux.write_to_decoder = NULL; - if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) { + result = dvb_dmx_init(&ttusb->dvb_demux); + if (result < 0) { printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; + result = -ENODEV; + goto err_i2c_del_adapter; } //FIXME dmxdev (nur WAS?) ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum; ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; ttusb->dmxdev.capabilities = 0; - if ((result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter)) < 0) { + result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter); + if (result < 0) { printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", result); - dvb_dmx_release(&ttusb->dvb_demux); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; + result = -ENODEV; + goto err_release_dmx; } if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { printk("ttusb_dvb: dvb_net_init failed!\n"); - dvb_dmxdev_release(&ttusb->dmxdev); - dvb_dmx_release(&ttusb->dvb_demux); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; + result = -ENODEV; + goto err_release_dmxdev; } usb_set_intfdata(intf, (void *) ttusb); @@ -1748,6 +1752,16 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i frontend_init(ttusb); return 0; + +err_release_dmxdev: + dvb_dmxdev_release(&ttusb->dmxdev); +err_release_dmx: + dvb_dmx_release(&ttusb->dvb_demux); +err_i2c_del_adapter: + i2c_del_adapter(&ttusb->i2c_adap); +err_unregister_adapter: + dvb_unregister_adapter (&ttusb->adapter); + return result; } static void ttusb_disconnect(struct usb_interface *intf) diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 21260aad1e54..5c45c9d0712d 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -87,8 +87,9 @@ static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, return 0; } -static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, @@ -113,8 +114,9 @@ static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, return 0; } -static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x01, @@ -135,7 +137,7 @@ static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_fron freq = htonl(p->frequency + (state->hi_band ? LOF_HI : LOF_LO)); memcpy(&b[4], &freq, sizeof(u32)); - sym_rate = htonl(p->u.qam.symbol_rate); + sym_rate = htonl(p->symbol_rate); memcpy(&b[12], &sym_rate, sizeof(u32)); band = htonl(state->hi_band ? LOF_HI : LOF_LO); memcpy(&b[24], &band, sizeof(u32)); @@ -241,10 +243,9 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf } static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", - .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 62500, @@ -265,10 +266,9 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { }; static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 6edc9ba81203..6f9eb94e85b3 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -108,8 +108,7 @@ static long media_device_enum_entities(struct media_device *mdev, u_ent.group_id = ent->group_id; u_ent.pads = ent->num_pads; u_ent.links = ent->num_links - ent->num_backlinks; - u_ent.v4l.major = ent->v4l.major; - u_ent.v4l.minor = ent->v4l.minor; + memcpy(&u_ent.raw, &ent->info, sizeof(ent->info)); if (copy_to_user(uent, &u_ent, sizeof(u_ent))) return -EFAULT; return 0; diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index ccd5f0d8a012..e954781c90bf 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -11,6 +11,162 @@ menuconfig RADIO_ADAPTERS if RADIO_ADAPTERS && VIDEO_V4L2 +config RADIO_SI470X + bool "Silicon Labs Si470x FM Radio Receiver support" + depends on VIDEO_V4L2 + +source "drivers/media/radio/si470x/Kconfig" + +config USB_MR800 + tristate "AverMedia MR 800 USB FM radio support" + depends on USB && VIDEO_V4L2 + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + To compile this driver as a module, choose M here: the + module will be called radio-mr800. + +config USB_DSBR + tristate "D-Link/GemTek USB FM radio support" + depends on USB && VIDEO_V4L2 + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + To compile this driver as a module, choose M here: the + module will be called dsbr100. + +config RADIO_MAXIRADIO + tristate "Guillemot MAXI Radio FM 2000 radio" + depends on VIDEO_V4L2 && PCI + ---help--- + Choose Y here if you have this radio card. This card may also be + found as Gemtek PCI FM. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-maxiradio. + + +config I2C_SI4713 + tristate "I2C driver for Silicon Labs Si4713 device" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want support to Si4713 I2C device. + This device driver supports only i2c bus. + + To compile this driver as a module, choose M here: the + module will be called si4713. + +config RADIO_SI4713 + tristate "Silicon Labs Si4713 FM Radio Transmitter support" + depends on I2C && VIDEO_V4L2 + select I2C_SI4713 + ---help--- + Say Y here if you want support to Si4713 FM Radio Transmitter. + This device can transmit audio through FM. It can transmit + RDS and RBDS signals as well. This module is the v4l2 radio + interface for the i2c driver of this device. + + To compile this driver as a module, choose M here: the + module will be called radio-si4713. + +config RADIO_TEA5764 + tristate "TEA5764 I2C FM radio support" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the TEA5764 FM chip found in + EZX phones. This FM chip is present in EZX phones from Motorola, + connected to internal pxa I2C bus. + + To compile this driver as a module, choose M here: the + module will be called radio-tea5764. + +config RADIO_TEA5764_XTAL + bool "TEA5764 crystal reference" + depends on RADIO_TEA5764=y + default y + help + Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N + here if TEA5764 reference frequency is connected in FREQIN. + +config RADIO_SAA7706H + tristate "SAA7706H Car Radio DSP" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the SAA7706H Car radio Digital + Signal Processor, found for instance on the Russellville development + board. On the russellville the device is connected to internal + timberdale I2C bus. + + To compile this driver as a module, choose M here: the + module will be called SAA7706H. + +config RADIO_TEF6862 + tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the TEF6862 Car Radio Enhanced + Selectivity Tuner, found for instance on the Russellville development + board. On the russellville the device is connected to internal + timberdale I2C bus. + + To compile this driver as a module, choose M here: the + module will be called TEF6862. + +config RADIO_TIMBERDALE + tristate "Enable the Timberdale radio driver" + depends on MFD_TIMBERDALE && VIDEO_V4L2 + depends on I2C # for RADIO_SAA7706H + select RADIO_TEF6862 + select RADIO_SAA7706H + ---help--- + This is a kind of umbrella driver for the Radio Tuner and DSP + found behind the Timberdale FPGA on the Russellville board. + Enabling this driver will automatically select the DSP and tuner. + +config RADIO_WL1273 + tristate "Texas Instruments WL1273 I2C FM Radio" + depends on I2C && VIDEO_V4L2 + select MFD_CORE + select MFD_WL1273_CORE + select FW_LOADER + ---help--- + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-wl1273. + +# TI's ST based wl128x FM radio +source "drivers/media/radio/wl128x/Kconfig" + +# +# ISA drivers configuration +# + +menuconfig V4L_RADIO_ISA_DRIVERS + bool "ISA radio devices" + depends on ISA + default n + ---help--- + Say Y here to enable support for these ISA drivers. + +if V4L_RADIO_ISA_DRIVERS + config RADIO_CADET tristate "ADS Cadet AM/FM Tuner" depends on ISA && VIDEO_V4L2 @@ -151,21 +307,6 @@ config RADIO_GEMTEK_PROBE following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and 0x28c. -config RADIO_MAXIRADIO - tristate "Guillemot MAXI Radio FM 2000 radio" - depends on VIDEO_V4L2 && PCI - ---help--- - Choose Y here if you have this radio card. This card may also be - found as Gemtek PCI FM. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - <file:Documentation/video4linux/API.html>. - - To compile this driver as a module, choose M here: the - module will be called radio-maxiradio. - config RADIO_MIROPCM20 tristate "miroSOUND PCM20 radio" depends on ISA && ISA_DMA_API && VIDEO_V4L2 && SND @@ -316,130 +457,6 @@ config RADIO_ZOLTRIX_PORT help Enter the I/O port of your Zoltrix radio card. -config I2C_SI4713 - tristate "I2C driver for Silicon Labs Si4713 device" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want support to Si4713 I2C device. - This device driver supports only i2c bus. - - To compile this driver as a module, choose M here: the - module will be called si4713. - -config RADIO_SI4713 - tristate "Silicon Labs Si4713 FM Radio Transmitter support" - depends on I2C && VIDEO_V4L2 - select I2C_SI4713 - ---help--- - Say Y here if you want support to Si4713 FM Radio Transmitter. - This device can transmit audio through FM. It can transmit - RDS and RBDS signals as well. This module is the v4l2 radio - interface for the i2c driver of this device. - - To compile this driver as a module, choose M here: the - module will be called radio-si4713. - -config USB_DSBR - tristate "D-Link/GemTek USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called dsbr100. - -config RADIO_SI470X - bool "Silicon Labs Si470x FM Radio Receiver support" - depends on VIDEO_V4L2 - -source "drivers/media/radio/si470x/Kconfig" - -config USB_MR800 - tristate "AverMedia MR 800 USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called radio-mr800. - -config RADIO_TEA5764 - tristate "TEA5764 I2C FM radio support" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the TEA5764 FM chip found in - EZX phones. This FM chip is present in EZX phones from Motorola, - connected to internal pxa I2C bus. - - To compile this driver as a module, choose M here: the - module will be called radio-tea5764. - -config RADIO_TEA5764_XTAL - bool "TEA5764 crystal reference" - depends on RADIO_TEA5764=y - default y - help - Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N - here if TEA5764 reference frequency is connected in FREQIN. - -config RADIO_SAA7706H - tristate "SAA7706H Car Radio DSP" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the SAA7706H Car radio Digital - Signal Processor, found for instance on the Russellville development - board. On the russellville the device is connected to internal - timberdale I2C bus. - - To compile this driver as a module, choose M here: the - module will be called SAA7706H. - -config RADIO_TEF6862 - tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the TEF6862 Car Radio Enhanced - Selectivity Tuner, found for instance on the Russellville development - board. On the russellville the device is connected to internal - timberdale I2C bus. - - To compile this driver as a module, choose M here: the - module will be called TEF6862. - -config RADIO_TIMBERDALE - tristate "Enable the Timberdale radio driver" - depends on MFD_TIMBERDALE && VIDEO_V4L2 - depends on I2C # for RADIO_SAA7706H - select RADIO_TEF6862 - select RADIO_SAA7706H - ---help--- - This is a kind of umbrella driver for the Radio Tuner and DSP - found behind the Timberdale FPGA on the Russellville board. - Enabling this driver will automatically select the DSP and tuner. - -config RADIO_WL1273 - tristate "Texas Instruments WL1273 I2C FM Radio" - depends on I2C && VIDEO_V4L2 - select MFD_WL1273_CORE - select FW_LOADER - ---help--- - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - <file:Documentation/video4linux/API.html>. - - To compile this driver as a module, choose M here: the - module will be called radio-wl1273. - -# TI's ST based wl128x FM radio -source "drivers/media/radio/wl128x/Kconfig" +endif # V4L_RADIO_ISA_DRIVERS endif # RADIO_ADAPTERS diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index edadc8449a3d..36ce0611c037 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -47,11 +47,11 @@ MODULE_VERSION("0.0.4"); #endif static int io = CONFIG_RADIO_GEMTEK_PORT; -static int probe = CONFIG_RADIO_GEMTEK_PROBE; -static int hardmute; -static int shutdown = 1; -static int keepmuted = 1; -static int initmute = 1; +static bool probe = CONFIG_RADIO_GEMTEK_PROBE; +static bool hardmute; +static bool shutdown = 1; +static bool keepmuted = 1; +static bool initmute = 1; static int radio_nr = -1; module_param(io, int, 0444); diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 3fb76e3834c9..87c1ee13b058 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -23,7 +23,7 @@ static int radio_nr = -1; module_param(radio_nr, int, 0); MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); -static int mono; +static bool mono; module_param(mono, bool, 0); MODULE_PARM_DESC(mono, "Force tuner into mono mode."); diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index d1fab5885061..c54210c7fef9 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -355,17 +355,4 @@ static struct platform_driver radio_si4713_pdriver = { .remove = __exit_p(radio_si4713_pdriver_remove), }; -/* Module Interface */ -static int __init radio_si4713_module_init(void) -{ - return platform_driver_register(&radio_si4713_pdriver); -} - -static void __exit radio_si4713_module_exit(void) -{ - platform_driver_unregister(&radio_si4713_pdriver); -} - -module_init(radio_si4713_module_init); -module_exit(radio_si4713_module_exit); - +module_platform_driver(radio_si4713_pdriver); diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 3e9209f84e09..5d9a90ac3a1c 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -226,20 +226,7 @@ static struct platform_driver timbradio_platform_driver = { .remove = timbradio_remove, }; -/*--------------------------------------------------------------------------*/ - -static int __init timbradio_init(void) -{ - return platform_driver_register(&timbradio_platform_driver); -} - -static void __exit timbradio_exit(void) -{ - platform_driver_unregister(&timbradio_platform_driver); -} - -module_init(timbradio_init); -module_exit(timbradio_exit); +module_platform_driver(timbradio_platform_driver); MODULE_DESCRIPTION("Timberdale Radio driver"); MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 8aa4968d57bc..f1b607099b6c 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -2148,8 +2148,6 @@ pdata_err: return r; } -MODULE_ALIAS("platform:wl1273_fm_radio"); - static struct platform_driver wl1273_fm_radio_driver = { .probe = wl1273_fm_radio_probe, .remove = __devexit_p(wl1273_fm_radio_remove), @@ -2159,20 +2157,9 @@ static struct platform_driver wl1273_fm_radio_driver = { }, }; -static int __init wl1273_fm_module_init(void) -{ - pr_info("%s\n", __func__); - return platform_driver_register(&wl1273_fm_radio_driver); -} -module_init(wl1273_fm_module_init); - -static void __exit wl1273_fm_module_exit(void) -{ - platform_driver_unregister(&wl1273_fm_radio_driver); - pr_info(DRIVER_DESC ", Exiting.\n"); -} -module_exit(wl1273_fm_module_exit); +module_platform_driver(wl1273_fm_radio_driver); MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wl1273_fm_radio"); diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 0991e1973678..3408685b690c 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -118,9 +118,11 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) i2cmsg[2] = pll & 0xff; err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg)); - if (!err) - state->freq = f->frequency; - return err; + if (err != sizeof(i2cmsg)) + return err < 0 ? err : -EIO; + + state->freq = f->frequency; + return 0; } static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig index 749f67b192e7..86b28579f0c7 100644 --- a/drivers/media/radio/wl128x/Kconfig +++ b/drivers/media/radio/wl128x/Kconfig @@ -5,7 +5,7 @@ menu "Texas Instruments WL128x FM driver (ST based)" config RADIO_WL128X tristate "Texas Instruments WL128x FM Radio" depends on VIDEO_V4L2 && RFKILL - select TI_ST + select TI_ST if NET && GPIOLIB help Choose Y here if you have this FM radio chip. diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 5991ab60303d..bf867a6b5ea0 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -387,7 +387,7 @@ static void send_tasklet(unsigned long arg) * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for * transmission */ -static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, +static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, int payload_len, struct completion *wait_completion) { struct sk_buff *skb; @@ -456,13 +456,13 @@ static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, } /* Sends FM Channel-8 command to the chip and waits for the response */ -u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, +int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, unsigned int payload_len, void *response, int *response_len) { struct sk_buff *skb; struct fm_event_msg_hdr *evt_hdr; unsigned long flags; - u32 ret; + int ret; init_completion(&fmdev->maintask_comp); ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len, @@ -470,8 +470,8 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, if (ret) return ret; - ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT); - if (!ret) { + if (!wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_TX_TIMEOUT)) { fmerr("Timeout(%d sec),didn't get reg" "completion signal from RX tasklet\n", jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); @@ -508,7 +508,7 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, } /* --- Helper functions used in FM interrupt handlers ---*/ -static inline u32 check_cmdresp_status(struct fmdev *fmdev, +static inline int check_cmdresp_status(struct fmdev *fmdev, struct sk_buff **skb) { struct fm_event_msg_hdr *fm_evt_hdr; @@ -1058,7 +1058,7 @@ static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) } /* Returns availability of RDS data in internel buffer */ -u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, +int fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, struct poll_table_struct *pts) { poll_wait(file, &fmdev->rx.rds.read_queue, pts); @@ -1069,7 +1069,7 @@ u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, } /* Copies RDS data from internal buffer to user buffer */ -u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, +int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, u8 __user *buf, size_t count) { u32 block_count; @@ -1113,7 +1113,7 @@ u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, return ret; } -u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) +int fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1127,7 +1127,7 @@ u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) } } -u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) +int fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) { if (fmdev->rx.freq == FM_UNDEFINED_FREQ) { fmerr("RX frequency is not set\n"); @@ -1153,7 +1153,7 @@ u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) } -u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) +int fmc_set_region(struct fmdev *fmdev, u8 region_to_set) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1167,7 +1167,7 @@ u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) } } -u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1181,7 +1181,7 @@ u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } } -u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1195,7 +1195,7 @@ u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) } } -u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1210,10 +1210,10 @@ u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) } /* Sends power off command to the chip */ -static u32 fm_power_down(struct fmdev *fmdev) +static int fm_power_down(struct fmdev *fmdev) { u16 payload; - u32 ret; + int ret; if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmerr("FM core is not ready\n"); @@ -1234,7 +1234,7 @@ static u32 fm_power_down(struct fmdev *fmdev) } /* Reads init command from FM firmware file and loads to the chip */ -static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) +static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) { const struct firmware *fw_entry; struct bts_header *fw_header; @@ -1299,7 +1299,7 @@ rel_fw: } /* Loads default RX configuration to the chip */ -static u32 load_default_rx_configuration(struct fmdev *fmdev) +static int load_default_rx_configuration(struct fmdev *fmdev) { int ret; @@ -1311,7 +1311,7 @@ static u32 load_default_rx_configuration(struct fmdev *fmdev) } /* Does FM power on sequence */ -static u32 fm_power_up(struct fmdev *fmdev, u8 mode) +static int fm_power_up(struct fmdev *fmdev, u8 mode) { u16 payload, asic_id, asic_ver; int resp_len, ret; @@ -1374,7 +1374,7 @@ rel: } /* Set FM Modes(TX, RX, OFF) */ -u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) +int fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) { int ret = 0; @@ -1427,7 +1427,7 @@ u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) } /* Returns current FM mode (TX, RX, OFF) */ -u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) +int fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) { if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmerr("FM core is not ready\n"); @@ -1483,10 +1483,10 @@ static void fm_st_reg_comp_cb(void *arg, char data) * This function will be called from FM V4L2 open function. * Register with ST driver and initialize driver data. */ -u32 fmc_prepare(struct fmdev *fmdev) +int fmc_prepare(struct fmdev *fmdev) { static struct st_proto_s fm_st_proto; - u32 ret; + int ret; if (test_bit(FM_CORE_READY, &fmdev->flag)) { fmdbg("FM Core is already up\n"); @@ -1512,10 +1512,8 @@ u32 fmc_prepare(struct fmdev *fmdev) fmdev->streg_cbdata = -EINPROGRESS; fmdbg("%s waiting for ST reg completion signal\n", __func__); - ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, - FM_ST_REG_TIMEOUT); - - if (!ret) { + if (!wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, + FM_ST_REG_TIMEOUT)) { fmerr("Timeout(%d sec), didn't get reg " "completion signal from ST\n", jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); @@ -1589,10 +1587,10 @@ u32 fmc_prepare(struct fmdev *fmdev) * This function will be called from FM V4L2 release function. * Unregister from ST driver. */ -u32 fmc_release(struct fmdev *fmdev) +int fmc_release(struct fmdev *fmdev) { static struct st_proto_s fm_st_proto; - u32 ret; + int ret; if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmdbg("FM Core is already down\n"); @@ -1631,7 +1629,7 @@ u32 fmc_release(struct fmdev *fmdev) static int __init fm_drv_init(void) { struct fmdev *fmdev = NULL; - u32 ret = -ENOMEM; + int ret = -ENOMEM; fmdbg("FM driver version %s\n", FM_DRV_VERSION); diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h index aee243bb6630..d9b9c6cf83b4 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.h +++ b/drivers/media/radio/wl128x/fmdrv_common.h @@ -368,27 +368,27 @@ struct fm_event_msg_hdr { #define FM_TX_ANT_IMP_500 2 /* Functions exported by FM common sub-module */ -u32 fmc_prepare(struct fmdev *); -u32 fmc_release(struct fmdev *); +int fmc_prepare(struct fmdev *); +int fmc_release(struct fmdev *); void fmc_update_region_info(struct fmdev *, u8); -u32 fmc_send_cmd(struct fmdev *, u8, u16, +int fmc_send_cmd(struct fmdev *, u8, u16, void *, unsigned int, void *, int *); -u32 fmc_is_rds_data_available(struct fmdev *, struct file *, +int fmc_is_rds_data_available(struct fmdev *, struct file *, struct poll_table_struct *); -u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, +int fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, u8 __user *, size_t); -u32 fmc_set_freq(struct fmdev *, u32); -u32 fmc_set_mode(struct fmdev *, u8); -u32 fmc_set_region(struct fmdev *, u8); -u32 fmc_set_mute_mode(struct fmdev *, u8); -u32 fmc_set_stereo_mono(struct fmdev *, u16); -u32 fmc_set_rds_mode(struct fmdev *, u8); +int fmc_set_freq(struct fmdev *, u32); +int fmc_set_mode(struct fmdev *, u8); +int fmc_set_region(struct fmdev *, u8); +int fmc_set_mute_mode(struct fmdev *, u8); +int fmc_set_stereo_mono(struct fmdev *, u16); +int fmc_set_rds_mode(struct fmdev *, u8); -u32 fmc_get_freq(struct fmdev *, u32 *); -u32 fmc_get_region(struct fmdev *, u8 *); -u32 fmc_get_mode(struct fmdev *, u8 *); +int fmc_get_freq(struct fmdev *, u32 *); +int fmc_get_region(struct fmdev *, u8 *); +int fmc_get_mode(struct fmdev *, u8 *); /* * channel spacing diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c index ec529b55b040..43fb72291bea 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.c +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -43,12 +43,13 @@ void fm_rx_reset_station_info(struct fmdev *fmdev) fmdev->rx.stat_info.af_list_max = 0; } -u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq) +int fm_rx_set_freq(struct fmdev *fmdev, u32 freq) { unsigned long timeleft; u16 payload, curr_frq, intr_flag; u32 curr_frq_in_khz; - u32 ret, resp_len; + u32 resp_len; + int ret; if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) { fmerr("Invalid frequency %d\n", freq); @@ -141,10 +142,10 @@ exit: return ret; } -static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) +static int fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) { u16 payload; - u32 ret; + int ret; if (spacing > 0 && spacing <= 50000) spacing = FM_CHANNEL_SPACING_50KHZ; @@ -165,7 +166,7 @@ static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) return ret; } -u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, +int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, u32 wrap_around, u32 spacing) { u32 resp_len; @@ -173,7 +174,7 @@ u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, u16 payload, int_reason, intr_flag; u16 offset, space_idx; unsigned long timeleft; - u32 ret; + int ret; /* Set channel spacing */ ret = fm_rx_set_channel_spacing(fmdev, spacing); @@ -296,10 +297,10 @@ again: return ret; } -u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) +int fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -322,7 +323,7 @@ u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) } /* Get volume */ -u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) +int fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -338,7 +339,7 @@ u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) } /* To get current band's bottom and top frequency */ -u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) +int fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) { if (bot_freq != NULL) *bot_freq = fmdev->rx.region.bot_freq; @@ -356,11 +357,11 @@ void fm_rx_get_region(struct fmdev *fmdev, u8 *region) } /* Sets band (0-Europe/US; 1-Japan) */ -u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) +int fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) { u16 payload; u32 new_frq = 0; - u32 ret; + int ret; if (region_to_set != FM_BAND_EUROPE_US && region_to_set != FM_BAND_JAPAN) { @@ -399,7 +400,7 @@ u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) } /* Reads current mute mode (Mute Off/On/Attenuate)*/ -u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) +int fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -414,10 +415,10 @@ u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) return 0; } -static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) +static int fm_config_rx_mute_reg(struct fmdev *fmdev) { u16 payload, muteval; - u32 ret; + int ret; muteval = 0; switch (fmdev->rx.mute_mode) { @@ -448,10 +449,10 @@ static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) } /* Configures mute mode (Mute Off/On/Attenuate) */ -u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { u8 org_state; - u32 ret; + int ret; if (fmdev->rx.mute_mode == mute_mode_toset) return 0; @@ -469,7 +470,7 @@ u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } /* Gets RF dependent soft mute mode enable/disable status */ -u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) +int fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -485,10 +486,10 @@ u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) } /* Sets RF dependent soft mute mode */ -u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) +int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) { u8 org_state; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -514,11 +515,11 @@ u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) } /* Returns the signal strength level of current channel */ -u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) +int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) { u16 curr_rssi_lel; u32 resp_len; - u32 ret; + int ret; if (rssilvl == NULL) { fmerr("Invalid memory\n"); @@ -539,10 +540,10 @@ u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) * Sets the signal strength level that once reached * will stop the auto search process */ -u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) +int fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) { u16 payload; - u32 ret; + int ret; if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN || rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) { @@ -561,7 +562,7 @@ u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) } /* Returns current RX RSSI threshold value */ -u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) +int fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -577,10 +578,10 @@ u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) } /* Sets RX stereo/mono modes */ -u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) { fmerr("Invalid mode\n"); @@ -605,10 +606,11 @@ u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) } /* Gets current RX stereo/mono mode */ -u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) +int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) { u16 curr_mode; - u32 ret, resp_len; + u32 resp_len; + int ret; if (mode == NULL) { fmerr("Invalid memory\n"); @@ -626,10 +628,10 @@ u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) } /* Choose RX de-emphasis filter mode (50us/75us) */ -u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) +int fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -652,7 +654,7 @@ u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) } /* Gets current RX de-emphasis filter mode */ -u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) +int fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -668,10 +670,10 @@ u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) } /* Enable/Disable RX RDS */ -u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { u16 payload; - u32 ret; + int ret; if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) { fmerr("Invalid rds option\n"); @@ -743,7 +745,7 @@ u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) } /* Returns current RX RDS enable/disable status */ -u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) +int fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -759,10 +761,10 @@ u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) } /* Sets RDS operation mode (RDS/RDBS) */ -u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) +int fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -784,7 +786,7 @@ u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) } /* Returns current RDS operation mode */ -u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) +int fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -800,10 +802,10 @@ u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) } /* Configures Alternate Frequency switch mode */ -u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) +int fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -831,7 +833,7 @@ u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) } /* Returns Alternate Frequency switch status */ -u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) +int fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h index 329e62f6be76..32add81f8d87 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.h +++ b/drivers/media/radio/wl128x/fmdrv_rx.h @@ -22,38 +22,38 @@ #ifndef _FMDRV_RX_H #define _FMDRV_RX_H -u32 fm_rx_set_freq(struct fmdev *, u32); -u32 fm_rx_set_mute_mode(struct fmdev *, u8); -u32 fm_rx_set_stereo_mono(struct fmdev *, u16); -u32 fm_rx_set_rds_mode(struct fmdev *, u8); -u32 fm_rx_set_rds_system(struct fmdev *, u8); -u32 fm_rx_set_volume(struct fmdev *, u16); -u32 fm_rx_set_rssi_threshold(struct fmdev *, short); -u32 fm_rx_set_region(struct fmdev *, u8); -u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8); -u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16); -u32 fm_rx_set_af_switch(struct fmdev *, u8); +int fm_rx_set_freq(struct fmdev *, u32); +int fm_rx_set_mute_mode(struct fmdev *, u8); +int fm_rx_set_stereo_mono(struct fmdev *, u16); +int fm_rx_set_rds_mode(struct fmdev *, u8); +int fm_rx_set_rds_system(struct fmdev *, u8); +int fm_rx_set_volume(struct fmdev *, u16); +int fm_rx_set_rssi_threshold(struct fmdev *, short); +int fm_rx_set_region(struct fmdev *, u8); +int fm_rx_set_rfdepend_softmute(struct fmdev *, u8); +int fm_rx_set_deemphasis_mode(struct fmdev *, u16); +int fm_rx_set_af_switch(struct fmdev *, u8); void fm_rx_reset_rds_cache(struct fmdev *); void fm_rx_reset_station_info(struct fmdev *); -u32 fm_rx_seek(struct fmdev *, u32, u32, u32); +int fm_rx_seek(struct fmdev *, u32, u32, u32); -u32 fm_rx_get_rds_mode(struct fmdev *, u8 *); -u32 fm_rx_get_rds_system(struct fmdev *, u8 *); -u32 fm_rx_get_mute_mode(struct fmdev *, u8 *); -u32 fm_rx_get_volume(struct fmdev *, u16 *); -u32 fm_rx_get_band_freq_range(struct fmdev *, +int fm_rx_get_rds_mode(struct fmdev *, u8 *); +int fm_rx_get_rds_system(struct fmdev *, u8 *); +int fm_rx_get_mute_mode(struct fmdev *, u8 *); +int fm_rx_get_volume(struct fmdev *, u16 *); +int fm_rx_get_band_freq_range(struct fmdev *, u32 *, u32 *); -u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *); -u32 fm_rx_get_rssi_level(struct fmdev *, u16 *); -u32 fm_rx_get_rssi_threshold(struct fmdev *, short *); -u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); -u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *); -u32 fm_rx_get_af_switch(struct fmdev *, u8 *); +int fm_rx_get_stereo_mono(struct fmdev *, u16 *); +int fm_rx_get_rssi_level(struct fmdev *, u16 *); +int fm_rx_get_rssi_threshold(struct fmdev *, short *); +int fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); +int fm_rx_get_deemph_mode(struct fmdev *, u16 *); +int fm_rx_get_af_switch(struct fmdev *, u8 *); void fm_rx_get_region(struct fmdev *, u8 *); -u32 fm_rx_set_chanl_spacing(struct fmdev *, u8); -u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *); +int fm_rx_set_chanl_spacing(struct fmdev *, u8); +int fm_rx_get_chanl_spacing(struct fmdev *, u8 *); #endif diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c index be54068b56a8..6ea33e09d63b 100644 --- a/drivers/media/radio/wl128x/fmdrv_tx.c +++ b/drivers/media/radio/wl128x/fmdrv_tx.c @@ -24,10 +24,10 @@ #include "fmdrv_common.h" #include "fmdrv_tx.h" -u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (fmdev->tx_data.aud_mode == mode) return 0; @@ -46,10 +46,10 @@ u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) return ret; } -static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) +static int set_rds_text(struct fmdev *fmdev, u8 *rds_text) { u16 payload; - u32 ret; + int ret; ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text, strlen(rds_text), NULL, NULL); @@ -66,10 +66,10 @@ static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) return 0; } -static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) +static int set_rds_data_mode(struct fmdev *fmdev, u8 mode) { u16 payload; - u32 ret; + int ret; /* Setting unique PI TODO: how unique? */ payload = (u16)0xcafe; @@ -89,10 +89,10 @@ static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) return 0; } -static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) +static int set_rds_len(struct fmdev *fmdev, u8 type, u16 len) { u16 payload; - u32 ret; + int ret; len |= type << 8; payload = len; @@ -105,10 +105,10 @@ static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) return 0; } -u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { u16 payload; - u32 ret; + int ret; u8 rds_text[] = "Zoom2\n"; fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis, @@ -148,10 +148,10 @@ u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) return 0; } -u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) +int fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -176,10 +176,10 @@ u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) return 0; } -u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) +int fm_tx_set_af(struct fmdev *fmdev, u32 af) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -196,10 +196,10 @@ u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) return 0; } -u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) +int fm_tx_set_region(struct fmdev *fmdev, u8 region) { u16 payload; - u32 ret; + int ret; if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) { fmerr("Invalid band\n"); @@ -216,10 +216,10 @@ u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) return 0; } -u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { u16 payload; - u32 ret; + int ret; fmdbg("tx: mute mode %d\n", mute_mode_toset); @@ -233,11 +233,11 @@ u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } /* Set TX Audio I/O */ -static u32 set_audio_io(struct fmdev *fmdev) +static int set_audio_io(struct fmdev *fmdev) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload; - u32 ret; + int ret; /* Set Audio I/O Enable */ payload = tx->audio_io; @@ -251,12 +251,12 @@ static u32 set_audio_io(struct fmdev *fmdev) } /* Start TX Transmission */ -static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) +static int enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) { struct fmtx_data *tx = &fmdev->tx_data; unsigned long timeleft; u16 payload; - u32 ret; + int ret; /* Enable POWER_ENB interrupts */ payload = FM_POW_ENB_EVENT; @@ -289,11 +289,11 @@ static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) } /* Set TX power level */ -u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) +int fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) { u16 payload; struct fmtx_data *tx = &fmdev->tx_data; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -328,11 +328,11 @@ u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us) * Convert V4L2 specified filter values to chip specific filter values. */ -u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) +int fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -360,10 +360,11 @@ u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) } /* Get the TX tuning capacitor value.*/ -u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) +int fm_tx_get_tune_cap_val(struct fmdev *fmdev) { u16 curr_val; - u32 ret, resp_len; + u32 resp_len; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -379,11 +380,11 @@ u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) } /* Set TX Frequency */ -u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) +int fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload, chanl_index; - u32 ret; + int ret; if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) { enable_xmit(fmdev, 0); diff --git a/drivers/media/radio/wl128x/fmdrv_tx.h b/drivers/media/radio/wl128x/fmdrv_tx.h index e393a2bdd49e..11ae2e4c2d03 100644 --- a/drivers/media/radio/wl128x/fmdrv_tx.h +++ b/drivers/media/radio/wl128x/fmdrv_tx.h @@ -22,16 +22,16 @@ #ifndef _FMDRV_TX_H #define _FMDRV_TX_H -u32 fm_tx_set_freq(struct fmdev *, u32); -u32 fm_tx_set_pwr_lvl(struct fmdev *, u8); -u32 fm_tx_set_region(struct fmdev *, u8); -u32 fm_tx_set_mute_mode(struct fmdev *, u8); -u32 fm_tx_set_stereo_mono(struct fmdev *, u16); -u32 fm_tx_set_rds_mode(struct fmdev *, u8); -u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8); -u32 fm_tx_set_af(struct fmdev *, u32); -u32 fm_tx_set_preemph_filter(struct fmdev *, u32); -u32 fm_tx_get_tune_cap_val(struct fmdev *); +int fm_tx_set_freq(struct fmdev *, u32); +int fm_tx_set_pwr_lvl(struct fmdev *, u8); +int fm_tx_set_region(struct fmdev *, u8); +int fm_tx_set_mute_mode(struct fmdev *, u8); +int fm_tx_set_stereo_mono(struct fmdev *, u16); +int fm_tx_set_rds_mode(struct fmdev *, u8); +int fm_tx_set_radio_text(struct fmdev *, u8 *, u8); +int fm_tx_set_af(struct fmdev *, u32); +int fm_tx_set_preemph_filter(struct fmdev *, u32); +int fm_tx_get_tune_cap_val(struct fmdev *); #endif diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 4f5c43d2566c..077d369a0173 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -84,6 +84,7 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, struct fmdev *fmdev; ret = copy_from_user(&rds, buf, sizeof(rds)); + rds.text[sizeof(rds.text) - 1] = '\0'; fmdbg("(%d)type: %d, text %s, af %d\n", ret, rds.text_type, rds.text, rds.af_freq); if (ret) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index aeb7f43dfb65..4df4affeea5f 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -87,6 +87,16 @@ config IR_RC5_SZ_DECODER uses an IR protocol that is almost standard RC-5, but not quite, as it uses an additional bit). +config IR_SANYO_DECODER + tristate "Enable IR raw decoder for the Sanyo protocol" + depends on RC_CORE + default y + + ---help--- + Enable this option if you have an infrared remote control which + uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes), + and you need software decoding support. + config IR_MCE_KBD_DECODER tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" depends on RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 2156e786b557..fb3dee2dd845 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o +obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 17f8db00435a..3c9431a9f62d 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -194,8 +194,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 2e5cd3100b64..95e630998aaf 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -357,6 +357,7 @@ static void init_decoders(struct work_struct *work) load_rc6_decode(); load_jvc_decode(); load_sony_decode(); + load_sanyo_decode(); load_mce_kbd_decode(); load_lirc_codec(); diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 140fb67e2f89..4cfdd7fa4bbd 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -18,24 +18,31 @@ /* * This decoder currently supports: * RC6-0-16 (standard toggle bit in header) + * RC6-6A-20 (no toggle bit) * RC6-6A-24 (no toggle bit) * RC6-6A-32 (MCE version with toggle bit in body) */ -#define RC6_UNIT 444444 /* us */ +#define RC6_UNIT 444444 /* nanosecs */ #define RC6_HEADER_NBITS 4 /* not including toggle bit */ #define RC6_0_NBITS 16 -#define RC6_6A_SMALL_NBITS 24 -#define RC6_6A_LARGE_NBITS 32 +#define RC6_6A_32_NBITS 32 +#define RC6_6A_NBITS 128 /* Variable 8..128 */ #define RC6_PREFIX_PULSE (6 * RC6_UNIT) #define RC6_PREFIX_SPACE (2 * RC6_UNIT) #define RC6_BIT_START (1 * RC6_UNIT) #define RC6_BIT_END (1 * RC6_UNIT) #define RC6_TOGGLE_START (2 * RC6_UNIT) #define RC6_TOGGLE_END (2 * RC6_UNIT) +#define RC6_SUFFIX_SPACE (6 * RC6_UNIT) #define RC6_MODE_MASK 0x07 /* for the header bits */ #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ +#define RC6_6A_LCC_MASK 0xffff0000 /* RC6-6A-32 long customer code mask */ +#define RC6_6A_MCE_CC 0x800f0000 /* MCE customer code */ +#ifndef CHAR_BIT +#define CHAR_BIT 8 /* Normally in <limits.h> */ +#endif enum rc6_mode { RC6_MODE_0, @@ -125,6 +132,7 @@ again: break; data->state = STATE_HEADER_BIT_START; + data->header = 0; return 0; case STATE_HEADER_BIT_START: @@ -171,20 +179,14 @@ again: data->state = STATE_BODY_BIT_START; decrease_duration(&ev, RC6_TOGGLE_END); data->count = 0; + data->body = 0; switch (rc6_mode(data)) { case RC6_MODE_0: data->wanted_bits = RC6_0_NBITS; break; case RC6_MODE_6A: - /* This might look weird, but we basically - check the value of the first body bit to - determine the number of bits in mode 6A */ - if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) || - geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) - data->wanted_bits = RC6_6A_LARGE_NBITS; - else - data->wanted_bits = RC6_6A_SMALL_NBITS; + data->wanted_bits = RC6_6A_NBITS; break; default: IR_dprintk(1, "RC6 unknown mode\n"); @@ -193,15 +195,21 @@ again: goto again; case STATE_BODY_BIT_START: - if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) - break; - - data->body <<= 1; - if (ev.pulse) - data->body |= 1; - data->count++; - data->state = STATE_BODY_BIT_END; - return 0; + if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) { + /* Discard LSB's that won't fit in data->body */ + if (data->count++ < CHAR_BIT * sizeof data->body) { + data->body <<= 1; + if (ev.pulse) + data->body |= 1; + } + data->state = STATE_BODY_BIT_END; + return 0; + } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse && + geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) { + data->state = STATE_FINISHED; + goto again; + } + break; case STATE_BODY_BIT_END: if (!is_transition(&ev, &dev->raw->prev_ev)) @@ -221,20 +229,27 @@ again: switch (rc6_mode(data)) { case RC6_MODE_0: - scancode = data->body & 0xffff; + scancode = data->body; toggle = data->toggle; IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", scancode, toggle); break; case RC6_MODE_6A: - if (data->wanted_bits == RC6_6A_LARGE_NBITS) { - toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0; - scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK; + if (data->count > CHAR_BIT * sizeof data->body) { + IR_dprintk(1, "RC6 too many (%u) data bits\n", + data->count); + goto out; + } + + scancode = data->body; + if (data->count == RC6_6A_32_NBITS && + (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) { + /* MCE RC */ + toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0; + scancode &= ~RC6_6A_MCE_TOGGLE_MASK; } else { toggle = 0; - scancode = data->body & 0xffffff; } - IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n", scancode, toggle); break; diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c new file mode 100644 index 000000000000..d38fbdd0b25a --- /dev/null +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -0,0 +1,205 @@ +/* ir-sanyo-decoder.c - handle SANYO IR Pulse/Space protocol + * + * Copyright (C) 2011 by Mauro Carvalho Chehab <mchehab@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 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. + * + * This protocol uses the NEC protocol timings. However, data is formatted as: + * 13 bits Custom Code + * 13 bits NOT(Custom Code) + * 8 bits Key data + * 8 bits NOT(Key data) + * + * According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon + * Information for this protocol is available at the Sanyo LC7461 datasheet. + */ + +#include <linux/module.h> +#include <linux/bitrev.h> +#include "rc-core-priv.h" + +#define SANYO_NBITS (13+13+8+8) +#define SANYO_UNIT 562500 /* ns */ +#define SANYO_HEADER_PULSE (16 * SANYO_UNIT) +#define SANYO_HEADER_SPACE (8 * SANYO_UNIT) +#define SANYO_BIT_PULSE (1 * SANYO_UNIT) +#define SANYO_BIT_0_SPACE (1 * SANYO_UNIT) +#define SANYO_BIT_1_SPACE (3 * SANYO_UNIT) +#define SANYO_REPEAT_SPACE (150 * SANYO_UNIT) +#define SANYO_TRAILER_PULSE (1 * SANYO_UNIT) +#define SANYO_TRAILER_SPACE (10 * SANYO_UNIT) /* in fact, 42 */ + +enum sanyo_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, + STATE_BIT_PULSE, + STATE_BIT_SPACE, + STATE_TRAILER_PULSE, + STATE_TRAILER_SPACE, +}; + +/** + * ir_sanyo_decode() - Decode one SANYO pulse or space + * @dev: the struct rc_dev descriptor of the device + * @duration: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct sanyo_dec *data = &dev->raw->sanyo; + u32 scancode; + u8 address, not_address, command, not_command; + + if (!(dev->raw->enabled_protocols & RC_TYPE_SANYO)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) { + IR_dprintk(1, "SANYO event reset received. reset to state 0\n"); + data->state = STATE_INACTIVE; + } + return 0; + } + + IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) { + data->count = 0; + data->state = STATE_HEADER_SPACE; + return 0; + } + break; + + + case STATE_HEADER_SPACE: + if (ev.pulse) + break; + + if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) { + data->state = STATE_BIT_PULSE; + return 0; + } + + break; + + case STATE_BIT_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2)) + break; + + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_SPACE: + if (ev.pulse) + break; + + if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) { + if (!dev->keypressed) { + IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n"); + } else { + rc_repeat(dev); + IR_dprintk(1, "SANYO repeat last key\n"); + data->state = STATE_INACTIVE; + } + return 0; + } + + data->bits <<= 1; + if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2)) + data->bits |= 1; + else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2)) + break; + data->count++; + + if (data->count == SANYO_NBITS) + data->state = STATE_TRAILER_PULSE; + else + data->state = STATE_BIT_PULSE; + + return 0; + + case STATE_TRAILER_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2)) + break; + + data->state = STATE_TRAILER_SPACE; + return 0; + + case STATE_TRAILER_SPACE: + if (ev.pulse) + break; + + if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2)) + break; + + address = bitrev16((data->bits >> 29) & 0x1fff) >> 3; + not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3; + command = bitrev8((data->bits >> 8) & 0xff); + not_command = bitrev8((data->bits >> 0) & 0xff); + + if ((command ^ not_command) != 0xff) { + IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n", + data->bits); + data->state = STATE_INACTIVE; + return 0; + } + + scancode = address << 8 | command; + IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode); + rc_keydown(dev, scancode, 0); + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler sanyo_handler = { + .protocols = RC_TYPE_SANYO, + .decode = ir_sanyo_decode, +}; + +static int __init ir_sanyo_decode_init(void) +{ + ir_raw_handler_register(&sanyo_handler); + + printk(KERN_INFO "IR SANYO protocol handler initialized\n"); + return 0; +} + +static void __exit ir_sanyo_decode_exit(void) +{ + ir_raw_handler_unregister(&sanyo_handler); +} + +module_init(ir_sanyo_decode_init); +module_exit(ir_sanyo_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("SANYO IR protocol decoder"); diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index e51c6163378b..929bbbc16393 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -183,6 +183,57 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1d3f, KEY_HOME }, /* + * Keycodes for PT# R-005 remote bundled with Haupauge HVR-930C + * Keycodes start with address = 0x1c + */ + { 0x1c3b, KEY_GOTO }, + { 0x1c3d, KEY_POWER }, + + { 0x1c14, KEY_UP }, + { 0x1c15, KEY_DOWN }, + { 0x1c16, KEY_LEFT }, + { 0x1c17, KEY_RIGHT }, + { 0x1c25, KEY_OK }, + + { 0x1c00, KEY_0 }, + { 0x1c01, KEY_1 }, + { 0x1c02, KEY_2 }, + { 0x1c03, KEY_3 }, + { 0x1c04, KEY_4 }, + { 0x1c05, KEY_5 }, + { 0x1c06, KEY_6 }, + { 0x1c07, KEY_7 }, + { 0x1c08, KEY_8 }, + { 0x1c09, KEY_9 }, + + { 0x1c1f, KEY_EXIT }, /* BACK */ + { 0x1c0d, KEY_MENU }, + { 0x1c1c, KEY_TV }, + + { 0x1c10, KEY_VOLUMEUP }, + { 0x1c11, KEY_VOLUMEDOWN }, + + { 0x1c20, KEY_CHANNELUP }, + { 0x1c21, KEY_CHANNELDOWN }, + + { 0x1c0f, KEY_MUTE }, + { 0x1c12, KEY_PREVIOUS }, /* Prev */ + + { 0x1c36, KEY_STOP }, + { 0x1c37, KEY_RECORD }, + + { 0x1c24, KEY_LAST }, /* <| */ + { 0x1c1e, KEY_NEXT }, /* >| */ + + { 0x1c0a, KEY_TEXT }, + { 0x1c0e, KEY_SUBTITLE }, /* CC */ + + { 0x1c32, KEY_REWIND }, + { 0x1c30, KEY_PAUSE }, + { 0x1c35, KEY_PLAY }, + { 0x1c34, KEY_FASTFORWARD }, + + /* * Keycodes for the old Black Remote Controller * This one also uses RC-5 protocol * Keycodes start with address = 0x00 diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c index 3bd1de1f585c..23ee05e53949 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c @@ -1,4 +1,4 @@ -/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller +/* videomate-k100.h - Keytable for videomate_k100 Remote Controller * * keymap imported from ir-keymaps.c * @@ -13,7 +13,7 @@ #include <media/rc-map.h> #include <linux/module.h> -static struct rc_map_table videomate_m1f[] = { +static struct rc_map_table videomate_k100[] = { { 0x01, KEY_POWER }, { 0x31, KEY_TUNER }, { 0x33, KEY_VIDEO }, @@ -67,27 +67,27 @@ static struct rc_map_table videomate_m1f[] = { { 0x18, KEY_TEXT }, }; -static struct rc_map_list videomate_m1f_map = { +static struct rc_map_list videomate_k100_map = { .map = { - .scan = videomate_m1f, - .size = ARRAY_SIZE(videomate_m1f), + .scan = videomate_k100, + .size = ARRAY_SIZE(videomate_k100), .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_VIDEOMATE_M1F, + .name = RC_MAP_VIDEOMATE_K100, } }; -static int __init init_rc_map_videomate_m1f(void) +static int __init init_rc_map_videomate_k100(void) { - return rc_map_register(&videomate_m1f_map); + return rc_map_register(&videomate_k100_map); } -static void __exit exit_rc_map_videomate_m1f(void) +static void __exit exit_rc_map_videomate_k100(void) { - rc_map_unregister(&videomate_m1f_map); + rc_map_unregister(&videomate_k100_map); } -module_init(init_rc_map_videomate_m1f) -module_exit(exit_rc_map_videomate_m1f) +module_init(init_rc_map_videomate_k100) +module_exit(exit_rc_map_videomate_k100) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>"); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 27997a9ceb0d..ca12d3289bfe 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -38,7 +38,7 @@ #include <media/lirc.h> #include <media/lirc_dev.h> -static int debug; +static bool debug; #define IRCTL_DEV_NAME "BaseRemoteCtl" #define NOPLUG -1 diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 20bb12d6fbbe..21105bf9594d 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -156,9 +156,9 @@ /* module parameters */ #ifdef CONFIG_USB_DEBUG -static int debug = 1; +static bool debug = 1; #else -static int debug; +static bool debug; #endif #define mce_dbg(dev, fmt, ...) \ diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index c6ca870e8b7e..b72f8580e317 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -84,6 +84,11 @@ struct ir_raw_event_ctrl { unsigned count; unsigned wanted_bits; } rc5_sz; + struct sanyo_dec { + int state; + unsigned count; + u64 bits; + } sanyo; struct mce_kbd_dec { struct input_dev *idev; struct timer_list rx_timeout; @@ -193,6 +198,13 @@ static inline void load_jvc_decode(void) { } static inline void load_sony_decode(void) { } #endif +/* from ir-sanyo-decoder.c */ +#ifdef CONFIG_IR_SANYO_DECODER_MODULE +#define load_sanyo_decode() request_module("ir-sanyo-decoder") +#else +static inline void load_sanyo_decode(void) { } +#endif + /* from ir-mce_kbd-decoder.c */ #ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE #define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder") diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f5db8b949bc3..f6a930b70c69 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -736,6 +736,7 @@ static struct { { RC_TYPE_JVC, "jvc" }, { RC_TYPE_SONY, "sony" }, { RC_TYPE_RC5_SZ, "rc-5-sz" }, + { RC_TYPE_SANYO, "sanyo" }, { RC_TYPE_MCE_KBD, "mce_kbd" }, { RC_TYPE_LIRC, "lirc" }, { RC_TYPE_OTHER, "other" }, diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 07322fb75eff..ad95c67a4dba 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -286,12 +286,6 @@ static void redrat3_issue_async(struct redrat3_dev *rr3) rr3_ftr(rr3->dev, "Entering %s\n", __func__); - if (!rr3->det_enabled) { - dev_warn(rr3->dev, "not issuing async read, " - "detector not enabled\n"); - return; - } - memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize); res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC); if (res) @@ -827,6 +821,7 @@ out: static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) { struct redrat3_dev *rr3; + int ret; if (!urb) return; @@ -840,15 +835,13 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) rr3_ftr(rr3->dev, "Entering %s\n", __func__); - if (!rr3->det_enabled) { - rr3_dbg(rr3->dev, "received a read callback but detector " - "disabled - ignoring\n"); - return; - } - switch (urb->status) { case 0: - redrat3_get_ir_data(rr3, urb->actual_length); + ret = redrat3_get_ir_data(rr3, urb->actual_length); + if (!ret) { + /* no error, prepare to read more */ + redrat3_issue_async(rr3); + } break; case -ECONNRESET: @@ -865,11 +858,6 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) rr3->pkttype = 0; break; } - - if (!rr3->transmitting) - redrat3_issue_async(rr3); - else - rr3_dbg(rr3->dev, "IR transmit in progress\n"); } static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs) @@ -896,21 +884,24 @@ static u16 mod_freq_to_val(unsigned int mod_freq) return (u16)(65536 - (mult / mod_freq)); } -static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier) +static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) { - struct redrat3_dev *rr3 = dev->priv; + struct redrat3_dev *rr3 = rcdev->priv; + struct device *dev = rr3->dev; + rr3_dbg(dev, "Setting modulation frequency to %u", carrier); rr3->carrier = carrier; return carrier; } -static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n) +static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, + unsigned count) { struct redrat3_dev *rr3 = rcdev->priv; struct device *dev = rr3->dev; struct redrat3_signal_header header; - int i, j, count, ret, ret_len, offset; + int i, j, ret, ret_len, offset; int lencheck, cur_sample_len, pipe; char *buffer = NULL, *sigdata = NULL; int *sample_lens = NULL; @@ -928,20 +919,13 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n) return -EAGAIN; } - count = n / sizeof(int); if (count > (RR3_DRIVER_MAXLENS * 2)) return -EINVAL; + /* rr3 will disable rc detector on transmit */ + rr3->det_enabled = false; rr3->transmitting = true; - redrat3_disable_detector(rr3); - - if (rr3->det_enabled) { - dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__); - ret = -EIO; - goto out; - } - sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL); if (!sample_lens) { ret = -ENOMEM; @@ -1055,7 +1039,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n) if (ret < 0) dev_err(dev, "Error: control msg send failed, rc %d\n", ret); else - ret = n; + ret = count; out: kfree(sample_lens); @@ -1063,8 +1047,8 @@ out: kfree(sigdata); rr3->transmitting = false; - - redrat3_enable_detector(rr3); + /* rr3 re-enables rc detector because it was enabled before */ + rr3->det_enabled = true; return ret; } diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index b1d29d09eeae..d6f4bfe09391 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -43,9 +43,9 @@ #define DRIVER_DESC "Streamzap Remote Control driver" #ifdef CONFIG_USB_DEBUG -static int debug = 1; +static bool debug = 1; #else -static int debug; +static bool debug; #endif #define USB_STREAMZAP_VENDOR_ID 0x0e9c diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index e7f7a57bf684..b09c5fae489b 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -226,11 +226,11 @@ module_param(protocol, uint, 0444); MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command " "(0 = RC5, 1 = NEC, 2 = RC6A, default)"); -static int invert; /* default = 0 */ +static bool invert; /* default = 0 */ module_param(invert, bool, 0444); MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver"); -static int txandrx; /* default = 0 */ +static bool txandrx; /* default = 0 */ module_param(txandrx, bool, 0444); MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX"); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index b303a3f8a9f8..9adada0d7447 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -533,6 +533,13 @@ config VIDEO_ADP1653 This is a driver for the ADP1653 flash controller. It is used for example in Nokia N900. +config VIDEO_AS3645A + tristate "AS3645A flash driver support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + ---help--- + This is a driver for the AS3645A and LM3555 flash controllers. It has + build in control for flash, torch and indicator LEDs. + comment "Video improvement chips" config VIDEO_UPD64031A @@ -580,25 +587,6 @@ config VIDEO_M52790 endmenu # encoder / decoder chips -config VIDEO_SH_VOU - tristate "SuperH VOU video output driver" - depends on VIDEO_DEV && ARCH_SHMOBILE - select VIDEOBUF_DMA_CONTIG - help - Support for the Video Output Unit (VOU) on SuperH SoCs. - -config VIDEO_VIU - tristate "Freescale VIU Video Driver" - depends on VIDEO_V4L2 && PPC_MPC512x - select VIDEOBUF_DMA_CONTIG - default y - ---help--- - Support for Freescale VIU video driver. This device captures - video data, or overlays video on DIU frame buffer. - - Say Y here if you want to enable VIU device on MPC5121e Rev2+. - In doubt, say N. - config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 @@ -613,66 +601,130 @@ config VIDEO_VIVI Say Y here if you want to test video apps or debug V4L devices. In doubt, say N. -source "drivers/media/video/davinci/Kconfig" +# +# USB Multimedia device configuration +# -source "drivers/media/video/omap/Kconfig" +menuconfig V4L_USB_DRIVERS + bool "V4L USB devices" + depends on USB + default y -source "drivers/media/video/bt8xx/Kconfig" +if V4L_USB_DRIVERS -config VIDEO_PMS - tristate "Mediavision Pro Movie Studio Video For Linux" - depends on ISA && VIDEO_V4L2 - help - Say Y if you have such a thing. +source "drivers/media/video/uvc/Kconfig" + +source "drivers/media/video/gspca/Kconfig" + +source "drivers/media/video/pvrusb2/Kconfig" + +source "drivers/media/video/hdpvr/Kconfig" + +source "drivers/media/video/em28xx/Kconfig" + +source "drivers/media/video/tlg2300/Kconfig" + +source "drivers/media/video/cx231xx/Kconfig" + +source "drivers/media/video/tm6000/Kconfig" + +source "drivers/media/video/usbvision/Kconfig" + +source "drivers/media/video/et61x251/Kconfig" + +source "drivers/media/video/sn9c102/Kconfig" + +source "drivers/media/video/pwc/Kconfig" + +source "drivers/media/video/cpia2/Kconfig" + +config USB_ZR364XX + tristate "USB ZR364XX Camera support" + depends on VIDEO_V4L2 + select VIDEOBUF_GEN + select VIDEOBUF_VMALLOC + ---help--- + Say Y here if you want to connect this type of camera to your + computer's USB port. + See <file:Documentation/video4linux/zr364xx.txt> for more info + and list of supported cameras. To compile this driver as a module, choose M here: the - module will be called pms. + module will be called zr364xx. -config VIDEO_BWQCAM - tristate "Quickcam BW Video For Linux" - depends on PARPORT && VIDEO_V4L2 - help - Say Y have if you the black and white version of the QuickCam - camera. See the next option for the color version. +config USB_STKWEBCAM + tristate "USB Syntek DC1125 Camera support" + depends on VIDEO_V4L2 && EXPERIMENTAL + ---help--- + Say Y here if you want to use this type of camera. + Supported devices are typically found in some Asus laptops, + with USB id 174f:a311 and 05e1:0501. Other Syntek cameras + may be supported by the stk11xx driver, from which this is + derived, see <http://sourceforge.net/projects/syntekdriver/> To compile this driver as a module, choose M here: the - module will be called bw-qcam. + module will be called stkwebcam. -config VIDEO_CQCAM - tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)" - depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2 +config USB_S2255 + tristate "USB Sensoray 2255 video capture device" + depends on VIDEO_V4L2 + select VIDEOBUF_VMALLOC + default n help - This is the video4linux driver for the colour version of the - Connectix QuickCam. If you have one of these cameras, say Y here, - otherwise say N. This driver does not work with the original - monochrome QuickCam, QuickCam VC or QuickClip. It is also available - as a module (c-qcam). - Read <file:Documentation/video4linux/CQcam.txt> for more information. + Say Y here if you want support for the Sensoray 2255 USB device. + This driver can be compiled as a module, called s2255drv. -config VIDEO_W9966 - tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" - depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 - help - Video4linux driver for Winbond's w9966 based Webcams. - Currently tested with the LifeView FlyCam Supra. - If you have one of these cameras, say Y here - otherwise say N. - This driver is also available as a module (w9966). +endif # V4L_USB_DRIVERS - Check out <file:Documentation/video4linux/w9966.txt> for more - information. +# +# PCI drivers configuration +# -source "drivers/media/video/cpia2/Kconfig" +menuconfig V4L_PCI_DRIVERS + bool "V4L PCI(e) devices" + depends on PCI + default y + ---help--- + Say Y here to enable support for these PCI(e) drivers. -config VIDEO_VINO - tristate "SGI Vino Video For Linux (EXPERIMENTAL)" - depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 - select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO - help - Say Y here to build in support for the Vino video input system found - on SGI Indy machines. +if V4L_PCI_DRIVERS -source "drivers/media/video/zoran/Kconfig" +source "drivers/media/video/au0828/Kconfig" + +source "drivers/media/video/bt8xx/Kconfig" + +source "drivers/media/video/cx18/Kconfig" + +source "drivers/media/video/cx23885/Kconfig" + +source "drivers/media/video/cx25821/Kconfig" + +source "drivers/media/video/cx88/Kconfig" + +config VIDEO_HEXIUM_GEMINI + tristate "Hexium Gemini frame grabber" + depends on PCI && VIDEO_V4L2 && I2C + select VIDEO_SAA7146_VV + ---help--- + This is a video4linux driver for the Hexium Gemini frame + grabber card by Hexium. Please note that the Gemini Dual + card is *not* fully supported. + + To compile this driver as a module, choose M here: the + module will be called hexium_gemini. + +config VIDEO_HEXIUM_ORION + tristate "Hexium HV-PCI6 and Orion frame grabber" + depends on PCI && VIDEO_V4L2 && I2C + select VIDEO_SAA7146_VV + ---help--- + This is a video4linux driver for the Hexium HV-PCI6 and + Orion frame grabber cards by Hexium. + + To compile this driver as a module, choose M here: the + module will be called hexium_orion. + +source "drivers/media/video/ivtv/Kconfig" config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" @@ -688,8 +740,6 @@ config VIDEO_MEYE To compile this driver as a module, choose M here: the module will be called meye. -source "drivers/media/video/saa7134/Kconfig" - config VIDEO_MXB tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" depends on PCI && VIDEO_V4L2 && I2C @@ -706,28 +756,119 @@ config VIDEO_MXB To compile this driver as a module, choose M here: the module will be called mxb. -config VIDEO_HEXIUM_ORION - tristate "Hexium HV-PCI6 and Orion frame grabber" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV +source "drivers/media/video/saa7134/Kconfig" + +source "drivers/media/video/saa7164/Kconfig" + +source "drivers/media/video/zoran/Kconfig" + +endif # V4L_PCI_DRIVERS + +# +# ISA & parallel port drivers configuration +# + +menuconfig V4L_ISA_PARPORT_DRIVERS + bool "V4L ISA and parallel port devices" + depends on ISA || PARPORT + default n ---help--- - This is a video4linux driver for the Hexium HV-PCI6 and - Orion frame grabber cards by Hexium. + Say Y here to enable support for these ISA and parallel port drivers. + +if V4L_ISA_PARPORT_DRIVERS + +config VIDEO_BWQCAM + tristate "Quickcam BW Video For Linux" + depends on PARPORT && VIDEO_V4L2 + help + Say Y have if you the black and white version of the QuickCam + camera. See the next option for the color version. To compile this driver as a module, choose M here: the - module will be called hexium_orion. + module will be called bw-qcam. -config VIDEO_HEXIUM_GEMINI - tristate "Hexium Gemini frame grabber" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV - ---help--- - This is a video4linux driver for the Hexium Gemini frame - grabber card by Hexium. Please note that the Gemini Dual - card is *not* fully supported. +config VIDEO_CQCAM + tristate "QuickCam Colour Video For Linux" + depends on PARPORT && VIDEO_V4L2 + help + This is the video4linux driver for the colour version of the + Connectix QuickCam. If you have one of these cameras, say Y here, + otherwise say N. This driver does not work with the original + monochrome QuickCam, QuickCam VC or QuickClip. It is also available + as a module (c-qcam). + Read <file:Documentation/video4linux/CQcam.txt> for more information. + +config VIDEO_PMS + tristate "Mediavision Pro Movie Studio Video For Linux" + depends on ISA && VIDEO_V4L2 + help + Say Y if you have the ISA Mediavision Pro Movie Studio + capture card. To compile this driver as a module, choose M here: the - module will be called hexium_gemini. + module will be called pms. + +config VIDEO_W9966 + tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" + depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 + help + Video4linux driver for Winbond's w9966 based Webcams. + Currently tested with the LifeView FlyCam Supra. + If you have one of these cameras, say Y here + otherwise say N. + This driver is also available as a module (w9966). + + Check out <file:Documentation/video4linux/w9966.txt> for more + information. + +endif # V4L_ISA_PARPORT_DRIVERS + +menuconfig V4L_PLATFORM_DRIVERS + bool "V4L platform devices" + default n + ---help--- + Say Y here to enable support for platform-specific V4L drivers. + +if V4L_PLATFORM_DRIVERS + +source "drivers/media/video/marvell-ccic/Kconfig" + +config VIDEO_VIA_CAMERA + tristate "VIAFB camera controller support" + depends on FB_VIA + select VIDEOBUF_DMA_SG + select VIDEO_OV7670 + help + Driver support for the integrated camera controller in VIA + Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems + with ov7670 sensors. + +# +# Platform multimedia device configuration +# + +source "drivers/media/video/davinci/Kconfig" + +source "drivers/media/video/omap/Kconfig" + +config VIDEO_SH_VOU + tristate "SuperH VOU video output driver" + depends on VIDEO_DEV && ARCH_SHMOBILE + select VIDEOBUF_DMA_CONTIG + help + Support for the Video Output Unit (VOU) on SuperH SoCs. + +config VIDEO_VIU + tristate "Freescale VIU Video Driver" + depends on VIDEO_V4L2 && PPC_MPC512x + select VIDEOBUF_DMA_CONTIG + default y + ---help--- + Support for Freescale VIU video driver. This device captures + video data, or overlays video on DIU frame buffer. + + Say Y here if you want to enable VIU device on MPC5121e Rev2+. + In doubt, say N. config VIDEO_TIMBERDALE tristate "Support for timberdale Video In/LogiWIN" @@ -739,21 +880,13 @@ config VIDEO_TIMBERDALE ---help--- Add support for the Video In peripherial of the timberdale FPGA. -source "drivers/media/video/cx88/Kconfig" - -source "drivers/media/video/cx23885/Kconfig" - -source "drivers/media/video/cx25821/Kconfig" - -source "drivers/media/video/au0828/Kconfig" - -source "drivers/media/video/ivtv/Kconfig" - -source "drivers/media/video/cx18/Kconfig" - -source "drivers/media/video/saa7164/Kconfig" - -source "drivers/media/video/marvell-ccic/Kconfig" +config VIDEO_VINO + tristate "SGI Vino Video For Linux" + depends on I2C && SGI_IP22 && VIDEO_V4L2 + select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO + help + Say Y here to build in support for the Vino video input system found + on SGI Indy machines. config VIDEO_M32R_AR tristate "AR devices" @@ -774,16 +907,6 @@ config VIDEO_M32R_AR_M64278 To compile this driver as a module, choose M here: the module will be called arv. -config VIDEO_VIA_CAMERA - tristate "VIAFB camera controller support" - depends on FB_VIA - select VIDEOBUF_DMA_SG - select VIDEO_OV7670 - help - Driver support for the integrated camera controller in VIA - Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems - with ov7670 sensors. - config VIDEO_OMAP3 tristate "OMAP 3 Camera support (EXPERIMENTAL)" depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL @@ -1002,78 +1125,7 @@ config VIDEO_S5P_MIPI_CSIS source "drivers/media/video/s5p-tv/Kconfig" -# -# USB Multimedia device configuration -# - -menuconfig V4L_USB_DRIVERS - bool "V4L USB devices" - depends on USB - default y - -if V4L_USB_DRIVERS && USB - -source "drivers/media/video/uvc/Kconfig" - -source "drivers/media/video/gspca/Kconfig" - -source "drivers/media/video/pvrusb2/Kconfig" - -source "drivers/media/video/hdpvr/Kconfig" - -source "drivers/media/video/em28xx/Kconfig" - -source "drivers/media/video/tlg2300/Kconfig" - -source "drivers/media/video/cx231xx/Kconfig" - -source "drivers/media/video/tm6000/Kconfig" - -source "drivers/media/video/usbvision/Kconfig" - -source "drivers/media/video/et61x251/Kconfig" - -source "drivers/media/video/sn9c102/Kconfig" - -source "drivers/media/video/pwc/Kconfig" - -config USB_ZR364XX - tristate "USB ZR364XX Camera support" - depends on VIDEO_V4L2 - select VIDEOBUF_GEN - select VIDEOBUF_VMALLOC - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. - See <file:Documentation/video4linux/zr364xx.txt> for more info - and list of supported cameras. - - To compile this driver as a module, choose M here: the - module will be called zr364xx. - -config USB_STKWEBCAM - tristate "USB Syntek DC1125 Camera support" - depends on VIDEO_V4L2 && EXPERIMENTAL - ---help--- - Say Y here if you want to use this type of camera. - Supported devices are typically found in some Asus laptops, - with USB id 174f:a311 and 05e1:0501. Other Syntek cameras - may be supported by the stk11xx driver, from which this is - derived, see <http://sourceforge.net/projects/syntekdriver/> - - To compile this driver as a module, choose M here: the - module will be called stkwebcam. - -config USB_S2255 - tristate "USB Sensoray 2255 video capture device" - depends on VIDEO_V4L2 - select VIDEOBUF_VMALLOC - default n - help - Say Y here if you want support for the Sensoray 2255 USB device. - This driver can be compiled as a module, called s2255drv. - -endif # V4L_USB_DRIVERS +endif # V4L_PLATFORM_DRIVERS endif # VIDEO_CAPTURE_DRIVERS menuconfig V4L_MEM2MEM_DRIVERS @@ -1098,6 +1150,23 @@ config VIDEO_MEM2MEM_TESTDEV This is a virtual test device for the memory-to-memory driver framework. +config VIDEO_SAMSUNG_S5P_G2D + tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" + depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + default n + ---help--- + This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D + 2d graphics accelerator. + +config VIDEO_SAMSUNG_S5P_JPEG + tristate "Samsung S5P/Exynos4 JPEG codec driver (EXPERIMENTAL)" + depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P && EXPERIMENTAL + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + ---help--- + 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" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 117f9c4b4cb9..354138804cda 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o +obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o @@ -177,9 +178,12 @@ obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ + obj-$(CONFIG_ARCH_DAVINCI) += davinci/ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 23ba5c37c3e4..879f1d839760 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c @@ -64,6 +64,11 @@ static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd) static char *inputs[] = { "pass_through", "play_back" }; +static enum v4l2_mbus_pixelcode adv7170_codes[] = { + V4L2_MBUS_FMT_UYVY8_2X8, + V4L2_MBUS_FMT_UYVY8_1X16, +}; + /* ----------------------------------------------------------------------- */ static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value) @@ -258,6 +263,60 @@ static int adv7170_s_routing(struct v4l2_subdev *sd, return 0; } +static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(adv7170_codes)) + return -EINVAL; + + *code = adv7170_codes[index]; + return 0; +} + +static int adv7170_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + u8 val = adv7170_read(sd, 0x7); + + if ((val & 0x40) == (1 << 6)) + mf->code = V4L2_MBUS_FMT_UYVY8_1X16; + else + mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + mf->width = 0; + mf->height = 0; + mf->field = V4L2_FIELD_ANY; + + return 0; +} + +static int adv7170_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + u8 val = adv7170_read(sd, 0x7); + int ret; + + switch (mf->code) { + case V4L2_MBUS_FMT_UYVY8_2X8: + val &= ~0x40; + break; + + case V4L2_MBUS_FMT_UYVY8_1X16: + val |= 0x40; + break; + + default: + v4l2_dbg(1, debug, sd, + "illegal v4l2_mbus_framefmt code: %d\n", mf->code); + return -EINVAL; + } + + ret = adv7170_write(sd, 0x7, val); + + return ret; +} + static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -274,6 +333,9 @@ static const struct v4l2_subdev_core_ops adv7170_core_ops = { static const struct v4l2_subdev_video_ops adv7170_video_ops = { .s_std_output = adv7170_s_std_output, .s_routing = adv7170_s_routing, + .s_mbus_fmt = adv7170_s_fmt, + .g_mbus_fmt = adv7170_g_fmt, + .enum_mbus_fmt = adv7170_enum_fmt, }; static const struct v4l2_subdev_ops adv7170_ops = { diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c new file mode 100644 index 000000000000..f241702a0f36 --- /dev/null +++ b/drivers/media/video/as3645a.c @@ -0,0 +1,905 @@ +/* + * drivers/media/video/as3645a.c - AS3645A and LM3555 flash controllers driver + * + * Copyright (C) 2008-2011 Nokia Corporation + * Copyright (c) 2011, Intel Corporation. + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * TODO: + * - Check hardware FSTROBE control when sensor driver add support for this + * + */ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/slab.h> + +#include <media/as3645a.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> + +#define AS_TIMER_MS_TO_CODE(t) (((t) - 100) / 50) +#define AS_TIMER_CODE_TO_MS(c) (50 * (c) + 100) + +/* Register definitions */ + +/* Read-only Design info register: Reset state: xxxx 0001 */ +#define AS_DESIGN_INFO_REG 0x00 +#define AS_DESIGN_INFO_FACTORY(x) (((x) >> 4)) +#define AS_DESIGN_INFO_MODEL(x) ((x) & 0x0f) + +/* Read-only Version control register: Reset state: 0000 0000 + * for first engineering samples + */ +#define AS_VERSION_CONTROL_REG 0x01 +#define AS_VERSION_CONTROL_RFU(x) (((x) >> 4)) +#define AS_VERSION_CONTROL_VERSION(x) ((x) & 0x0f) + +/* Read / Write (Indicator and timer register): Reset state: 0000 1111 */ +#define AS_INDICATOR_AND_TIMER_REG 0x02 +#define AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT 0 +#define AS_INDICATOR_AND_TIMER_VREF_SHIFT 4 +#define AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT 6 + +/* Read / Write (Current set register): Reset state: 0110 1001 */ +#define AS_CURRENT_SET_REG 0x03 +#define AS_CURRENT_ASSIST_LIGHT_SHIFT 0 +#define AS_CURRENT_LED_DET_ON (1 << 3) +#define AS_CURRENT_FLASH_CURRENT_SHIFT 4 + +/* Read / Write (Control register): Reset state: 1011 0100 */ +#define AS_CONTROL_REG 0x04 +#define AS_CONTROL_MODE_SETTING_SHIFT 0 +#define AS_CONTROL_STROBE_ON (1 << 2) +#define AS_CONTROL_OUT_ON (1 << 3) +#define AS_CONTROL_EXT_TORCH_ON (1 << 4) +#define AS_CONTROL_STROBE_TYPE_EDGE (0 << 5) +#define AS_CONTROL_STROBE_TYPE_LEVEL (1 << 5) +#define AS_CONTROL_COIL_PEAK_SHIFT 6 + +/* Read only (D3 is read / write) (Fault and info): Reset state: 0000 x000 */ +#define AS_FAULT_INFO_REG 0x05 +#define AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT (1 << 1) +#define AS_FAULT_INFO_INDICATOR_LED (1 << 2) +#define AS_FAULT_INFO_LED_AMOUNT (1 << 3) +#define AS_FAULT_INFO_TIMEOUT (1 << 4) +#define AS_FAULT_INFO_OVER_TEMPERATURE (1 << 5) +#define AS_FAULT_INFO_SHORT_CIRCUIT (1 << 6) +#define AS_FAULT_INFO_OVER_VOLTAGE (1 << 7) + +/* Boost register */ +#define AS_BOOST_REG 0x0d +#define AS_BOOST_CURRENT_DISABLE (0 << 0) +#define AS_BOOST_CURRENT_ENABLE (1 << 0) + +/* Password register is used to unlock boost register writing */ +#define AS_PASSWORD_REG 0x0f +#define AS_PASSWORD_UNLOCK_VALUE 0x55 + +enum as_mode { + AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT, + AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT, + AS_MODE_ASSIST = 2 << AS_CONTROL_MODE_SETTING_SHIFT, + AS_MODE_FLASH = 3 << AS_CONTROL_MODE_SETTING_SHIFT, +}; + +/* + * struct as3645a + * + * @subdev: V4L2 subdev + * @pdata: Flash platform data + * @power_lock: Protects power_count + * @power_count: Power reference count + * @led_mode: V4L2 flash LED mode + * @timeout: Flash timeout in microseconds + * @flash_current: Flash current (0=200mA ... 15=500mA). Maximum + * values are 400mA for two LEDs and 500mA for one LED. + * @assist_current: Torch/Assist light current (0=20mA, 1=40mA ... 7=160mA) + * @indicator_current: Indicator LED current (0=0mA, 1=2.5mA ... 4=10mA) + * @strobe_source: Flash strobe source (software or external) + */ +struct as3645a { + struct v4l2_subdev subdev; + const struct as3645a_platform_data *pdata; + + struct mutex power_lock; + int power_count; + + /* Controls */ + struct v4l2_ctrl_handler ctrls; + + enum v4l2_flash_led_mode led_mode; + unsigned int timeout; + u8 flash_current; + u8 assist_current; + u8 indicator_current; + enum v4l2_flash_strobe_source strobe_source; +}; + +#define to_as3645a(sd) container_of(sd, struct as3645a, subdev) + +/* Return negative errno else zero on success */ +static int as3645a_write(struct as3645a *flash, u8 addr, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int rval; + + rval = i2c_smbus_write_byte_data(client, addr, val); + + dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val, + rval < 0 ? "fail" : "ok"); + + return rval; +} + +/* Return negative errno else a data byte received from the device. */ +static int as3645a_read(struct as3645a *flash, u8 addr) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int rval; + + rval = i2c_smbus_read_byte_data(client, addr); + + dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, rval, + rval < 0 ? "fail" : "ok"); + + return rval; +} + +/* ----------------------------------------------------------------------------- + * Hardware configuration and trigger + */ + +/* + * as3645a_set_config - Set flash configuration registers + * @flash: The flash + * + * Configure the hardware with flash, assist and indicator currents, as well as + * flash timeout. + * + * Return 0 on success, or a negative error code if an I2C communication error + * occurred. + */ +static int as3645a_set_config(struct as3645a *flash) +{ + int ret; + u8 val; + + val = (flash->flash_current << AS_CURRENT_FLASH_CURRENT_SHIFT) + | (flash->assist_current << AS_CURRENT_ASSIST_LIGHT_SHIFT) + | AS_CURRENT_LED_DET_ON; + + ret = as3645a_write(flash, AS_CURRENT_SET_REG, val); + if (ret < 0) + return ret; + + val = AS_TIMER_MS_TO_CODE(flash->timeout / 1000) + << AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT; + + val |= (flash->pdata->vref << AS_INDICATOR_AND_TIMER_VREF_SHIFT) + | ((flash->indicator_current ? flash->indicator_current - 1 : 0) + << AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT); + + return as3645a_write(flash, AS_INDICATOR_AND_TIMER_REG, val); +} + +/* + * as3645a_set_control - Set flash control register + * @flash: The flash + * @mode: Desired output mode + * @on: Desired output state + * + * Configure the hardware with output mode and state. + * + * Return 0 on success, or a negative error code if an I2C communication error + * occurred. + */ +static int +as3645a_set_control(struct as3645a *flash, enum as_mode mode, bool on) +{ + u8 reg; + + /* Configure output parameters and operation mode. */ + reg = (flash->pdata->peak << AS_CONTROL_COIL_PEAK_SHIFT) + | (on ? AS_CONTROL_OUT_ON : 0) + | mode; + + if (flash->led_mode == V4L2_FLASH_LED_MODE_FLASH && + flash->strobe_source == V4L2_FLASH_STROBE_SOURCE_EXTERNAL) { + reg |= AS_CONTROL_STROBE_TYPE_LEVEL + | AS_CONTROL_STROBE_ON; + } + + return as3645a_write(flash, AS_CONTROL_REG, reg); +} + +/* + * as3645a_set_output - Configure output and operation mode + * @flash: Flash controller + * @strobe: Strobe the flash (only valid in flash mode) + * + * Turn the LEDs output on/off and set the operation mode based on the current + * parameters. + * + * The AS3645A can't control the indicator LED independently of the flash/torch + * LED. If the flash controller is in V4L2_FLASH_LED_MODE_NONE mode, set the + * chip to indicator mode. Otherwise set it to assist light (torch) or flash + * mode. + * + * In indicator and assist modes, turn the output on/off based on the indicator + * and torch currents. In software strobe flash mode, turn the output on/off + * based on the strobe parameter. + */ +static int as3645a_set_output(struct as3645a *flash, bool strobe) +{ + enum as_mode mode; + bool on; + + switch (flash->led_mode) { + case V4L2_FLASH_LED_MODE_NONE: + on = flash->indicator_current != 0; + mode = AS_MODE_INDICATOR; + break; + case V4L2_FLASH_LED_MODE_TORCH: + on = true; + mode = AS_MODE_ASSIST; + break; + case V4L2_FLASH_LED_MODE_FLASH: + on = strobe; + mode = AS_MODE_FLASH; + break; + default: + BUG(); + } + + /* Configure output parameters and operation mode. */ + return as3645a_set_control(flash, mode, on); +} + +/* ----------------------------------------------------------------------------- + * V4L2 controls + */ + +static int as3645a_is_active(struct as3645a *flash) +{ + int ret; + + ret = as3645a_read(flash, AS_CONTROL_REG); + return ret < 0 ? ret : !!(ret & AS_CONTROL_OUT_ON); +} + +static int as3645a_read_fault(struct as3645a *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int rval; + + /* NOTE: reading register clear fault status */ + rval = as3645a_read(flash, AS_FAULT_INFO_REG); + if (rval < 0) + return rval; + + if (rval & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT) + dev_dbg(&client->dev, "Inductor Peak limit fault\n"); + + if (rval & AS_FAULT_INFO_INDICATOR_LED) + dev_dbg(&client->dev, "Indicator LED fault: " + "Short circuit or open loop\n"); + + dev_dbg(&client->dev, "%u connected LEDs\n", + rval & AS_FAULT_INFO_LED_AMOUNT ? 2 : 1); + + if (rval & AS_FAULT_INFO_TIMEOUT) + dev_dbg(&client->dev, "Timeout fault\n"); + + if (rval & AS_FAULT_INFO_OVER_TEMPERATURE) + dev_dbg(&client->dev, "Over temperature fault\n"); + + if (rval & AS_FAULT_INFO_SHORT_CIRCUIT) + dev_dbg(&client->dev, "Short circuit fault\n"); + + if (rval & AS_FAULT_INFO_OVER_VOLTAGE) + dev_dbg(&client->dev, "Over voltage fault: " + "Indicates missing capacitor or open connection\n"); + + return rval; +} + +static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl) +{ + struct as3645a *flash = + container_of(ctrl->handler, struct as3645a, ctrls); + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int value; + + switch (ctrl->id) { + case V4L2_CID_FLASH_FAULT: + value = as3645a_read_fault(flash); + if (value < 0) + return value; + + ctrl->cur.val = 0; + if (value & AS_FAULT_INFO_SHORT_CIRCUIT) + ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; + if (value & AS_FAULT_INFO_OVER_TEMPERATURE) + ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; + if (value & AS_FAULT_INFO_TIMEOUT) + ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT; + if (value & AS_FAULT_INFO_OVER_VOLTAGE) + ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE; + if (value & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT) + ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_CURRENT; + if (value & AS_FAULT_INFO_INDICATOR_LED) + ctrl->cur.val |= V4L2_FLASH_FAULT_INDICATOR; + break; + + case V4L2_CID_FLASH_STROBE_STATUS: + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) { + ctrl->cur.val = 0; + break; + } + + value = as3645a_is_active(flash); + if (value < 0) + return value; + + ctrl->cur.val = value; + break; + } + + dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, ctrl->cur.val); + + return 0; +} + +static int as3645a_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct as3645a *flash = + container_of(ctrl->handler, struct as3645a, ctrls); + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int ret; + + dev_dbg(&client->dev, "S_CTRL %08x:%d\n", ctrl->id, ctrl->val); + + /* If a control that doesn't apply to the current mode is modified, + * we store the value and return immediately. The setting will be + * applied when the LED mode is changed. Otherwise we apply the setting + * immediately. + */ + + switch (ctrl->id) { + case V4L2_CID_FLASH_LED_MODE: + if (flash->indicator_current) + return -EBUSY; + + ret = as3645a_set_config(flash); + if (ret < 0) + return ret; + + flash->led_mode = ctrl->val; + return as3645a_set_output(flash, false); + + case V4L2_CID_FLASH_STROBE_SOURCE: + flash->strobe_source = ctrl->val; + + /* Applies to flash mode only. */ + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + break; + + return as3645a_set_output(flash, false); + + case V4L2_CID_FLASH_STROBE: + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + return -EBUSY; + + return as3645a_set_output(flash, true); + + case V4L2_CID_FLASH_STROBE_STOP: + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + return -EBUSY; + + return as3645a_set_output(flash, false); + + case V4L2_CID_FLASH_TIMEOUT: + flash->timeout = ctrl->val; + + /* Applies to flash mode only. */ + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + break; + + return as3645a_set_config(flash); + + case V4L2_CID_FLASH_INTENSITY: + flash->flash_current = (ctrl->val - AS3645A_FLASH_INTENSITY_MIN) + / AS3645A_FLASH_INTENSITY_STEP; + + /* Applies to flash mode only. */ + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + break; + + return as3645a_set_config(flash); + + case V4L2_CID_FLASH_TORCH_INTENSITY: + flash->assist_current = + (ctrl->val - AS3645A_TORCH_INTENSITY_MIN) + / AS3645A_TORCH_INTENSITY_STEP; + + /* Applies to torch mode only. */ + if (flash->led_mode != V4L2_FLASH_LED_MODE_TORCH) + break; + + return as3645a_set_config(flash); + + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + if (flash->led_mode != V4L2_FLASH_LED_MODE_NONE) + return -EBUSY; + + flash->indicator_current = + (ctrl->val - AS3645A_INDICATOR_INTENSITY_MIN) + / AS3645A_INDICATOR_INTENSITY_STEP; + + ret = as3645a_set_config(flash); + if (ret < 0) + return ret; + + if ((ctrl->val == 0) == (ctrl->cur.val == 0)) + break; + + return as3645a_set_output(flash, false); + } + + return 0; +} + +static const struct v4l2_ctrl_ops as3645a_ctrl_ops = { + .g_volatile_ctrl = as3645a_get_ctrl, + .s_ctrl = as3645a_set_ctrl, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev core operations + */ + +/* Put device into know state. */ +static int as3645a_setup(struct as3645a *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int ret; + + /* clear errors */ + ret = as3645a_read(flash, AS_FAULT_INFO_REG); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Fault info: %02x\n", ret); + + ret = as3645a_set_config(flash); + if (ret < 0) + return ret; + + ret = as3645a_set_output(flash, false); + if (ret < 0) + return ret; + + /* read status */ + ret = as3645a_read_fault(flash); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "AS_INDICATOR_AND_TIMER_REG: %02x\n", + as3645a_read(flash, AS_INDICATOR_AND_TIMER_REG)); + dev_dbg(&client->dev, "AS_CURRENT_SET_REG: %02x\n", + as3645a_read(flash, AS_CURRENT_SET_REG)); + dev_dbg(&client->dev, "AS_CONTROL_REG: %02x\n", + as3645a_read(flash, AS_CONTROL_REG)); + + return ret & ~AS_FAULT_INFO_LED_AMOUNT ? -EIO : 0; +} + +static int __as3645a_set_power(struct as3645a *flash, int on) +{ + int ret; + + if (!on) + as3645a_set_control(flash, AS_MODE_EXT_TORCH, false); + + if (flash->pdata->set_power) { + ret = flash->pdata->set_power(&flash->subdev, on); + if (ret < 0) + return ret; + } + + if (!on) + return 0; + + ret = as3645a_setup(flash); + if (ret < 0) { + if (flash->pdata->set_power) + flash->pdata->set_power(&flash->subdev, 0); + } + + return ret; +} + +static int as3645a_set_power(struct v4l2_subdev *sd, int on) +{ + struct as3645a *flash = to_as3645a(sd); + int ret = 0; + + mutex_lock(&flash->power_lock); + + if (flash->power_count == !on) { + ret = __as3645a_set_power(flash, !!on); + if (ret < 0) + goto done; + } + + flash->power_count += on ? 1 : -1; + WARN_ON(flash->power_count < 0); + +done: + mutex_unlock(&flash->power_lock); + return ret; +} + +static int as3645a_registered(struct v4l2_subdev *sd) +{ + struct as3645a *flash = to_as3645a(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int rval, man, model, rfu, version; + const char *vendor; + + /* Power up the flash driver and read manufacturer ID, model ID, RFU + * and version. + */ + rval = as3645a_set_power(&flash->subdev, 1); + if (rval < 0) + return rval; + + rval = as3645a_read(flash, AS_DESIGN_INFO_REG); + if (rval < 0) + goto power_off; + + man = AS_DESIGN_INFO_FACTORY(rval); + model = AS_DESIGN_INFO_MODEL(rval); + + rval = as3645a_read(flash, AS_VERSION_CONTROL_REG); + if (rval < 0) + goto power_off; + + rfu = AS_VERSION_CONTROL_RFU(rval); + version = AS_VERSION_CONTROL_VERSION(rval); + + /* Verify the chip model and version. */ + if (model != 0x01 || rfu != 0x00) { + dev_err(&client->dev, "AS3645A not detected " + "(model %d rfu %d)\n", model, rfu); + rval = -ENODEV; + goto power_off; + } + + switch (man) { + case 1: + vendor = "AMS, Austria Micro Systems"; + break; + case 2: + vendor = "ADI, Analog Devices Inc."; + break; + case 3: + vendor = "NSC, National Semiconductor"; + break; + case 4: + vendor = "NXP"; + break; + case 5: + vendor = "TI, Texas Instrument"; + break; + default: + vendor = "Unknown"; + } + + dev_info(&client->dev, "Chip vendor: %s (%d) Version: %d\n", vendor, + man, version); + + rval = as3645a_write(flash, AS_PASSWORD_REG, AS_PASSWORD_UNLOCK_VALUE); + if (rval < 0) + goto power_off; + + rval = as3645a_write(flash, AS_BOOST_REG, AS_BOOST_CURRENT_DISABLE); + if (rval < 0) + goto power_off; + + /* Setup default values. This makes sure that the chip is in a known + * state, in case the power rail can't be controlled. + */ + rval = as3645a_setup(flash); + +power_off: + as3645a_set_power(&flash->subdev, 0); + + return rval; +} + +static int as3645a_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return as3645a_set_power(sd, 1); +} + +static int as3645a_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return as3645a_set_power(sd, 0); +} + +static const struct v4l2_subdev_core_ops as3645a_core_ops = { + .s_power = as3645a_set_power, +}; + +static const struct v4l2_subdev_ops as3645a_ops = { + .core = &as3645a_core_ops, +}; + +static const struct v4l2_subdev_internal_ops as3645a_internal_ops = { + .registered = as3645a_registered, + .open = as3645a_open, + .close = as3645a_close, +}; + +/* ----------------------------------------------------------------------------- + * I2C driver + */ +#ifdef CONFIG_PM + +static int as3645a_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct as3645a *flash = to_as3645a(subdev); + int rval; + + if (flash->power_count == 0) + return 0; + + rval = __as3645a_set_power(flash, 0); + + dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok"); + + return rval; +} + +static int as3645a_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct as3645a *flash = to_as3645a(subdev); + int rval; + + if (flash->power_count == 0) + return 0; + + rval = __as3645a_set_power(flash, 1); + + dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok"); + + return rval; +} + +#else + +#define as3645a_suspend NULL +#define as3645a_resume NULL + +#endif /* CONFIG_PM */ + +/* + * as3645a_init_controls - Create controls + * @flash: The flash + * + * The number of LEDs reported in platform data is used to compute default + * limits. Parameters passed through platform data can override those limits. + */ +static int as3645a_init_controls(struct as3645a *flash) +{ + const struct as3645a_platform_data *pdata = flash->pdata; + struct v4l2_ctrl *ctrl; + int maximum; + + v4l2_ctrl_handler_init(&flash->ctrls, 10); + + /* V4L2_CID_FLASH_LED_MODE */ + v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_LED_MODE, 2, ~7, + V4L2_FLASH_LED_MODE_NONE); + + /* V4L2_CID_FLASH_STROBE_SOURCE */ + v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_STROBE_SOURCE, + pdata->ext_strobe ? 1 : 0, + pdata->ext_strobe ? ~3 : ~1, + V4L2_FLASH_STROBE_SOURCE_SOFTWARE); + + flash->strobe_source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; + + /* V4L2_CID_FLASH_STROBE */ + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_STROBE, 0, 0, 0, 0); + + /* V4L2_CID_FLASH_STROBE_STOP */ + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0); + + /* V4L2_CID_FLASH_STROBE_STATUS */ + ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_STROBE_STATUS, 0, 1, 1, 1); + if (ctrl != NULL) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + + /* V4L2_CID_FLASH_TIMEOUT */ + maximum = pdata->timeout_max; + + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_TIMEOUT, AS3645A_FLASH_TIMEOUT_MIN, + maximum, AS3645A_FLASH_TIMEOUT_STEP, maximum); + + flash->timeout = maximum; + + /* V4L2_CID_FLASH_INTENSITY */ + maximum = pdata->flash_max_current; + + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_INTENSITY, AS3645A_FLASH_INTENSITY_MIN, + maximum, AS3645A_FLASH_INTENSITY_STEP, maximum); + + flash->flash_current = (maximum - AS3645A_FLASH_INTENSITY_MIN) + / AS3645A_FLASH_INTENSITY_STEP; + + /* V4L2_CID_FLASH_TORCH_INTENSITY */ + maximum = pdata->torch_max_current; + + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_TORCH_INTENSITY, + AS3645A_TORCH_INTENSITY_MIN, maximum, + AS3645A_TORCH_INTENSITY_STEP, + AS3645A_TORCH_INTENSITY_MIN); + + flash->assist_current = 0; + + /* V4L2_CID_FLASH_INDICATOR_INTENSITY */ + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_INDICATOR_INTENSITY, + AS3645A_INDICATOR_INTENSITY_MIN, + AS3645A_INDICATOR_INTENSITY_MAX, + AS3645A_INDICATOR_INTENSITY_STEP, + AS3645A_INDICATOR_INTENSITY_MIN); + + flash->indicator_current = 0; + + /* V4L2_CID_FLASH_FAULT */ + ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_FAULT, 0, + V4L2_FLASH_FAULT_OVER_VOLTAGE | + V4L2_FLASH_FAULT_TIMEOUT | + V4L2_FLASH_FAULT_OVER_TEMPERATURE | + V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0); + if (ctrl != NULL) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + + flash->subdev.ctrl_handler = &flash->ctrls; + + return flash->ctrls.error; +} + +static int as3645a_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct as3645a *flash; + int ret; + + if (client->dev.platform_data == NULL) + return -ENODEV; + + flash = kzalloc(sizeof(*flash), GFP_KERNEL); + if (flash == NULL) + return -ENOMEM; + + flash->pdata = client->dev.platform_data; + + v4l2_i2c_subdev_init(&flash->subdev, client, &as3645a_ops); + flash->subdev.internal_ops = &as3645a_internal_ops; + flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + ret = as3645a_init_controls(flash); + if (ret < 0) + goto done; + + ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0); + if (ret < 0) + goto done; + + flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + + mutex_init(&flash->power_lock); + + flash->led_mode = V4L2_FLASH_LED_MODE_NONE; + +done: + if (ret < 0) { + v4l2_ctrl_handler_free(&flash->ctrls); + kfree(flash); + } + + return ret; +} + +static int __exit as3645a_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct as3645a *flash = to_as3645a(subdev); + + v4l2_device_unregister_subdev(subdev); + v4l2_ctrl_handler_free(&flash->ctrls); + media_entity_cleanup(&flash->subdev.entity); + mutex_destroy(&flash->power_lock); + kfree(flash); + + return 0; +} + +static const struct i2c_device_id as3645a_id_table[] = { + { AS3645A_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, as3645a_id_table); + +static const struct dev_pm_ops as3645a_pm_ops = { + .suspend = as3645a_suspend, + .resume = as3645a_resume, +}; + +static struct i2c_driver as3645a_i2c_driver = { + .driver = { + .name = AS3645A_NAME, + .pm = &as3645a_pm_ops, + }, + .probe = as3645a_probe, + .remove = __exit_p(as3645a_remove), + .id_table = as3645a_id_table, +}; + +static int __init as3645a_init(void) +{ + int rval; + + rval = i2c_add_driver(&as3645a_i2c_driver); + if (rval) + pr_err("%s: Failed to register the driver\n", AS3645A_NAME); + + return rval; +} + +static void __exit as3645a_exit(void) +{ + i2c_del_driver(&as3645a_i2c_driver); +} + +module_init(as3645a_init); +module_exit(as3645a_exit); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 8c775c59e120..9fe4519176a4 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -90,7 +90,10 @@ struct atmel_isi { struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; struct completion complete; + /* ISI peripherial clock */ struct clk *pclk; + /* ISI_MCK, feed to camera sensor to generate pixel clock */ + struct clk *mck; unsigned int irq; struct isi_platform_data *pdata; @@ -766,6 +769,12 @@ static int isi_camera_add_device(struct soc_camera_device *icd) if (ret) return ret; + ret = clk_enable(isi->mck); + if (ret) { + clk_disable(isi->pclk); + return ret; + } + isi->icd = icd; dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n", icd->devnum); @@ -779,6 +788,7 @@ static void isi_camera_remove_device(struct soc_camera_device *icd) BUG_ON(icd != isi->icd); + clk_disable(isi->mck); clk_disable(isi->pclk); isi->icd = NULL; @@ -803,7 +813,7 @@ static int isi_camera_querycap(struct soc_camera_host *ici, return 0; } -static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) +static int isi_camera_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); @@ -874,7 +884,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) if (isi->pdata->has_emb_sync) cfg1 |= ISI_CFG1_EMB_SYNC; - if (isi->pdata->isi_full_mode) + if (isi->pdata->full_mode) cfg1 |= ISI_CFG1_FULL_MODE; isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); @@ -912,6 +922,7 @@ static int __devexit atmel_isi_remove(struct platform_device *pdev) isi->fb_descriptors_phys); iounmap(isi->regs); + clk_put(isi->mck); clk_put(isi->pclk); kfree(isi); @@ -930,7 +941,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) struct isi_platform_data *pdata; pdata = dev->platform_data; - if (!pdata || !pdata->data_width_flags) { + if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) { dev_err(&pdev->dev, "No config available for Atmel ISI\n"); return -EINVAL; @@ -959,6 +970,19 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isi->video_buffer_list); INIT_LIST_HEAD(&isi->dma_desc_head); + /* Get ISI_MCK, provided by programmable clock or external clock */ + isi->mck = clk_get(dev, "isi_mck"); + if (IS_ERR(isi->mck)) { + dev_err(dev, "Failed to get isi_mck\n"); + ret = PTR_ERR(isi->mck); + goto err_clk_get; + } + + /* Set ISI_MCK's frequency, it should be faster than pixel clock */ + ret = clk_set_rate(isi->mck, pdata->mck_hz); + if (ret < 0) + goto err_set_mck_rate; + isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, sizeof(struct fbd) * MAX_BUFFER_NUM, &isi->fb_descriptors_phys, @@ -1034,9 +1058,12 @@ err_alloc_ctx: isi->p_fb_descriptors, isi->fb_descriptors_phys); err_alloc_descriptors: +err_set_mck_rate: + clk_put(isi->mck); +err_clk_get: kfree(isi); err_alloc_isi: - clk_put(isi->pclk); + clk_put(pclk); return ret; } diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig index 0c3a5ba0e857..81ba9d9d1b52 100644 --- a/drivers/media/video/au0828/Kconfig +++ b/drivers/media/video/au0828/Kconfig @@ -2,6 +2,7 @@ config VIDEO_AU0828 tristate "Auvitek AU0828 support" depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 + depends on DVB_CAPTURE_DRIVERS select I2C_ALGOBIT select VIDEO_TVEEPROM select VIDEOBUF_VMALLOC diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c index cbdb65c34f21..05c299fa5d79 100644 --- a/drivers/media/video/au0828/au0828-i2c.c +++ b/drivers/media/video/au0828/au0828-i2c.c @@ -348,7 +348,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int au0828_i2c_register(struct au0828_dev *dev) { dprintk(1, "%s()\n", __func__); diff --git a/drivers/media/video/bt8xx/bt848.h b/drivers/media/video/bt8xx/bt848.h index 0bcd95303bb0..c37e6acffded 100644 --- a/drivers/media/video/bt8xx/bt848.h +++ b/drivers/media/video/bt8xx/bt848.h @@ -30,6 +30,10 @@ #ifndef PCI_DEVICE_ID_BT849 #define PCI_DEVICE_ID_BT849 0x351 #endif +#ifndef PCI_DEVICE_ID_FUSION879 +#define PCI_DEVICE_ID_FUSION879 0x36c +#endif + #ifndef PCI_DEVICE_ID_BT878 #define PCI_DEVICE_ID_BT878 0x36e #endif @@ -37,7 +41,6 @@ #define PCI_DEVICE_ID_BT879 0x36f #endif - /* Brooktree 848 registers */ #define BT848_DSTATUS 0x000 diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 5939021d8eba..ff2933ab705f 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -80,6 +80,8 @@ static void phytec_muxsel(struct bttv *btv, unsigned int input); static void gv800s_muxsel(struct bttv *btv, unsigned int input); static void gv800s_init(struct bttv *btv); +static void td3116_muxsel(struct bttv *btv, unsigned int input); + static int terratec_active_radio_upgrade(struct bttv *btv); static int tea5757_read(struct bttv *btv); static int tea5757_write(struct bttv *btv, int value); @@ -284,7 +286,8 @@ static struct CARD { { 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" }, { 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, { 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" }, + { 0x03116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 311" }, + { 0x06116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 611" }, { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" }, { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" }, { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" }, @@ -341,6 +344,7 @@ static struct CARD { { 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" }, { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" }, { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" }, + { 0x3116f200, BTTV_BOARD_TVT_TD3116, "Tongwei Video Technology TD-3116" }, { 0, -1, NULL } }; @@ -1526,10 +1530,10 @@ struct tvcard bttv_tvcards[] = { GPIO20,22,23: R30,R29,R28 */ }, - [BTTV_BOARD_SENSORAY311] = { + [BTTV_BOARD_SENSORAY311_611] = { /* Clay Kunz <ckunz@mail.arc.nasa.gov> */ - /* you must jumper JP5 for the card to work */ - .name = "Sensoray 311", + /* you must jumper JP5 for the 311 card (PC/104+) to work */ + .name = "Sensoray 311/611", .video_inputs = 5, /* .audio_inputs= 0, */ .svhs = 4, @@ -2879,6 +2883,16 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, }, + [BTTV_BOARD_TVT_TD3116] = { + .name = "Tongwei Video Technology TD-3116", + .video_inputs = 16, + .gpiomask = 0xc00ff, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), + .muxsel_hook = td3116_muxsel, + .svhs = NO_SVHS, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -3228,6 +3242,42 @@ static void geovision_muxsel(struct bttv *btv, unsigned int input) gpio_bits(0xf, inmux); } +/* + * The TD3116 has 2 74HC4051 muxes wired to the MUX0 input of a bt878. + * The first 74HC4051 has the lower 8 inputs, the second one the higher 8. + * The muxes are controlled via a 74HC373 latch which is connected to + * GPIOs 0-7. GPIO 18 is connected to the LE signal of the latch. + * Q0 of the latch is connected to the Enable (~E) input of the first + * 74HC4051. Q1 - Q3 are connected to S0 - S2 of the same 74HC4051. + * Q4 - Q7 are connected to the second 74HC4051 in the same way. + */ + +static void td3116_latch_value(struct bttv *btv, u32 value) +{ + gpio_bits((1<<18) | 0xff, value); + gpio_bits((1<<18) | 0xff, (1<<18) | value); + udelay(1); + gpio_bits((1<<18) | 0xff, value); +} + +static void td3116_muxsel(struct bttv *btv, unsigned int input) +{ + u32 value; + u32 highbit; + + highbit = (input & 0x8) >> 3 ; + + /* Disable outputs and set value in the mux */ + value = 0x11; /* Disable outputs */ + value |= ((input & 0x7) << 1) << (4 * highbit); + td3116_latch_value(btv, value); + + /* Enable the correct output */ + value &= ~0x11; + value |= ((highbit ^ 0x1) << 4) | highbit; + td3116_latch_value(btv, value); +} + /* ----------------------------------------------------------------------- */ static void bttv_reset_audio(struct bttv *btv) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 3dd06607aec2..76c301f05095 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -4572,6 +4572,7 @@ static struct pci_device_id bttv_pci_tbl[] = { {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 0}, {0,} }; diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index e3952af7e56e..580c8e682392 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -346,7 +346,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int __devinit init_bttv_i2c(struct bttv *btv) { strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE); diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index c6333595c6b9..c5171619ac79 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -96,7 +96,7 @@ #define BTTV_BOARD_PV_BT878P_PLUS 0x46 #define BTTV_BOARD_FLYVIDEO98EZ 0x47 #define BTTV_BOARD_PV_BT878P_9B 0x48 -#define BTTV_BOARD_SENSORAY311 0x49 +#define BTTV_BOARD_SENSORAY311_611 0x49 #define BTTV_BOARD_RV605 0x4a #define BTTV_BOARD_POWERCLR_MTV878 0x4b #define BTTV_BOARD_WINDVR 0x4c @@ -183,6 +183,7 @@ #define BTTV_BOARD_GEOVISION_GV800S 0x9d #define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e #define BTTV_BOARD_PV183 0x9f +#define BTTV_BOARD_TVT_TD3116 0xa0 /* more card-specific defines */ diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index cd8ff0473184..fda32f52554a 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -72,7 +72,7 @@ struct qcam { static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; static int probe = 2; -static int force_rgb; +static bool force_rgb; static int video_nr = -1; /* FIXME: parport=auto would never have worked, surely? --RR */ diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 5909f2557ab4..1d64af9adf71 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -31,7 +31,7 @@ MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index d93e5ab45fd3..51c5b9ad67d8 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -35,7 +35,7 @@ MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index c6ff32a6137c..349bd9c2aff5 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -75,7 +75,7 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static unsigned cardtype_c = 1; static unsigned tuner_c = 1; -static unsigned radio_c = 1; +static bool radio_c = 1; static char pal[] = "--"; static char secam[] = "--"; static char ntsc[] = "-"; diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 14cb961c22bd..4bfd865a4106 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -751,20 +751,10 @@ int cx18_v4l2_close(struct file *filp) CX18_DEBUG_IOCTL("close() of %s\n", s->name); - v4l2_fh_del(fh); - v4l2_fh_exit(fh); - - /* Easy case first: this stream was never claimed by us */ - if (s->id != id->open_id) { - kfree(id); - return 0; - } - - /* 'Unclaim' this stream */ - - /* Stop radio */ mutex_lock(&cx->serialize_lock); - if (id->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Stop radio */ + if (id->type == CX18_ENC_STREAM_TYPE_RAD && + v4l2_fh_is_singular_file(filp)) { /* Closing radio device, return to TV mode */ cx18_mute(cx); /* Mark that the radio is no longer in use */ @@ -781,10 +771,14 @@ int cx18_v4l2_close(struct file *filp) } /* Done! Unmute and continue. */ cx18_unmute(cx); - cx18_release_stream(s); - } else { - cx18_stop_capture(id, 0); } + + v4l2_fh_del(fh); + v4l2_fh_exit(fh); + + /* 'Unclaim' this stream */ + if (s->id == id->open_id) + cx18_stop_capture(id, 0); kfree(id); mutex_unlock(&cx->serialize_lock); return 0; @@ -810,21 +804,15 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) item->open_id = cx->open_id++; filp->private_data = &item->fh; + v4l2_fh_add(&item->fh); - if (item->type == CX18_ENC_STREAM_TYPE_RAD) { - /* Try to claim this stream */ - if (cx18_claim_stream(item, item->type)) { - /* No, it's already in use */ - v4l2_fh_exit(&item->fh); - kfree(item); - return -EBUSY; - } - + if (item->type == CX18_ENC_STREAM_TYPE_RAD && + v4l2_fh_is_singular_file(filp)) { if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { if (atomic_read(&cx->ana_capturing) > 0) { /* switching to radio while capture is in progress is not polite */ - cx18_release_stream(s); + v4l2_fh_del(&item->fh); v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; @@ -842,7 +830,6 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) /* Done! Unmute and continue. */ cx18_unmute(cx); } - v4l2_fh_add(&item->fh); return 0; } diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index 040aaa87579d..51609d5c88ce 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -232,7 +232,7 @@ static struct i2c_algo_bit_data cx18_i2c_algo_template = { .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ }; -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int init_cx18_i2c(struct cx18 *cx) { int i, err; diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h index bdfd1921e300..1180fdc8d983 100644 --- a/drivers/media/video/cx18/cx18-i2c.h +++ b/drivers/media/video/cx18/cx18-i2c.h @@ -24,6 +24,6 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx); struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw); -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int init_cx18_i2c(struct cx18 *cx); void exit_cx18_i2c(struct cx18 *cx); diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig index ae85a7a7bd73..446f692aabb7 100644 --- a/drivers/media/video/cx231xx/Kconfig +++ b/drivers/media/video/cx231xx/Kconfig @@ -40,10 +40,10 @@ config VIDEO_CX231XX_ALSA config VIDEO_CX231XX_DVB tristate "DVB/ATSC Support for Cx231xx based TV cards" - depends on VIDEO_CX231XX && DVB_CORE + depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS select VIDEOBUF_DVB - select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE select DVB_MB86A20S if !DVB_FE_CUSTOMISE ---help--- diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c index 30d13c15739a..a2c2b7d343ec 100644 --- a/drivers/media/video/cx231xx/cx231xx-audio.c +++ b/drivers/media/video/cx231xx/cx231xx-audio.c @@ -111,6 +111,9 @@ static void cx231xx_audio_isocirq(struct urb *urb) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; + if (dev->state & DEV_DISCONNECTED) + return; + switch (urb->status) { case 0: /* success */ case -ETIMEDOUT: /* NAK */ @@ -196,6 +199,9 @@ static void cx231xx_audio_bulkirq(struct urb *urb) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; + if (dev->state & DEV_DISCONNECTED) + return; + switch (urb->status) { case 0: /* success */ case -ETIMEDOUT: /* NAK */ @@ -273,6 +279,9 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__); + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { @@ -298,7 +307,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvisocpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->interval = 1; urb->complete = cx231xx_audio_isocirq; @@ -331,6 +340,9 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__); + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { @@ -356,7 +368,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvbulkpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->complete = cx231xx_audio_bulkirq; urb->transfer_buffer_length = sb_size; @@ -432,6 +444,11 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) return -ENODEV; } + if (dev->state & DEV_DISCONNECTED) { + cx231xx_errdev("Can't open. the device was removed.\n"); + return -ENODEV; + } + /* Sets volume, mute, etc */ dev->mute = 0; @@ -571,6 +588,9 @@ static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream, struct cx231xx *dev = snd_pcm_substream_chip(substream); int retval; + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + spin_lock(&dev->adev.slock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 60b021e79864..875a7ce94736 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -843,25 +843,34 @@ void cx231xx_release_resources(struct cx231xx *dev) cx231xx_remove_from_devlist(dev); + cx231xx_ir_exit(dev); + /* Release I2C buses */ cx231xx_dev_uninit(dev); - cx231xx_ir_exit(dev); + /* delete v4l2 device */ + v4l2_device_unregister(&dev->v4l2_dev); usb_put_dev(dev->udev); /* Mark device as unused */ - cx231xx_devused &= ~(1 << dev->devno); + clear_bit(dev->devno, &cx231xx_devused); + + kfree(dev->video_mode.alt_max_pkt_size); + kfree(dev->vbi_mode.alt_max_pkt_size); + kfree(dev->sliced_cc_mode.alt_max_pkt_size); + kfree(dev->ts1_mode.alt_max_pkt_size); + kfree(dev); + dev = NULL; } /* * cx231xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device */ -static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev, +static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, int minor) { - struct cx231xx *dev = *devhandle; int retval = -ENOMEM; int errCode; unsigned int maxh, maxw; @@ -1016,7 +1025,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, int i, isoc_pipe = 0; char *speed; char descr[255] = ""; - struct usb_interface *lif = NULL; struct usb_interface_assoc_descriptor *assoc_desc; udev = usb_get_dev(interface_to_usbdev(interface)); @@ -1030,21 +1038,21 @@ static int cx231xx_usb_probe(struct usb_interface *interface, return -ENODEV; /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); - cx231xx_devused |= 1 << nr; - - if (nr >= CX231XX_MAXBOARDS) { - cx231xx_err(DRIVER_NAME - ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS); - cx231xx_devused &= ~(1 << nr); - return -ENOMEM; - } + do { + nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); + if (nr >= CX231XX_MAXBOARDS) { + /* No free device slots */ + cx231xx_err(DRIVER_NAME ": Supports only %i devices.\n", + CX231XX_MAXBOARDS); + return -ENOMEM; + } + } while (test_and_set_bit(nr, &cx231xx_devused)); /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { cx231xx_err(DRIVER_NAME ": out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(nr, &cx231xx_devused); return -ENOMEM; } @@ -1071,9 +1079,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, /* init CIR module TBD */ - /* store the current interface */ - lif = interface; - /*mode_tv: digital=1 or analog=0*/ dev->mode_tv = 0; @@ -1113,9 +1118,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, le16_to_cpu(udev->descriptor.idProduct), dev->max_iad_interface_count); - /* store the interface 0 back */ - lif = udev->actconfig->interface[0]; - /* increment interface count */ dev->interface_count++; @@ -1126,7 +1128,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (assoc_desc->bFirstInterface != ifnum) { cx231xx_err(DRIVER_NAME ": Not found " "matching IAD interface\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); kfree(dev); dev = NULL; return -ENODEV; @@ -1135,7 +1137,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, cx231xx_info("registering interface %d\n", ifnum); /* save our data pointer in this interface device */ - usb_set_intfdata(lif, dev); + usb_set_intfdata(interface, dev); /* * AV device initialization - only done at the last interface @@ -1145,19 +1147,19 @@ static int cx231xx_usb_probe(struct usb_interface *interface, retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); if (retval) { cx231xx_errdev("v4l2_device_register failed\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); kfree(dev); dev = NULL; return -EIO; } /* allocate device struct */ - retval = cx231xx_init_dev(&dev, udev, nr); + retval = cx231xx_init_dev(dev, udev, nr); if (retval) { - cx231xx_devused &= ~(1 << dev->devno); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; - usb_set_intfdata(lif, NULL); + usb_set_intfdata(interface, NULL); return retval; } @@ -1178,7 +1180,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->video_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1212,7 +1214,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->vbi_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1247,7 +1249,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1283,7 +1285,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->ts1_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1334,10 +1336,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) if (!dev->udev) return; - flush_request_modules(dev); + dev->state |= DEV_DISCONNECTED; - /* delete v4l2 device */ - v4l2_device_unregister(&dev->v4l2_dev); + flush_request_modules(dev); /* wait until all current v4l2 io is finished then deallocate resources */ @@ -1351,31 +1352,24 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) "deallocation are deferred on close.\n", video_device_node_name(dev->vdev)); - dev->state |= DEV_MISCONFIGURED; + /* Even having users, it is safe to remove the RC i2c driver */ + cx231xx_ir_exit(dev); + if (dev->USE_ISO) cx231xx_uninit_isoc(dev); else cx231xx_uninit_bulk(dev); - dev->state |= DEV_DISCONNECTED; wake_up_interruptible(&dev->wait_frame); wake_up_interruptible(&dev->wait_stream); } else { - dev->state |= DEV_DISCONNECTED; - cx231xx_release_resources(dev); } cx231xx_close_extension(dev); mutex_unlock(&dev->lock); - if (!dev->users) { - kfree(dev->video_mode.alt_max_pkt_size); - kfree(dev->vbi_mode.alt_max_pkt_size); - kfree(dev->sliced_cc_mode.alt_max_pkt_size); - kfree(dev->ts1_mode.alt_max_pkt_size); - kfree(dev); - dev = NULL; - } + if (!dev->users) + cx231xx_release_resources(dev); } static struct usb_driver cx231xx_usb_driver = { diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c index d4457f9488ee..08dd930f882a 100644 --- a/drivers/media/video/cx231xx/cx231xx-core.c +++ b/drivers/media/video/cx231xx/cx231xx-core.c @@ -166,6 +166,9 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus, u8 _i2c_nostop = 0; u8 _i2c_reserve = 0; + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + /* Get the I2C period, nostop and reserve parameters */ _i2c_period = i2c_bus->i2c_period; _i2c_nostop = i2c_bus->i2c_nostop; @@ -1071,7 +1074,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, sb_size, cx231xx_isoc_irq_callback, dma_q, 1); urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; k = 0; for (j = 0; j < max_packets; j++) { @@ -1182,7 +1185,7 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, return -ENOMEM; } dev->video_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; dev->video_mode.bulk_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c index da9a4a0aab79..7c4e360ba9bc 100644 --- a/drivers/media/video/cx231xx/cx231xx-dvb.c +++ b/drivers/media/video/cx231xx/cx231xx-dvb.c @@ -196,7 +196,7 @@ static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -228,7 +228,7 @@ static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c index 45e14cac4622..96176e9db5a2 100644 --- a/drivers/media/video/cx231xx/cx231xx-input.c +++ b/drivers/media/video/cx231xx/cx231xx-input.c @@ -27,12 +27,16 @@ static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { + int rc; u8 cmd, scancode; dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__); /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &cmd, 1)) + rc = i2c_master_recv(ir->c, &cmd, 1); + if (rc < 0) + return rc; + if (rc != 1) return -EIO; /* it seems that 0xFE indicates that a button is still hold @@ -102,11 +106,14 @@ int cx231xx_ir_init(struct cx231xx *dev) ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master; dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n", ir_i2c_bus, info.addr); - i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info); + dev->ir_i2c_client = i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info); return 0; } void cx231xx_ir_exit(struct cx231xx *dev) { + if (dev->ir_i2c_client) + i2c_unregister_device(dev->ir_i2c_client); + dev->ir_i2c_client = NULL; } diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c index 1c7a4daafecf..8cdee5f78f13 100644 --- a/drivers/media/video/cx231xx/cx231xx-vbi.c +++ b/drivers/media/video/cx231xx/cx231xx-vbi.c @@ -93,7 +93,7 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -452,7 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, return -ENOMEM; } dev->vbi_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; dev->vbi_mode.bulk_ctl.transfer_buffer[i] = kzalloc(sb_size, GFP_KERNEL); diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index 6e81f970dc7d..829a41b0c9ef 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -337,7 +337,7 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -440,7 +440,7 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -1000,12 +1000,6 @@ static int check_dev(struct cx231xx *dev) cx231xx_errdev("v4l2 ioctl: device not present\n"); return -ENODEV; } - - if (dev->state & DEV_MISCONFIGURED) { - cx231xx_errdev("v4l2 ioctl: device is misconfigured; " - "close and open it again\n"); - return -EIO; - } return 0; } @@ -2347,7 +2341,8 @@ static int cx231xx_v4l2_close(struct file *filp) return 0; } - if (dev->users == 1) { + dev->users--; + if (!dev->users) { videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); @@ -2374,7 +2369,6 @@ static int cx231xx_v4l2_close(struct file *filp) cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); } kfree(fh); - dev->users--; wake_up_interruptible_nr(&dev->open, 1); return 0; } diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 2000bc64c497..e17447554a0d 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -377,7 +377,6 @@ struct cx231xx_board { enum cx231xx_dev_state { DEV_INITIALIZED = 0x01, DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, }; enum AFE_MODE { @@ -621,6 +620,7 @@ struct cx231xx { /* For I2C IR support */ struct IR_i2c_init_data init_data; + struct i2c_client *ir_i2c_client; unsigned int stream_on:1; /* Locks streams */ unsigned int vbi_stream_on:1; /* Locks streams for VBI */ diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 67c4a59bd882..f5c79e53e5a1 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -900,6 +900,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) int i, retval = 0; u32 value = 0; u32 gpio_output = 0; + u32 gpio_value; u32 checksum = 0; u32 *dataptr; @@ -907,7 +908,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) /* Save GPIO settings before reset of APU */ retval |= mc417_memory_read(dev, 0x9020, &gpio_output); - retval |= mc417_memory_read(dev, 0x900C, &value); + retval |= mc417_memory_read(dev, 0x900C, &gpio_value); retval = mc417_register_write(dev, IVTV_REG_VPU, 0xFFFFFFED); @@ -991,11 +992,18 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) /* F/W power up disturbs the GPIOs, restore state */ retval |= mc417_register_write(dev, 0x9020, gpio_output); - retval |= mc417_register_write(dev, 0x900C, value); + retval |= mc417_register_write(dev, 0x900C, gpio_value); retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); + /* Hardcoded GPIO's here */ + retval |= mc417_register_write(dev, 0x9020, 0x4000); + retval |= mc417_register_write(dev, 0x900C, 0x4000); + + mc417_register_read(dev, 0x9020, &gpio_output); + mc417_register_read(dev, 0x900C, &gpio_value); + if (retval < 0) printk(KERN_ERR "%s: Error with mc417_register_write\n", __func__); @@ -1015,6 +1023,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __func__); + /* Dynamically change the height based on video standard */ + if (dev->encodernorm.id & V4L2_STD_525_60) + dev->ts1.height = 480; + else + dev->ts1.height = 576; + /* assign frame size */ cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, dev->ts1.height, dev->ts1.width); @@ -1030,7 +1044,7 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); } -static int cx23885_initialize_codec(struct cx23885_dev *dev) +static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) { int version; int retval; @@ -1112,9 +1126,11 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev) mc417_memory_write(dev, 2120, 0x00000080); /* start capturing to the host interface */ - cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, - CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); - msleep(10); + if (startencoder) { + cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, + CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); + msleep(10); + } return 0; } @@ -1196,6 +1212,16 @@ static int cx23885_querymenu(struct cx23885_dev *dev, cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + call_all(dev, core, g_std, id); + + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx23885_fh *fh = file->private_data; @@ -1208,55 +1234,31 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) if (i == ARRAY_SIZE(cx23885_tvnorms)) return -EINVAL; dev->encodernorm = cx23885_tvnorms[i]; + + /* Have the drier core notify the subdevices */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, *id); + mutex_unlock(&dev->lock); + return 0; } static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) + struct v4l2_input *i) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_input *input; - int n; - - if (i->index >= 4) - return -EINVAL; - - input = &cx23885_boards[dev->board].input[i->index]; - - if (input->type == 0) - return -EINVAL; - - /* FIXME - * strcpy(i->name, input->name); */ - strcpy(i->name, "unset"); - - if (input->type == CX23885_VMUX_TELEVISION || - input->type == CX23885_VMUX_CABLE) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++) - i->std |= cx23885_tvnorms[n].id; - return 0; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + return cx23885_enum_input(dev, i); } static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - *i = dev->input; - return 0; + return cx23885_get_input(file, priv, i); } static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { - if (i >= 4) - return -EINVAL; - - return 0; + return cx23885_set_input(file, priv, i); } static int vidioc_g_tuner(struct file *file, void *priv, @@ -1309,43 +1311,25 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - - dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n", - dev->tuner_type); - dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n", - f->tuner, f->type); - if (UNSET == dev->tuner_type) - return -EINVAL; - if (f->tuner != 0) - return -EINVAL; - if (f->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - dev->freq = f->frequency; - - call_all(dev, tuner, s_frequency, f); + return cx23885_set_frequency(file, priv, f); +} - cx23885_initialize_codec(dev); +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - return 0; + return cx23885_get_control(dev, ctl); } static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) + struct v4l2_control *ctl) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - /* Update the A/V core */ - call_all(dev, core, s_ctrl, ctl); - return 0; + return cx23885_set_control(dev, ctl); } static int vidioc_querycap(struct file *file, void *priv, @@ -1636,7 +1620,7 @@ static ssize_t mpeg_read(struct file *file, char __user *data, /* Start mpeg encoder on first read. */ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx23885_initialize_codec(dev) < 0) + if (cx23885_initialize_codec(dev, 1) < 0) return -EINVAL; } } @@ -1677,6 +1661,8 @@ static struct v4l2_file_operations mpeg_fops = { }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { + .vidioc_querystd = vidioc_g_std, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1686,6 +1672,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1746,8 +1733,8 @@ static struct video_device *cx23885_video_dev_alloc( if (NULL == vfd) return NULL; *vfd = *template; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, - type, cx23885_boards[tsport->dev->board].name); + snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", + cx23885_boards[tsport->dev->board].name, type); vfd->parent = &pci->dev; vfd->release = video_device_release; return vfd; @@ -1791,5 +1778,11 @@ int cx23885_417_register(struct cx23885_dev *dev) printk(KERN_INFO "%s: registered device %s [mpeg]\n", dev->name, video_device_node_name(dev->v4l_device)); + /* ST: Configure the encoder paramaters, but don't begin + * encoding, this resolves an issue where the first time the + * encoder is started video can be choppy. + */ + cx23885_initialize_codec(dev, 0); + return 0; } diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index c3cf08945e4c..19b5499d2624 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -213,8 +213,8 @@ struct cx23885_board cx23885_boards[] = { .portc = CX23885_MPEG_DVB, .tuner_type = TUNER_XC4000, .tuner_addr = 0x61, - .radio_type = TUNER_XC4000, - .radio_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, .input = {{ .type = CX23885_VMUX_TELEVISION, .vmux = CX25840_VIN2_CH1 | @@ -335,8 +335,33 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1850] = { .name = "Hauppauge WinTV-HVR1850", + .porta = CX23885_ANALOG_VIDEO, .portb = CX23885_MPEG_ENCODER, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x42, /* 0x84 >> 1 */ + .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1 | + CX25840_DIF_ON, + .amux = CX25840_AUDIO8, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + } }, }, [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = { .name = "Compro VideoMate E800", @@ -438,6 +463,41 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0, } }, }, + [CX23885_BOARD_MYGICA_X8507] = { + .name = "Mygica X8507", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_bus = 1, + .porta = CX23885_ANALOG_VIDEO, + .input = { + { + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_COMPOSITE2, + .amux = CX25840_AUDIO8, + }, + { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE8, + }, + { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + }, + { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_COMPONENT_ON | + CX25840_VIN1_CH1 | + CX25840_VIN6_CH2 | + CX25840_VIN7_CH3, + }, + }, + }, + [CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL] = { + .name = "TerraTec Cinergy T PCIe Dual", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + } }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -637,6 +697,14 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x1b55, .subdevice = 0xe2e4, .card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF, + }, { + .subvendor = 0x14f1, + .subdevice = 0x8502, + .card = CX23885_BOARD_MYGICA_X8507, + }, { + .subvendor = 0x153b, + .subdevice = 0x117e, + .card = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1068,6 +1136,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) break; case CX23885_BOARD_MYGICA_X8506: case CX23885_BOARD_MAGICPRO_PROHDTVE2: + case CX23885_BOARD_MYGICA_X8507: /* GPIO-0 (0)Analog / (1)Digital TV */ /* GPIO-1 reset XC5000 */ /* GPIO-2 reset LGS8GL5 / LGS8G75 */ @@ -1367,6 +1436,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1800: /* Defaults for VID B - Analog encoder */ /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */ @@ -1377,6 +1447,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) /* APB_TSVALERR_POL (active low)*/ ts1->vld_misc_val = 0x2000; ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc); + cx_write(0x130184, 0xc); /* Defaults for VID C */ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ @@ -1396,6 +1467,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) break; case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; @@ -1431,7 +1503,6 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1210: - case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: @@ -1468,6 +1539,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_MPX885: + case CX23885_BOARD_MYGICA_X8507: + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 40e68b22015e..6ad227029a0f 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -206,12 +206,12 @@ static struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA1_CNT2, }, [SRAM_CH02] = { - .name = "ch2", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "VID A (VBI)", + .cmds_start = 0x10050, + .ctrl_start = 0x105F0, + .cdt = 0x10810, + .fifo_start = 0x3000, + .fifo_size = 0x1000, .ptr1_reg = DMA2_PTR1, .ptr2_reg = DMA2_PTR2, .cnt1_reg = DMA2_CNT1, @@ -266,12 +266,12 @@ static struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA5_CNT2, }, [SRAM_CH07] = { - .name = "ch7", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TV Audio", + .cmds_start = 0x10190, + .ctrl_start = 0x106B0, + .cdt = 0x10930, + .fifo_start = 0x7000, + .fifo_size = 0x1000, .ptr1_reg = DMA6_PTR1, .ptr2_reg = DMA6_PTR2, .cnt1_reg = DMA6_CNT1, diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index bcb45be44bb2..6835eb1fc093 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -61,6 +61,8 @@ #include "cx23885-f300.h" #include "altera-ci.h" #include "stv0367.h" +#include "drxk.h" +#include "mt2063.h" static unsigned int debug; @@ -111,6 +113,8 @@ static void dvb_buf_release(struct videobuf_queue *q, cx23885_free_buffer(q, (struct cx23885_buffer *)vb); } +static int cx23885_dvb_set_frontend(struct dvb_frontend *fe); + static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) { struct videobuf_dvb_frontends *f; @@ -125,6 +129,12 @@ static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); + + /* + * FIXME: Improve this path to avoid calling the + * cx23885_dvb_set_frontend() every time it passes here. + */ + cx23885_dvb_set_frontend(fe->dvb.frontend); } static struct videobuf_queue_ops dvb_qops = { @@ -479,15 +489,15 @@ static struct xc5000_config mygica_x8506_xc5000_config = { .if_khz = 5380, }; -static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1275: - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: cx23885_gpio_clear(dev, GPIO_5); break; @@ -507,31 +517,6 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, return 0; } -static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe, - unsigned int cmd, void *parg, - unsigned int stage) -{ - int err = 0; - - switch (stage) { - case DVB_FE_IOCTL_PRE: - - switch (cmd) { - case FE_SET_FRONTEND: - err = cx23885_dvb_set_frontend(fe, - (struct dvb_frontend_parameters *) parg); - break; - } - break; - - case DVB_FE_IOCTL_POST: - /* no post-ioctl handling required */ - break; - } - return err; -}; - - static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { .prod = LGS8GXX_PROD_LGS8G75, .demod_address = 0x19, @@ -617,6 +602,24 @@ static struct xc5000_config netup_xc5000_config[] = { }, }; +static struct drxk_config terratec_drxk_config[] = { + { + .adr = 0x29, + .no_i2c_bridge = 1, + }, { + .adr = 0x2a, + .no_i2c_bridge = 1, + }, +}; + +static struct mt2063_config terratec_mt2063_config[] = { + { + .tuner_address = 0x60, + }, { + .tuner_address = 0x67, + }, +}; + int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -940,6 +943,11 @@ static int dvb_register(struct cx23885_tsport *port) fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->i2c_bus[1].i2c_adap, &cfg); + if (!fe) { + printk(KERN_ERR "%s/2: xc4000 attach failed\n", + dev->name); + goto frontend_detach; + } } break; case CX23885_BOARD_TBS_6920: @@ -1043,6 +1051,20 @@ static int dvb_register(struct cx23885_tsport *port) } break; case CX23885_BOARD_HAUPPAUGE_HVR1850: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[0].i2c_adap, + &hauppauge_tda18271_config); + + tda18271_attach(&dev->ts1.analog_fe, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + + break; case CX23885_BOARD_HAUPPAUGE_HVR1290: i2c_bus = &dev->i2c_bus[0]; fe0->dvb.frontend = dvb_attach(s5h1411_attach, @@ -1118,6 +1140,39 @@ static int dvb_register(struct cx23885_tsport *port) goto frontend_detach; } break; + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + + switch (port->nr) { + /* port b */ + case 1: + fe0->dvb.frontend = dvb_attach(drxk_attach, + &terratec_drxk_config[0], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(mt2063_attach, + fe0->dvb.frontend, + &terratec_mt2063_config[0], + &i2c_bus2->i2c_adap)) + goto frontend_detach; + } + break; + /* port c */ + case 2: + fe0->dvb.frontend = dvb_attach(drxk_attach, + &terratec_drxk_config[1], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(mt2063_attach, + fe0->dvb.frontend, + &terratec_mt2063_config[1], + &i2c_bus2->i2c_adap)) + goto frontend_detach; + } + break; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", @@ -1151,7 +1206,7 @@ static int dvb_register(struct cx23885_tsport *port) /* register everything */ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, &dev->pci->dev, adapter_nr, mfe_shared, - cx23885_dvb_fe_ioctl_override); + NULL); if (ret) goto frontend_detach; diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 0ff7a9e98f3e..be1e21d8295c 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -309,7 +309,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int cx23885_i2c_register(struct cx23885_i2c *bus) { struct cx23885_dev *dev = bus->dev; diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index e730b9263016..c654bdc7ccb2 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -253,9 +253,9 @@ static struct cx23885_ctrl cx23885_ctls[] = { .id = V4L2_CID_AUDIO_VOLUME, .name = "Volume", .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, + .maximum = 65535, + .step = 65535 / 100, + .default_value = 65535, .type = V4L2_CTRL_TYPE_INTEGER, }, .reg = PATH1_VOL_CTL, @@ -316,7 +316,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, __func__, bc); } -static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) +int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) { dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", __func__, @@ -344,8 +344,8 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, cx23885_boards[dev->board].name); + snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", + cx23885_boards[dev->board].name, type); video_set_drvdata(vfd, dev); return vfd; } @@ -492,7 +492,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) dev->input = input; if (dev->board == CX23885_BOARD_MYGICA_X8506 || - dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) { + dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2 || + dev->board == CX23885_BOARD_MYGICA_X8507) { /* Select Analog TV */ if (INPUT(input)->type == CX23885_VMUX_TELEVISION) cx23885_gpio_clear(dev, GPIO_0); @@ -503,7 +504,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) INPUT(input)->vmux, 0, 0); if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || - (dev->board == CX23885_BOARD_MPX885)) { + (dev->board == CX23885_BOARD_MPX885) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, INPUT(input)->amux, 0, 0); @@ -649,6 +651,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, int rc, init_buffer = 0; u32 line0_offset, line1_offset; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + int field_tff; BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || @@ -690,15 +693,25 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) { + if (dev->tvnorm & V4L2_STD_NTSC) + /* NTSC or */ + field_tff = 1; + else + field_tff = 0; + + if (cx23885_boards[dev->board].force_bff) + /* PAL / SECAM OR 888 in NTSC MODE */ + field_tff = 0; + + if (field_tff) { /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating NTSC risc\n", + dprintk(1, "%s() Creating TFF/NTSC risc\n", __func__); line0_offset = buf->bpl; line1_offset = 0; } else { /* All other formats are top field first */ - dprintk(1, "%s() Creating PAL/SECAM risc\n", + dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", __func__); line0_offset = 0; line1_offset = buf->bpl; @@ -981,6 +994,8 @@ static int video_release(struct file *file) } videobuf_mmap_free(&fh->vidq); + videobuf_mmap_free(&fh->vbiq); + file->private_data = NULL; kfree(fh); @@ -1002,7 +1017,7 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) /* ------------------------------------------------------------------ */ /* VIDEO CTRL IOCTLS */ -static int cx23885_get_control(struct cx23885_dev *dev, +int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); @@ -1010,7 +1025,7 @@ static int cx23885_get_control(struct cx23885_dev *dev, return 0; } -static int cx23885_set_control(struct cx23885_dev *dev, +int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); @@ -1229,6 +1244,16 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return 0; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + + call_all(dev, core, g_std, id); + + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1241,7 +1266,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) return 0; } -static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) +int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) { static const char *iname[] = { [CX23885_VMUX_COMPOSITE1] = "Composite1", @@ -1278,6 +1303,15 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) if (INPUT(n)->type != CX23885_VMUX_TELEVISION) i->audioset = 0x3; + if (dev->input == n) { + /* enum'd input matches our configured input. + * Ask the video decoder to process the call + * and give it an oppertunity to update the + * status field. + */ + call_all(dev, video, g_input_status, &i->status); + } + return 0; } @@ -1289,7 +1323,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return cx23885_enum_input(dev, i); } -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +int cx23885_get_input(struct file *file, void *priv, unsigned int *i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1298,7 +1332,12 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + return cx23885_get_input(file, priv, i); +} + +int cx23885_set_input(struct file *file, void *priv, unsigned int i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1322,6 +1361,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + return cx23885_set_input(file, priv, i); +} + static int vidioc_log_status(struct file *file, void *priv) { struct cx23885_fh *fh = priv; @@ -1329,11 +1373,11 @@ static int vidioc_log_status(struct file *file, void *priv) printk(KERN_INFO "%s/0: ============ START LOG STATUS ============\n", - dev->name); + dev->name); call_all(dev, core, log_status); printk(KERN_INFO "%s/0: ============= END LOG STATUS =============\n", - dev->name); + dev->name); return 0; } @@ -1471,6 +1515,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) { + struct v4l2_control ctrl; + if (unlikely(UNSET == dev->tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) @@ -1479,29 +1525,103 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) mutex_lock(&dev->lock); dev->freq = f->frequency; + /* I need to mute audio here */ + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = 1; + cx23885_set_control(dev, &ctrl); + call_all(dev, tuner, s_frequency, f); /* When changing channels it is required to reset TVAUDIO */ - msleep(10); + msleep(100); + + /* I need to unmute audio here */ + ctrl.value = 0; + cx23885_set_control(dev, &ctrl); mutex_unlock(&dev->lock); return 0; } -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) +static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, + struct v4l2_frequency *f) +{ + struct v4l2_control ctrl; + struct videobuf_dvb_frontend *vfe; + struct dvb_frontend *fe; + + struct analog_parameters params = { + .mode = V4L2_TUNER_ANALOG_TV, + .audmode = V4L2_TUNER_MODE_STEREO, + .std = dev->tvnorm, + .frequency = f->frequency + }; + + mutex_lock(&dev->lock); + dev->freq = f->frequency; + + /* I need to mute audio here */ + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = 1; + cx23885_set_control(dev, &ctrl); + + /* If HVR1850 */ + dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, + params.frequency, f->tuner, params.std); + + vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); + if (!vfe) { + mutex_unlock(&dev->lock); + return -EINVAL; + } + + fe = vfe->dvb.frontend; + + if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) + fe = &dev->ts1.analog_fe; + + if (fe && fe->ops.tuner_ops.set_analog_params) { + call_all(dev, core, s_std, dev->tvnorm); + fe->ops.tuner_ops.set_analog_params(fe, ¶ms); + } + else + printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); + + /* When changing channels it is required to reset TVAUDIO */ + msleep(100); + + /* I need to unmute audio here */ + ctrl.value = 0; + cx23885_set_control(dev, &ctrl); + + mutex_unlock(&dev->lock); + + return 0; +} + +int cx23885_set_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) { struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; + int ret; - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1850: + ret = cx23885_set_freq_via_ops(dev, f); + break; + default: + ret = cx23885_set_freq(dev, f); + } - return - cx23885_set_freq(dev, f); + return ret; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + return cx23885_set_frequency(file, priv, f); } /* ----------------------------------------------------------- */ @@ -1613,6 +1733,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, + .vidioc_querystd = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index b49036fe3ffd..f020f0568df4 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -87,6 +87,8 @@ #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31 #define CX23885_BOARD_MPX885 32 +#define CX23885_BOARD_MYGICA_X8507 33 +#define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 @@ -226,6 +228,8 @@ struct cx23885_board { u32 clk_freq; struct cx23885_input input[MAX_CX23885_INPUT]; int ci_type; /* for NetUP */ + /* Force bottom field first during DMA (888 workaround) */ + u32 force_bff; }; struct cx23885_subid { @@ -310,6 +314,9 @@ struct cx23885_tsport { u32 num_frontends; void (*gate_ctrl)(struct cx23885_tsport *port, int open); void *port_priv; + + /* Workaround for a temp dvb_frontend that the tuner can attached to */ + struct dvb_frontend analog_fe; }; struct cx23885_kernel_ir { @@ -574,6 +581,13 @@ extern void cx23885_video_unregister(struct cx23885_dev *dev); extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); extern void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count); +int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i); +int cx23885_set_input(struct file *file, void *priv, unsigned int i); +int cx23885_get_input(struct file *file, void *priv, unsigned int *i); +int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f); +int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl); +int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl); +int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); /* ----------------------------------------------------------- */ /* cx23885-vbi.c */ diff --git a/drivers/media/video/cx25821/cx25821-alsa.c b/drivers/media/video/cx25821/cx25821-alsa.c index 09e99de5fd21..03cfac476b03 100644 --- a/drivers/media/video/cx25821/cx25821-alsa.c +++ b/drivers/media/video/cx25821/cx25821-alsa.c @@ -102,7 +102,7 @@ struct cx25821_audio_dev { static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 }; +static bool enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 }; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled."); @@ -176,8 +176,7 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) /* Set the input mode to 16-bit */ tmp = cx_read(AUD_A_CFG); - cx_write(AUD_A_CFG, - tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE | + cx_write(AUD_A_CFG, tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE | FLD_AUD_CLK_ENABLE); /* @@ -188,9 +187,8 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) */ /* Enables corresponding bits at AUD_INT_STAT */ - cx_write(AUD_A_INT_MSK, - FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | FLD_AUD_DST_SYNC | - FLD_AUD_DST_OPC_ERR); + cx_write(AUD_A_INT_MSK, FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | + FLD_AUD_DST_SYNC | FLD_AUD_DST_OPC_ERR); /* Clean any pending interrupt bits already set */ cx_write(AUD_A_INT_STAT, ~0); @@ -200,8 +198,8 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) /* Turn on audio downstream fifo and risc enable 0x101 */ tmp = cx_read(AUD_INT_DMA_CTL); - cx_set(AUD_INT_DMA_CTL, - tmp | (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN)); + cx_set(AUD_INT_DMA_CTL, tmp | + (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN)); mdelay(100); return 0; @@ -220,9 +218,8 @@ static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip) /* disable irqs */ cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT); - cx_clear(AUD_A_INT_MSK, - AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 | - AUD_INT_DN_RISCI1); + cx_clear(AUD_A_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); return 0; } @@ -234,15 +231,15 @@ static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip) */ static char *cx25821_aud_irqs[32] = { "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ - NULL, /* reserved */ + NULL, /* reserved */ "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ - NULL, /* reserved */ - "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ - NULL, /* reserved */ - "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ - NULL, /* reserved */ - "opc_err", "par_err", "rip_err", /* 16-18 */ - "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ + NULL, /* reserved */ + "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ + NULL, /* reserved */ + "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ + NULL, /* reserved */ + "opc_err", "par_err", "rip_err", /* 16-18 */ + "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ }; /* @@ -258,10 +255,8 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status, cx_write(AUD_A_INT_STAT, status); if (debug > 1 || (status & mask & ~0xff)) - cx25821_print_irqbits(dev->name, "irq aud", - cx25821_aud_irqs, - ARRAY_SIZE(cx25821_aud_irqs), status, - mask); + cx25821_print_irqbits(dev->name, "irq aud", cx25821_aud_irqs, + ARRAY_SIZE(cx25821_aud_irqs), status, mask); /* risc op code error */ if (status & AUD_INT_OPC_ERR) { @@ -270,8 +265,7 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status, cx_clear(AUD_INT_DMA_CTL, FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); cx25821_sram_channel_dump_audio(dev, - &cx25821_sram_channels - [AUDIO_SRAM_CHANNEL]); + &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]); } if (status & AUD_INT_DN_SYNC) { pr_warn("WARNING %s: Downstream sync error!\n", dev->name); @@ -317,8 +311,9 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id) cx25821_aud_irq(chip, audint_status, audint_mask); break; - } else + } else { goto out; + } } handled = 1; @@ -361,9 +356,8 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip) */ #define DEFAULT_FIFO_SIZE 384 static struct snd_pcm_hardware snd_cx25821_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, @@ -396,8 +390,8 @@ static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream) return -ENODEV; } - err = - snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); + err = snd_pcm_hw_constraint_pow2(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) goto _error; @@ -468,8 +462,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, dma = &buf->dma; videobuf_dma_init(dma); ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, - (PAGE_ALIGN(chip->dma_size) >> - PAGE_SHIFT)); + (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); if (ret < 0) goto error; @@ -477,10 +470,8 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto error; - ret = - cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, - chip->period_size, chip->num_periods, - 1); + ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, + chip->period_size, chip->num_periods, 1); if (ret < 0) { pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n"); goto error; @@ -686,7 +677,7 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) } err = snd_card_create(index[devno], id[devno], THIS_MODULE, - sizeof(struct cx25821_audio_dev), &card); + sizeof(struct cx25821_audio_dev), &card); if (err < 0) { pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n", __func__); @@ -711,8 +702,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) IRQF_SHARED, chip->dev->name, chip); if (err < 0) { - pr_err("ERROR %s: can't get IRQ %d for ALSA\n", - chip->dev->name, dev->pci->irq); + pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name, + dev->pci->irq); goto error; } @@ -730,8 +721,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) chip->iobase, chip->irq); strcpy(card->mixername, "CX25821"); - pr_info("%s/%i: ALSA support for cx25821 boards\n", - card->driver, devno); + pr_info("%s/%i: ALSA support for cx25821 boards\n", card->driver, + devno); err = snd_card_register(card); if (err < 0) { diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.c b/drivers/media/video/cx25821/cx25821-audio-upstream.c index c20d6dece154..20c7ca3351a8 100644 --- a/drivers/media/video/cx25821/cx25821-audio-upstream.c +++ b/drivers/media/video/cx25821/cx25821-audio-upstream.c @@ -107,7 +107,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev, { unsigned int line; struct sram_channel *sram_ch = - dev->channels[dev->_audio_upstream_channel].sram_channels; + dev->channels[dev->_audio_upstream_channel].sram_channels; int offset = 0; /* scan lines */ @@ -175,10 +175,8 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, } rp = cx25821_risc_field_upstream_audio(dev, rp, - dev-> - _audiodata_buf_phys_addr - + databuf_offset, bpl, - fifo_enable); + dev->_audiodata_buf_phys_addr + databuf_offset, + bpl, fifo_enable); if (USE_RISC_NOOP_AUDIO) { for (i = 0; i < NUM_NO_OPS; i++) @@ -193,7 +191,7 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, /* Recalculate virtual address based on frame index */ rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 + - (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4); + (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4); } return 0; @@ -218,7 +216,7 @@ void cx25821_free_memory_audio(struct cx25821_dev *dev) void cx25821_stop_upstream_audio(struct cx25821_dev *dev) { struct sram_channel *sram_ch = - dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels; + dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels; u32 tmp = 0; if (!dev->_audio_is_running) { @@ -286,14 +284,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev, } else { if (!(myfile->f_op)) { pr_err("%s(): File has no file operations registered!\n", - __func__); + __func__); filp_close(myfile, NULL); return -EIO; } if (!myfile->f_op->read) { pr_err("%s(): File has no READ operations registered!\n", - __func__); + __func__); filp_close(myfile, NULL); return -EIO; } @@ -305,14 +303,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev, for (i = 0; i < dev->_audio_lines_count; i++) { pos = file_offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size && dev->_audiodata_buf_virt_addr != NULL) { memcpy((void *)(dev->_audiodata_buf_virt_addr + frame_offset / 4), mybuf, - vfs_read_retval); + vfs_read_retval); } file_offset += vfs_read_retval; @@ -328,8 +326,8 @@ int cx25821_get_audio_data(struct cx25821_dev *dev, if (i > 0) dev->_audioframe_count++; - dev->_audiofile_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_audiofile_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); filp_close(myfile, NULL); @@ -340,12 +338,12 @@ int cx25821_get_audio_data(struct cx25821_dev *dev, static void cx25821_audioups_handler(struct work_struct *work) { - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _audio_work_entry); + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _audio_work_entry); if (!dev) { pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", - __func__); + __func__); return; } @@ -370,19 +368,19 @@ int cx25821_openfile_audio(struct cx25821_dev *dev, if (IS_ERR(myfile)) { const int open_errno = -PTR_ERR(myfile); pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_audiofilename, open_errno); + __func__, dev->_audiofilename, open_errno); return PTR_ERR(myfile); } else { if (!(myfile->f_op)) { pr_err("%s(): File has no file operations registered!\n", - __func__); + __func__); filp_close(myfile, NULL); return -EIO; } if (!myfile->f_op->read) { pr_err("%s(): File has no READ operations registered!\n", - __func__); + __func__); filp_close(myfile, NULL); return -EIO; } @@ -395,12 +393,12 @@ int cx25821_openfile_audio(struct cx25821_dev *dev, for (i = 0; i < dev->_audio_lines_count; i++) { pos = offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); - if (vfs_read_retval > 0 - && vfs_read_retval == line_size - && dev->_audiodata_buf_virt_addr != NULL) { + if (vfs_read_retval > 0 && + vfs_read_retval == line_size && + dev->_audiodata_buf_virt_addr != NULL) { memcpy((void *)(dev-> _audiodata_buf_virt_addr + offset / 4), mybuf, @@ -423,8 +421,8 @@ int cx25821_openfile_audio(struct cx25821_dev *dev, break; } - dev->_audiofile_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_audiofile_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); myfile->f_pos = 0; @@ -444,9 +442,8 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, cx25821_free_memory_audio(dev); - dev->_risc_virt_addr = - pci_alloc_consistent(dev->pci, dev->audio_upstream_riscbuf_size, - &dma_addr); + dev->_risc_virt_addr = pci_alloc_consistent(dev->pci, + dev->audio_upstream_riscbuf_size, &dma_addr); dev->_risc_virt_start_addr = dev->_risc_virt_addr; dev->_risc_phys_start_addr = dma_addr; dev->_risc_phys_addr = dma_addr; @@ -454,22 +451,21 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, if (!dev->_risc_virt_addr) { printk(KERN_DEBUG - pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n")); + pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n")); return -ENOMEM; } /* Clear out memory at address */ memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size); /* For Audio Data buffer allocation */ - dev->_audiodata_buf_virt_addr = - pci_alloc_consistent(dev->pci, dev->audio_upstream_databuf_size, - &data_dma_addr); + dev->_audiodata_buf_virt_addr = pci_alloc_consistent(dev->pci, + dev->audio_upstream_databuf_size, &data_dma_addr); dev->_audiodata_buf_phys_addr = data_dma_addr; dev->_audiodata_buf_size = dev->audio_upstream_databuf_size; if (!dev->_audiodata_buf_virt_addr) { printk(KERN_DEBUG - pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n")); + pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n")); return -ENOMEM; } /* Clear out memory at address */ @@ -480,12 +476,11 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, return ret; /* Creating RISC programs */ - ret = - cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl, - dev->_audio_lines_count); + ret = cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl, + dev->_audio_lines_count); if (ret < 0) { printk(KERN_DEBUG - pr_fmt("ERROR creating audio upstream RISC programs!\n")); + pr_fmt("ERROR creating audio upstream RISC programs!\n")); goto error; } @@ -533,9 +528,9 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, if (dev->_risc_virt_start_addr != NULL) { risc_phys_jump_addr = - dev->_risc_phys_start_addr + - RISC_SYNC_INSTRUCTION_SIZE + - AUDIO_RISC_DMA_BUF_SIZE; + dev->_risc_phys_start_addr + + RISC_SYNC_INSTRUCTION_SIZE + + AUDIO_RISC_DMA_BUF_SIZE; rp = cx25821_risc_field_upstream_audio(dev, dev->_risc_virt_start_addr + 1, @@ -632,7 +627,7 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev, /* 10 millisecond timeout */ if (count++ > 1000) { pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n", - __func__); + __func__); return; } @@ -661,9 +656,9 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, /* Set the input mode to 16-bit */ tmp = cx_read(sram_ch->aud_cfg); - tmp |= - FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE | - FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | FLD_AUD_SONY_MODE; + tmp |= FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE | + FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | + FLD_AUD_SONY_MODE; cx_write(sram_ch->aud_cfg, tmp); /* Read and write back the interrupt status register to clear it */ @@ -678,12 +673,11 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, tmp = cx_read(sram_ch->int_msk); cx_write(sram_ch->int_msk, tmp |= _intr_msk); - err = - request_irq(dev->pci->irq, cx25821_upstream_irq_audio, + err = request_irq(dev->pci->irq, cx25821_upstream_irq_audio, IRQF_SHARED, dev->name, dev); if (err < 0) { - pr_err("%s: can't get upstream IRQ %d\n", - dev->name, dev->pci->irq); + pr_err("%s: can't get upstream IRQ %d\n", dev->name, + dev->pci->irq); goto fail_irq; } @@ -726,7 +720,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) if (!dev->_irq_audio_queues) { printk(KERN_DEBUG - pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n")); + pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n")); return -ENOMEM; } @@ -739,33 +733,30 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) if (dev->input_audiofilename) { str_length = strlen(dev->input_audiofilename); - dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL); + dev->_audiofilename = kmemdup(dev->input_audiofilename, + str_length + 1, GFP_KERNEL); if (!dev->_audiofilename) goto error; - memcpy(dev->_audiofilename, dev->input_audiofilename, - str_length + 1); - /* Default if filename is empty string */ if (strcmp(dev->input_audiofilename, "") == 0) dev->_audiofilename = "/root/audioGOOD.wav"; } else { str_length = strlen(_defaultAudioName); - dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL); + dev->_audiofilename = kmemdup(_defaultAudioName, + str_length + 1, GFP_KERNEL); if (!dev->_audiofilename) goto error; - - memcpy(dev->_audiofilename, _defaultAudioName, str_length + 1); } retval = cx25821_sram_channel_setup_upstream_audio(dev, sram_ch, _line_size, 0); dev->audio_upstream_riscbuf_size = - AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS + - RISC_SYNC_INSTRUCTION_SIZE; + AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS + + RISC_SYNC_INSTRUCTION_SIZE; dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS; /* Allocating buffers and prepare RISC program */ @@ -773,7 +764,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) _line_size); if (retval < 0) { pr_err("%s: Failed to set up Audio upstream buffers!\n", - dev->name); + dev->name); goto error; } /* Start RISC engine */ diff --git a/drivers/media/video/cx25821/cx25821-audio.h b/drivers/media/video/cx25821/cx25821-audio.h index 8eb55b7b88cb..1fc2d24f5110 100644 --- a/drivers/media/video/cx25821/cx25821-audio.h +++ b/drivers/media/video/cx25821/cx25821-audio.h @@ -23,39 +23,40 @@ #ifndef __CX25821_AUDIO_H__ #define __CX25821_AUDIO_H__ -#define USE_RISC_NOOP 1 -#define LINES_PER_BUFFER 15 -#define AUDIO_LINE_SIZE 128 +#define USE_RISC_NOOP 1 +#define LINES_PER_BUFFER 15 +#define AUDIO_LINE_SIZE 128 /* Number of buffer programs to use at once. */ -#define NUMBER_OF_PROGRAMS 8 +#define NUMBER_OF_PROGRAMS 8 /* * Max size of the RISC program for a buffer. - worst case is 2 writes per line * Space is also added for the 4 no-op instructions added on the end. */ #ifndef USE_RISC_NOOP -#define MAX_BUFFER_PROGRAM_SIZE \ - (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE * 4) +#define MAX_BUFFER_PROGRAM_SIZE \ + (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE * 4) #endif /* MAE 12 July 2005 Try to use NOOP RISC instruction instead */ #ifdef USE_RISC_NOOP -#define MAX_BUFFER_PROGRAM_SIZE \ - (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ - RISC_NOOP_INSTRUCTION_SIZE * 4) +#define MAX_BUFFER_PROGRAM_SIZE \ + (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ + RISC_NOOP_INSTRUCTION_SIZE * 4) #endif /* Sizes of various instructions in bytes. Used when adding instructions. */ -#define RISC_WRITE_INSTRUCTION_SIZE 12 -#define RISC_JUMP_INSTRUCTION_SIZE 12 -#define RISC_SKIP_INSTRUCTION_SIZE 4 -#define RISC_SYNC_INSTRUCTION_SIZE 4 -#define RISC_WRITECR_INSTRUCTION_SIZE 16 -#define RISC_NOOP_INSTRUCTION_SIZE 4 - -#define MAX_AUDIO_DMA_BUFFER_SIZE \ -(MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + RISC_SYNC_INSTRUCTION_SIZE) +#define RISC_WRITE_INSTRUCTION_SIZE 12 +#define RISC_JUMP_INSTRUCTION_SIZE 12 +#define RISC_SKIP_INSTRUCTION_SIZE 4 +#define RISC_SYNC_INSTRUCTION_SIZE 4 +#define RISC_WRITECR_INSTRUCTION_SIZE 16 +#define RISC_NOOP_INSTRUCTION_SIZE 4 + +#define MAX_AUDIO_DMA_BUFFER_SIZE \ + (MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + \ + RISC_SYNC_INSTRUCTION_SIZE) #endif diff --git a/drivers/media/video/cx25821/cx25821-cards.c b/drivers/media/video/cx25821/cx25821-cards.c index 6ace60313b49..99988c988095 100644 --- a/drivers/media/video/cx25821/cx25821-cards.c +++ b/drivers/media/video/cx25821/cx25821-cards.c @@ -67,6 +67,6 @@ void cx25821_card_setup(struct cx25821_dev *dev) if (dev->i2c_bus[0].i2c_rc == 0) { dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, - sizeof(eeprom)); + sizeof(eeprom)); } } diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c index a7fa38f9594e..f617474f9073 100644 --- a/drivers/media/video/cx25821/cx25821-core.c +++ b/drivers/media/video/cx25821/cx25821-core.c @@ -804,8 +804,8 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select, u32 format) { if (channel_select <= 7 && channel_select >= 0) { - cx_write(dev->channels[channel_select]. - sram_channels->pix_frmt, format); + cx_write(dev->channels[channel_select].sram_channels->pix_frmt, + format); dev->channels[channel_select].pixel_formats = format; } } @@ -855,21 +855,19 @@ static void cx25821_initialize(struct cx25821_dev *dev) } cx25821_sram_channel_setup_audio(dev, - dev->channels[SRAM_CH08].sram_channels, - 128, 0); + dev->channels[SRAM_CH08].sram_channels, 128, 0); cx25821_gpio_init(dev); } static int cx25821_get_resources(struct cx25821_dev *dev) { - if (request_mem_region - (pci_resource_start(dev->pci, 0), pci_resource_len(dev->pci, 0), - dev->name)) + if (request_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0), dev->name)) return 0; pr_err("%s: can't get MMIO memory @ 0x%llx\n", - dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); + dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); return -EBUSY; } @@ -972,8 +970,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0)); if (!dev->lmmio) { - CX25821_ERR - ("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n"); + CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n"); cx25821_iounmap(dev); return -ENOMEM; } @@ -994,7 +991,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) * cx25821_i2c_register(&dev->i2c_bus[2]); */ CX25821_INFO("i2c register! bus->i2c_rc = %d\n", - dev->i2c_bus[0].i2c_rc); + dev->i2c_bus[0].i2c_rc); cx25821_card_setup(dev); @@ -1004,9 +1001,8 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) cx25821_video_register(dev); /* register IOCTL device */ - dev->ioctl_dev = - cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template, - "video"); + dev->ioctl_dev = cx25821_vdev_init(dev, dev->pci, + &cx25821_videoioctl_template, "video"); if (video_register_device (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) { @@ -1103,16 +1099,15 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, } if (bpl <= sg_dma_len(sg) - offset) { /* fits into current chunk */ - *(rp++) = - cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | + bpl); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++) = - cpu_to_le32(RISC_WRITE | RISC_SOL | + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | (sg_dma_len(sg) - offset)); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ @@ -1120,8 +1115,8 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, offset = 0; sg++; while (todo > sg_dma_len(sg)) { - *(rp++) = - cpu_to_le32(RISC_WRITE | sg_dma_len(sg)); + *(rp++) = cpu_to_le32(RISC_WRITE | + sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= sg_dma_len(sg); @@ -1160,8 +1155,8 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, can cause next bpl to start close to a page border. First DMA region may be smaller than PAGE_SIZE */ /* write and jump need and extra dword */ - instructions = - fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); + instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + + lines); instructions += 2; rc = btcx_riscmem_alloc(pci, risc, instructions * 12); @@ -1215,8 +1210,8 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, if (bpl <= sg_dma_len(sg) - offset) { /* fits into current chunk */ - *(rp++) = - cpu_to_le32(RISC_WRITE | sol | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(RISC_WRITE | sol | RISC_EOL | + bpl); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += bpl; @@ -1224,7 +1219,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, /* scanline needs to be split */ todo = bpl; *(rp++) = cpu_to_le32(RISC_WRITE | sol | - (sg_dma_len(sg) - offset)); + (sg_dma_len(sg) - offset)); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= (sg_dma_len(sg) - offset); @@ -1232,7 +1227,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, sg++; while (todo > sg_dma_len(sg)) { *(rp++) = cpu_to_le32(RISC_WRITE | - sg_dma_len(sg)); + sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= sg_dma_len(sg); @@ -1339,8 +1334,8 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id) sram_channels->int_stat); if (vid_status) - handled += - cx25821_video_irq(dev, i, vid_status); + handled += cx25821_video_irq(dev, i, + vid_status); cx_write(PCI_INT_STAT, mask[i]); } @@ -1427,9 +1422,8 @@ static int __devinit cx25821_initdev(struct pci_dev *pci_dev, goto fail_irq; } - err = - request_irq(pci_dev->irq, cx25821_irq, IRQF_SHARED, - dev->name, dev); + err = request_irq(pci_dev->irq, cx25821_irq, + IRQF_SHARED, dev->name, dev); if (err < 0) { pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); @@ -1512,6 +1506,5 @@ static void __exit cx25821_fini(void) pci_unregister_driver(&cx25821_pci_driver); } - module_init(cx25821_init); module_exit(cx25821_fini); diff --git a/drivers/media/video/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c index 4d3d0ce40785..12d7300fa1e9 100644 --- a/drivers/media/video/cx25821/cx25821-i2c.c +++ b/drivers/media/video/cx25821/cx25821-i2c.c @@ -252,8 +252,8 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && msgs[i].addr == msgs[i + 1].addr) { /* write then read from same address */ - retval = - i2c_sendbytes(i2c_adap, &msgs[i], msgs[i + 1].len); + retval = i2c_sendbytes(i2c_adap, &msgs[i], + msgs[i + 1].len); if (retval < 0) goto err; @@ -276,10 +276,8 @@ err: static u32 cx25821_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | - I2C_FUNC_I2C | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; } static struct i2c_algorithm cx25821_i2c_algo_template = { @@ -300,7 +298,7 @@ static struct i2c_client cx25821_i2c_client_template = { .name = "cx25821 internal", }; -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int cx25821_i2c_register(struct cx25821_i2c *bus) { struct cx25821_dev *dev = bus->dev; diff --git a/drivers/media/video/cx25821/cx25821-medusa-defines.h b/drivers/media/video/cx25821/cx25821-medusa-defines.h index 60d197f57556..7a9e6470ba22 100644 --- a/drivers/media/video/cx25821/cx25821-medusa-defines.h +++ b/drivers/media/video/cx25821/cx25821-medusa-defines.h @@ -23,7 +23,7 @@ #ifndef _MEDUSA_DEF_H_ #define _MEDUSA_DEF_H_ -/* Video deocder that we supported */ +/* Video decoder that we supported */ #define VDEC_A 0 #define VDEC_B 1 #define VDEC_C 2 @@ -34,9 +34,9 @@ #define VDEC_H 7 /* end of display sequence */ -#define END_OF_SEQ 0xF; +#define END_OF_SEQ 0xF; /* registry string size */ -#define MAX_REGISTRY_SZ 40; +#define MAX_REGISTRY_SZ 40; #endif diff --git a/drivers/media/video/cx25821/cx25821-medusa-reg.h b/drivers/media/video/cx25821/cx25821-medusa-reg.h index 1c1c228352d1..c98ac946b277 100644 --- a/drivers/media/video/cx25821/cx25821-medusa-reg.h +++ b/drivers/media/video/cx25821/cx25821-medusa-reg.h @@ -28,22 +28,22 @@ #define HOST_REGISTER2 0x0001 /* Chip Configuration Registers */ -#define CHIP_CTRL 0x0100 -#define AFE_AB_CTRL 0x0104 -#define AFE_CD_CTRL 0x0108 -#define AFE_EF_CTRL 0x010C -#define AFE_GH_CTRL 0x0110 +#define CHIP_CTRL 0x0100 +#define AFE_AB_CTRL 0x0104 +#define AFE_CD_CTRL 0x0108 +#define AFE_EF_CTRL 0x010C +#define AFE_GH_CTRL 0x0110 #define DENC_AB_CTRL 0x0114 -#define BYP_AB_CTRL 0x0118 -#define MON_A_CTRL 0x011C -#define DISP_SEQ_A 0x0120 -#define DISP_SEQ_B 0x0124 -#define DISP_AB_CNT 0x0128 -#define DISP_CD_CNT 0x012C -#define DISP_EF_CNT 0x0130 -#define DISP_GH_CNT 0x0134 -#define DISP_IJ_CNT 0x0138 -#define PIN_OE_CTRL 0x013C +#define BYP_AB_CTRL 0x0118 +#define MON_A_CTRL 0x011C +#define DISP_SEQ_A 0x0120 +#define DISP_SEQ_B 0x0124 +#define DISP_AB_CNT 0x0128 +#define DISP_CD_CNT 0x012C +#define DISP_EF_CNT 0x0130 +#define DISP_GH_CNT 0x0134 +#define DISP_IJ_CNT 0x0138 +#define PIN_OE_CTRL 0x013C #define PIN_SPD_CTRL 0x0140 #define PIN_SPD_CTRL2 0x0144 #define IRQ_STAT_CTRL 0x0148 @@ -51,8 +51,8 @@ #define POWER_CTRL_CD 0x0150 #define POWER_CTRL_EF 0x0154 #define POWER_CTRL_GH 0x0158 -#define TUNE_CTRL 0x015C -#define BIAS_CTRL 0x0160 +#define TUNE_CTRL 0x015C +#define BIAS_CTRL 0x0160 #define AFE_AB_DIAG_CTRL 0x0164 #define AFE_CD_DIAG_CTRL 0x0168 #define AFE_EF_DIAG_CTRL 0x016C @@ -61,17 +61,17 @@ #define PLL_CD_DIAG_CTRL 0x0178 #define PLL_EF_DIAG_CTRL 0x017C #define PLL_GH_DIAG_CTRL 0x0180 -#define TEST_CTRL 0x0184 -#define BIST_STAT 0x0188 -#define BIST_STAT2 0x018C -#define BIST_VID_PLL_AB_STAT 0x0190 -#define BIST_VID_PLL_CD_STAT 0x0194 -#define BIST_VID_PLL_EF_STAT 0x0198 -#define BIST_VID_PLL_GH_STAT 0x019C +#define TEST_CTRL 0x0184 +#define BIST_STAT 0x0188 +#define BIST_STAT2 0x018C +#define BIST_VID_PLL_AB_STAT 0x0190 +#define BIST_VID_PLL_CD_STAT 0x0194 +#define BIST_VID_PLL_EF_STAT 0x0198 +#define BIST_VID_PLL_GH_STAT 0x019C #define DLL_DIAG_CTRL 0x01A0 #define DEV_CH_ID_CTRL 0x01A4 #define ABIST_CTRL_STATUS 0x01A8 -#define ABIST_FREQ 0x01AC +#define ABIST_FREQ 0x01AC #define ABIST_GOERT_SHIFT 0x01B0 #define ABIST_COEF12 0x01B4 #define ABIST_COEF34 0x01B8 @@ -92,357 +92,357 @@ #define ABIST_CLAMP_E 0x01F4 #define ABIST_CLAMP_F 0x01F8 -/* Digital Video Encoder A Registers */ -#define DENC_A_REG_1 0x0200 -#define DENC_A_REG_2 0x0204 -#define DENC_A_REG_3 0x0208 -#define DENC_A_REG_4 0x020C -#define DENC_A_REG_5 0x0210 -#define DENC_A_REG_6 0x0214 -#define DENC_A_REG_7 0x0218 -#define DENC_A_REG_8 0x021C +/* Digital Video Encoder A Registers */ +#define DENC_A_REG_1 0x0200 +#define DENC_A_REG_2 0x0204 +#define DENC_A_REG_3 0x0208 +#define DENC_A_REG_4 0x020C +#define DENC_A_REG_5 0x0210 +#define DENC_A_REG_6 0x0214 +#define DENC_A_REG_7 0x0218 +#define DENC_A_REG_8 0x021C -/* Digital Video Encoder B Registers */ -#define DENC_B_REG_1 0x0300 -#define DENC_B_REG_2 0x0304 -#define DENC_B_REG_3 0x0308 -#define DENC_B_REG_4 0x030C -#define DENC_B_REG_5 0x0310 -#define DENC_B_REG_6 0x0314 -#define DENC_B_REG_7 0x0318 -#define DENC_B_REG_8 0x031C +/* Digital Video Encoder B Registers */ +#define DENC_B_REG_1 0x0300 +#define DENC_B_REG_2 0x0304 +#define DENC_B_REG_3 0x0308 +#define DENC_B_REG_4 0x030C +#define DENC_B_REG_5 0x0310 +#define DENC_B_REG_6 0x0314 +#define DENC_B_REG_7 0x0318 +#define DENC_B_REG_8 0x031C -/* Video Decoder A Registers */ -#define MODE_CTRL 0x1000 -#define OUT_CTRL1 0x1004 -#define OUT_CTRL_NS 0x1008 -#define GEN_STAT 0x100C -#define INT_STAT_MASK 0x1010 -#define LUMA_CTRL 0x1014 -#define CHROMA_CTRL 0x1018 -#define CRUSH_CTRL 0x101C -#define HORIZ_TIM_CTRL 0x1020 -#define VERT_TIM_CTRL 0x1024 -#define MISC_TIM_CTRL 0x1028 -#define FIELD_COUNT 0x102C -#define HSCALE_CTRL 0x1030 -#define VSCALE_CTRL 0x1034 -#define MAN_VGA_CTRL 0x1038 -#define MAN_AGC_CTRL 0x103C -#define DFE_CTRL1 0x1040 -#define DFE_CTRL2 0x1044 -#define DFE_CTRL3 0x1048 -#define PLL_CTRL 0x104C -#define PLL_CTRL_FAST 0x1050 -#define HTL_CTRL 0x1054 -#define SRC_CFG 0x1058 -#define SC_STEP_SIZE 0x105C -#define SC_CONVERGE_CTRL 0x1060 -#define SC_LOOP_CTRL 0x1064 -#define COMB_2D_HFS_CFG 0x1068 -#define COMB_2D_HFD_CFG 0x106C -#define COMB_2D_LF_CFG 0x1070 -#define COMB_2D_BLEND 0x1074 -#define COMB_MISC_CTRL 0x1078 +/* Video Decoder A Registers */ +#define MODE_CTRL 0x1000 +#define OUT_CTRL1 0x1004 +#define OUT_CTRL_NS 0x1008 +#define GEN_STAT 0x100C +#define INT_STAT_MASK 0x1010 +#define LUMA_CTRL 0x1014 +#define CHROMA_CTRL 0x1018 +#define CRUSH_CTRL 0x101C +#define HORIZ_TIM_CTRL 0x1020 +#define VERT_TIM_CTRL 0x1024 +#define MISC_TIM_CTRL 0x1028 +#define FIELD_COUNT 0x102C +#define HSCALE_CTRL 0x1030 +#define VSCALE_CTRL 0x1034 +#define MAN_VGA_CTRL 0x1038 +#define MAN_AGC_CTRL 0x103C +#define DFE_CTRL1 0x1040 +#define DFE_CTRL2 0x1044 +#define DFE_CTRL3 0x1048 +#define PLL_CTRL 0x104C +#define PLL_CTRL_FAST 0x1050 +#define HTL_CTRL 0x1054 +#define SRC_CFG 0x1058 +#define SC_STEP_SIZE 0x105C +#define SC_CONVERGE_CTRL 0x1060 +#define SC_LOOP_CTRL 0x1064 +#define COMB_2D_HFS_CFG 0x1068 +#define COMB_2D_HFD_CFG 0x106C +#define COMB_2D_LF_CFG 0x1070 +#define COMB_2D_BLEND 0x1074 +#define COMB_MISC_CTRL 0x1078 #define COMB_FLAT_THRESH_CTRL 0x107C -#define COMB_TEST 0x1080 -#define BP_MISC_CTRL 0x1084 -#define VCR_DET_CTRL 0x1088 -#define NOISE_DET_CTRL 0x108C +#define COMB_TEST 0x1080 +#define BP_MISC_CTRL 0x1084 +#define VCR_DET_CTRL 0x1088 +#define NOISE_DET_CTRL 0x108C #define COMB_FLAT_NOISE_CTRL 0x1090 -#define VERSION 0x11F8 -#define SOFT_RST_CTRL 0x11FC +#define VERSION 0x11F8 +#define SOFT_RST_CTRL 0x11FC -/* Video Decoder B Registers */ -#define VDEC_B_MODE_CTRL 0x1200 -#define VDEC_B_OUT_CTRL1 0x1204 -#define VDEC_B_OUT_CTRL_NS 0x1208 -#define VDEC_B_GEN_STAT 0x120C +/* Video Decoder B Registers */ +#define VDEC_B_MODE_CTRL 0x1200 +#define VDEC_B_OUT_CTRL1 0x1204 +#define VDEC_B_OUT_CTRL_NS 0x1208 +#define VDEC_B_GEN_STAT 0x120C #define VDEC_B_INT_STAT_MASK 0x1210 -#define VDEC_B_LUMA_CTRL 0x1214 -#define VDEC_B_CHROMA_CTRL 0x1218 -#define VDEC_B_CRUSH_CTRL 0x121C +#define VDEC_B_LUMA_CTRL 0x1214 +#define VDEC_B_CHROMA_CTRL 0x1218 +#define VDEC_B_CRUSH_CTRL 0x121C #define VDEC_B_HORIZ_TIM_CTRL 0x1220 #define VDEC_B_VERT_TIM_CTRL 0x1224 #define VDEC_B_MISC_TIM_CTRL 0x1228 -#define VDEC_B_FIELD_COUNT 0x122C -#define VDEC_B_HSCALE_CTRL 0x1230 -#define VDEC_B_VSCALE_CTRL 0x1234 -#define VDEC_B_MAN_VGA_CTRL 0x1238 -#define VDEC_B_MAN_AGC_CTRL 0x123C -#define VDEC_B_DFE_CTRL1 0x1240 -#define VDEC_B_DFE_CTRL2 0x1244 -#define VDEC_B_DFE_CTRL3 0x1248 -#define VDEC_B_PLL_CTRL 0x124C +#define VDEC_B_FIELD_COUNT 0x122C +#define VDEC_B_HSCALE_CTRL 0x1230 +#define VDEC_B_VSCALE_CTRL 0x1234 +#define VDEC_B_MAN_VGA_CTRL 0x1238 +#define VDEC_B_MAN_AGC_CTRL 0x123C +#define VDEC_B_DFE_CTRL1 0x1240 +#define VDEC_B_DFE_CTRL2 0x1244 +#define VDEC_B_DFE_CTRL3 0x1248 +#define VDEC_B_PLL_CTRL 0x124C #define VDEC_B_PLL_CTRL_FAST 0x1250 -#define VDEC_B_HTL_CTRL 0x1254 -#define VDEC_B_SRC_CFG 0x1258 -#define VDEC_B_SC_STEP_SIZE 0x125C +#define VDEC_B_HTL_CTRL 0x1254 +#define VDEC_B_SRC_CFG 0x1258 +#define VDEC_B_SC_STEP_SIZE 0x125C #define VDEC_B_SC_CONVERGE_CTRL 0x1260 -#define VDEC_B_SC_LOOP_CTRL 0x1264 +#define VDEC_B_SC_LOOP_CTRL 0x1264 #define VDEC_B_COMB_2D_HFS_CFG 0x1268 #define VDEC_B_COMB_2D_HFD_CFG 0x126C #define VDEC_B_COMB_2D_LF_CFG 0x1270 #define VDEC_B_COMB_2D_BLEND 0x1274 #define VDEC_B_COMB_MISC_CTRL 0x1278 -#define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C -#define VDEC_B_COMB_TEST 0x1280 -#define VDEC_B_BP_MISC_CTRL 0x1284 -#define VDEC_B_VCR_DET_CTRL 0x1288 +#define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C +#define VDEC_B_COMB_TEST 0x1280 +#define VDEC_B_BP_MISC_CTRL 0x1284 +#define VDEC_B_VCR_DET_CTRL 0x1288 #define VDEC_B_NOISE_DET_CTRL 0x128C #define VDEC_B_COMB_FLAT_NOISE_CTRL 0x1290 -#define VDEC_B_VERSION 0x13F8 +#define VDEC_B_VERSION 0x13F8 #define VDEC_B_SOFT_RST_CTRL 0x13FC /* Video Decoder C Registers */ -#define VDEC_C_MODE_CTRL 0x1400 -#define VDEC_C_OUT_CTRL1 0x1404 -#define VDEC_C_OUT_CTRL_NS 0x1408 -#define VDEC_C_GEN_STAT 0x140C +#define VDEC_C_MODE_CTRL 0x1400 +#define VDEC_C_OUT_CTRL1 0x1404 +#define VDEC_C_OUT_CTRL_NS 0x1408 +#define VDEC_C_GEN_STAT 0x140C #define VDEC_C_INT_STAT_MASK 0x1410 -#define VDEC_C_LUMA_CTRL 0x1414 -#define VDEC_C_CHROMA_CTRL 0x1418 -#define VDEC_C_CRUSH_CTRL 0x141C +#define VDEC_C_LUMA_CTRL 0x1414 +#define VDEC_C_CHROMA_CTRL 0x1418 +#define VDEC_C_CRUSH_CTRL 0x141C #define VDEC_C_HORIZ_TIM_CTRL 0x1420 #define VDEC_C_VERT_TIM_CTRL 0x1424 #define VDEC_C_MISC_TIM_CTRL 0x1428 -#define VDEC_C_FIELD_COUNT 0x142C -#define VDEC_C_HSCALE_CTRL 0x1430 -#define VDEC_C_VSCALE_CTRL 0x1434 -#define VDEC_C_MAN_VGA_CTRL 0x1438 -#define VDEC_C_MAN_AGC_CTRL 0x143C -#define VDEC_C_DFE_CTRL1 0x1440 -#define VDEC_C_DFE_CTRL2 0x1444 -#define VDEC_C_DFE_CTRL3 0x1448 -#define VDEC_C_PLL_CTRL 0x144C +#define VDEC_C_FIELD_COUNT 0x142C +#define VDEC_C_HSCALE_CTRL 0x1430 +#define VDEC_C_VSCALE_CTRL 0x1434 +#define VDEC_C_MAN_VGA_CTRL 0x1438 +#define VDEC_C_MAN_AGC_CTRL 0x143C +#define VDEC_C_DFE_CTRL1 0x1440 +#define VDEC_C_DFE_CTRL2 0x1444 +#define VDEC_C_DFE_CTRL3 0x1448 +#define VDEC_C_PLL_CTRL 0x144C #define VDEC_C_PLL_CTRL_FAST 0x1450 -#define VDEC_C_HTL_CTRL 0x1454 -#define VDEC_C_SRC_CFG 0x1458 -#define VDEC_C_SC_STEP_SIZE 0x145C +#define VDEC_C_HTL_CTRL 0x1454 +#define VDEC_C_SRC_CFG 0x1458 +#define VDEC_C_SC_STEP_SIZE 0x145C #define VDEC_C_SC_CONVERGE_CTRL 0x1460 -#define VDEC_C_SC_LOOP_CTRL 0x1464 +#define VDEC_C_SC_LOOP_CTRL 0x1464 #define VDEC_C_COMB_2D_HFS_CFG 0x1468 #define VDEC_C_COMB_2D_HFD_CFG 0x146C #define VDEC_C_COMB_2D_LF_CFG 0x1470 #define VDEC_C_COMB_2D_BLEND 0x1474 #define VDEC_C_COMB_MISC_CTRL 0x1478 -#define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C -#define VDEC_C_COMB_TEST 0x1480 -#define VDEC_C_BP_MISC_CTRL 0x1484 -#define VDEC_C_VCR_DET_CTRL 0x1488 +#define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C +#define VDEC_C_COMB_TEST 0x1480 +#define VDEC_C_BP_MISC_CTRL 0x1484 +#define VDEC_C_VCR_DET_CTRL 0x1488 #define VDEC_C_NOISE_DET_CTRL 0x148C #define VDEC_C_COMB_FLAT_NOISE_CTRL 0x1490 -#define VDEC_C_VERSION 0x15F8 +#define VDEC_C_VERSION 0x15F8 #define VDEC_C_SOFT_RST_CTRL 0x15FC /* Video Decoder D Registers */ -#define VDEC_D_MODE_CTRL 0x1600 -#define VDEC_D_OUT_CTRL1 0x1604 -#define VDEC_D_OUT_CTRL_NS 0x1608 -#define VDEC_D_GEN_STAT 0x160C +#define VDEC_D_MODE_CTRL 0x1600 +#define VDEC_D_OUT_CTRL1 0x1604 +#define VDEC_D_OUT_CTRL_NS 0x1608 +#define VDEC_D_GEN_STAT 0x160C #define VDEC_D_INT_STAT_MASK 0x1610 -#define VDEC_D_LUMA_CTRL 0x1614 -#define VDEC_D_CHROMA_CTRL 0x1618 -#define VDEC_D_CRUSH_CTRL 0x161C +#define VDEC_D_LUMA_CTRL 0x1614 +#define VDEC_D_CHROMA_CTRL 0x1618 +#define VDEC_D_CRUSH_CTRL 0x161C #define VDEC_D_HORIZ_TIM_CTRL 0x1620 #define VDEC_D_VERT_TIM_CTRL 0x1624 #define VDEC_D_MISC_TIM_CTRL 0x1628 -#define VDEC_D_FIELD_COUNT 0x162C -#define VDEC_D_HSCALE_CTRL 0x1630 -#define VDEC_D_VSCALE_CTRL 0x1634 -#define VDEC_D_MAN_VGA_CTRL 0x1638 -#define VDEC_D_MAN_AGC_CTRL 0x163C -#define VDEC_D_DFE_CTRL1 0x1640 -#define VDEC_D_DFE_CTRL2 0x1644 -#define VDEC_D_DFE_CTRL3 0x1648 -#define VDEC_D_PLL_CTRL 0x164C +#define VDEC_D_FIELD_COUNT 0x162C +#define VDEC_D_HSCALE_CTRL 0x1630 +#define VDEC_D_VSCALE_CTRL 0x1634 +#define VDEC_D_MAN_VGA_CTRL 0x1638 +#define VDEC_D_MAN_AGC_CTRL 0x163C +#define VDEC_D_DFE_CTRL1 0x1640 +#define VDEC_D_DFE_CTRL2 0x1644 +#define VDEC_D_DFE_CTRL3 0x1648 +#define VDEC_D_PLL_CTRL 0x164C #define VDEC_D_PLL_CTRL_FAST 0x1650 -#define VDEC_D_HTL_CTRL 0x1654 -#define VDEC_D_SRC_CFG 0x1658 -#define VDEC_D_SC_STEP_SIZE 0x165C +#define VDEC_D_HTL_CTRL 0x1654 +#define VDEC_D_SRC_CFG 0x1658 +#define VDEC_D_SC_STEP_SIZE 0x165C #define VDEC_D_SC_CONVERGE_CTRL 0x1660 -#define VDEC_D_SC_LOOP_CTRL 0x1664 +#define VDEC_D_SC_LOOP_CTRL 0x1664 #define VDEC_D_COMB_2D_HFS_CFG 0x1668 #define VDEC_D_COMB_2D_HFD_CFG 0x166C #define VDEC_D_COMB_2D_LF_CFG 0x1670 #define VDEC_D_COMB_2D_BLEND 0x1674 #define VDEC_D_COMB_MISC_CTRL 0x1678 -#define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C -#define VDEC_D_COMB_TEST 0x1680 -#define VDEC_D_BP_MISC_CTRL 0x1684 -#define VDEC_D_VCR_DET_CTRL 0x1688 +#define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C +#define VDEC_D_COMB_TEST 0x1680 +#define VDEC_D_BP_MISC_CTRL 0x1684 +#define VDEC_D_VCR_DET_CTRL 0x1688 #define VDEC_D_NOISE_DET_CTRL 0x168C #define VDEC_D_COMB_FLAT_NOISE_CTRL 0x1690 -#define VDEC_D_VERSION 0x17F8 +#define VDEC_D_VERSION 0x17F8 #define VDEC_D_SOFT_RST_CTRL 0x17FC /* Video Decoder E Registers */ -#define VDEC_E_MODE_CTRL 0x1800 -#define VDEC_E_OUT_CTRL1 0x1804 -#define VDEC_E_OUT_CTRL_NS 0x1808 -#define VDEC_E_GEN_STAT 0x180C +#define VDEC_E_MODE_CTRL 0x1800 +#define VDEC_E_OUT_CTRL1 0x1804 +#define VDEC_E_OUT_CTRL_NS 0x1808 +#define VDEC_E_GEN_STAT 0x180C #define VDEC_E_INT_STAT_MASK 0x1810 -#define VDEC_E_LUMA_CTRL 0x1814 -#define VDEC_E_CHROMA_CTRL 0x1818 -#define VDEC_E_CRUSH_CTRL 0x181C +#define VDEC_E_LUMA_CTRL 0x1814 +#define VDEC_E_CHROMA_CTRL 0x1818 +#define VDEC_E_CRUSH_CTRL 0x181C #define VDEC_E_HORIZ_TIM_CTRL 0x1820 #define VDEC_E_VERT_TIM_CTRL 0x1824 #define VDEC_E_MISC_TIM_CTRL 0x1828 -#define VDEC_E_FIELD_COUNT 0x182C -#define VDEC_E_HSCALE_CTRL 0x1830 -#define VDEC_E_VSCALE_CTRL 0x1834 -#define VDEC_E_MAN_VGA_CTRL 0x1838 -#define VDEC_E_MAN_AGC_CTRL 0x183C -#define VDEC_E_DFE_CTRL1 0x1840 -#define VDEC_E_DFE_CTRL2 0x1844 -#define VDEC_E_DFE_CTRL3 0x1848 -#define VDEC_E_PLL_CTRL 0x184C +#define VDEC_E_FIELD_COUNT 0x182C +#define VDEC_E_HSCALE_CTRL 0x1830 +#define VDEC_E_VSCALE_CTRL 0x1834 +#define VDEC_E_MAN_VGA_CTRL 0x1838 +#define VDEC_E_MAN_AGC_CTRL 0x183C +#define VDEC_E_DFE_CTRL1 0x1840 +#define VDEC_E_DFE_CTRL2 0x1844 +#define VDEC_E_DFE_CTRL3 0x1848 +#define VDEC_E_PLL_CTRL 0x184C #define VDEC_E_PLL_CTRL_FAST 0x1850 -#define VDEC_E_HTL_CTRL 0x1854 -#define VDEC_E_SRC_CFG 0x1858 -#define VDEC_E_SC_STEP_SIZE 0x185C +#define VDEC_E_HTL_CTRL 0x1854 +#define VDEC_E_SRC_CFG 0x1858 +#define VDEC_E_SC_STEP_SIZE 0x185C #define VDEC_E_SC_CONVERGE_CTRL 0x1860 -#define VDEC_E_SC_LOOP_CTRL 0x1864 +#define VDEC_E_SC_LOOP_CTRL 0x1864 #define VDEC_E_COMB_2D_HFS_CFG 0x1868 #define VDEC_E_COMB_2D_HFD_CFG 0x186C #define VDEC_E_COMB_2D_LF_CFG 0x1870 #define VDEC_E_COMB_2D_BLEND 0x1874 #define VDEC_E_COMB_MISC_CTRL 0x1878 -#define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C -#define VDEC_E_COMB_TEST 0x1880 -#define VDEC_E_BP_MISC_CTRL 0x1884 -#define VDEC_E_VCR_DET_CTRL 0x1888 +#define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C +#define VDEC_E_COMB_TEST 0x1880 +#define VDEC_E_BP_MISC_CTRL 0x1884 +#define VDEC_E_VCR_DET_CTRL 0x1888 #define VDEC_E_NOISE_DET_CTRL 0x188C #define VDEC_E_COMB_FLAT_NOISE_CTRL 0x1890 -#define VDEC_E_VERSION 0x19F8 +#define VDEC_E_VERSION 0x19F8 #define VDEC_E_SOFT_RST_CTRL 0x19FC /* Video Decoder F Registers */ -#define VDEC_F_MODE_CTRL 0x1A00 -#define VDEC_F_OUT_CTRL1 0x1A04 -#define VDEC_F_OUT_CTRL_NS 0x1A08 -#define VDEC_F_GEN_STAT 0x1A0C +#define VDEC_F_MODE_CTRL 0x1A00 +#define VDEC_F_OUT_CTRL1 0x1A04 +#define VDEC_F_OUT_CTRL_NS 0x1A08 +#define VDEC_F_GEN_STAT 0x1A0C #define VDEC_F_INT_STAT_MASK 0x1A10 -#define VDEC_F_LUMA_CTRL 0x1A14 -#define VDEC_F_CHROMA_CTRL 0x1A18 -#define VDEC_F_CRUSH_CTRL 0x1A1C +#define VDEC_F_LUMA_CTRL 0x1A14 +#define VDEC_F_CHROMA_CTRL 0x1A18 +#define VDEC_F_CRUSH_CTRL 0x1A1C #define VDEC_F_HORIZ_TIM_CTRL 0x1A20 #define VDEC_F_VERT_TIM_CTRL 0x1A24 #define VDEC_F_MISC_TIM_CTRL 0x1A28 -#define VDEC_F_FIELD_COUNT 0x1A2C -#define VDEC_F_HSCALE_CTRL 0x1A30 -#define VDEC_F_VSCALE_CTRL 0x1A34 -#define VDEC_F_MAN_VGA_CTRL 0x1A38 -#define VDEC_F_MAN_AGC_CTRL 0x1A3C -#define VDEC_F_DFE_CTRL1 0x1A40 -#define VDEC_F_DFE_CTRL2 0x1A44 -#define VDEC_F_DFE_CTRL3 0x1A48 -#define VDEC_F_PLL_CTRL 0x1A4C +#define VDEC_F_FIELD_COUNT 0x1A2C +#define VDEC_F_HSCALE_CTRL 0x1A30 +#define VDEC_F_VSCALE_CTRL 0x1A34 +#define VDEC_F_MAN_VGA_CTRL 0x1A38 +#define VDEC_F_MAN_AGC_CTRL 0x1A3C +#define VDEC_F_DFE_CTRL1 0x1A40 +#define VDEC_F_DFE_CTRL2 0x1A44 +#define VDEC_F_DFE_CTRL3 0x1A48 +#define VDEC_F_PLL_CTRL 0x1A4C #define VDEC_F_PLL_CTRL_FAST 0x1A50 -#define VDEC_F_HTL_CTRL 0x1A54 -#define VDEC_F_SRC_CFG 0x1A58 -#define VDEC_F_SC_STEP_SIZE 0x1A5C +#define VDEC_F_HTL_CTRL 0x1A54 +#define VDEC_F_SRC_CFG 0x1A58 +#define VDEC_F_SC_STEP_SIZE 0x1A5C #define VDEC_F_SC_CONVERGE_CTRL 0x1A60 -#define VDEC_F_SC_LOOP_CTRL 0x1A64 +#define VDEC_F_SC_LOOP_CTRL 0x1A64 #define VDEC_F_COMB_2D_HFS_CFG 0x1A68 #define VDEC_F_COMB_2D_HFD_CFG 0x1A6C #define VDEC_F_COMB_2D_LF_CFG 0x1A70 #define VDEC_F_COMB_2D_BLEND 0x1A74 #define VDEC_F_COMB_MISC_CTRL 0x1A78 -#define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C -#define VDEC_F_COMB_TEST 0x1A80 -#define VDEC_F_BP_MISC_CTRL 0x1A84 -#define VDEC_F_VCR_DET_CTRL 0x1A88 +#define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C +#define VDEC_F_COMB_TEST 0x1A80 +#define VDEC_F_BP_MISC_CTRL 0x1A84 +#define VDEC_F_VCR_DET_CTRL 0x1A88 #define VDEC_F_NOISE_DET_CTRL 0x1A8C #define VDEC_F_COMB_FLAT_NOISE_CTRL 0x1A90 -#define VDEC_F_VERSION 0x1BF8 +#define VDEC_F_VERSION 0x1BF8 #define VDEC_F_SOFT_RST_CTRL 0x1BFC /* Video Decoder G Registers */ -#define VDEC_G_MODE_CTRL 0x1C00 -#define VDEC_G_OUT_CTRL1 0x1C04 -#define VDEC_G_OUT_CTRL_NS 0x1C08 -#define VDEC_G_GEN_STAT 0x1C0C +#define VDEC_G_MODE_CTRL 0x1C00 +#define VDEC_G_OUT_CTRL1 0x1C04 +#define VDEC_G_OUT_CTRL_NS 0x1C08 +#define VDEC_G_GEN_STAT 0x1C0C #define VDEC_G_INT_STAT_MASK 0x1C10 -#define VDEC_G_LUMA_CTRL 0x1C14 -#define VDEC_G_CHROMA_CTRL 0x1C18 -#define VDEC_G_CRUSH_CTRL 0x1C1C +#define VDEC_G_LUMA_CTRL 0x1C14 +#define VDEC_G_CHROMA_CTRL 0x1C18 +#define VDEC_G_CRUSH_CTRL 0x1C1C #define VDEC_G_HORIZ_TIM_CTRL 0x1C20 #define VDEC_G_VERT_TIM_CTRL 0x1C24 #define VDEC_G_MISC_TIM_CTRL 0x1C28 -#define VDEC_G_FIELD_COUNT 0x1C2C -#define VDEC_G_HSCALE_CTRL 0x1C30 -#define VDEC_G_VSCALE_CTRL 0x1C34 -#define VDEC_G_MAN_VGA_CTRL 0x1C38 -#define VDEC_G_MAN_AGC_CTRL 0x1C3C -#define VDEC_G_DFE_CTRL1 0x1C40 -#define VDEC_G_DFE_CTRL2 0x1C44 -#define VDEC_G_DFE_CTRL3 0x1C48 -#define VDEC_G_PLL_CTRL 0x1C4C +#define VDEC_G_FIELD_COUNT 0x1C2C +#define VDEC_G_HSCALE_CTRL 0x1C30 +#define VDEC_G_VSCALE_CTRL 0x1C34 +#define VDEC_G_MAN_VGA_CTRL 0x1C38 +#define VDEC_G_MAN_AGC_CTRL 0x1C3C +#define VDEC_G_DFE_CTRL1 0x1C40 +#define VDEC_G_DFE_CTRL2 0x1C44 +#define VDEC_G_DFE_CTRL3 0x1C48 +#define VDEC_G_PLL_CTRL 0x1C4C #define VDEC_G_PLL_CTRL_FAST 0x1C50 -#define VDEC_G_HTL_CTRL 0x1C54 -#define VDEC_G_SRC_CFG 0x1C58 -#define VDEC_G_SC_STEP_SIZE 0x1C5C +#define VDEC_G_HTL_CTRL 0x1C54 +#define VDEC_G_SRC_CFG 0x1C58 +#define VDEC_G_SC_STEP_SIZE 0x1C5C #define VDEC_G_SC_CONVERGE_CTRL 0x1C60 -#define VDEC_G_SC_LOOP_CTRL 0x1C64 +#define VDEC_G_SC_LOOP_CTRL 0x1C64 #define VDEC_G_COMB_2D_HFS_CFG 0x1C68 #define VDEC_G_COMB_2D_HFD_CFG 0x1C6C #define VDEC_G_COMB_2D_LF_CFG 0x1C70 #define VDEC_G_COMB_2D_BLEND 0x1C74 #define VDEC_G_COMB_MISC_CTRL 0x1C78 -#define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C -#define VDEC_G_COMB_TEST 0x1C80 -#define VDEC_G_BP_MISC_CTRL 0x1C84 -#define VDEC_G_VCR_DET_CTRL 0x1C88 +#define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C +#define VDEC_G_COMB_TEST 0x1C80 +#define VDEC_G_BP_MISC_CTRL 0x1C84 +#define VDEC_G_VCR_DET_CTRL 0x1C88 #define VDEC_G_NOISE_DET_CTRL 0x1C8C #define VDEC_G_COMB_FLAT_NOISE_CTRL 0x1C90 -#define VDEC_G_VERSION 0x1DF8 +#define VDEC_G_VERSION 0x1DF8 #define VDEC_G_SOFT_RST_CTRL 0x1DFC -/* Video Decoder H Registers */ -#define VDEC_H_MODE_CTRL 0x1E00 -#define VDEC_H_OUT_CTRL1 0x1E04 -#define VDEC_H_OUT_CTRL_NS 0x1E08 -#define VDEC_H_GEN_STAT 0x1E0C +/* Video Decoder H Registers */ +#define VDEC_H_MODE_CTRL 0x1E00 +#define VDEC_H_OUT_CTRL1 0x1E04 +#define VDEC_H_OUT_CTRL_NS 0x1E08 +#define VDEC_H_GEN_STAT 0x1E0C #define VDEC_H_INT_STAT_MASK 0x1E1E -#define VDEC_H_LUMA_CTRL 0x1E14 -#define VDEC_H_CHROMA_CTRL 0x1E18 -#define VDEC_H_CRUSH_CTRL 0x1E1C +#define VDEC_H_LUMA_CTRL 0x1E14 +#define VDEC_H_CHROMA_CTRL 0x1E18 +#define VDEC_H_CRUSH_CTRL 0x1E1C #define VDEC_H_HORIZ_TIM_CTRL 0x1E20 #define VDEC_H_VERT_TIM_CTRL 0x1E24 #define VDEC_H_MISC_TIM_CTRL 0x1E28 -#define VDEC_H_FIELD_COUNT 0x1E2C -#define VDEC_H_HSCALE_CTRL 0x1E30 -#define VDEC_H_VSCALE_CTRL 0x1E34 -#define VDEC_H_MAN_VGA_CTRL 0x1E38 -#define VDEC_H_MAN_AGC_CTRL 0x1E3C -#define VDEC_H_DFE_CTRL1 0x1E40 -#define VDEC_H_DFE_CTRL2 0x1E44 -#define VDEC_H_DFE_CTRL3 0x1E48 -#define VDEC_H_PLL_CTRL 0x1E4C +#define VDEC_H_FIELD_COUNT 0x1E2C +#define VDEC_H_HSCALE_CTRL 0x1E30 +#define VDEC_H_VSCALE_CTRL 0x1E34 +#define VDEC_H_MAN_VGA_CTRL 0x1E38 +#define VDEC_H_MAN_AGC_CTRL 0x1E3C +#define VDEC_H_DFE_CTRL1 0x1E40 +#define VDEC_H_DFE_CTRL2 0x1E44 +#define VDEC_H_DFE_CTRL3 0x1E48 +#define VDEC_H_PLL_CTRL 0x1E4C #define VDEC_H_PLL_CTRL_FAST 0x1E50 -#define VDEC_H_HTL_CTRL 0x1E54 -#define VDEC_H_SRC_CFG 0x1E58 -#define VDEC_H_SC_STEP_SIZE 0x1E5C +#define VDEC_H_HTL_CTRL 0x1E54 +#define VDEC_H_SRC_CFG 0x1E58 +#define VDEC_H_SC_STEP_SIZE 0x1E5C #define VDEC_H_SC_CONVERGE_CTRL 0x1E60 -#define VDEC_H_SC_LOOP_CTRL 0x1E64 +#define VDEC_H_SC_LOOP_CTRL 0x1E64 #define VDEC_H_COMB_2D_HFS_CFG 0x1E68 #define VDEC_H_COMB_2D_HFD_CFG 0x1E6C #define VDEC_H_COMB_2D_LF_CFG 0x1E70 #define VDEC_H_COMB_2D_BLEND 0x1E74 #define VDEC_H_COMB_MISC_CTRL 0x1E78 -#define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C -#define VDEC_H_COMB_TEST 0x1E80 -#define VDEC_H_BP_MISC_CTRL 0x1E84 -#define VDEC_H_VCR_DET_CTRL 0x1E88 +#define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C +#define VDEC_H_COMB_TEST 0x1E80 +#define VDEC_H_BP_MISC_CTRL 0x1E84 +#define VDEC_H_VCR_DET_CTRL 0x1E88 #define VDEC_H_NOISE_DET_CTRL 0x1E8C #define VDEC_H_COMB_FLAT_NOISE_CTRL 0x1E90 -#define VDEC_H_VERSION 0x1FF8 +#define VDEC_H_VERSION 0x1FF8 #define VDEC_H_SOFT_RST_CTRL 0x1FFC /*****************************************************************************/ /* LUMA_CTRL register fields */ -#define VDEC_A_BRITE_CTRL 0x1014 +#define VDEC_A_BRITE_CTRL 0x1014 #define VDEC_A_CNTRST_CTRL 0x1015 #define VDEC_A_PEAK_SEL 0x1016 diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c index fc780d0908dc..298a68d98c2f 100644 --- a/drivers/media/video/cx25821/cx25821-medusa-video.c +++ b/drivers/media/video/cx25821/cx25821-medusa-video.c @@ -99,82 +99,67 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev) for (i = 0; i < MAX_DECODERS; i++) { /* set video format NTSC-M */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), &tmp); value &= 0xFFFFFFF0; /* enable the fast locking mode bit[16] */ value |= 0x10001; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), value); /* resolution NTSC 720x480 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), &tmp); value &= 0x00C00C00; value |= 0x612D0074; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), value); - value = - cx25821_i2c_read(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), &tmp); value &= 0x00C00C00; value |= 0x1C1E001A; /* vblank_cnt + 2 to get camera ID */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), value); /* chroma subcarrier step size */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - SC_STEP_SIZE + (0x200 * i), 0x43E00000); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + SC_STEP_SIZE + (0x200 * i), 0x43E00000); /* enable VIP optional active */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), &tmp); value &= 0xFFFBFFFF; value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), value); /* enable VIP optional active (VIP_OPT_AL) for direct output. */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), &tmp); value &= 0xFFFBFFFF; value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), value); /* * clear VPRES_VERT_EN bit, fixes the chroma run away problem * when the input switching rate < 16 fields */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), &tmp); /* disable special play detection */ value = setBitAtPos(value, 14); value = clearBitAtPos(value, 15); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), value); /* set vbi_gate_en to 0 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), &tmp); value = clearBitAtPos(value, 29); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), value); /* Enable the generation of blue field output if no video */ medusa_enable_bluefield_output(dev, i, 1); @@ -182,61 +167,49 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev) for (i = 0; i < MAX_ENCODERS; i++) { /* NTSC hclock */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), &tmp); value &= 0xF000FC00; value |= 0x06B402D0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), value); /* burst begin and burst end */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), &tmp); value &= 0xFF000000; value |= 0x007E9054; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), value); - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), &tmp); value &= 0xFC00FE00; value |= 0x00EC00F0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), value); /* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), &tmp); value &= 0x00FCFFFF; value |= 0x13020000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), value); - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), &tmp); value &= 0xFFFF0000; value |= 0x0000E575; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), value); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_6 + (0x100 * i), 0x009A89C1); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_6 + (0x100 * i), 0x009A89C1); /* Subcarrier Increment */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_7 + (0x100 * i), 0x21F07C1F); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_7 + (0x100 * i), 0x21F07C1F); } /* set picture resolutions */ @@ -261,34 +234,27 @@ static int medusa_PALCombInit(struct cx25821_dev *dev, int dec) u32 value = 0, tmp = 0; /* Setup for 2D threshold */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFS_CFG + (0x200 * dec), - 0x20002861); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFD_CFG + (0x200 * dec), - 0x20002861); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_LF_CFG + (0x200 * dec), - 0x200A1023); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_HFS_CFG + (0x200 * dec), 0x20002861); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_HFD_CFG + (0x200 * dec), 0x20002861); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_LF_CFG + (0x200 * dec), 0x200A1023); /* Setup flat chroma and luma thresholds */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp); value &= 0x06230000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - COMB_FLAT_THRESH_CTRL + (0x200 * dec), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_FLAT_THRESH_CTRL + (0x200 * dec), value); /* set comb 2D blend */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_BLEND + (0x200 * dec), - 0x210F0F0F); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_BLEND + (0x200 * dec), 0x210F0F0F); /* COMB MISC CONTROL */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_MISC_CTRL + (0x200 * dec), - 0x41120A7F); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_MISC_CTRL + (0x200 * dec), 0x41120A7F); return ret_val; } @@ -304,83 +270,68 @@ static int medusa_initialize_pal(struct cx25821_dev *dev) for (i = 0; i < MAX_DECODERS; i++) { /* set video format PAL-BDGHI */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), &tmp); value &= 0xFFFFFFF0; /* enable the fast locking mode bit[16] */ value |= 0x10004; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), value); /* resolution PAL 720x576 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), &tmp); value &= 0x00C00C00; value |= 0x632D007D; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), value); /* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), &tmp); value &= 0x00C00C00; value |= 0x28240026; /* vblank_cnt + 2 to get camera ID */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), value); /* chroma subcarrier step size */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - SC_STEP_SIZE + (0x200 * i), 0x5411E2D0); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + SC_STEP_SIZE + (0x200 * i), 0x5411E2D0); /* enable VIP optional active */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), &tmp); value &= 0xFFFBFFFF; value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), value); /* enable VIP optional active (VIP_OPT_AL) for direct output. */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), &tmp); value &= 0xFFFBFFFF; value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), value); /* * clear VPRES_VERT_EN bit, fixes the chroma run away problem * when the input switching rate < 16 fields */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), &tmp); /* disable special play detection */ value = setBitAtPos(value, 14); value = clearBitAtPos(value, 15); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), value); /* set vbi_gate_en to 0 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), &tmp); value = clearBitAtPos(value, 29); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), value); medusa_PALCombInit(dev, i); @@ -390,62 +341,50 @@ static int medusa_initialize_pal(struct cx25821_dev *dev) for (i = 0; i < MAX_ENCODERS; i++) { /* PAL hclock */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), &tmp); value &= 0xF000FC00; value |= 0x06C002D0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), value); /* burst begin and burst end */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), &tmp); value &= 0xFF000000; value |= 0x007E9754; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), value); /* hblank and vactive */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), &tmp); value &= 0xFC00FE00; value |= 0x00FC0120; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), value); /* set PAL vblank, phase alternation, 0 IRE pedestal */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), &tmp); value &= 0x00FCFFFF; value |= 0x14010000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), value); - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), &tmp); value &= 0xFFFF0000; value |= 0x0000F078; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), value); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_6 + (0x100 * i), 0x00A493CF); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_6 + (0x100 * i), 0x00A493CF); /* Subcarrier Increment */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_7 + (0x100 * i), 0x2A098ACB); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_7 + (0x100 * i), 0x2A098ACB); } /* set picture resolutions */ @@ -499,7 +438,7 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width, mutex_lock(&dev->lock); - /* validate the width - cannot be negative */ + /* validate the width */ if (width > MAX_WIDTH) { pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n", __func__, width, MAX_WIDTH); @@ -543,12 +482,10 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width, for (; decoder < decoder_count; decoder++) { /* write scaling values for each decoder */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HSCALE_CTRL + (0x200 * decoder), hscale); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VSCALE_CTRL + (0x200 * decoder), vscale); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + HSCALE_CTRL + (0x200 * decoder), hscale); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + VSCALE_CTRL + (0x200 * decoder), vscale); } mutex_unlock(&dev->lock); @@ -606,8 +543,8 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, } /* Map to Medusa register setting */ -static int mapM(int srcMin, - int srcMax, int srcVal, int dstMin, int dstMax, int *dstVal) +static int mapM(int srcMin, int srcMax, int srcVal, int dstMin, int dstMax, + int *dstVal) { int numerator; int denominator; @@ -654,23 +591,19 @@ int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder) u32 val = 0, tmp = 0; mutex_lock(&dev->lock); - if ((brightness > VIDEO_PROCAMP_MAX) - || (brightness < VIDEO_PROCAMP_MIN)) { + if ((brightness > VIDEO_PROCAMP_MAX) || + (brightness < VIDEO_PROCAMP_MIN)) { mutex_unlock(&dev->lock); return -1; } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness, - SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness, + SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); value = convert_to_twos(value, 8); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_BRITE_CTRL + (0x200 * decoder), - val | value); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_BRITE_CTRL + (0x200 * decoder), val | value); mutex_unlock(&dev->lock); return ret_val; } @@ -688,17 +621,13 @@ int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder) return -1; } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast, - UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp); + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast, + UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_CNTRST_CTRL + (0x200 * decoder), - val | value); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_CNTRST_CTRL + (0x200 * decoder), val | value); mutex_unlock(&dev->lock); return ret_val; @@ -717,19 +646,16 @@ int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder) return -1; } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, SIGNED_BYTE_MIN, - SIGNED_BYTE_MAX, &value); + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, + SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); value = convert_to_twos(value, 8); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_HUE_CTRL + (0x200 * decoder), val | value); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_HUE_CTRL + (0x200 * decoder), val | value); mutex_unlock(&dev->lock); return ret_val; @@ -743,33 +669,26 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder) mutex_lock(&dev->lock); - if ((saturation > VIDEO_PROCAMP_MAX) - || (saturation < VIDEO_PROCAMP_MIN)) { + if ((saturation > VIDEO_PROCAMP_MAX) || + (saturation < VIDEO_PROCAMP_MIN)) { mutex_unlock(&dev->lock); return -1; } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation, - UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation, + UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_USAT_CTRL + (0x200 * decoder), - val | value); - - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_USAT_CTRL + (0x200 * decoder), val | value); + + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_VSAT_CTRL + (0x200 * decoder), - val | value); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_VSAT_CTRL + (0x200 * decoder), val | value); mutex_unlock(&dev->lock); return ret_val; @@ -830,9 +749,8 @@ int medusa_video_init(struct cx25821_dev *dev) /* select AFE clock to output mode */ value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp); value &= 0x83FFFFFF; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, - value | 0x10000000); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, + value | 0x10000000); if (ret_val < 0) goto error; diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c index 2a724ddfa53f..5a157cf4a95e 100644 --- a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c +++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c @@ -65,9 +65,8 @@ static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev, *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) - || !(dev->_isNTSC_ch2)) { + if ((lines <= NTSC_FIELD_HEIGHT) || + (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { offset += dist_betwn_starts; } } @@ -85,7 +84,7 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, { unsigned int line, i; struct sram_channel *sram_ch = - dev->channels[dev->_channel2_upstream_select].sram_channels; + dev->channels[dev->_channel2_upstream_select].sram_channels; int dist_betwn_starts = bpl * 2; /* sync instruction */ @@ -103,9 +102,8 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, *(rp++) = cpu_to_le32(databuf_phys_addr + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) - || !(dev->_isNTSC_ch2)) { + if ((lines <= NTSC_FIELD_HEIGHT) || + (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { offset += dist_betwn_starts; } @@ -173,7 +171,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, fifo_enable = FIFO_DISABLE; - /* Even field */ + /* Even field */ rp = cx25821_risc_field_upstream_ch2(dev, rp, dev->_data_buf_phys_addr_ch2 + databuf_offset, bottom_offset, 0x200, bpl, singlefield_lines, @@ -189,9 +187,9 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, } /* - Loop to 2ndFrameRISC or to Start of - Risc program & generate IRQ - */ + * Loop to 2ndFrameRISC or to Start of + * Risc program & generate IRQ + */ *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); *(rp++) = cpu_to_le32(risc_phys_jump_addr); *(rp++) = cpu_to_le32(0); @@ -203,7 +201,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) { struct sram_channel *sram_ch = - dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; + dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; u32 tmp = 0; if (!dev->_is_running_ch2) { @@ -262,9 +260,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) struct file *myfile; int frame_index_temp = dev->_frame_index_ch2; int i = 0; - int line_size = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; + int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; int frame_size = 0; int frame_offset = 0; ssize_t vfs_read_retval = 0; @@ -277,14 +274,11 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) return 0; if (dev->_isNTSC_ch2) { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; } else { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; } frame_offset = (frame_index_temp > 0) ? frame_size : 0; @@ -318,14 +312,14 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) for (i = 0; i < dev->_lines_count_ch2; i++) { pos = file_offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size && dev->_data_buf_virt_addr_ch2 != NULL) { memcpy((void *)(dev->_data_buf_virt_addr_ch2 + frame_offset / 4), mybuf, - vfs_read_retval); + vfs_read_retval); } file_offset += vfs_read_retval; @@ -341,8 +335,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) if (i > 0) dev->_frame_count_ch2++; - dev->_file_status_ch2 = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_file_status_ch2 = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); filp_close(myfile, NULL); @@ -353,8 +347,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) static void cx25821_vidups_handler_ch2(struct work_struct *work) { - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _irq_work_entry_ch2); + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _irq_work_entry_ch2); if (!dev) { pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", @@ -362,18 +356,16 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work) return; } - cx25821_get_frame_ch2(dev, - dev->channels[dev-> - _channel2_upstream_select].sram_channels); + cx25821_get_frame_ch2(dev, dev->channels[dev-> + _channel2_upstream_select].sram_channels); } int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; - int line_size = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; + int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; ssize_t vfs_read_retval = 0; char mybuf[line_size]; loff_t pos; @@ -410,16 +402,16 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) for (i = 0; i < dev->_lines_count_ch2; i++) { pos = offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); - if (vfs_read_retval > 0 - && vfs_read_retval == line_size - && dev->_data_buf_virt_addr_ch2 != NULL) { + if (vfs_read_retval > 0 && + vfs_read_retval == line_size && + dev->_data_buf_virt_addr_ch2 != NULL) { memcpy((void *)(dev-> _data_buf_virt_addr_ch2 + offset / 4), mybuf, - vfs_read_retval); + vfs_read_retval); } offset += vfs_read_retval; @@ -438,8 +430,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) break; } - dev->_file_status_ch2 = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_file_status_ch2 = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); myfile->f_pos = 0; @@ -463,9 +455,8 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, dev->_dma_phys_addr_ch2); } - dev->_dma_virt_addr_ch2 = - pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, - &dma_addr); + dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci, + dev->upstream_riscbuf_size_ch2, &dma_addr); dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; dev->_dma_phys_start_addr_ch2 = dma_addr; dev->_dma_phys_addr_ch2 = dma_addr; @@ -485,9 +476,8 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, dev->_data_buf_phys_addr_ch2); } /* For Video Data buffer allocation */ - dev->_data_buf_virt_addr_ch2 = - pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2, - &data_dma_addr); + dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci, + dev->upstream_databuf_size_ch2, &data_dma_addr); dev->_data_buf_phys_addr_ch2 = data_dma_addr; dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; @@ -563,8 +553,8 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, else line_size_in_bytes = Y422_LINE_SZ; risc_phys_jump_addr = - dev->_dma_phys_start_addr_ch2 + - odd_risc_prog_size; + dev->_dma_phys_start_addr_ch2 + + odd_risc_prog_size; rp = cx25821_update_riscprogram_ch2(dev, dev->_dma_virt_start_addr_ch2, @@ -612,11 +602,9 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) vid_status = cx_read(sram_ch->int_stat); /* Only deal with our interrupt */ - if (vid_status) { - handled = - cx25821_video_upstream_irq_ch2(dev, channel_num, - vid_status); - } + if (vid_status) + handled = cx25821_video_upstream_irq_ch2(dev, channel_num, + vid_status); if (handled < 0) cx25821_stop_upstream_video_ch2(dev); @@ -691,8 +679,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, tmp = cx_read(sram_ch->int_msk); cx_write(sram_ch->int_msk, tmp |= _intr_msk); - err = - request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, + err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, IRQF_SHARED, dev->name, dev); if (err < 0) { pr_err("%s: can't get upstream IRQ %d\n", @@ -752,45 +739,38 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, dev->_file_status_ch2 = RESET_STATUS; dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; dev->_pixel_format_ch2 = pixel_format; - dev->_line_size_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; - risc_buffer_size = - dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; + risc_buffer_size = dev->_isNTSC_ch2 ? + NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; if (dev->input_filename_ch2) { str_length = strlen(dev->input_filename_ch2); - dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); + dev->_filename_ch2 = kmemdup(dev->input_filename_ch2, + str_length + 1, GFP_KERNEL); if (!dev->_filename_ch2) goto error; - - memcpy(dev->_filename_ch2, dev->input_filename_ch2, - str_length + 1); } else { str_length = strlen(dev->_defaultname_ch2); - dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); + dev->_filename_ch2 = kmemdup(dev->_defaultname_ch2, + str_length + 1, GFP_KERNEL); if (!dev->_filename_ch2) goto error; - - memcpy(dev->_filename_ch2, dev->_defaultname_ch2, - str_length + 1); } /* Default if filename is empty string */ if (strcmp(dev->input_filename_ch2, "") == 0) { if (dev->_isNTSC_ch2) { - dev->_filename_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? "/root/vid411.yuv" : - "/root/vidtest.yuv"; + dev->_filename_ch2 = (dev->_pixel_format_ch2 == + PIXEL_FRMT_411) ? "/root/vid411.yuv" : + "/root/vidtest.yuv"; } else { - dev->_filename_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? "/root/pal411.yuv" : - "/root/pal422.yuv"; + dev->_filename_ch2 = (dev->_pixel_format_ch2 == + PIXEL_FRMT_411) ? "/root/pal411.yuv" : + "/root/pal422.yuv"; } } diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.c b/drivers/media/video/cx25821/cx25821-video-upstream.c index c0b80068f468..21e7d657f049 100644 --- a/drivers/media/video/cx25821/cx25821-video-upstream.c +++ b/drivers/media/video/cx25821/cx25821-video-upstream.c @@ -136,7 +136,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, { unsigned int line, i; struct sram_channel *sram_ch = - dev->channels[dev->_channel_upstream_select].sram_channels; + dev->channels[dev->_channel_upstream_select].sram_channels; int dist_betwn_starts = bpl * 2; /* sync instruction */ @@ -194,15 +194,12 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, if (dev->_isNTSC) { odd_num_lines = singlefield_lines + 1; risc_program_size = FRAME1_VID_PROG_SIZE; - frame_size = - (bpl == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; + frame_size = (bpl == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; } else { risc_program_size = PAL_VID_PROG_SIZE; - frame_size = - (bpl == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; + frame_size = (bpl == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; } /* Virtual address of Risc buffer program */ @@ -214,13 +211,9 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, if (UNSET != top_offset) { fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; rp = cx25821_risc_field_upstream(dev, rp, - dev-> - _data_buf_phys_addr + - databuf_offset, - top_offset, 0, bpl, - odd_num_lines, - fifo_enable, - ODD_FIELD); + dev->_data_buf_phys_addr + + databuf_offset, top_offset, 0, bpl, + odd_num_lines, fifo_enable, ODD_FIELD); } fifo_enable = FIFO_DISABLE; @@ -234,8 +227,8 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, if (frame == 0) { risc_flag = RISC_CNT_RESET; - risc_phys_jump_addr = - dev->_dma_phys_start_addr + risc_program_size; + risc_phys_jump_addr = dev->_dma_phys_start_addr + + risc_program_size; } else { risc_phys_jump_addr = dev->_dma_phys_start_addr; risc_flag = RISC_CNT_INC; @@ -255,7 +248,7 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) { struct sram_channel *sram_ch = - dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; + dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; u32 tmp = 0; if (!dev->_is_running) { @@ -312,9 +305,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) struct file *myfile; int frame_index_temp = dev->_frame_index; int i = 0; - int line_size = - (dev->_pixel_format == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; + int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; int frame_size = 0; int frame_offset = 0; ssize_t vfs_read_retval = 0; @@ -326,16 +318,12 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) if (dev->_file_status == END_OF_FILE) return 0; - if (dev->_isNTSC) { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; - } else { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; - } + if (dev->_isNTSC) + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; + else + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; frame_offset = (frame_index_temp > 0) ? frame_size : 0; file_offset = dev->_frame_count * frame_size; @@ -369,8 +357,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) for (i = 0; i < dev->_lines_count; i++) { pos = file_offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size && dev->_data_buf_virt_addr != NULL) { @@ -392,8 +380,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) if (i > 0) dev->_frame_count++; - dev->_file_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_file_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); filp_close(myfile, NULL); @@ -404,8 +392,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) static void cx25821_vidups_handler(struct work_struct *work) { - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _irq_work_entry); + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _irq_work_entry); if (!dev) { pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", @@ -413,18 +401,16 @@ static void cx25821_vidups_handler(struct work_struct *work) return; } - cx25821_get_frame(dev, - dev->channels[dev->_channel_upstream_select]. - sram_channels); + cx25821_get_frame(dev, dev->channels[dev->_channel_upstream_select]. + sram_channels); } int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; - int line_size = - (dev->_pixel_format == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; + int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; ssize_t vfs_read_retval = 0; char mybuf[line_size]; loff_t pos; @@ -461,8 +447,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) for (i = 0; i < dev->_lines_count; i++) { pos = offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size @@ -489,8 +475,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) break; } - dev->_file_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_file_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); myfile->f_pos = 0; @@ -507,14 +493,12 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, dma_addr_t dma_addr; dma_addr_t data_dma_addr; - if (dev->_dma_virt_addr != NULL) { + if (dev->_dma_virt_addr != NULL) pci_free_consistent(dev->pci, dev->upstream_riscbuf_size, - dev->_dma_virt_addr, dev->_dma_phys_addr); - } + dev->_dma_virt_addr, dev->_dma_phys_addr); - dev->_dma_virt_addr = - pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size, - &dma_addr); + dev->_dma_virt_addr = pci_alloc_consistent(dev->pci, + dev->upstream_riscbuf_size, &dma_addr); dev->_dma_virt_start_addr = dev->_dma_virt_addr; dev->_dma_phys_start_addr = dma_addr; dev->_dma_phys_addr = dma_addr; @@ -528,15 +512,13 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, /* Clear memory at address */ memset(dev->_dma_virt_addr, 0, dev->_risc_size); - if (dev->_data_buf_virt_addr != NULL) { + if (dev->_data_buf_virt_addr != NULL) pci_free_consistent(dev->pci, dev->upstream_databuf_size, - dev->_data_buf_virt_addr, - dev->_data_buf_phys_addr); - } + dev->_data_buf_virt_addr, + dev->_data_buf_phys_addr); /* For Video Data buffer allocation */ - dev->_data_buf_virt_addr = - pci_alloc_consistent(dev->pci, dev->upstream_databuf_size, - &data_dma_addr); + dev->_data_buf_virt_addr = pci_alloc_consistent(dev->pci, + dev->upstream_databuf_size, &data_dma_addr); dev->_data_buf_phys_addr = data_dma_addr; dev->_data_buf_size = dev->upstream_databuf_size; @@ -553,9 +535,8 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, return ret; /* Create RISC programs */ - ret = - cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, - dev->_lines_count); + ret = cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, + dev->_lines_count); if (ret < 0) { pr_info("Failed creating Video Upstream Risc programs!\n"); goto error; @@ -672,10 +653,9 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) vid_status = cx_read(sram_ch->int_stat); /* Only deal with our interrupt */ - if (vid_status) { - handled = - cx25821_video_upstream_irq(dev, channel_num, vid_status); - } + if (vid_status) + handled = cx25821_video_upstream_irq(dev, channel_num, + vid_status); if (handled < 0) cx25821_stop_upstream_video_ch1(dev); @@ -747,8 +727,7 @@ int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, tmp = cx_read(sram_ch->int_msk); cx_write(sram_ch->int_msk, tmp |= _intr_msk); - err = - request_irq(dev->pci->irq, cx25821_upstream_irq, + err = request_irq(dev->pci->irq, cx25821_upstream_irq, IRQF_SHARED, dev->name, dev); if (err < 0) { pr_err("%s: can't get upstream IRQ %d\n", @@ -807,43 +786,38 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, dev->_file_status = RESET_STATUS; dev->_lines_count = dev->_isNTSC ? 480 : 576; dev->_pixel_format = pixel_format; - dev->_line_size = - (dev->_pixel_format == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; - risc_buffer_size = - dev->_isNTSC ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; + risc_buffer_size = dev->_isNTSC ? + NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; if (dev->input_filename) { str_length = strlen(dev->input_filename); - dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); + dev->_filename = kmemdup(dev->input_filename, str_length + 1, + GFP_KERNEL); if (!dev->_filename) goto error; - - memcpy(dev->_filename, dev->input_filename, str_length + 1); } else { str_length = strlen(dev->_defaultname); - dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); + dev->_filename = kmemdup(dev->_defaultname, str_length + 1, + GFP_KERNEL); if (!dev->_filename) goto error; - - memcpy(dev->_filename, dev->_defaultname, str_length + 1); } /* Default if filename is empty string */ if (strcmp(dev->input_filename, "") == 0) { if (dev->_isNTSC) { dev->_filename = - (dev->_pixel_format == - PIXEL_FRMT_411) ? "/root/vid411.yuv" : - "/root/vidtest.yuv"; + (dev->_pixel_format == PIXEL_FRMT_411) ? + "/root/vid411.yuv" : "/root/vidtest.yuv"; } else { dev->_filename = - (dev->_pixel_format == - PIXEL_FRMT_411) ? "/root/pal411.yuv" : - "/root/pal422.yuv"; + (dev->_pixel_format == PIXEL_FRMT_411) ? + "/root/pal411.yuv" : "/root/pal422.yuv"; } } @@ -852,13 +826,11 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, dev->_file_status = RESET_STATUS; dev->_lines_count = dev->_isNTSC ? 480 : 576; dev->_pixel_format = pixel_format; - dev->_line_size = - (dev->_pixel_format == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; - retval = - cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size, - 0); + retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, + dev->_line_size, 0); /* setup fifo + format */ cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format); diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c index 4d6907cda75b..ffd8bc79c02e 100644 --- a/drivers/media/video/cx25821/cx25821-video.c +++ b/drivers/media/video/cx25821/cx25821-video.c @@ -118,12 +118,12 @@ void cx25821_dump_video_queue(struct cx25821_dev *dev, if (!list_empty(&q->active)) { list_for_each(item, &q->active) - buf = list_entry(item, struct cx25821_buffer, vb.queue); + buf = list_entry(item, struct cx25821_buffer, vb.queue); } if (!list_empty(&q->queued)) { list_for_each(item, &q->queued) - buf = list_entry(item, struct cx25821_buffer, vb.queue); + buf = list_entry(item, struct cx25821_buffer, vb.queue); } } @@ -140,8 +140,8 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, break; } - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); /* count comes from the hw and it is 16bit wide -- * this trick handles wrap-arounds correctly for @@ -318,8 +318,8 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev, struct list_head *item; if (!list_empty(&q->active)) { - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); cx25821_start_video_dma(dev, q, buf, channel); @@ -337,8 +337,8 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev, if (list_empty(&q->queued)) return 0; - buf = - list_entry(q->queued.next, struct cx25821_buffer, vb.queue); + buf = list_entry(q->queued.next, struct cx25821_buffer, + vb.queue); if (NULL == prev) { list_move_tail(&buf->vb.queue, &q->active); @@ -375,8 +375,8 @@ void cx25821_vid_timeout(unsigned long data) spin_lock_irqsave(&dev->slock, flags); while (!list_empty(&q->active)) { - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); list_del(&buf->vb.queue); buf->vb.state = VIDEOBUF_ERROR; @@ -484,8 +484,7 @@ int cx25821_video_register(struct cx25821_dev *dev) cx25821_init_controls(dev, i); cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, - dev->channels[i].sram_channels->dma_ctl, - 0x11, 0); + dev->channels[i].sram_channels->dma_ctl, 0x11, 0); dev->channels[i].sram_channels = &cx25821_sram_channels[i]; dev->channels[i].video_dev = NULL; @@ -499,15 +498,14 @@ int cx25821_video_register(struct cx25821_dev *dev) dev->channels[i].timeout_data.dev = dev; dev->channels[i].timeout_data.channel = &cx25821_sram_channels[i]; - dev->channels[i].vidq.timeout.function = - cx25821_vid_timeout; + dev->channels[i].vidq.timeout.function = cx25821_vid_timeout; dev->channels[i].vidq.timeout.data = (unsigned long)&dev->channels[i].timeout_data; init_timer(&dev->channels[i].vidq.timeout); /* register v4l devices */ - dev->channels[i].video_dev = cx25821_vdev_init(dev, - dev->pci, &cx25821_video_device, "video"); + dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci, + &cx25821_video_device, "video"); err = video_register_device(dev->channels[i].video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); @@ -528,7 +526,6 @@ int cx25821_video_register(struct cx25821_dev *dev) #endif mutex_unlock(&dev->lock); - return 0; fail_unreg: @@ -558,7 +555,7 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct cx25821_fh *fh = q->priv_data; struct cx25821_dev *dev = fh->dev; struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); + container_of(vb, struct cx25821_buffer, vb); int rc, init_buffer = 0; u32 line0_offset, line1_offset; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); @@ -617,14 +614,13 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (channel_opened >= 0 && channel_opened <= 7) { if (dev->channels[channel_opened] .use_cif_resolution) { - if (dev->tvnorm & V4L2_STD_PAL_BG - || dev->tvnorm & V4L2_STD_PAL_DK) + if (dev->tvnorm & V4L2_STD_PAL_BG || + dev->tvnorm & V4L2_STD_PAL_DK) bpl_local = 352 << 1; else - bpl_local = - dev->channels[channel_opened]. - cif_width << - 1; + bpl_local = dev->channels[ + channel_opened]. + cif_width << 1; } } } @@ -685,7 +681,7 @@ void cx25821_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); + container_of(vb, struct cx25821_buffer, vb); cx25821_free_buffer(q, buf); } @@ -723,7 +719,7 @@ int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); + container_of(vb, struct cx25821_buffer, vb); struct cx25821_buffer *prev; struct cx25821_fh *fh = vq->priv_data; struct cx25821_dev *dev = fh->dev; @@ -814,7 +810,7 @@ static int video_open(struct file *file) for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) { if (h->channels[i].video_dev && - h->channels[i].video_dev->minor == minor) { + h->channels[i].video_dev->minor == minor) { dev = h; ch_id = i; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -848,11 +844,10 @@ static int video_open(struct file *file) v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio); - videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx25821_buffer), fh, NULL); + videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev, + &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), + fh, NULL); dprintk(1, "post videobuf_queue_init()\n"); mutex_unlock(&cx25821_devlist_mutex); @@ -1168,8 +1163,8 @@ int cx25821_vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); cap->version = CX25821_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; if (UNSET != dev->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; @@ -1454,38 +1449,38 @@ static const struct v4l2_queryctrl no_ctl = { static struct v4l2_queryctrl cx25821_ctls[] = { /* --- video --- */ { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 6200, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - } + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 6200, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + } }; static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls); @@ -1623,7 +1618,8 @@ int cx25821_vidioc_cropcap(struct file *file, void *priv, if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.left = 0; cropcap->bounds.width = 720; cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480; cropcap->pixelaspect.numerator = @@ -1829,8 +1825,11 @@ static long video_ioctl_set(struct file *file, unsigned int cmd, struct downstream_user_struct *data_from_user; int command; int width = 720; - int selected_channel = 0, pix_format = 0, i = 0; - int cif_enable = 0, cif_width = 0; + int selected_channel = 0; + int pix_format = 0; + int i = 0; + int cif_enable = 0; + int cif_width = 0; u32 value = 0; data_from_user = (struct downstream_user_struct *)arg; @@ -1895,8 +1894,8 @@ static long video_ioctl_set(struct file *file, unsigned int cmd, } if (selected_channel <= 7 && selected_channel >= 0) { - dev->channels[selected_channel]. - use_cif_resolution = cif_enable; + dev->channels[selected_channel].use_cif_resolution = + cif_enable; dev->channels[selected_channel].cif_width = width; } else { for (i = 0; i < VID_CHANNEL_NUM; i++) { @@ -1932,9 +1931,9 @@ static long video_ioctl_set(struct file *file, unsigned int cmd, static long cx25821_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret = 0; + int ret = 0; - struct cx25821_fh *fh = file->private_data; + struct cx25821_fh *fh = file->private_data; /* check to see if it's the video upstream */ if (fh->channel_id == SRAM_CH09) { diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h index 2d2d00932823..b9aa801b00a7 100644 --- a/drivers/media/video/cx25821/cx25821.h +++ b/drivers/media/video/cx25821/cx25821.h @@ -67,7 +67,7 @@ #define MAX_CAMERAS 16 /* Max number of inputs by card */ -#define MAX_CX25821_INPUT 8 +#define MAX_CX25821_INPUT 8 #define INPUT(nr) (&cx25821_boards[dev->board].input[nr]) #define RESOURCE_VIDEO0 1 #define RESOURCE_VIDEO1 2 @@ -85,7 +85,7 @@ #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ -#define UNKNOWN_BOARD 0 +#define UNKNOWN_BOARD 0 #define CX25821_BOARD 1 /* Currently supported by the driver */ diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 005f11093642..34b96c7cfd62 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -480,7 +480,6 @@ void cx25840_audio_set_path(struct i2c_client *client) static void set_volume(struct i2c_client *client, int volume) { - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); int vol; /* Convert the volume to msp3400 values (0-127) */ @@ -496,14 +495,7 @@ static void set_volume(struct i2c_client *client, int volume) } /* PATH1_VOLUME */ - if (is_cx2388x(state)) { - /* for cx23885 volume doesn't work, - * the calculation always results in - * e4 regardless. - */ - cx25840_write(client, 0x8d4, volume); - } else - cx25840_write(client, 0x8d4, 228 - (vol * 2)); + cx25840_write(client, 0x8d4, 228 - (vol * 2)); } static void set_balance(struct i2c_client *client, int balance) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index cd9976408ab3..05247d4c340a 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -18,6 +18,9 @@ * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net> * + * CX23888 DIF support for the HVR1850 + * Copyright (C) 2011 Steven Toth <stoth@kernellabs.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 @@ -40,6 +43,7 @@ #include <linux/videodev2.h> #include <linux/i2c.h> #include <linux/delay.h> +#include <linux/math64.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> #include <media/cx25840.h> @@ -80,6 +84,7 @@ MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); /* ----------------------------------------------------------------------- */ +static void cx23885_std_setup(struct i2c_client *client); int cx25840_write(struct i2c_client *client, u16 addr, u8 value) { @@ -498,8 +503,13 @@ static void cx23885_initialize(struct i2c_client *client) * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz * 572.73 MHz before post divide */ - cx25840_write4(client, 0x11c, 0x00e8ba26); - cx25840_write4(client, 0x118, 0x0000040b); + /* HVR1850 or 50MHz xtal */ + cx25840_write(client, 0x2, 0x71); + cx25840_write4(client, 0x11c, 0x01d1744c); + cx25840_write4(client, 0x118, 0x00000416); + cx25840_write4(client, 0x404, 0x0010253e); + cx25840_write4(client, 0x42c, 0x42600000); + cx25840_write4(client, 0x44c, 0x161f1000); break; case V4L2_IDENT_CX23887_AV: /* @@ -533,8 +543,18 @@ static void cx23885_initialize(struct i2c_client *client) * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz * 432.0 MHz before post divide */ - cx25840_write4(client, 0x10c, 0x002be2c9); - cx25840_write4(client, 0x108, 0x0000040f); + + /* HVR1850 */ + switch (state->id) { + case V4L2_IDENT_CX23888_AV: + /* 888/HVR1250 specific */ + cx25840_write4(client, 0x10c, 0x13333333); + cx25840_write4(client, 0x108, 0x00000515); + break; + default: + cx25840_write4(client, 0x10c, 0x002be2c9); + cx25840_write4(client, 0x108, 0x0000040f); + } /* Luma */ cx25840_write4(client, 0x414, 0x00107d12); @@ -556,8 +576,9 @@ static void cx23885_initialize(struct i2c_client *client) * 368.64 MHz before post divide * 122.88 MHz / 0xa = 12.288 MHz */ - cx25840_write4(client, 0x114, 0x00bedfa4); - cx25840_write4(client, 0x110, 0x000a0307); + /* HVR1850 or 50MHz xtal */ + cx25840_write4(client, 0x114, 0x017dbf48); + cx25840_write4(client, 0x110, 0x000a030e); break; case V4L2_IDENT_CX23887_AV: /* @@ -617,7 +638,10 @@ static void cx23885_initialize(struct i2c_client *client) finish_wait(&state->fw_wait, &wait); destroy_workqueue(q); - cx25840_std_setup(client); + /* Call the cx23885 specific std setup func, we no longer rely on + * the generic cx24840 func. + */ + cx23885_std_setup(client); /* (re)set input */ set_input(client, state->vid_input, state->aud_input); @@ -631,6 +655,37 @@ static void cx23885_initialize(struct i2c_client *client) /* Disable and clear audio interrupts - we don't use them */ cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff); cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff); + + /* CC raw enable */ + /* - VIP 1.1 control codes - 10bit, blue field enable. + * - enable raw data during vertical blanking. + * - enable ancillary Data insertion for 656 or VIP. + */ + cx25840_write4(client, 0x404, 0x0010253e); + + /* CC on - Undocumented Register */ + cx25840_write(client, 0x42f, 0x66); + + /* HVR-1250 / HVR1850 DIF related */ + /* Power everything up */ + cx25840_write4(client, 0x130, 0x0); + + /* Undocumented */ + cx25840_write4(client, 0x478, 0x6628021F); + + /* AFE_CLK_OUT_CTRL - Select the clock output source as output */ + cx25840_write4(client, 0x144, 0x5); + + /* I2C_OUT_CTL - I2S output configuration as + * Master, Sony, Left justified, left sample on WS=1 + */ + cx25840_write4(client, 0x918, 0x1a0); + + /* AFE_DIAG_CTRL1 */ + cx25840_write4(client, 0x134, 0x000a1800); + + /* AFE_DIAG_CTRL3 - Inverted Polarity for Audio and Video */ + cx25840_write4(client, 0x13c, 0x00310000); } /* ----------------------------------------------------------------------- */ @@ -945,9 +1000,14 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp vid_input <= CX25840_COMPOSITE8); u8 is_component = (vid_input & CX25840_COMPONENT_ON) == CX25840_COMPONENT_ON; + u8 is_dif = (vid_input & CX25840_DIF_ON) == + CX25840_DIF_ON; + u8 is_svideo = (vid_input & CX25840_SVIDEO_ON) == + CX25840_SVIDEO_ON; int luma = vid_input & 0xf0; int chroma = vid_input & 0xf00; u8 reg; + u32 val; v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n", @@ -1012,6 +1072,66 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp else cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); + if (is_cx2388x(state)) { + + /* Enable or disable the DIF for tuner use */ + if (is_dif) { + cx25840_and_or(client, 0x102, ~0x80, 0x80); + + /* Set of defaults for NTSC and PAL */ + cx25840_write4(client, 0x31c, 0xc2262600); + cx25840_write4(client, 0x320, 0xc2262600); + + /* 18271 IF - Nobody else yet uses a different + * tuner with the DIF, so these are reasonable + * assumptions (HVR1250 and HVR1850 specific). + */ + cx25840_write4(client, 0x318, 0xda262600); + cx25840_write4(client, 0x33c, 0x2a24c800); + cx25840_write4(client, 0x104, 0x0704dd00); + } else { + cx25840_write4(client, 0x300, 0x015c28f5); + + cx25840_and_or(client, 0x102, ~0x80, 0); + cx25840_write4(client, 0x340, 0xdf7df83); + cx25840_write4(client, 0x104, 0x0704dd80); + cx25840_write4(client, 0x314, 0x22400600); + cx25840_write4(client, 0x318, 0x40002600); + cx25840_write4(client, 0x324, 0x40002600); + cx25840_write4(client, 0x32c, 0x0250e620); + cx25840_write4(client, 0x39c, 0x01FF0B00); + + cx25840_write4(client, 0x410, 0xffff0dbf); + cx25840_write4(client, 0x414, 0x00137d03); + cx25840_write4(client, 0x418, 0x01008080); + cx25840_write4(client, 0x41c, 0x00000000); + cx25840_write4(client, 0x420, 0x001c3e0f); + cx25840_write4(client, 0x42c, 0x42600000); + cx25840_write4(client, 0x430, 0x0000039b); + cx25840_write4(client, 0x438, 0x00000000); + + cx25840_write4(client, 0x440, 0xF8E3E824); + cx25840_write4(client, 0x444, 0x401040dc); + cx25840_write4(client, 0x448, 0xcd3f02a0); + cx25840_write4(client, 0x44c, 0x161f1000); + cx25840_write4(client, 0x450, 0x00000802); + + cx25840_write4(client, 0x91c, 0x01000000); + cx25840_write4(client, 0x8e0, 0x03063870); + cx25840_write4(client, 0x8d4, 0x7FFF0024); + cx25840_write4(client, 0x8d0, 0x00063073); + + cx25840_write4(client, 0x8c8, 0x00010000); + cx25840_write4(client, 0x8cc, 0x00080023); + + /* DIF BYPASS */ + cx25840_write4(client, 0x33c, 0x2a04c800); + } + + /* Reset the DIF */ + cx25840_write4(client, 0x398, 0); + } + if (!is_cx2388x(state) && !is_cx231xx(state)) { /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); @@ -1036,6 +1156,33 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_and_or(client, 0x102, ~0x2, 0); } } + + /* cx23885 / SVIDEO */ + if (is_cx2388x(state) && is_svideo) { +#define AFE_CTRL (0x104) +#define MODE_CTRL (0x400) + cx25840_and_or(client, 0x102, ~0x2, 0x2); + + val = cx25840_read4(client, MODE_CTRL); + val &= 0xFFFFF9FF; + + /* YC */ + val |= 0x00000200; + val &= ~0x2000; + cx25840_write4(client, MODE_CTRL, val); + + val = cx25840_read4(client, AFE_CTRL); + + /* Chroma in select */ + val |= 0x00001000; + val &= 0xfffffe7f; + /* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8). + * This sets them to use video rather than audio. + * Only one of the two will be in use. + */ + cx25840_write4(client, AFE_CTRL, val); + } else + cx25840_and_or(client, 0x102, ~0x2, 0); } state->vid_input = vid_input; @@ -1086,6 +1233,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write4(client, 0x8d0, 0x1f063870); } + if (is_cx2388x(state)) { + /* HVR1850 */ + /* AUD_IO_CTRL - I2S Input, Parallel1*/ + /* - Channel 1 src - Parallel1 (Merlin out) */ + /* - Channel 2 src - Parallel2 (Merlin out) */ + /* - Channel 3 src - Parallel3 (Merlin AC97 out) */ + /* - I2S source and dir - Merlin, output */ + cx25840_write4(client, 0x124, 0x100); + + if (!is_dif) { + /* Stop microcontroller if we don't need it + * to avoid audio popping on svideo/composite use. + */ + cx25840_and_or(client, 0x803, ~0x10, 0x00); + } + } + return 0; } @@ -1134,7 +1298,10 @@ static int set_v4lstd(struct i2c_client *client) } cx25840_and_or(client, 0x400, ~0xf, fmt); cx25840_and_or(client, 0x403, ~0x3, pal_m); - cx25840_std_setup(client); + if (is_cx2388x(state)) + cx23885_std_setup(client); + else + cx25840_std_setup(client); if (!is_cx2583x(state)) input_change(client); return 0; @@ -1539,6 +1706,56 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +/* Query the current detected video format */ +static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + v4l2_std_id stds[] = { + /* 0000 */ V4L2_STD_UNKNOWN, + + /* 0001 */ V4L2_STD_NTSC_M, + /* 0010 */ V4L2_STD_NTSC_M_JP, + /* 0011 */ V4L2_STD_NTSC_443, + /* 0100 */ V4L2_STD_PAL, + /* 0101 */ V4L2_STD_PAL_M, + /* 0110 */ V4L2_STD_PAL_N, + /* 0111 */ V4L2_STD_PAL_Nc, + /* 1000 */ V4L2_STD_PAL_60, + + /* 1001 */ V4L2_STD_UNKNOWN, + /* 1010 */ V4L2_STD_UNKNOWN, + /* 1001 */ V4L2_STD_UNKNOWN, + /* 1010 */ V4L2_STD_UNKNOWN, + /* 1011 */ V4L2_STD_UNKNOWN, + /* 1110 */ V4L2_STD_UNKNOWN, + /* 1111 */ V4L2_STD_UNKNOWN + }; + + u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf; + *std = stds[ fmt ]; + + v4l_dbg(1, cx25840_debug, client, "g_std fmt = %x, v4l2_std_id = 0x%x\n", + fmt, (unsigned int)stds[ fmt ]); + + return 0; +} + +static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* A limited function that checks for signal status and returns + * the state. + */ + + /* Check for status of Horizontal lock (SRC lock isn't reliable) */ + if ((cx25840_read4(client, 0x40c) & 0x00010000) == 0) + *status |= V4L2_IN_ST_NO_SIGNAL; + + return 0; +} + static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct cx25840_state *state = to_state(sd); @@ -1565,6 +1782,9 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd, struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + if (is_cx2388x(state)) + cx23885_std_setup(client); + return set_input(client, input, state->aud_input); } @@ -1574,6 +1794,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd, struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + if (is_cx2388x(state)) + cx23885_std_setup(client); return set_input(client, state->vid_input, input); } @@ -1786,6 +2008,3007 @@ static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, /* ----------------------------------------------------------------------- */ +#define DIF_PLL_FREQ_WORD (0x300) +#define DIF_BPF_COEFF01 (0x348) +#define DIF_BPF_COEFF23 (0x34c) +#define DIF_BPF_COEFF45 (0x350) +#define DIF_BPF_COEFF67 (0x354) +#define DIF_BPF_COEFF89 (0x358) +#define DIF_BPF_COEFF1011 (0x35c) +#define DIF_BPF_COEFF1213 (0x360) +#define DIF_BPF_COEFF1415 (0x364) +#define DIF_BPF_COEFF1617 (0x368) +#define DIF_BPF_COEFF1819 (0x36c) +#define DIF_BPF_COEFF2021 (0x370) +#define DIF_BPF_COEFF2223 (0x374) +#define DIF_BPF_COEFF2425 (0x378) +#define DIF_BPF_COEFF2627 (0x37c) +#define DIF_BPF_COEFF2829 (0x380) +#define DIF_BPF_COEFF3031 (0x384) +#define DIF_BPF_COEFF3233 (0x388) +#define DIF_BPF_COEFF3435 (0x38c) +#define DIF_BPF_COEFF36 (0x390) + +void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) +{ + u64 pll_freq; + u32 pll_freq_word; + + v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz); + + /* Assuming TV */ + /* Calculate the PLL frequency word based on the adjusted ifHz */ + pll_freq = div_u64((u64)ifHz * 268435456, 50000000); + pll_freq_word = (u32)pll_freq; + + cx25840_write4(client, DIF_PLL_FREQ_WORD, pll_freq_word); + + /* Round down to the nearest 100KHz */ + ifHz = (ifHz / 100000) * 100000; + + if (ifHz < 3000000) + ifHz = 3000000; + + if (ifHz > 16000000) + ifHz = 16000000; + + v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz); + + switch (ifHz) { + case 3000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0024); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001bfff8); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff50); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed8fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe34); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfebaffc7); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d031f); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04f0065d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07010688); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x04c901d6); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f9d3); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f342); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f337); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf64efb22); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105070f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0c460fce); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00220032); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00370026); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff91); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0efe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fdcc); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe0afedb); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440224); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0434060c); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738074e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06090361); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99fb39); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef3b6); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21af2a5); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf573fa33); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034067d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bfb0fb9); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00200038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004c004f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x002fffdf); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff5cfeb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dfd92); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7ffe03); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36010a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x03410575); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x072607d2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x071804d5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134fcb7); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff451); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223f22e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4a7f94b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xff6405e8); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bae0fa4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00000008); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0036); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0056006d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00670030); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffbdff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46fd8d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd25fd4f); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35ffe0); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0224049f); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9080e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x07ef0627); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9fe45); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f513); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250f1d2); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3ecf869); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930552); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b5f0f8f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0001); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000f002c); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0054007d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0093007c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0024ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6fdbb); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd03fcca); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51feb9); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x00eb0392); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270802); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08880750); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x044dffdb); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf5f8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0f193); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf342f78f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc404b9); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b0e0f78); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff9); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0002001b); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0046007d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad00ba); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00870000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe1a); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1bfc7e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fda4); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xffa5025c); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x054507ad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08dd0847); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80172); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef6ff); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313f170); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2abf6bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6041f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0abc0f61); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff3); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff50006); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002f006c); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b200e3); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00dc007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9fea0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd6bfc71); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fcb1); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe65010b); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x042d0713); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ec0906); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020302); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff823); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7f16a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf228f5f5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2a0384); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a670f4a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7ffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9fff1); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0010004d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a100f2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x011a00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053ff44); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdedfca2); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fbef); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd39ffae); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x02ea0638); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08b50987); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230483); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f960); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45bf180); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1b8f537); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb6102e7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a110f32); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffdd); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00024); + cx25840_write4(client, DIF_BPF_COEFF89, 0x007c00e5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013a014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e6fff8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe98fd0f); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fb67); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc32fe54); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x01880525); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x083909c7); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x091505ee); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7fab3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52df1b4); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf15df484); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9b0249); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x09ba0f19); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffcf); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1fff6); + cx25840_write4(client, DIF_BPF_COEFF89, 0x004800be); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01390184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x016300ac); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff5efdb1); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb23); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb5cfd0d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x001703e4); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x077b09c4); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d2073c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251fc18); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61cf203); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf118f3dc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d801aa); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x09600eff); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffefff4); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffca); + cx25840_write4(client, DIF_BPF_COEFF89, 0x000b0082); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01170198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10152); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0030fe7b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb24); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfac3fbe9); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5027f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0683097f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a560867); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2fd89); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723f26f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0e8f341); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919010a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x09060ee5); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fffb); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8ffca); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffa4); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffcd0036); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d70184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f601dc); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ffff60); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb6d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6efaf5); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd410103); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x055708f9); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e0969); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543ff02); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842f2f5); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cef2b2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85e006b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x08aa0ecb); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00050003); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff3ffd3); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaff8b); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ffe5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0080014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe023f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ba0050); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fbf8); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa62fa3b); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9ff7e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x04010836); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa90a3d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f007f); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf975f395); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cbf231); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ffcb); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x084c0eaf); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000a); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0000ffe4); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff81); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff96); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x001c00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70271); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0254013b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fcbd); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa9ff9c5); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbfdfe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x028c073b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a750adf); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e101fa); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab8f44e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0ddf1be); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ff2b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x07ed0e94); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000efff8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff87); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff54); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffb5007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01860270); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c00210); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fdb2); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb22f997); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2fc90); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0102060f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a050b4c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902036e); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0af51e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf106f15a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64efe8b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x078d0e77); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0019000e); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff9e); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff25); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff560000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112023b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f702c0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfec8); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbe5f9b3); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947fb41); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xff7004b9); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a0b81); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a0004d8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd65f603); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf144f104); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aafdec); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x072b0e5a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00060012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00200022); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ffc1); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ff10); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff09ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x008601d7); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f50340); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fff0); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcddfa19); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa1e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfde30343); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08790b7f); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50631); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec7f6fc); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf198f0bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50dfd4e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x06c90e3d); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00220030); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffed); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff87ff15); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed6ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffed014c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b90386); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110119); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfdfefac4); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6f92f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc6701b7); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07670b44); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0776); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x002df807); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf200f086); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477fcb1); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x06650e1e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0009); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003f001b); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffbcff36); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec2feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff5600a5); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0248038d); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00232); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff39fbab); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4f87f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb060020); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x062a0ad2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf908a3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0192f922); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf27df05e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8fc14); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x06000e00); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0002); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00160037); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00510046); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff9ff6d); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed0fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefff0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01aa0356); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413032b); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x007ffcc5); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cf812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9cefe87); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c90a2c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4309b4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f3fa4a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf30ef046); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361fb7a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x059b0de0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000a002d); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00570067); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0037ffb5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfefffe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62ff3d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ec02e3); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x043503f6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x01befe05); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa27f7ee); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8c6fcf8); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x034c0954); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0aa4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x044cfb7e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3b1f03f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2fae1); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x05340dc0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff4); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffd001e); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0051007b); + cx25840_write4(client, DIF_BPF_COEFF89, 0x006e0006); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff48fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfe9a); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x001d023e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130488); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x02e6ff5b); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1ef812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7f7fb7f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bc084e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430b72); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x059afcba); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf467f046); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cfa4a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x04cd0da0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff00009); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003f007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00980056); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffa5feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe15); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff4b0170); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b004d7); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x03e800b9); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc48f87f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf768fa23); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022071f); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90c1b); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x06dafdfd); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf52df05e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef9b5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x04640d7f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6fff3); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00250072); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00af009c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x000cff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13fdb8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe870089); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104e1); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04b8020f); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd98f92f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf71df8f0); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe8805ce); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0c9c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0808ff44); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf603f086); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af922); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x03fb0d5e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe0); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00050056); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b000d1); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0071ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53fd8c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfddfff99); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104a3); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x054a034d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xff01fa1e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf717f7ed); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf50461); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50cf4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0921008d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf6e7f0bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff891); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x03920d3b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffffff3); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffd1); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5002f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x009c00ed); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00cb0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfebafd94); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd61feb0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d0422); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05970464); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0074fb41); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf759f721); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb7502de); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000d21); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a2201d4); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7d9f104); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf804); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x03280d19); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fffa); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3ffc9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc90002); + cx25840_write4(client, DIF_BPF_COEFF89, 0x007500ef); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x010e007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3dfdcf); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd16fddd); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440365); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x059b0548); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3fc90); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7dff691); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0f014d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020d23); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0318); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8d7f15a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f779); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x02bd0cf6); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00060001); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffecffc9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffd4); + cx25840_write4(client, DIF_BPF_COEFF89, 0x004000d5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013600f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd3fe39); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd04fd31); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff360277); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x055605ef); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x033efdfe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8a5f642); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbffb6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10cfb); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50456); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9dff1be); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f6f2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x02520cd2); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080009); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff8ffd2); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffac); + cx25840_write4(client, DIF_BPF_COEFF89, 0x000200a3); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013c014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x006dfec9); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2bfcb7); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe350165); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04cb0651); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477ff7e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9a5f635); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1fe20); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0ca8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c81058b); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfaf0f231); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f66d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x01e60cae); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0005ffe1); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffacff90); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5005f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01210184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fcff72); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd8afc77); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51003f); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04020669); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830103); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfad7f66b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8fc93); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430c2b); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d06b5); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfc08f2b2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af5ec); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x017b0c89); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0012fff5); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaff82); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff8e000f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e80198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750028); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe18fc75); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99ff15); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x03050636); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0656027f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc32f6e2); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614fb17); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20b87); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d7707d2); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfd26f341); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf56f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x010f0c64); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00050012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001c000b); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff84); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ffbe); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00960184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd00da); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeccfcb2); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fdf9); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x01e005bc); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e703e4); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfdabf798); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f9b3); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510abd); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf08df); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfe48f3dc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f4f6); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x00a20c3e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0002000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0021001f); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff97); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff74); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0034014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa0179); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff97fd2a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fcfa); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x00a304fe); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310525); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xff37f886); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf86e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c709d0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de209db); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xff6df484); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf481); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x00360c18); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe000a); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0021002f); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ffb8); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff3b); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffcc00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa01fa); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0069fdd4); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fc26); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff5d0407); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310638); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x00c9f9a8); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf74e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff3908c3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de20ac3); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0093f537); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf410); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xffca0bf2); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb0003); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001c0037); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002fffe2); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ff17); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff6a007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd0251); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0134fea5); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb8b); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe2002e0); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e70713); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0255faf5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f658); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0799); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf0b96); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x01b8f5f5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f3a3); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xff5e0bca); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00120037); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00460010); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff8eff0f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff180000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750276); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01e8ff8d); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb31); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcfb0198); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x065607ad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x03cefc64); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614f592); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0656); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d770c52); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x02daf6bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf33b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfef10ba3); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff5); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0005002f); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0054003c); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5ff22); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedfff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fc0267); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0276007e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb1c); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbfe003e); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830802); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0529fdec); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8f4fe); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd04ff); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d0cf6); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x03f8f78f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af2d7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe850b7b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff80020); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00560060); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0002ff4e); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec4ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x006d0225); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02d50166); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb4e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb35fee1); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477080e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x065bff82); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1f4a0); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610397); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c810d80); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0510f869); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f278); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe1a0b52); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffaffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffec000c); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0078); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0040ff8e); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecafeb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd301b6); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fc0235); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fbc5); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaaafd90); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x033e07d2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x075b011b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbf47a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f0224); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50def); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0621f94b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f21e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfdae0b29); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3fff6); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0037007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0075ffdc); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef2fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3d0122); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02ea02dd); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fc79); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa65fc5d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3074e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x082102ad); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0ff48c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe00a9); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0e43); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0729fa33); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f1c9); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfd430b00); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0001fff3); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe2); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001b0076); + cx25840_write4(client, DIF_BPF_COEFF89, 0x009c002d); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff35fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfeba0076); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x029f0352); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfd60); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa69fb53); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x00740688); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08a7042d); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb75f4d6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600ff2d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a220e7a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0827fb22); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf17a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfcd80ad6); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff9); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffd2); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb005e); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b0007a); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8ffe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53ffc1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0221038c); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fe6e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfab6fa80); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xff010587); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e90590); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf5f556); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfdb3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x09210e95); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0919fc15); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff12f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc6e0aab); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00070000); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6ffc9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0039); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00af00b8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfff4feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13ff10); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01790388); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311ff92); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb48f9ed); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd980453); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e306cd); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe88f60a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fc40); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x08080e93); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x09fdfd0c); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af0ea); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc050a81); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080008); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff0ffc9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1000d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x009800e2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x005bff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe74); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00b50345); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000bc); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc18f9a1); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc4802f9); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x089807dc); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022f6f0); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fada); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x06da0e74); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ad3fe06); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef0ab); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb9c0a55); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffdffd0); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffdf); + cx25840_write4(client, DIF_BPF_COEFF89, 0x006e00f2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00b8ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfdf8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xffe302c8); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x041301dc); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd1af99e); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1e0183); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x080908b5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bcf801); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf985); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x059a0e38); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b99ff03); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cf071); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb330a2a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00070011); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000affdf); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffa9ffb5); + cx25840_write4(client, DIF_BPF_COEFF89, 0x003700e6); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01010000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62fda8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff140219); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x043502e1); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe42f9e6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa270000); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x073a0953); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x034cf939); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a4f845); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x044c0de1); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c4f0000); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2f03c); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfacc09fe); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00040012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0016fff3); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffafff95); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff900c0); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0130007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefd89); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe560146); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x041303bc); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff81fa76); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cfe7d); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x063209b1); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c9fa93); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf71e); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f30d6e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cf200fd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361f00e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa6509d1); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00010010); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0008); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ff84); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffbc0084); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013e00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff56fd9f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdb8005c); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00460); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x00c7fb45); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4fd07); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x04fa09ce); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x062afc07); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407f614); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x01920ce0); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d8301fa); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8efe5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa0009a4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd000b); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001d); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff82); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff870039); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x012a014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffedfde7); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd47ff6b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104c6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0202fc4c); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6fbad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x039909a7); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0767fd8e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482f52b); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x002d0c39); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e0002f4); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477efc2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf99b0977); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa0004); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0020002d); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff91); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ffe8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f70184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0086fe5c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0bfe85); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104e5); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0323fd7d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa79); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x021d093f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0879ff22); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bf465); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec70b79); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e6803eb); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50defa5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf937094a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffd); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00190036); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001bffaf); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff99); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00aa0198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112fef3); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd09fdb9); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04be); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x041bfecc); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947f978); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x00900897); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a00b9); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f3c5); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd650aa3); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ebc04de); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aaef8e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf8d5091c); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff6); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000e0038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ffd7); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff56); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x004b0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0186ffa1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd40fd16); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440452); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04de0029); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2f8b2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfefe07b5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a05024d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef34d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0a09b8); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0efa05cd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64eef7d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf87308ed); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00000031); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0005); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff27); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffe4014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70057); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdacfca6); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3603a7); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05610184); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbf82e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd74069f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a7503d6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff2ff); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab808b9); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f2306b5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ef72); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf81308bf); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff30022); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00560032); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ff10); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8000f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe0106); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe46fc71); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3502c7); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x059e02ce); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9f7f2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfbff055b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa9054c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f2db); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf97507aa); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f350797); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ef6d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7b40890); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8000f); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00540058); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffcdff14); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff29007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f6019e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff01fc7c); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5101bf); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x059203f6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd41f7fe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfaa903f3); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e06a9); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf2e2); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842068b); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f320871); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85eef6e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7560860); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fff2); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1fff9); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00460073); + cx25840_write4(client, DIF_BPF_COEFF89, 0x000bff34); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee90000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10215); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xffd0fcc5); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99009d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x053d04f1); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5f853); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf97d0270); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a5607e4); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef314); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723055f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f180943); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919ef75); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6fa0830); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff8); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe4); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002f007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0048ff6b); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec7ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0163025f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00a2fd47); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff73); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04a405b2); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0017f8ed); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf88500dc); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d208f9); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff370); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61c0429); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ee80a0b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d8ef82); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6a00800); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007ffff); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffd4); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0010007a); + cx25840_write4(client, DIF_BPF_COEFF89, 0x007cffb2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec6ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e60277); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0168fdf9); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fe50); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x03ce0631); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0188f9c8); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7c7ff43); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x091509e3); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f3f6); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52d02ea); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ea30ac9); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9bef95); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf64607d0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00090007); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9ffca); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00065); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a10003); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee6feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053025b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0213fed0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fd46); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x02c70668); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x02eafadb); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf74bfdae); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230a9c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f4a3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45b01a6); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e480b7c); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb61efae); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf5ef079f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000d); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff5ffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10043); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b20053); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff24fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9020c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0295ffbb); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fc64); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x019b0654); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x042dfc1c); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf714fc2a); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020b21); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f575); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7005e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0dd80c24); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2aefcd); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf599076e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00060011); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0002ffcf); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffba0018); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad009a); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff79fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff260192); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e500ab); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fbb6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x005b05f7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545fd81); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf723fabf); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80b70); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f669); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313ff15); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d550cbf); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6eff2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544073d); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00030012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000fffdd); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffea); + cx25840_write4(client, DIF_BPF_COEFF89, 0x009300cf); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdcfe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea600f7); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fd0190); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb46); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff150554); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0627fefd); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf778f978); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x044d0b87); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f77d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0fdcf); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbe0d4e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc4f01d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2070b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00000010); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001afff0); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffbf); + cx25840_write4(client, DIF_BPF_COEFF89, 0x006700ed); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe460047); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02db0258); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb1b); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddc0473); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c90082); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf811f85e); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c90b66); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff8ad); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250fc8d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c140dcf); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe93f04d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a106d9); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc000c); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00200006); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff9c); + cx25840_write4(client, DIF_BPF_COEFF89, 0x002f00ef); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a4ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dff92); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x028102f7); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb37); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbf035e); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07260202); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e8f778); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x01340b0d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f9f4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223fb51); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b590e42); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xff64f083); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf45206a7); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90005); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001a); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff86); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff000d7); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fee5); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f60362); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb99); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbcc0222); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07380370); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f7f6cc); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff990a7e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902fb50); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21afa1f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8d0ea6); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034f0bf); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4050675); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffe); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001e002b); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff81); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffb400a5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe50); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01460390); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfc3a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb1000ce); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x070104bf); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb37f65f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe0009bc); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00fcbb); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f8f8); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b20efc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105f101); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3ba0642); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff7); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00150036); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff8c); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff810061); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013d007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe71fddf); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x007c0380); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fd13); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa94ff70); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x068005e2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9bf633); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc7308ca); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5fe30); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf274f7e0); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c90f43); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d4f147); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371060f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fff1); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00090038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffa7); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff5e0012); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013200f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee3fd9b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaa0331); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fe15); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa60fe18); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bd06d1); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1bf64a); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafa07ae); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7effab); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d5f6d7); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d30f7a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a3f194); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf32905dc); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffb0032); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003fffcd); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effc1); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6efd8a); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfedd02aa); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0ff34); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa74fcd7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bf0781); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaaf6a3); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99e066b); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90128); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf359f5e1); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d20fa2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0370f1e5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e405a8); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffef0024); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0051fffa); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff54ff77); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00be0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0006fdad); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe2701f3); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413005e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad1fbba); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x039007ee); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x013bf73d); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868050a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4302a1); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fdf4fe); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c70fba); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x043bf23c); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a10575); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fff1); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe50011); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00570027); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff70ff3c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00620198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x009efe01); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95011a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350183); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb71fad0); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x023c0812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c3f811); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75e0390); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0411); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c1f432); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b30fc1); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0503f297); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2610541); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0006fff7); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdffffc); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00510050); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff9dff18); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffc0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0128fe80); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32002e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130292); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4dfa21); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d107ee); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0435f91c); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6850205); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430573); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a1f37d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x03990fba); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c7f2f8); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222050d); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffe); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdfffe7); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003f006e); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffd6ff0f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0197ff1f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd05ff3e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0037c); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd59f9b7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5d0781); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0585fa56); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4006f); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf906c4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69df2e0); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x02790fa2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0688f35d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e604d8); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00090005); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4ffd6); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0025007e); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0014ff20); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3c00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e1ffd0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd12fe5c); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110433); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88f996); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf106d1); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aafbb7); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57efed8); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e07ff); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b0f25e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x01560f7a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0745f3c7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1ac04a4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000c); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffedffcb); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0005007d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0050ff4c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ff0086); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd58fd97); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104ad); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xffcaf9c0); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc9905e2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x079afd35); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf555fd46); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50920); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d9f1f6); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x00310f43); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fdf435); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174046f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00050011); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffaffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5006b); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0082ff8c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f00130); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd2fcfc); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04e3); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x010efa32); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb6404bf); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x084efec5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569fbc2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000a23); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa15f1ab); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0b0efc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b0f4a7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13f043a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00020012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0007ffcd); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9004c); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a4ffd9); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b401c1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe76fc97); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404d2); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0245fae8); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5f0370); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1005f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bcfa52); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020b04); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb60f17b); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde70ea6); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x095df51e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10c0405); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0011); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0014ffdb); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40023); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2002a); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedbff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150022d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff38fc6f); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36047b); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x035efbda); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9940202); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ee01f5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf649f8fe); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10bc2); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb6f169); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc60e42); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a04f599); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0db03d0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb000d); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001dffed); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaafff5); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00aa0077); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00ce026b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x000afc85); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3503e3); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x044cfcfb); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90c0082); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5037f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf710f7cc); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0c59); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe16f173); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaa0dcf); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa5f617); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0ad039b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90006); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00210003); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffc8); + cx25840_write4(client, DIF_BPF_COEFF89, 0x008e00b6); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff63fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x003a0275); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00dafcda); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd510313); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0501fe40); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cbfefd); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x087604f0); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80af6c2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430cc8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7af19a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa940d4e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3ff699); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0810365); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffff); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00210018); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffa3); + cx25840_write4(client, DIF_BPF_COEFF89, 0x006000e1); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc4fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0024b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x019afd66); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc990216); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0575ff99); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4fd81); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d40640); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf932f5e6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20d0d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x00dff1de); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9860cbf); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd1f71e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058032f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff8); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001b0029); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff8a); + cx25840_write4(client, DIF_BPF_COEFF89, 0x002600f2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x002cfe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0f01f0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x023bfe20); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc1700fa); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a200f7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf927fc1c); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f40765); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa82f53b); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510d27); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0243f23d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8810c24); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5cf7a7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf03102fa); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00110035); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff81); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffe700e7); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x008ffeb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94016d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b0fefb); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3ffd1); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05850249); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c1fadb); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x05de0858); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf2f4c4); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c70d17); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a0f2b8); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7870b7c); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdff833); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00d02c4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00040038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ff88); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffac00c2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e2ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe3900cb); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f1ffe9); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3feaa); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05210381); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9cf9c8); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x04990912); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7af484); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff390cdb); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f4f34d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69a0ac9); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5af8c1); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefec028e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0000ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff60033); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002fff9f); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff7b0087); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x011eff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe080018); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f900d8); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fd96); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04790490); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbadf8ed); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x032f098e); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff10f47d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0c75); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x063cf3fc); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5ba0a0b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dccf952); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcd0258); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff1); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffea0026); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0046ffc3); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff5a003c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04ff63); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c801b8); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fca6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397056a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcecf853); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x01ad09c9); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x00acf4ad); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0be7); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0773f4c2); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e90943); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35f9e6); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb10221); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff6); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe20014); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0054ffee); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effeb); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2efebb); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260027a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fbe6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x02870605); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4af7fe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x001d09c1); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0243f515); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd0b32); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0897f59e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4280871); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e95fa7c); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef9701eb); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffd); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffff); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0056001d); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff57ff9c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x011300f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe82fe2e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ca0310); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb62); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155065a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xffbaf7f2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8c0977); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x03cef5b2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610a58); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a5f68f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3790797); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eebfb14); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef8001b5); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080004); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe9); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0047); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff75ff58); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef9fdc8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111036f); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb21); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x00120665); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x012df82e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd0708ec); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542f682); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f095c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9af792); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2db06b5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f38fbad); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6c017e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000b); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe7ffd8); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00370068); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffa4ff28); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00790184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87fd91); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00430392); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb26); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfece0626); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294f8b2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb990825); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0698f77f); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe0842); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b73f8a7); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf25105cd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7bfc48); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5a0148); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00050010); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff2ffcc); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001b007b); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffdfff10); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00140198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0020fd8e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff710375); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb73); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9a059f); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e0f978); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4e0726); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c8f8a7); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600070c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2ff9c9); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1db04de); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4fce5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4b0111); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00010012); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffffffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb007e); + cx25840_write4(client, DIF_BPF_COEFF89, 0x001dff14); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffad0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b7fdbe); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9031b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fc01); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc8504d6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0504fa79); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf93005f6); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08caf9f2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52b05c0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccbfaf9); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf17903eb); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3fd83); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3f00db); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe0011); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000cffcc); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0071); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0058ff32); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4f014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x013cfe1f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfb028a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fcc9); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9d03d6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f4fbad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848049d); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0999fb5b); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf4820461); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d46fc32); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12d02f4); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x1007fe21); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3600a4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0017ffd9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc10055); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0088ff68); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0400f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a6fea7); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7501cc); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fdc0); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaef02a8); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a7fd07); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79d0326); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a31fcda); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf40702f3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9ffd72); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f601fa); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x1021fec0); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2f006d); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80007); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001fffeb); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaf002d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a8ffb0); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e9ff4c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2000ee); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fed8); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82015c); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0715fe7d); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7340198); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8dfe69); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bd017c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd5feb8); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d500fd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x1031ff60); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2b0037); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff70000); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00220000); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffa90000); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b30000); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec20000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x02000000); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd030000); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350000); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa5e0000); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x073b0000); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7110000); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aac0000); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a40000); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de70000); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0c90000); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x10360000); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef290000); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff9); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001f0015); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffd3); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a80050); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e900b4); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd20ff12); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130128); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82fea4); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07150183); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf734fe68); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8d0197); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdfe84); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd50148); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d5ff03); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x103100a0); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2bffc9); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00170027); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ffab); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00880098); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff04ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a60159); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd75fe34); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00240); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaeffd58); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a702f9); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79dfcda); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a310326); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fd0d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9f028e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f6fe06); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x10210140); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2fff93); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000c0034); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff8f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x005800ce); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4ffeb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x013c01e1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfbfd76); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110337); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9dfc2a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f40453); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848fb63); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x099904a5); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fb9f); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d4603ce); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12dfd0c); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x100701df); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef36ff5c); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0001ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffff0038); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff82); + cx25840_write4(client, DIF_BPF_COEFF89, 0x001d00ec); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffadfe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b70242); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9fce5); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024103ff); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc85fb2a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05040587); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf930fa0a); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08ca060e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfa40); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccb0507); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf179fc15); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3027d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3fff25); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff20034); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001bff85); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffdf00f0); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0014fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00200272); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff71fc8b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d048d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9afa61); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e00688); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4ef8da); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c80759); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f8f4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2f0637); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1dbfb22); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4031b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4bfeef); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff5); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe70028); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ff98); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffa400d8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0079fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87026f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0043fc6e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404da); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfecef9da); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294074e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb99f7db); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x06980881); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef7be); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b730759); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf251fa33); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7b03b8); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5afeb8); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffc); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe00017); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004cffb9); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff7500a8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef90238); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111fc91); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604df); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0012f99b); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x012d07d2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd07f714); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542097e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff6a4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9a086e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2dbf94b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f380453); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6cfe82); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080003); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffde0001); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0056ffe3); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff570064); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0113ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe8201d2); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01cafcf0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35049e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155f9a6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xffba080e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8cf689); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x03ce0a4e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f5a8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a50971); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf379f869); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eeb04ec); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef80fe4b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000a); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe2ffec); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00540012); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e0015); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2e0145); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260fd86); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51041a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0287f9fb); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4a0802); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x001df63f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x02430aeb); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf4ce); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x08970a62); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf428f78f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e950584); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef97fe15); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffeaffda); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0046003d); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff5affc4); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04009d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c8fe48); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99035a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397fa96); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcec07ad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x01adf637); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x00ac0b53); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef419); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x07730b3e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e9f6bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35061a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb1fddf); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00000012); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff6ffcd); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002f0061); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff7bff79); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x011e007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe08ffe8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f9ff28); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17026a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0479fb70); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbad0713); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x032ff672); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff100b83); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff38b); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x063c0c04); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5baf5f5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dcc06ae); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcdfda8); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0004ffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00100078); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffacff3e); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e200f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe39ff35); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f10017); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd30156); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0521fc7f); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9c0638); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0499f6ee); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7a0b7c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f325); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f40cb3); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69af537); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5a073f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefecfd72); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0011ffcb); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffe7ff19); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x008f014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94fe93); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b00105); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3002f); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0585fdb7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c10525); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x05def7a8); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf20b3c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f2e9); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a00d48); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf787f484); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdf07cd); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00dfd3c); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80008); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001bffd7); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10076); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0026ff0e); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x002c0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0ffe10); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x023b01e0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff06); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a2ff09); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf92703e4); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f4f89b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa820ac5); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f2d9); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x02430dc3); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf881f3dc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5c0859); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf031fd06); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80001); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0021ffe8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffba005d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0060ff1f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc40198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0fdb5); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x019a029a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fdea); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05750067); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4027f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d4f9c0); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf9320a1a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f2f3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x00df0e22); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf986f341); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd108e2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058fcd1); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0021fffd); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0038); + cx25840_write4(client, DIF_BPF_COEFF89, 0x008eff4a); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff630184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x003afd8b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00da0326); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fced); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x050101c0); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cb0103); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0876fb10); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80a093e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f338); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7a0e66); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa94f2b2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3f0967); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf081fc9b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff3); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001d0013); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa000b); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00aaff89); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00cefd95); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x000a037b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fc1d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x044c0305); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90cff7e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5fc81); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7100834); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff3a7); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe160e8d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaaf231); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa509e9); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0adfc65); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00140025); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffdd); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2ffd6); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedb00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150fdd3); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff380391); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb85); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x035e0426); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf994fdfe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08eefe0b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6490702); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f43e); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb60e97); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc6f1be); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a040a67); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0dbfc30); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0002ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00070033); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ffb4); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a40027); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b4fe3f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe760369); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb2e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x02450518); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5ffc90); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1ffa1); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bc05ae); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902f4fc); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb600e85); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde7f15a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x095d0ae2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10cfbfb); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0005ffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffa0038); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff95); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00820074); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f0fed0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd20304); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb1d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x010e05ce); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb64fb41); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x084e013b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569043e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00f5dd); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa150e55); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0bf104); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b00b59); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13ffbc6); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fff4); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffed0035); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff83); + cx25840_write4(client, DIF_BPF_COEFF89, 0x005000b4); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ffff7a); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd580269); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fb53); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xffca0640); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc99fa1e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x079a02cb); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55502ba); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5f6e0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d90e0a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0031f0bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fd0bcb); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174fb91); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0009fffb); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4002a); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ff82); + cx25840_write4(client, DIF_BPF_COEFF89, 0x001400e0); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3cff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e10030); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1201a4); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fbcd); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88066a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf1f92f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aa0449); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57e0128); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7ef801); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b00da2); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0156f086); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x07450c39); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1acfb5c); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080002); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0019); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003fff92); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffd600f1); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x019700e1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0500c2); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fc84); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd590649); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5df87f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x058505aa); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4ff91); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9f93c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69d0d20); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0279f05e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x06880ca3); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e6fb28); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00060009); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0004); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0051ffb0); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff9d00e8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffcfe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01280180); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32ffd2); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fd6e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4d05df); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d1f812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x043506e4); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf685fdfb); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fa8d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a10c83); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0399f046); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c70d08); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222faf3); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe5ffef); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0057ffd9); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff7000c4); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0062fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x009e01ff); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95fee6); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0435fe7d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb710530); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x023cf7ee); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c307ef); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75efc70); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5cfbef); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c10bce); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b3f03f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x05030d69); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf261fabf); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0012); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffefffdc); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00510006); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff540089); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00befe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00060253); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe27fe0d); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413ffa2); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad10446); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0390f812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x013b08c3); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868faf6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fd5f); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fd0b02); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c7f046); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x043b0dc4); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a1fa8b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0012); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffbffce); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003f0033); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e003f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6e0276); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeddfd56); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000cc); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa740329); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bff87f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaa095d); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99ef995); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9fed8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3590a1f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d2f05e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x03700e1b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e4fa58); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0009ffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00250059); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff5effee); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0132ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee30265); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaafccf); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x031101eb); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6001e8); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bdf92f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1b09b6); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafaf852); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0055); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d50929); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d3f086); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a30e6c); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf329fa24); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80009); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0015ffca); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00050074); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff81ff9f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013dff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe710221); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x007cfc80); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024102ed); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa940090); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0680fa1e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9b09cd); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc73f736); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad501d0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2740820); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c9f0bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d40eb9); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371f9f1); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80002); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001effd5); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff5b); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2401b0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0146fc70); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d03c6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb10ff32); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0701fb41); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb3709a1); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f644); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000345); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2350708); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b2f104); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x01050eff); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3baf9be); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0022ffe6); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9007a); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff29); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01011b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f6fc9e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440467); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbccfdde); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738fc90); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f70934); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99f582); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x090204b0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21a05e1); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8df15a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x00340f41); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf405f98b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcfff4); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0020fffa); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40064); + cx25840_write4(client, DIF_BPF_COEFF89, 0x002fff11); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a400f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0d006e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0281fd09); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604c9); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbffca2); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0726fdfe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e80888); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134f4f3); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1060c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf22304af); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b59f1be); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xff640f7d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf452f959); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0000fff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0010); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa0041); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0067ff13); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46ffb9); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02dbfda8); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3504e5); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddcfb8d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9ff7e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf81107a2); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9f49a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0753); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2500373); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c14f231); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930fb3); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a1f927); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000f0023); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0016); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0093ff31); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdc0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6ff09); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fdfe70); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5104ba); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff15faac); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270103); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7780688); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x044df479); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430883); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a00231); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbef2b2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc40fe3); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2f8f5); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 16000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0006ffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00020031); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffe8); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00adff66); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff790198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe6e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e5ff55); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99044a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x005bfa09); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545027f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7230541); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b8f490); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20997); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf31300eb); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d55f341); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6100e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544f8c3); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + } +} + +static void cx23885_std_setup(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + v4l2_std_id std = state->std; + u32 ifHz; + + cx25840_write4(client, 0x478, 0x6628021F); + cx25840_write4(client, 0x400, 0x0); + cx25840_write4(client, 0x4b4, 0x20524030); + cx25840_write4(client, 0x47c, 0x010a8263); + + if (std & V4L2_STD_NTSC) { + v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC", + __func__); + + /* Horiz / vert timing */ + cx25840_write4(client, 0x428, 0x1e1e601a); + cx25840_write4(client, 0x424, 0x5b2d007a); + + /* DIF NTSC */ + cx25840_write4(client, 0x304, 0x6503bc0c); + cx25840_write4(client, 0x308, 0xbd038c85); + cx25840_write4(client, 0x30c, 0x1db4640a); + cx25840_write4(client, 0x310, 0x00008800); + cx25840_write4(client, 0x314, 0x44400400); + cx25840_write4(client, 0x32c, 0x0c800800); + cx25840_write4(client, 0x330, 0x27000100); + cx25840_write4(client, 0x334, 0x1f296e1f); + cx25840_write4(client, 0x338, 0x009f50c1); + cx25840_write4(client, 0x340, 0x1befbf06); + cx25840_write4(client, 0x344, 0x000035e8); + + /* DIF I/F */ + ifHz = 5400000; + + } else { + v4l_dbg(1, cx25840_debug, client, "%s() Selecting PAL-BG", + __func__); + + /* Horiz / vert timing */ + cx25840_write4(client, 0x428, 0x28244024); + cx25840_write4(client, 0x424, 0x5d2d0084); + + /* DIF */ + cx25840_write4(client, 0x304, 0x6503bc0c); + cx25840_write4(client, 0x308, 0xbd038c85); + cx25840_write4(client, 0x30c, 0x1db4640a); + cx25840_write4(client, 0x310, 0x00008800); + cx25840_write4(client, 0x314, 0x44400600); + cx25840_write4(client, 0x32c, 0x0c800800); + cx25840_write4(client, 0x330, 0x27000100); + cx25840_write4(client, 0x334, 0x213530ec); + cx25840_write4(client, 0x338, 0x00a65ba8); + cx25840_write4(client, 0x340, 0x1befbf06); + cx25840_write4(client, 0x344, 0x000035e8); + + /* DIF I/F */ + ifHz = 6000000; + } + + cx23885_dif_setup(client, ifHz); + + /* Explicitly ensure the inputs are reconfigured after + * a standard change. + */ + set_input(client, state->vid_input, state->aud_input); +} + +/* ----------------------------------------------------------------------- */ + static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { .s_ctrl = cx25840_s_ctrl, }; @@ -1801,6 +5024,7 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = { .queryctrl = v4l2_subdev_queryctrl, .querymenu = v4l2_subdev_querymenu, .s_std = cx25840_s_std, + .g_std = cx25840_g_std, .reset = cx25840_reset, .load_fw = cx25840_load_fw, .s_io_pin_config = common_s_io_pin_config, @@ -1828,6 +5052,7 @@ static const struct v4l2_subdev_video_ops cx25840_video_ops = { .s_routing = cx25840_s_video_routing, .s_mbus_fmt = cx25840_s_mbus_fmt, .s_stream = cx25840_s_stream, + .g_input_status = cx25840_g_input_status, }; static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = { diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 5c42abdf422f..3598dc087b08 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -70,11 +70,6 @@ config VIDEO_CX88_DVB To compile this driver as a module, choose M here: the module will be called cx88-dvb. -config VIDEO_CX88_MPEG - tristate - depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD - default y - config VIDEO_CX88_VP3054 tristate "VP-3054 Secondary I2C Bus Support" default m @@ -84,3 +79,8 @@ config VIDEO_CX88_VP3054 Conexant 2388x chip and the MT352 demodulator, which also require support for the VP-3054 Secondary I2C bus, such at DNTV Live! DVB-T Pro. + +config VIDEO_CX88_MPEG + tristate + depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD + default y diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 68d1240f493c..04bf6627d362 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -96,7 +96,7 @@ typedef struct cx88_audio_dev snd_cx88_card_t; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; +static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 0d719faafd8a..cbd5d119a2c6 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1306,7 +1306,7 @@ static const struct cx88_board cx88_boards[] = { }, [CX88_BOARD_WINFAST_DTV2000H_J] = { .name = "WinFast DTV2000 H rev. J", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FMD1216MEX_MK3, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -1573,8 +1573,8 @@ static const struct cx88_board cx88_boards[] = { .name = "Pinnacle Hybrid PCTV", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -1611,8 +1611,8 @@ static const struct cx88_board cx88_boards[] = { .name = "Leadtek TV2000 XP Global", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -1643,6 +1643,78 @@ static const struct cx88_board cx88_boards[] = { .gpio3 = 0x0000, }, }, + [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36] = { + .name = "Leadtek TV2000 XP Global (SC4100)", + .tuner_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C04, /* pin 18 = 1, pin 19 = 0 */ + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ + .gpio3 = 0x0000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C00, /* pin 18 = 0, pin 19 = 0 */ + .gpio3 = 0x0000, + }, + }, + [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43] = { + .name = "Leadtek TV2000 XP Global (XC4100)", + .tuner_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6040, /* pin 14 = 1, pin 13 = 0 */ + .gpio2 = 0x0000, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 14 = 1, pin 13 = 1 */ + .gpio2 = 0x0000, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 14 = 1, pin 13 = 1 */ + .gpio2 = 0x0000, + .gpio3 = 0x0000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6000, /* pin 14 = 1, pin 13 = 0 */ + .gpio2 = 0x0000, + .gpio3 = 0x0000, + }, + }, [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = { .name = "PowerColor RA330", /* Long names may confuse LIRC. */ .tuner_type = TUNER_XC2028, @@ -2043,8 +2115,8 @@ static const struct cx88_board cx88_boards[] = { .name = "Terratec Cinergy HT PCI MKII", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, - .radio_type = TUNER_XC2028, - .radio_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -2082,9 +2154,9 @@ static const struct cx88_board cx88_boards[] = { [CX88_BOARD_WINFAST_DTV1800H] = { .name = "Leadtek WinFast DTV1800 Hybrid", .tuner_type = TUNER_XC2028, - .radio_type = TUNER_XC2028, + .radio_type = UNSET, .tuner_addr = 0x61, - .radio_addr = 0x61, + .radio_addr = ADDR_UNSET, /* * GPIO setting * @@ -2123,9 +2195,9 @@ static const struct cx88_board cx88_boards[] = { [CX88_BOARD_WINFAST_DTV1800H_XC4000] = { .name = "Leadtek WinFast DTV1800 H (XC4000)", .tuner_type = TUNER_XC4000, - .radio_type = TUNER_XC4000, + .radio_type = UNSET, .tuner_addr = 0x61, - .radio_addr = 0x61, + .radio_addr = ADDR_UNSET, /* * GPIO setting * @@ -2164,9 +2236,9 @@ static const struct cx88_board cx88_boards[] = { [CX88_BOARD_WINFAST_DTV2000H_PLUS] = { .name = "Leadtek WinFast DTV2000 H PLUS", .tuner_type = TUNER_XC4000, - .radio_type = TUNER_XC4000, + .radio_type = UNSET, .tuner_addr = 0x61, - .radio_addr = 0x61, + .radio_addr = ADDR_UNSET, /* * GPIO * 2: 1: mute audio @@ -2719,6 +2791,21 @@ static const struct cx88_subid cx88_subids[] = { .subdevice = 0x6618, .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, }, { + /* TV2000 XP Global [107d:6618] */ + .subvendor = 0x107d, + .subdevice = 0x6619, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, + }, { + /* WinFast TV2000 XP Global with XC4000 tuner */ + .subvendor = 0x107d, + .subdevice = 0x6f36, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36, + }, { + /* WinFast TV2000 XP Global with XC4000 tuner and different GPIOs */ + .subvendor = 0x107d, + .subdevice = 0x6f43, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43, + }, { .subvendor = 0xb034, .subdevice = 0x3034, .card = CX88_BOARD_PROF_7301, @@ -3075,6 +3162,8 @@ static int cx88_xc4000_tuner_callback(struct cx88_core *core, switch (core->boardnr) { case CX88_BOARD_WINFAST_DTV1800H_XC4000: case CX88_BOARD_WINFAST_DTV2000H_PLUS: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43: return cx88_xc4000_winfast2000h_plus_callback(core, command, arg); } @@ -3232,6 +3321,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) cx_set(MO_GP0_IO, 0x00001010); break; + case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR4000: /* Init GPIO */ @@ -3250,6 +3340,8 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) case CX88_BOARD_WINFAST_DTV1800H_XC4000: case CX88_BOARD_WINFAST_DTV2000H_PLUS: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43: cx88_xc4000_winfast2000h_plus_callback(core, XC4000_TUNER_RESET, 0); break; diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index cf3d33ab541b..003937cd72f5 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -815,9 +815,9 @@ static const u8 samsung_smt_7020_inittab[] = { }; -static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx8802_dev *dev = fe->dvb->priv; u8 buf[4]; u32 div; @@ -827,14 +827,14 @@ static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe, .buf = buf, .len = sizeof(buf) }; - div = params->frequency / 125; + div = c->frequency / 125; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x84; /* 0xC4 */ buf[3] = 0x00; - if (params->frequency < 1500000) + if (c->frequency < 1500000) buf[3] |= 0x10; if (fe->ops.i2c_gate_ctrl) @@ -954,6 +954,7 @@ static int dvb_register(struct cx8802_dev *dev) struct cx88_core *core = dev->core; struct videobuf_dvb_frontend *fe0, *fe1 = NULL; int mfe_shared = 0; /* bus not shared by default */ + int res = -EINVAL; if (0 != core->i2c_rc) { printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); @@ -999,7 +1000,6 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_WINFAST_DTV2000H: - case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1100LP: case CX88_BOARD_HAUPPAUGE_HVR1300: @@ -1013,6 +1013,17 @@ static int dvb_register(struct cx8802_dev *dev) goto frontend_detach; } break; + case CX88_BOARD_WINFAST_DTV2000H_J: + fe0->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216MEX_MK3)) + goto frontend_detach; + } + break; case CX88_BOARD_HAUPPAUGE_HVR3000: /* MFE frontend 1 */ mfe_shared = 1; @@ -1566,13 +1577,16 @@ static int dvb_register(struct cx8802_dev *dev) call_all(core, core, s_power, 0); /* register everything */ - return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, - &dev->pci->dev, adapter_nr, mfe_shared, NULL); + res = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, + &dev->pci->dev, adapter_nr, mfe_shared, NULL); + if (res) + goto frontend_detach; + return res; frontend_detach: core->gate_ctrl = NULL; videobuf_dvb_dealloc_frontends(&dev->frontends); - return -EINVAL; + return res; } /* ----------------------------------------------------------- */ diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index a1fe0abb6e43..de0f1af74e41 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -132,7 +132,7 @@ static void do_i2c_scan(const char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) { /* Prevents usage of invalid delay values */ diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index e614201b5ed3..ebf448c48ca3 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -103,6 +103,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) case CX88_BOARD_WINFAST_DTV1800H_XC4000: case CX88_BOARD_WINFAST_DTV2000H_PLUS: case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43: gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); auxgpio = gpio; break; @@ -302,6 +304,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_WINFAST2000XP_EXPERT: case CX88_BOARD_WINFAST_DTV1000: case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43: ir_codes = RC_MAP_WINFAST; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index fa8d307e1a3d..c9659def2a78 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -244,6 +244,8 @@ extern const struct sram_channel const cx88_sram_channels[]; #define CX88_BOARD_TEVII_S464 86 #define CX88_BOARD_WINFAST_DTV2000H_PLUS 87 #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88 +#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89 +#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c index bd443ee76fff..f83baf3a52b0 100644 --- a/drivers/media/video/davinci/dm355_ccdc.c +++ b/drivers/media/video/davinci/dm355_ccdc.c @@ -1069,15 +1069,4 @@ static struct platform_driver dm355_ccdc_driver = { .probe = dm355_ccdc_probe, }; -static int __init dm355_ccdc_init(void) -{ - return platform_driver_register(&dm355_ccdc_driver); -} - -static void __exit dm355_ccdc_exit(void) -{ - platform_driver_unregister(&dm355_ccdc_driver); -} - -module_init(dm355_ccdc_init); -module_exit(dm355_ccdc_exit); +module_platform_driver(dm355_ccdc_driver); diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c index 8051c2956478..9303fe553b07 100644 --- a/drivers/media/video/davinci/dm644x_ccdc.c +++ b/drivers/media/video/davinci/dm644x_ccdc.c @@ -1078,15 +1078,4 @@ static struct platform_driver dm644x_ccdc_driver = { .probe = dm644x_ccdc_probe, }; -static int __init dm644x_ccdc_init(void) -{ - return platform_driver_register(&dm644x_ccdc_driver); -} - -static void __exit dm644x_ccdc_exit(void) -{ - platform_driver_unregister(&dm644x_ccdc_driver); -} - -module_init(dm644x_ccdc_init); -module_exit(dm644x_ccdc_exit); +module_platform_driver(dm644x_ccdc_driver); diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c index 29c29c668596..1e63852374be 100644 --- a/drivers/media/video/davinci/isif.c +++ b/drivers/media/video/davinci/isif.c @@ -1156,17 +1156,6 @@ static struct platform_driver isif_driver = { .probe = isif_probe, }; -static int __init isif_init(void) -{ - return platform_driver_register(&isif_driver); -} - -static void isif_exit(void) -{ - platform_driver_unregister(&isif_driver); -} - -module_init(isif_init); -module_exit(isif_exit); +module_platform_driver(isif_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c index d773d30de221..c4a82a1a8a97 100644 --- a/drivers/media/video/davinci/vpbe.c +++ b/drivers/media/video/davinci/vpbe.c @@ -141,11 +141,12 @@ static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, return 0; } -static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode) +static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode, + int output_index) { struct vpbe_config *cfg = vpbe_dev->cfg; struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; + int curr_output = output_index; int i; if (NULL == mode) @@ -245,6 +246,8 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) struct encoder_config_info *curr_enc_info = vpbe_current_encoder_info(vpbe_dev); struct vpbe_config *cfg = vpbe_dev->cfg; + struct venc_platform_data *venc_device = vpbe_dev->venc_device; + enum v4l2_mbus_pixelcode if_params; int enc_out_index; int sd_index; int ret = 0; @@ -274,6 +277,8 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) goto out; } + if_params = cfg->outputs[index].if_params; + venc_device->setup_if_config(if_params); if (ret) goto out; } @@ -293,7 +298,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) * encoder. */ ret = vpbe_get_mode_info(vpbe_dev, - cfg->outputs[index].default_mode); + cfg->outputs[index].default_mode, index); if (!ret) { struct osd_state *osd_device = vpbe_dev->osd_device; @@ -367,6 +372,11 @@ static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, s_dv_preset, dv_preset); + if (!ret && (vpbe_dev->amp != NULL)) { + /* Call amplifier subdevice */ + ret = v4l2_subdev_call(vpbe_dev->amp, video, + s_dv_preset, dv_preset); + } /* set the lcd controller output for the given mode */ if (!ret) { struct osd_state *osd_device = vpbe_dev->osd_device; @@ -566,6 +576,8 @@ static int platform_device_get(struct device *dev, void *data) if (strcmp("vpbe-osd", pdev->name) == 0) vpbe_dev->osd_device = platform_get_drvdata(pdev); + if (strcmp("vpbe-venc", pdev->name) == 0) + vpbe_dev->venc_device = dev_get_platdata(&pdev->dev); return 0; } @@ -584,6 +596,7 @@ static int platform_device_get(struct device *dev, void *data) static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) { struct encoder_config_info *enc_info; + struct amp_config_info *amp_info; struct v4l2_subdev **enc_subdev; struct osd_state *osd_device; struct i2c_adapter *i2c_adap; @@ -704,6 +717,32 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" " currently not supported"); } + /* Add amplifier subdevice for dm365 */ + if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) && + vpbe_dev->cfg->amp != NULL) { + amp_info = vpbe_dev->cfg->amp; + if (amp_info->is_i2c) { + vpbe_dev->amp = v4l2_i2c_new_subdev_board( + &vpbe_dev->v4l2_dev, i2c_adap, + &_info->board_info, NULL); + if (!vpbe_dev->amp) { + v4l2_err(&vpbe_dev->v4l2_dev, + "amplifier %s failed to register", + amp_info->module_name); + ret = -ENODEV; + goto vpbe_fail_amp_register; + } + v4l2_info(&vpbe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + amp_info->module_name); + } else { + vpbe_dev->amp = NULL; + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers" + " currently not supported"); + } + } else { + vpbe_dev->amp = NULL; + } /* set the current encoder and output to that of venc by default */ vpbe_dev->current_sd_index = 0; @@ -731,6 +770,8 @@ 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: kfree(vpbe_dev->encoders); vpbe_fail_v4l2_device: @@ -757,6 +798,7 @@ static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) clk_put(vpbe_dev->dac_clk); + kfree(vpbe_dev->amp); kfree(vpbe_dev->encoders); vpbe_dev->initialized = 0; /* disable vpss clocks */ @@ -811,8 +853,10 @@ static __devinit int vpbe_probe(struct platform_device *pdev) if (cfg->outputs->num_modes > 0) vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; - else + else { + kfree(vpbe_dev); return -ENODEV; + } /* set the driver data in platform device */ platform_set_drvdata(pdev, vpbe_dev); @@ -839,26 +883,4 @@ static struct platform_driver vpbe_driver = { .remove = vpbe_remove, }; -/** - * vpbe_init: initialize the vpbe driver - * - * This function registers device and driver to the kernel - */ -static __init int vpbe_init(void) -{ - return platform_driver_register(&vpbe_driver); -} - -/** - * vpbe_cleanup : cleanup function for vpbe driver - * - * This will un-registers the device and driver to the kernel - */ -static void vpbe_cleanup(void) -{ - platform_driver_unregister(&vpbe_driver); -} - -/* Function for module initialization and cleanup */ -module_init(vpbe_init); -module_exit(vpbe_cleanup); +module_platform_driver(vpbe_driver); diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c index 8588a86d9b45..1f3b1c729252 100644 --- a/drivers/media/video/davinci/vpbe_display.c +++ b/drivers/media/video/davinci/vpbe_display.c @@ -1746,15 +1746,16 @@ static __devinit int vpbe_display_probe(struct platform_device *pdev) for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { if (register_device(disp_dev->dev[i], disp_dev, pdev)) { err = -ENODEV; - goto probe_out; + goto probe_out_irq; } } printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n"); return 0; -probe_out: +probe_out_irq: free_irq(res->start, disp_dev); +probe_out: for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { /* Get the pointer to the layer object */ vpbe_display_layer = disp_dev->dev[k]; @@ -1816,43 +1817,7 @@ static struct platform_driver vpbe_display_driver = { .remove = __devexit_p(vpbe_display_remove), }; -/* - * vpbe_display_init() - * This function registers device and driver to the kernel, requests irq - * handler and allocates memory for layer objects - */ -static __devinit int vpbe_display_init(void) -{ - int err; - - printk(KERN_DEBUG "vpbe_display_init\n"); - - /* Register driver to the kernel */ - err = platform_driver_register(&vpbe_display_driver); - if (0 != err) - return err; - - printk(KERN_DEBUG "vpbe_display_init:" - "VPBE V4L2 Display Driver V1.0 loaded\n"); - return 0; -} - -/* - * vpbe_display_cleanup() - * This function un-registers device and driver to the kernel, frees requested - * irq handler and de-allocates memory allocated for layer objects. - */ -static void vpbe_display_cleanup(void) -{ - printk(KERN_DEBUG "vpbe_display_cleanup\n"); - - /* platform driver unregister */ - platform_driver_unregister(&vpbe_display_driver); -} - -/* Function for module initialization and cleanup */ -module_init(vpbe_display_init); -module_exit(vpbe_display_cleanup); +module_platform_driver(vpbe_display_driver); MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c index ceccf4302518..d6488b79ae3b 100644 --- a/drivers/media/video/davinci/vpbe_osd.c +++ b/drivers/media/video/davinci/vpbe_osd.c @@ -248,11 +248,29 @@ static void _osd_set_rec601_attenuation(struct osd_state *sd, osd_modify(sd, OSD_OSDWIN0MD_ATN0E, enable ? OSD_OSDWIN0MD_ATN0E : 0, OSD_OSDWIN0MD); + if (sd->vpbe_type == VPBE_VERSION_1) + osd_modify(sd, OSD_OSDWIN0MD_ATN0E, + enable ? OSD_OSDWIN0MD_ATN0E : 0, + OSD_OSDWIN0MD); + else if ((sd->vpbe_type == VPBE_VERSION_3) || + (sd->vpbe_type == VPBE_VERSION_2)) + osd_modify(sd, OSD_EXTMODE_ATNOSD0EN, + enable ? OSD_EXTMODE_ATNOSD0EN : 0, + OSD_EXTMODE); break; case OSDWIN_OSD1: osd_modify(sd, OSD_OSDWIN1MD_ATN1E, enable ? OSD_OSDWIN1MD_ATN1E : 0, OSD_OSDWIN1MD); + if (sd->vpbe_type == VPBE_VERSION_1) + osd_modify(sd, OSD_OSDWIN1MD_ATN1E, + enable ? OSD_OSDWIN1MD_ATN1E : 0, + OSD_OSDWIN1MD); + else if ((sd->vpbe_type == VPBE_VERSION_3) || + (sd->vpbe_type == VPBE_VERSION_2)) + osd_modify(sd, OSD_EXTMODE_ATNOSD1EN, + enable ? OSD_EXTMODE_ATNOSD1EN : 0, + OSD_EXTMODE); break; } } @@ -273,15 +291,71 @@ static void _osd_set_blending_factor(struct osd_state *sd, } } +static void _osd_enable_rgb888_pixblend(struct osd_state *sd, + enum osd_win_layer osdwin) +{ + + osd_modify(sd, OSD_MISCCTL_BLDSEL, 0, OSD_MISCCTL); + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_EXTMODE_OSD0BLDCHR, + OSD_EXTMODE_OSD0BLDCHR, OSD_EXTMODE); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_EXTMODE_OSD1BLDCHR, + OSD_EXTMODE_OSD1BLDCHR, OSD_EXTMODE); + break; + } +} + static void _osd_enable_color_key(struct osd_state *sd, enum osd_win_layer osdwin, unsigned colorkey, enum osd_pix_format pixfmt) { switch (pixfmt) { + case PIXFMT_1BPP: + case PIXFMT_2BPP: + case PIXFMT_4BPP: + case PIXFMT_8BPP: + if (sd->vpbe_type == VPBE_VERSION_3) { + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_TRANSPBMPIDX_BMP0, + colorkey << + OSD_TRANSPBMPIDX_BMP0_SHIFT, + OSD_TRANSPBMPIDX); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_TRANSPBMPIDX_BMP1, + colorkey << + OSD_TRANSPBMPIDX_BMP1_SHIFT, + OSD_TRANSPBMPIDX); + break; + } + } + break; case PIXFMT_RGB565: - osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, - OSD_TRANSPVAL); + if (sd->vpbe_type == VPBE_VERSION_1) + osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, + OSD_TRANSPVAL); + else if (sd->vpbe_type == VPBE_VERSION_3) + osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL, + OSD_TRANSPVALL); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + if (sd->vpbe_type == VPBE_VERSION_3) + osd_modify(sd, OSD_TRANSPVALU_Y, colorkey, + OSD_TRANSPVALU); + break; + case PIXFMT_RGB888: + if (sd->vpbe_type == VPBE_VERSION_3) { + osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL, + OSD_TRANSPVALL); + osd_modify(sd, OSD_TRANSPVALU_RGBU, colorkey >> 16, + OSD_TRANSPVALU); + } break; default: break; @@ -470,23 +544,188 @@ static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, return 0; } +#define OSD_SRC_ADDR_HIGH4 0x7800000 +#define OSD_SRC_ADDR_HIGH7 0x7F0000 +#define OSD_SRCADD_OFSET_SFT 23 +#define OSD_SRCADD_ADD_SFT 16 +#define OSD_WINADL_MASK 0xFFFF +#define OSD_WINOFST_MASK 0x1000 +#define VPBE_REG_BASE 0x80000000 + static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, unsigned long fb_base_phys, unsigned long cbcr_ofst) { - switch (layer) { - case WIN_OSD0: - osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); - break; - case WIN_VID0: - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); - break; - case WIN_OSD1: - osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); - break; - case WIN_VID1: - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); - break; + + if (sd->vpbe_type == VPBE_VERSION_1) { + switch (layer) { + case WIN_OSD0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); + break; + case WIN_VID0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + break; + case WIN_OSD1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); + break; + case WIN_VID1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); + break; + } + } else if (sd->vpbe_type == VPBE_VERSION_3) { + unsigned long fb_offset_32 = + (fb_base_phys - VPBE_REG_BASE) >> 5; + + switch (layer) { + case WIN_OSD0: + osd_modify(sd, OSD_OSDWINADH_O0AH, + fb_offset_32 >> (OSD_SRCADD_ADD_SFT - + OSD_OSDWINADH_O0AH_SHIFT), + OSD_OSDWINADH); + osd_write(sd, fb_offset_32 & OSD_OSDWIN0ADL_O0AL, + OSD_OSDWIN0ADL); + break; + case WIN_VID0: + osd_modify(sd, OSD_VIDWINADH_V0AH, + fb_offset_32 >> (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V0AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_VIDWIN0ADL_V0AL, + OSD_VIDWIN0ADL); + break; + case WIN_OSD1: + osd_modify(sd, OSD_OSDWINADH_O1AH, + fb_offset_32 >> (OSD_SRCADD_ADD_SFT - + OSD_OSDWINADH_O1AH_SHIFT), + OSD_OSDWINADH); + osd_write(sd, fb_offset_32 & OSD_OSDWIN1ADL_O1AL, + OSD_OSDWIN1ADL); + break; + case WIN_VID1: + osd_modify(sd, OSD_VIDWINADH_V1AH, + fb_offset_32 >> (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V1AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_VIDWIN1ADL_V1AL, + OSD_VIDWIN1ADL); + break; + } + } else if (sd->vpbe_type == VPBE_VERSION_2) { + struct osd_window_state *win = &sd->win[layer]; + unsigned long fb_offset_32, cbcr_offset_32; + + fb_offset_32 = fb_base_phys - VPBE_REG_BASE; + if (cbcr_ofst) + cbcr_offset_32 = cbcr_ofst; + else + cbcr_offset_32 = win->lconfig.line_length * + win->lconfig.ysize; + cbcr_offset_32 += fb_offset_32; + fb_offset_32 = fb_offset_32 >> 5; + cbcr_offset_32 = cbcr_offset_32 >> 5; + /* + * DM365: start address is 27-bit long address b26 - b23 are + * in offset register b12 - b9, and * bit 26 has to be '1' + */ + if (win->lconfig.pixfmt == PIXFMT_NV12) { + switch (layer) { + case WIN_VID0: + case WIN_VID1: + /* Y is in VID0 */ + osd_modify(sd, OSD_VIDWIN0OFST_V0AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | + OSD_WINOFST_MASK, OSD_VIDWIN0OFST); + osd_modify(sd, OSD_VIDWINADH_V0AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V0AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_VIDWIN0ADL); + /* CbCr is in VID1 */ + osd_modify(sd, OSD_VIDWIN1OFST_V1AH, + ((cbcr_offset_32 & + OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | + OSD_WINOFST_MASK, OSD_VIDWIN1OFST); + osd_modify(sd, OSD_VIDWINADH_V1AH, + (cbcr_offset_32 & + OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V1AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, cbcr_offset_32 & OSD_WINADL_MASK, + OSD_VIDWIN1ADL); + break; + default: + break; + } + } + + switch (layer) { + case WIN_OSD0: + osd_modify(sd, OSD_OSDWIN0OFST_O0AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK, + OSD_OSDWIN0OFST); + osd_modify(sd, OSD_OSDWINADH_O0AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_OSDWINADH_O0AH_SHIFT), OSD_OSDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_OSDWIN0ADL); + break; + case WIN_VID0: + if (win->lconfig.pixfmt != PIXFMT_NV12) { + osd_modify(sd, OSD_VIDWIN0OFST_V0AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | + OSD_WINOFST_MASK, OSD_VIDWIN0OFST); + osd_modify(sd, OSD_VIDWINADH_V0AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V0AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_VIDWIN0ADL); + } + break; + case WIN_OSD1: + osd_modify(sd, OSD_OSDWIN1OFST_O1AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK, + OSD_OSDWIN1OFST); + osd_modify(sd, OSD_OSDWINADH_O1AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_OSDWINADH_O1AH_SHIFT), + OSD_OSDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_OSDWIN1ADL); + break; + case WIN_VID1: + if (win->lconfig.pixfmt != PIXFMT_NV12) { + osd_modify(sd, OSD_VIDWIN1OFST_V1AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | + OSD_WINOFST_MASK, OSD_VIDWIN1OFST); + osd_modify(sd, OSD_VIDWINADH_V1AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V1AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_VIDWIN1ADL); + } + break; + } } } @@ -545,7 +784,7 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, { struct osd_state *osd = sd; struct osd_window_state *win = &osd->win[layer]; - int bad_config; + int bad_config = 0; /* verify that the pixel format is compatible with the layer */ switch (lconfig->pixfmt) { @@ -554,17 +793,25 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, case PIXFMT_4BPP: case PIXFMT_8BPP: case PIXFMT_RGB565: - bad_config = !is_osd_win(layer); + if (osd->vpbe_type == VPBE_VERSION_1) + bad_config = !is_vid_win(layer); break; case PIXFMT_YCbCrI: case PIXFMT_YCrCbI: bad_config = !is_vid_win(layer); break; case PIXFMT_RGB888: - bad_config = !is_vid_win(layer); + if (osd->vpbe_type == VPBE_VERSION_1) + bad_config = !is_vid_win(layer); + else if ((osd->vpbe_type == VPBE_VERSION_3) || + (osd->vpbe_type == VPBE_VERSION_2)) + bad_config = !is_osd_win(layer); break; case PIXFMT_NV12: - bad_config = 1; + if (osd->vpbe_type != VPBE_VERSION_2) + bad_config = 1; + else + bad_config = is_osd_win(layer); break; case PIXFMT_OSD_ATTR: bad_config = (layer != WIN_OSD1); @@ -584,7 +831,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, /* DM6446: */ /* only one OSD window at a time can use RGB pixel formats */ - if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { + if ((osd->vpbe_type == VPBE_VERSION_1) && + is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { enum osd_pix_format pixfmt; if (layer == WIN_OSD0) pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; @@ -602,7 +850,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, } /* DM6446: only one video window at a time can use RGB888 */ - if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) { + if ((osd->vpbe_type == VPBE_VERSION_1) && is_vid_win(layer) && + lconfig->pixfmt == PIXFMT_RGB888) { enum osd_pix_format pixfmt; if (layer == WIN_VID0) @@ -652,7 +901,8 @@ static void _osd_disable_vid_rgb888(struct osd_state *sd) * The caller must ensure that neither video window is currently * configured for RGB888 pixel format. */ - osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); + if (sd->vpbe_type == VPBE_VERSION_1) + osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); } static void _osd_enable_vid_rgb888(struct osd_state *sd, @@ -665,13 +915,14 @@ static void _osd_enable_vid_rgb888(struct osd_state *sd, * currently configured for RGB888 pixel format, as this routine will * disable RGB888 pixel format for the other window. */ - if (layer == WIN_VID0) { - osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL_RGBEN, OSD_MISCCTL); - } else if (layer == WIN_VID1) { - osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL); + if (sd->vpbe_type == VPBE_VERSION_1) { + if (layer == WIN_VID0) + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN, OSD_MISCCTL); + else if (layer == WIN_VID1) + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL); } } @@ -697,9 +948,30 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, switch (layer) { case WIN_OSD0: - winmd_mask |= OSD_OSDWIN0MD_RGB0E; - if (lconfig->pixfmt == PIXFMT_RGB565) - winmd |= OSD_OSDWIN0MD_RGB0E; + if (sd->vpbe_type == VPBE_VERSION_1) { + winmd_mask |= OSD_OSDWIN0MD_RGB0E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN0MD_RGB0E; + } else if ((sd->vpbe_type == VPBE_VERSION_3) || + (sd->vpbe_type == VPBE_VERSION_2)) { + winmd_mask |= OSD_OSDWIN0MD_BMP0MD; + switch (lconfig->pixfmt) { + case PIXFMT_RGB565: + winmd |= (1 << + OSD_OSDWIN0MD_BMP0MD_SHIFT); + break; + case PIXFMT_RGB888: + winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT); + _osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT); + break; + default: + break; + } + } winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; @@ -749,12 +1021,59 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, * For YUV420P format the register contents are * duplicated in both VID registers */ + if ((sd->vpbe_type == VPBE_VERSION_2) && + (lconfig->pixfmt == PIXFMT_NV12)) { + /* other window also */ + if (lconfig->interlaced) { + winmd_mask |= OSD_VIDWINMD_VFF1; + winmd |= OSD_VIDWINMD_VFF1; + osd_modify(sd, winmd_mask, winmd, + OSD_VIDWINMD); + } + + osd_modify(sd, OSD_MISCCTL_S420D, + OSD_MISCCTL_S420D, OSD_MISCCTL); + osd_write(sd, lconfig->line_length >> 5, + OSD_VIDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); + /* + * if NV21 pixfmt and line length not 32B + * aligned (e.g. NTSC), Need to set window + * X pixel size to be 32B aligned as well + */ + if (lconfig->xsize % 32) { + osd_write(sd, + ((lconfig->xsize + 31) & ~31), + OSD_VIDWIN1XL); + osd_write(sd, + ((lconfig->xsize + 31) & ~31), + OSD_VIDWIN0XL); + } + } else if ((sd->vpbe_type == VPBE_VERSION_2) && + (lconfig->pixfmt != PIXFMT_NV12)) { + osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, + OSD_MISCCTL); + } + if (lconfig->interlaced) { osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); + if ((sd->vpbe_type == VPBE_VERSION_2) && + lconfig->pixfmt == PIXFMT_NV12) { + osd_write(sd, lconfig->ypos >> 1, + OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, + OSD_VIDWIN1YL); + } } else { osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); + if ((sd->vpbe_type == VPBE_VERSION_2) && + lconfig->pixfmt == PIXFMT_NV12) { + osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); + } } break; case WIN_OSD1: @@ -764,14 +1083,43 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, * attribute mode to a normal mode. */ if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { - winmd_mask |= - OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E | - OSD_OSDWIN1MD_CLUTS1 | - OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; + if (sd->vpbe_type == VPBE_VERSION_1) { + winmd_mask |= OSD_OSDWIN1MD_ATN1E | + OSD_OSDWIN1MD_RGB1E | OSD_OSDWIN1MD_CLUTS1 | + OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; + } else { + winmd_mask |= OSD_OSDWIN1MD_BMP1MD | + OSD_OSDWIN1MD_CLUTS1 | OSD_OSDWIN1MD_BLND1 | + OSD_OSDWIN1MD_TE1; + } } else { - winmd_mask |= OSD_OSDWIN1MD_RGB1E; - if (lconfig->pixfmt == PIXFMT_RGB565) - winmd |= OSD_OSDWIN1MD_RGB1E; + if (sd->vpbe_type == VPBE_VERSION_1) { + winmd_mask |= OSD_OSDWIN1MD_RGB1E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN1MD_RGB1E; + } else if ((sd->vpbe_type == VPBE_VERSION_3) + || (sd->vpbe_type == VPBE_VERSION_2)) { + winmd_mask |= OSD_OSDWIN1MD_BMP1MD; + switch (lconfig->pixfmt) { + case PIXFMT_RGB565: + winmd |= + (1 << OSD_OSDWIN1MD_BMP1MD_SHIFT); + break; + case PIXFMT_RGB888: + winmd |= + (2 << OSD_OSDWIN1MD_BMP1MD_SHIFT); + _osd_enable_rgb888_pixblend(sd, + OSDWIN_OSD1); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + winmd |= + (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT); + break; + default: + break; + } + } winmd_mask |= OSD_OSDWIN1MD_BMW1; switch (lconfig->pixfmt) { @@ -822,15 +1170,45 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, * For YUV420P format the register contents are * duplicated in both VID registers */ - osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, - OSD_MISCCTL); + if (sd->vpbe_type == VPBE_VERSION_2) { + if (lconfig->pixfmt == PIXFMT_NV12) { + /* other window also */ + if (lconfig->interlaced) { + winmd_mask |= OSD_VIDWINMD_VFF0; + winmd |= OSD_VIDWINMD_VFF0; + osd_modify(sd, winmd_mask, winmd, + OSD_VIDWINMD); + } + osd_modify(sd, OSD_MISCCTL_S420D, + OSD_MISCCTL_S420D, OSD_MISCCTL); + osd_write(sd, lconfig->line_length >> 5, + OSD_VIDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); + } else { + osd_modify(sd, OSD_MISCCTL_S420D, + ~OSD_MISCCTL_S420D, OSD_MISCCTL); + } + } if (lconfig->interlaced) { osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); + if ((sd->vpbe_type == VPBE_VERSION_2) && + lconfig->pixfmt == PIXFMT_NV12) { + osd_write(sd, lconfig->ypos >> 1, + OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, + OSD_VIDWIN0YL); + } } else { osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); + if ((sd->vpbe_type == VPBE_VERSION_2) && + lconfig->pixfmt == PIXFMT_NV12) { + osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); + } } break; } @@ -1089,6 +1467,11 @@ static void _osd_init(struct osd_state *sd) osd_write(sd, 0, OSD_OSDWIN1MD); osd_write(sd, 0, OSD_RECTCUR); osd_write(sd, 0, OSD_MISCCTL); + if (sd->vpbe_type == VPBE_VERSION_3) { + osd_write(sd, 0, OSD_VBNDRY); + osd_write(sd, 0, OSD_EXTMODE); + osd_write(sd, OSD_MISCCTL_DMANG, OSD_MISCCTL); + } } static void osd_set_left_margin(struct osd_state *sd, u32 val) @@ -1110,6 +1493,14 @@ static int osd_initialize(struct osd_state *osd) /* set default Cb/Cr order */ osd->yc_pixfmt = PIXFMT_YCbCrI; + if (osd->vpbe_type == VPBE_VERSION_3) { + /* + * ROM CLUT1 on the DM355 is similar (identical?) to ROM CLUT0 + * on the DM6446, so make ROM_CLUT1 the default on the DM355. + */ + osd->rom_clut = ROM_CLUT1; + } + _osd_set_field_inversion(osd, osd->field_inversion); _osd_set_rom_clut(osd, osd->rom_clut); @@ -1208,23 +1599,7 @@ static struct platform_driver osd_driver = { }, }; -static int osd_init(void) -{ - if (platform_driver_register(&osd_driver)) { - printk(KERN_ERR "Unable to register davinci osd driver\n"); - return -ENODEV; - } - - return 0; -} - -static void osd_exit(void) -{ - platform_driver_unregister(&osd_driver); -} - -module_init(osd_init); -module_exit(osd_exit); +module_platform_driver(osd_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c index 03a3e5c65ee7..00e80f59d5d5 100644 --- a/drivers/media/video/davinci/vpbe_venc.c +++ b/drivers/media/video/davinci/vpbe_venc.c @@ -99,6 +99,8 @@ static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) return val; } +#define VDAC_COMPONENT 0x543 +#define VDAC_S_VIDEO 0x210 /* This function sets the dac of the VPBE for various outputs */ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) @@ -109,11 +111,12 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) venc_write(sd, VENC_DACSEL, 0); break; case 1: - v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n"); - venc_write(sd, VENC_DACSEL, 0x210); + v4l2_dbg(debug, 1, sd, "Setting output to Component\n"); + venc_write(sd, VENC_DACSEL, VDAC_COMPONENT); break; - case 2: - venc_write(sd, VENC_DACSEL, 0x543); + case 2: + v4l2_dbg(debug, 1, sd, "Setting output to S-video\n"); + venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO); break; default: return -EINVAL; @@ -124,6 +127,8 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) { + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); if (benable) { @@ -155,7 +160,8 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) /* Disable LCD output control (accepting default polarity) */ venc_write(sd, VENC_LCDOUT, 0); - venc_write(sd, VENC_CMPNT, 0x100); + if (pdata->venc_type != VPBE_VERSION_3) + venc_write(sd, VENC_CMPNT, 0x100); venc_write(sd, VENC_HSPLS, 0); venc_write(sd, VENC_HINT, 0); venc_write(sd, VENC_HSTART, 0); @@ -178,11 +184,14 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) } } +#define VDAC_CONFIG_SD_V3 0x0E21A6B6 +#define VDAC_CONFIG_SD_V2 0x081141CF /* * setting NTSC mode */ static int venc_set_ntsc(struct v4l2_subdev *sd) { + u32 val; struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; @@ -195,12 +204,22 @@ static int venc_set_ntsc(struct v4l2_subdev *sd) venc_enabledigitaloutput(sd, 0); - /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ - venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); - /* Set REC656 Mode */ - venc_write(sd, VENC_YCCCTL, 0x1); - venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); + if (pdata->venc_type == VPBE_VERSION_3) { + venc_write(sd, VENC_CLKCTL, 0x01); + venc_write(sd, VENC_VIDCTL, 0); + val = vdaccfg_write(sd, VDAC_CONFIG_SD_V3); + } else if (pdata->venc_type == VPBE_VERSION_2) { + venc_write(sd, VENC_CLKCTL, 0x01); + venc_write(sd, VENC_VIDCTL, 0); + vdaccfg_write(sd, VDAC_CONFIG_SD_V2); + } else { + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); + } venc_write(sd, VENC_VMOD, 0); venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), @@ -220,6 +239,7 @@ static int venc_set_ntsc(struct v4l2_subdev *sd) static int venc_set_pal(struct v4l2_subdev *sd) { struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); @@ -230,10 +250,20 @@ static int venc_set_pal(struct v4l2_subdev *sd) venc_enabledigitaloutput(sd, 0); - /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ - venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); - /* Set REC656 Mode */ - venc_write(sd, VENC_YCCCTL, 0x1); + if (pdata->venc_type == VPBE_VERSION_3) { + venc_write(sd, VENC_CLKCTL, 0x1); + venc_write(sd, VENC_VIDCTL, 0); + vdaccfg_write(sd, VDAC_CONFIG_SD_V3); + } else if (pdata->venc_type == VPBE_VERSION_2) { + venc_write(sd, VENC_CLKCTL, 0x1); + venc_write(sd, VENC_VIDCTL, 0); + vdaccfg_write(sd, VDAC_CONFIG_SD_V2); + } else { + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + } venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, VENC_SYNCCTL_OVD); @@ -252,6 +282,7 @@ static int venc_set_pal(struct v4l2_subdev *sd) return 0; } +#define VDAC_CONFIG_HD_V2 0x081141EF /* * venc_set_480p59_94 * @@ -263,6 +294,9 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) struct venc_platform_data *pdata = venc->pdata; v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); + if ((pdata->venc_type != VPBE_VERSION_1) && + (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_480P59_94) < 0) @@ -270,12 +304,18 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) venc_enabledigitaloutput(sd, 0); + if (pdata->venc_type == VPBE_VERSION_2) + vdaccfg_write(sd, VDAC_CONFIG_HD_V2); venc_write(sd, VENC_OSDCLK0, 0); venc_write(sd, VENC_OSDCLK1, 1); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, - VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, - VENC_VDPRO_DAUPS); + + if (pdata->venc_type == VPBE_VERSION_1) { + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + } + venc_write(sd, VENC_VMOD, 0); venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), VENC_VMOD_VIE); @@ -302,19 +342,27 @@ static int venc_set_576p50(struct v4l2_subdev *sd) v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); + if ((pdata->venc_type != VPBE_VERSION_1) && + (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) return -EINVAL; venc_enabledigitaloutput(sd, 0); + if (pdata->venc_type == VPBE_VERSION_2) + vdaccfg_write(sd, VDAC_CONFIG_HD_V2); + venc_write(sd, VENC_OSDCLK0, 0); venc_write(sd, VENC_OSDCLK1, 1); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, - VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, - VENC_VDPRO_DAUPS); + if (pdata->venc_type == VPBE_VERSION_1) { + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + } venc_write(sd, VENC_VMOD, 0); venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), @@ -330,6 +378,63 @@ static int venc_set_576p50(struct v4l2_subdev *sd) return 0; } +/* + * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only + */ +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) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + + venc_write(sd, VENC_VMOD, 0); + /* DM365 component HD mode */ + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + venc_write(sd, VENC_XHINTVL, 0); + return 0; +} + +/* + * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only + */ +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) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + + + venc_write(sd, VENC_VMOD, 0); + /* DM365 component HD mode */ + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + venc_write(sd, VENC_XHINTVL, 0); + return 0; +} + static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) { v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); @@ -345,13 +450,30 @@ static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) static int venc_s_dv_preset(struct v4l2_subdev *sd, struct v4l2_dv_preset *dv_preset) { + struct venc_state *venc = to_state(sd); + int ret; + v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); if (dv_preset->preset == V4L2_DV_576P50) return venc_set_576p50(sd); else if (dv_preset->preset == V4L2_DV_480P59_94) return venc_set_480p59_94(sd); - + else if ((dv_preset->preset == V4L2_DV_720P60) && + (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) && + (venc->pdata->venc_type == VPBE_VERSION_2)) { + /* TBD setup internal 1080i mode here */ + ret = venc_set_1080i30_internal(sd); + /* for DM365 VPBE, there is DAC inside */ + vdaccfg_write(sd, VDAC_CONFIG_HD_V2); + return ret; + } return -EINVAL; } @@ -508,11 +630,41 @@ static int venc_probe(struct platform_device *pdev) goto release_venc_mem_region; } + if (venc->pdata->venc_type != VPBE_VERSION_1) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(venc->pdev, + "Unable to get VDAC_CONFIG address map\n"); + ret = -ENODEV; + goto unmap_venc_io; + } + + if (!request_mem_region(res->start, + resource_size(res), "venc")) { + dev_err(venc->pdev, + "Unable to reserve VDAC_CONFIG MMIO region\n"); + ret = -ENODEV; + goto unmap_venc_io; + } + + venc->vdaccfg_reg = ioremap_nocache(res->start, + resource_size(res)); + if (!venc->vdaccfg_reg) { + dev_err(venc->pdev, + "Unable to map VDAC_CONFIG IO space\n"); + ret = -ENODEV; + goto release_vdaccfg_mem_region; + } + } spin_lock_init(&venc->lock); platform_set_drvdata(pdev, venc); dev_notice(venc->pdev, "VENC sub device probe success\n"); return 0; +release_vdaccfg_mem_region: + release_mem_region(res->start, resource_size(res)); +unmap_venc_io: + iounmap(venc->venc_base); release_venc_mem_region: res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); @@ -529,6 +681,11 @@ static int venc_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap((void *)venc->venc_base); release_mem_region(res->start, resource_size(res)); + if (venc->pdata->venc_type != VPBE_VERSION_1) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + iounmap((void *)venc->vdaccfg_reg); + release_mem_region(res->start, resource_size(res)); + } kfree(venc); return 0; @@ -543,23 +700,7 @@ static struct platform_driver venc_driver = { }, }; -static int venc_init(void) -{ - if (platform_driver_register(&venc_driver)) { - printk(KERN_ERR "Unable to register venc driver\n"); - return -ENODEV; - } - return 0; -} - -static void venc_exit(void) -{ - platform_driver_unregister(&venc_driver); - return; -} - -module_init(venc_init); -module_exit(venc_exit); +module_platform_driver(venc_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VPBE VENC Driver"); diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 5b38fc93ff28..20cf271a774b 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -2076,20 +2076,4 @@ static struct platform_driver vpfe_driver = { .remove = __devexit_p(vpfe_remove), }; -static __init int vpfe_init(void) -{ - printk(KERN_NOTICE "vpfe_init\n"); - /* Register driver to the kernel */ - return platform_driver_register(&vpfe_driver); -} - -/* - * vpfe_cleanup : This function un-registers device driver - */ -static void vpfe_cleanup(void) -{ - platform_driver_unregister(&vpfe_driver); -} - -module_init(vpfe_init); -module_exit(vpfe_cleanup); +module_platform_driver(vpfe_driver); diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 49e4deb50043..6504e40a31dd 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -2177,6 +2177,12 @@ static __init int vpif_probe(struct platform_device *pdev) return err; } + err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); + if (err) { + v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); + return err; + } + k = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { @@ -2246,12 +2252,6 @@ static __init int vpif_probe(struct platform_device *pdev) goto probe_out; } - err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); - if (err) { - v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - goto probe_subdev_out; - } - for (i = 0; i < subdev_count; i++) { subdevdata = &config->subdev_info[i]; vpif_obj.sd[i] = @@ -2281,7 +2281,6 @@ probe_subdev_out: j = VPIF_CAPTURE_MAX_DEVICES; probe_out: - v4l2_device_unregister(&vpif_obj.v4l2_dev); for (k = 0; k < j; k++) { /* Get the pointer to the channel object */ ch = vpif_obj.dev[k]; @@ -2303,6 +2302,7 @@ vpif_int_err: if (res) i = res->end; } + v4l2_device_unregister(&vpif_obj.v4l2_dev); return err; } diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index cff0768afbf5..e2a7b77c39c7 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -193,7 +193,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) urb->dev = dev->udev; urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); + urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO); urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->interval = 1; diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 93807dcf944e..4561cd89938d 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -336,6 +336,23 @@ static struct em28xx_reg_seq pctv_460e[] = { { -1, -1, -1, -1}, }; +#if 0 +static struct em28xx_reg_seq hauppauge_930c_gpio[] = { + {EM2874_R80_GPIO, 0x6f, 0xff, 10}, + {EM2874_R80_GPIO, 0x4f, 0xff, 10}, /* xc5000 reset */ + {EM2874_R80_GPIO, 0x6f, 0xff, 10}, + {EM2874_R80_GPIO, 0x4f, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq hauppauge_930c_digital[] = { + {EM2874_R80_GPIO, 0xf6, 0xff, 10}, + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + {EM2874_R80_GPIO, 0xa6, 0xff, 10}, + { -1, -1, -1, -1}, +}; +#endif + /* * Board definitions */ @@ -839,6 +856,10 @@ struct em28xx_board em28xx_boards[] = { [EM2870_BOARD_KWORLD_355U] = { .name = "Kworld 355 U DVB-T", .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, + .tuner_gpio = default_tuner_gpio, + .has_dvb = 1, + .dvb_gpio = default_digital, }, [EM2870_BOARD_PINNACLE_PCTV_DVB] = { .name = "Pinnacle PCTV DVB-T", @@ -887,6 +908,37 @@ struct em28xx_board em28xx_boards[] = { .tuner_addr = 0x41, .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */ .tuner_gpio = terratec_h5_gpio, +#else + .tuner_type = TUNER_ABSENT, +#endif + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + }, + [EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = { + .name = "Hauppauge WinTV HVR 930C", + .has_dvb = 1, +#if 0 /* FIXME: Add analog support */ + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x41, + .dvb_gpio = hauppauge_930c_digital, + .tuner_gpio = hauppauge_930c_gpio, +#else + .tuner_type = TUNER_ABSENT, +#endif + .ir_codes = RC_MAP_HAUPPAUGE, + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + }, + [EM2884_BOARD_CINERGY_HTC_STICK] = { + .name = "Terratec Cinergy HTC Stick", + .has_dvb = 1, +#if 0 + .tuner_type = TUNER_PHILIPS_TDA8290, + .tuner_addr = 0x41, + .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */ + .tuner_gpio = terratec_h5_gpio, #endif .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | EM28XX_I2C_CLK_WAIT_ENABLE | @@ -1127,7 +1179,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Cinergy 200 USB", .is_em2800 = 1, .has_ir_i2c = 1, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tuner_type = TUNER_LG_TALN, .tda9887_conf = TDA9887_PRESENT, .decoder = EM28XX_SAA711X, .input = { { @@ -1218,7 +1270,7 @@ struct em28xx_board em28xx_boards[] = { }, [EM2820_BOARD_PINNACLE_DVC_90] = { .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker " - "/ Kworld DVD Maker 2", + "/ Kworld DVD Maker 2 / Plextor ConvertX PX-AV100U", .tuner_type = TUNER_ABSENT, /* capture only board */ .decoder = EM28XX_SAA711X, .input = { { @@ -1840,6 +1892,22 @@ struct em28xx_board em28xx_boards[] = { .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, + /* eb1a:5006 Honestech VIDBOX NW03 + * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */ + [EM2860_BOARD_HT_VIDBOX_NW03] = { + .name = "Honestech Vidbox NW03", + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs confirming */ + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1899,6 +1967,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, { USB_DEVICE(0xeb1a, 0xe357), .driver_info = EM2870_BOARD_KWORLD_355U }, + { USB_DEVICE(0xeb1a, 0xe359), + .driver_info = EM2870_BOARD_KWORLD_355U }, { USB_DEVICE(0x1b80, 0xe302), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */ { USB_DEVICE(0x1b80, 0xe304), @@ -1914,17 +1984,23 @@ struct usb_device_id em28xx_id_table[] = { { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, { USB_DEVICE(0x0ccd, 0x0043), + .driver_info = EM2870_BOARD_TERRATEC_XS }, + { USB_DEVICE(0x0ccd, 0x008e), /* Cinergy HTC USB XS Rev. 1 */ + .driver_info = EM2884_BOARD_TERRATEC_H5 }, + { USB_DEVICE(0x0ccd, 0x00ac), /* Cinergy HTC USB XS Rev. 2 */ + .driver_info = EM2884_BOARD_TERRATEC_H5 }, + { USB_DEVICE(0x0ccd, 0x10a2), /* H5 Rev. 1 */ .driver_info = EM2884_BOARD_TERRATEC_H5 }, - { USB_DEVICE(0x0ccd, 0x10a2), /* Rev. 1 */ + { USB_DEVICE(0x0ccd, 0x10ad), /* H5 Rev. 2 */ .driver_info = EM2884_BOARD_TERRATEC_H5 }, - { USB_DEVICE(0x0ccd, 0x10ad), /* Rev. 2 */ - .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { USB_DEVICE(0x0ccd, 0x0084), .driver_info = EM2860_BOARD_TERRATEC_AV350 }, { USB_DEVICE(0x0ccd, 0x0096), .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x0ccd, 0x10AF), .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, + { USB_DEVICE(0x0ccd, 0x00b2), + .driver_info = EM2884_BOARD_CINERGY_HTC_STICK }, { USB_DEVICE(0x0fd9, 0x0033), .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, { USB_DEVICE(0x185b, 0x2870), @@ -1963,6 +2039,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, { USB_DEVICE(0x0413, 0x6023), .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, + { USB_DEVICE(0x093b, 0xa003), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x093b, 0xa005), .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, { USB_DEVICE(0x04bb, 0x0515), @@ -1975,6 +2053,12 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28174_BOARD_PCTV_290E }, { USB_DEVICE(0x2013, 0x024c), .driver_info = EM28174_BOARD_PCTV_460E }, + { USB_DEVICE(0x2040, 0x1605), + .driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C }, + { USB_DEVICE(0xeb1a, 0x5006), + .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 }, + { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */ + .driver_info = EM2860_BOARD_EASYCAP }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -2028,10 +2112,10 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg) int rc = 0; struct em28xx *dev = ptr; - if (dev->tuner_type != TUNER_XC2028) + if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000) return 0; - if (command != XC2028_TUNER_RESET) + if (command != XC2028_TUNER_RESET && command != XC5000_TUNER_RESET) return 0; rc = em28xx_gpio_set(dev, dev->board.tuner_gpio); @@ -2203,7 +2287,8 @@ void em28xx_pre_card_setup(struct em28xx *dev) /* Set the initial XCLK and I2C clock values based on the board definition */ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); + if (!dev->board.is_em2800) + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); msleep(50); /* request some modules */ @@ -2832,11 +2917,10 @@ void em28xx_release_resources(struct em28xx *dev) * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device */ -static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, +static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, struct usb_interface *interface, int minor) { - struct em28xx *dev = *devhandle; int retval; dev->udev = udev; @@ -2931,7 +3015,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, if (!dev->board.is_em2800) { /* Resets I2C speed */ - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); + retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { em28xx_errdev("%s: em28xx_write_reg failed!" " retval [%d]\n", @@ -3031,12 +3115,11 @@ unregister_dev: static int em28xx_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) { - const struct usb_endpoint_descriptor *endpoint; struct usb_device *udev; struct em28xx *dev = NULL; int retval; - bool is_audio_only = false, has_audio = false; - int i, nr, isoc_pipe; + bool has_audio = false, has_video = false, has_dvb = false; + int i, nr; const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; char *speed; char descr[255] = ""; @@ -3068,54 +3151,65 @@ static int em28xx_usb_probe(struct usb_interface *interface, goto err; } + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + em28xx_err(DRIVER_NAME ": out of memory!\n"); + retval = -ENOMEM; + goto err; + } + + /* compute alternate max packet sizes */ + dev->alt_max_pkt_size = kmalloc(sizeof(dev->alt_max_pkt_size[0]) * + interface->num_altsetting, GFP_KERNEL); + if (dev->alt_max_pkt_size == NULL) { + em28xx_errdev("out of memory!\n"); + kfree(dev); + retval = -ENOMEM; + goto err; + } + /* Get endpoints */ for (i = 0; i < interface->num_altsetting; i++) { int ep; for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { - struct usb_host_endpoint *e; - e = &interface->altsetting[i].endpoint[ep]; - - if (e->desc.bEndpointAddress == 0x83) - has_audio = true; + const struct usb_endpoint_descriptor *e; + int sizedescr, size; + + e = &interface->altsetting[i].endpoint[ep].desc; + + sizedescr = le16_to_cpu(e->wMaxPacketSize); + size = sizedescr & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(sizedescr); + + if (usb_endpoint_xfer_isoc(e) && + usb_endpoint_dir_in(e)) { + switch (e->bEndpointAddress) { + case EM28XX_EP_AUDIO: + has_audio = true; + break; + case EM28XX_EP_ANALOG: + has_video = true; + dev->alt_max_pkt_size[i] = size; + break; + case EM28XX_EP_DIGITAL: + has_dvb = true; + if (size > dev->dvb_max_pkt_size) { + dev->dvb_max_pkt_size = size; + dev->dvb_alt = i; + } + break; + } + } } } - endpoint = &interface->cur_altsetting->endpoint[0].desc; - - /* check if the device has the iso in endpoint at the correct place */ - if (usb_endpoint_xfer_isoc(endpoint) - && - (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) { - /* It's a newer em2874/em2875 device */ - isoc_pipe = 0; - } else { - int check_interface = 1; - isoc_pipe = 1; - endpoint = &interface->cur_altsetting->endpoint[1].desc; - if (!usb_endpoint_xfer_isoc(endpoint)) - check_interface = 0; - - if (usb_endpoint_dir_out(endpoint)) - check_interface = 0; - - if (!check_interface) { - if (has_audio) { - is_audio_only = true; - } else { - em28xx_err(DRIVER_NAME " video device (%04x:%04x): " - "interface %i, class %i found.\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - em28xx_err(DRIVER_NAME " This is an anciliary " - "interface not used by the driver\n"); - - retval = -ENODEV; - goto err; - } - } + if (!(has_audio || has_video || has_dvb)) { + retval = -ENODEV; + goto err_free; } switch (udev->speed) { @@ -3141,6 +3235,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, strlcat(descr, " ", sizeof(descr)); strlcat(descr, udev->product, sizeof(descr)); } + if (*descr) strlcat(descr, " ", sizeof(descr)); @@ -3157,6 +3252,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, printk(KERN_INFO DRIVER_NAME ": Audio Vendor Class interface %i found\n", ifnum); + if (has_video) + printk(KERN_INFO DRIVER_NAME + ": Video interface %i found\n", + ifnum); + if (has_dvb) + printk(KERN_INFO DRIVER_NAME + ": DVB interface %i found\n", + ifnum); /* * Make sure we have 480 Mbps of bandwidth, otherwise things like @@ -3168,22 +3271,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, printk(DRIVER_NAME ": Device must be connected to a high-speed" " USB 2.0 port.\n"); retval = -ENODEV; - goto err; - } - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - em28xx_err(DRIVER_NAME ": out of memory!\n"); - retval = -ENOMEM; - goto err; + goto err_free; } snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr); dev->devno = nr; dev->model = id->driver_info; dev->alt = -1; - dev->is_audio_only = is_audio_only; + dev->is_audio_only = has_audio && !(has_video || has_dvb); dev->has_alsa_audio = has_audio; dev->audio_ifnum = ifnum; @@ -3196,26 +3291,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, } } - /* compute alternate max packet sizes */ dev->num_alt = interface->num_altsetting; - dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); - - if (dev->alt_max_pkt_size == NULL) { - em28xx_errdev("out of memory!\n"); - kfree(dev); - retval = -ENOMEM; - goto err; - } - - for (i = 0; i < dev->num_alt ; i++) { - u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); - unsigned int size = tmp & 0x7ff; - - if (udev->speed == USB_SPEED_HIGH) - size = size * hb_mult(tmp); - - dev->alt_max_pkt_size[i] = size; - } if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) dev->model = card[nr]; @@ -3226,12 +3302,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* allocate device struct */ mutex_init(&dev->lock); mutex_lock(&dev->lock); - retval = em28xx_init_dev(&dev, udev, interface, nr); + retval = em28xx_init_dev(dev, udev, interface, nr); if (retval) { - mutex_unlock(&dev->lock); - kfree(dev->alt_max_pkt_size); - kfree(dev); - goto err; + goto unlock_and_free; } request_modules(dev); @@ -3250,6 +3323,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, return 0; +unlock_and_free: + mutex_unlock(&dev->lock); + +err_free: + kfree(dev->alt_max_pkt_size); + kfree(dev); + err: clear_bit(nr, &em28xx_devused); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 804a4ab47ac6..0aacc96f9a23 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -568,7 +568,7 @@ int em28xx_audio_setup(struct em28xx *dev) em28xx_warn("AC97 features = 0x%04x\n", feat); /* Try to identify what audio processor we have */ - if ((vid == 0xffffffff) && (feat == 0x6a90)) + if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90)) dev->audio_mode.ac97 = EM28XX_AC97_EM202; else if ((vid >> 8) == 0x838476) dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL; @@ -1070,7 +1070,8 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, should also be using 'desc.bInterval' */ pipe = usb_rcvisocpipe(dev->udev, - dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84); + dev->mode == EM28XX_ANALOG_MODE ? + EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL); usb_fill_int_urb(urb, dev->udev, pipe, dev->isoc_ctl.transfer_buffer[i], sb_size, @@ -1108,62 +1109,6 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, } EXPORT_SYMBOL_GPL(em28xx_init_isoc); -/* Determine the packet size for the DVB stream for the given device - (underlying value programmed into the eeprom) */ -int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) -{ - unsigned int chip_cfg2; - unsigned int packet_size; - - switch (dev->chip_id) { - case CHIP_ID_EM2710: - case CHIP_ID_EM2750: - case CHIP_ID_EM2800: - case CHIP_ID_EM2820: - case CHIP_ID_EM2840: - case CHIP_ID_EM2860: - /* No DVB support */ - return -EINVAL; - case CHIP_ID_EM2870: - case CHIP_ID_EM2883: - /* TS max packet size stored in bits 1-0 of R01 */ - chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); - switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) { - case EM28XX_CHIPCFG2_TS_PACKETSIZE_188: - packet_size = 188; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_376: - packet_size = 376; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_564: - packet_size = 564; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_752: - packet_size = 752; - break; - } - break; - case CHIP_ID_EM2874: - /* - * FIXME: for now assumes 564 like it was before, but the - * em2874 code should be added to return the proper value - */ - packet_size = 564; - break; - case CHIP_ID_EM2884: - case CHIP_ID_EM28174: - default: - /* - * FIXME: same as em2874. 564 was enough for 22 Mbit DVB-T - * but not enough for 44 Mbit DVB-C. - */ - packet_size = 752; - } - - return packet_size; -} -EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize); - /* * em28xx_wake_i2c() * configure i2c attached devices diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index cef7a2d409cb..9449423098e0 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -44,6 +44,7 @@ #include "drxk.h" #include "tda10071.h" #include "a8293.h" +#include "qt1010.h" MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); @@ -163,12 +164,12 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) struct em28xx *dev = dvb->adapter.priv; int max_dvb_packet_size; - usb_set_interface(dev->udev, 0, 1); + usb_set_interface(dev->udev, 0, dev->dvb_alt); rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; - max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev); + max_dvb_packet_size = dev->dvb_max_pkt_size; if (max_dvb_packet_size < 0) return max_dvb_packet_size; dprintk(1, "Using %d buffers each with %d bytes\n", @@ -302,10 +303,12 @@ static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = { }; static struct drxd_config em28xx_drxd = { - .index = 0, .demod_address = 0x70, .demod_revision = 0xa2, - .demoda_address = 0x00, .pll_address = 0x00, - .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1, - .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000, + .demod_address = 0x70, + .demod_revision = 0xa2, + .pll_type = DRXD_PLL_NONE, + .clock = 12000, + .insert_rs_byte = 1, + .IF = 42800000, .disable_i2c_gate_ctrl = 1, }; @@ -316,6 +319,14 @@ struct drxk_config terratec_h5_drxk = { .microcode_name = "dvb-usb-terratec-h5-drxk.fw", }; +struct drxk_config hauppauge_930c_drxk = { + .adr = 0x29, + .single_master = 1, + .no_i2c_bridge = 1, + .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw", + .chunk_size = 56, +}; + static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct em28xx_dvb *dvb = fe->sec_priv; @@ -334,6 +345,73 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) return status; } +static void hauppauge_hvr930c_init(struct em28xx *dev) +{ + int i; + + struct em28xx_reg_seq hauppauge_hvr930c_init[] = { + {EM2874_R80_GPIO, 0xff, 0xff, 0x65}, + {EM2874_R80_GPIO, 0xfb, 0xff, 0x32}, + {EM2874_R80_GPIO, 0xff, 0xff, 0xb8}, + { -1, -1, -1, -1}, + }; + struct em28xx_reg_seq hauppauge_hvr930c_end[] = { + {EM2874_R80_GPIO, 0xef, 0xff, 0x01}, + {EM2874_R80_GPIO, 0xaf, 0xff, 0x65}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x76}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x01}, + {EM2874_R80_GPIO, 0xcf, 0xff, 0x0b}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x40}, + + {EM2874_R80_GPIO, 0xcf, 0xff, 0x65}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x65}, + {EM2874_R80_GPIO, 0xcf, 0xff, 0x0b}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x65}, + + { -1, -1, -1, -1}, + }; + + struct { + unsigned char r[4]; + int len; + } regs[] = { + {{ 0x06, 0x02, 0x00, 0x31 }, 4}, + {{ 0x01, 0x02 }, 2}, + {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0xff, 0xaf }, 4}, + {{ 0x01, 0x00, 0x03, 0xa0 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0x73, 0xaf }, 4}, + {{ 0x04, 0x00 }, 2}, + {{ 0x00, 0x04 }, 2}, + {{ 0x00, 0x04, 0x00, 0x0a }, 4}, + {{ 0x04, 0x14 }, 2}, + {{ 0x04, 0x14, 0x00, 0x00 }, 4}, + }; + + em28xx_gpio_set(dev, hauppauge_hvr930c_init); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); + msleep(10); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); + msleep(10); + + dev->i2c_client.addr = 0x82 >> 1; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + em28xx_gpio_set(dev, hauppauge_hvr930c_end); + + msleep(100); + + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); + msleep(30); + + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); + msleep(10); + +} + static void terratec_h5_init(struct em28xx *dev) { int i; @@ -425,13 +503,6 @@ static struct tda10023_config em28xx_tda10023_config = { static struct cxd2820r_config em28xx_cxd2820r_config = { .i2c_address = (0xd8 >> 1), .ts_mode = CXD2820R_TS_SERIAL, - .if_dvbt_6 = 3300, - .if_dvbt_7 = 3500, - .if_dvbt_8 = 4000, - .if_dvbt2_6 = 3300, - .if_dvbt2_7 = 3500, - .if_dvbt2_8 = 4000, - .if_dvbc = 5000, /* enable LNA for DVB-T2 and DVB-C */ .gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L, @@ -456,6 +527,17 @@ static const struct a8293_config em28xx_a8293_config = { .i2c_addr = 0x08, /* (0x10 >> 1) */ }; +static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = { + .demod_address = (0x1e >> 1), + .disable_i2c_gate_ctrl = 1, + .no_tuner = 1, + .parallel_ts = 1, +}; +static struct qt1010_config em28xx_qt1010_config = { + .i2c_address = 0x62 + +}; + /* ------------------------------------------------------------------ */ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) @@ -708,6 +790,14 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2870_BOARD_KWORLD_355U: + dvb->fe[0] = dvb_attach(zl10353_attach, + &em28xx_zl10353_no_i2c_gate_dev, + &dev->i2c_adap); + if (dvb->fe[0] != NULL) + dvb_attach(qt1010_attach, dvb->fe[0], + &dev->i2c_adap, &em28xx_qt1010_config); + break; case EM2883_BOARD_KWORLD_HYBRID_330U: case EM2882_BOARD_EVGA_INDTUBE: dvb->fe[0] = dvb_attach(s5h1409_attach, @@ -761,50 +851,72 @@ static int em28xx_dvb_init(struct em28xx *dev) &dev->i2c_adap, &kworld_a340_config); break; case EM28174_BOARD_PCTV_290E: - /* MFE - * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */ - /* FE 0 */ dvb->fe[0] = dvb_attach(cxd2820r_attach, - &em28xx_cxd2820r_config, &dev->i2c_adap, NULL); + &em28xx_cxd2820r_config, + &dev->i2c_adap, + NULL); if (dvb->fe[0]) { /* FE 0 attach tuner */ - if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { + if (!dvb_attach(tda18271_attach, + dvb->fe[0], + 0x60, + &dev->i2c_adap, + &em28xx_cxd2820r_tda18271_config)) { + dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; } - /* FE 1. This dvb_attach() cannot fail. */ - dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL, - dvb->fe[0]); - dvb->fe[1]->id = 1; - /* FE 1 attach tuner */ - if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60, - &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { - dvb_frontend_detach(dvb->fe[1]); - /* leave FE 0 still active */ - } + } + break; + case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: + { + struct xc5000_config cfg; + hauppauge_hvr930c_init(dev); + + dvb->fe[0] = dvb_attach(drxk_attach, + &hauppauge_930c_drxk, &dev->i2c_adap); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + /* FIXME: do we need a pll semaphore? */ + dvb->fe[0]->sec_priv = dvb; + sema_init(&dvb->pll_mutex, 1); + dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl; + dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; - mfe_shared = 1; + /* Attach xc5000 */ + memset(&cfg, 0, sizeof(cfg)); + cfg.i2c_address = 0x61; + cfg.if_khz = 4000; + + if (dvb->fe[0]->ops.i2c_gate_ctrl) + dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); + if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap, + &cfg)) { + result = -EINVAL; + goto out_free; } + if (dvb->fe[0]->ops.i2c_gate_ctrl) + dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0); + break; + } case EM2884_BOARD_TERRATEC_H5: + case EM2884_BOARD_CINERGY_HTC_STICK: terratec_h5_init(dev); - dvb->dont_attach_fe1 = 1; - - dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]); + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; } - /* FIXME: do we need a pll semaphore? */ dvb->fe[0]->sec_priv = dvb; sema_init(&dvb->pll_mutex, 1); dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl; dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; - dvb->fe[1]->id = 1; /* Attach tda18271 to DVB-C frontend */ if (dvb->fe[0]->ops.i2c_gate_ctrl) @@ -816,12 +928,6 @@ static int em28xx_dvb_init(struct em28xx *dev) if (dvb->fe[0]->ops.i2c_gate_ctrl) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0); - /* Hack - needed by drxk/tda18271c2dd */ - dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv; - memcpy(&dvb->fe[1]->ops.tuner_ops, - &dvb->fe[0]->ops.tuner_ops, - sizeof(dvb->fe[0]->ops.tuner_ops)); - break; case EM28174_BOARD_PCTV_460E: /* attach demod */ @@ -845,6 +951,8 @@ static int em28xx_dvb_init(struct em28xx *dev) } /* define general-purpose callback pointer */ dvb->fe[0]->callback = em28xx_tuner_callback; + if (dvb->fe[1]) + dvb->fe[1]->callback = em28xx_tuner_callback; /* register everything */ result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 679da4804281..2630b265b0e8 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -306,7 +306,8 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir) poll_result.rc_data[0], poll_result.toggle_bit); - if (ir->dev->chip_id == CHIP_ID_EM2874) + if (ir->dev->chip_id == CHIP_ID_EM2874 || + ir->dev->chip_id == CHIP_ID_EM2884) /* The em2874 clears the readcount field every time the register is read. The em2860/2880 datasheet says that it is supposed to clear the readcount, but it doesn't. So with @@ -371,13 +372,15 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) case CHIP_ID_EM2883: ir->get_key = default_polling_getkey; break; + case CHIP_ID_EM2884: case CHIP_ID_EM2874: case CHIP_ID_EM28174: ir->get_key = em2874_polling_getkey; em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); break; default: - printk("Unrecognized em28xx chip id: IR not supported\n"); + printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n", + dev->chip_id); rc = -EINVAL; } diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index 66f792361b97..2f6268505726 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h @@ -12,6 +12,11 @@ #define EM_GPO_2 (1 << 2) #define EM_GPO_3 (1 << 3) +/* em28xx endpoints */ +#define EM28XX_EP_ANALOG 0x82 +#define EM28XX_EP_AUDIO 0x83 +#define EM28XX_EP_DIGITAL 0x84 + /* em2800 registers */ #define EM2800_R08_AUDIOSRC 0x08 diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 9b4557a2f6d0..613300b51a9e 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1070,6 +1070,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, /* the em2800 can only scale down to 50% */ height = height > (3 * maxh / 4) ? maxh : maxh / 2; width = width > (3 * maxw / 4) ? maxw : maxw / 2; + /* MaxPacketSize for em2800 is too small to capture at full resolution + * use half of maxw as the scaler can only scale to 50% */ + if (width == maxw && height == maxh) + width /= 2; } else { /* width must even because of the YUYV format height must be even because of interlacing */ @@ -2503,6 +2507,7 @@ int em28xx_register_analog_devices(struct em28xx *dev) { u8 val; int ret; + unsigned int maxw; printk(KERN_INFO "%s: v4l2 driver version %s\n", dev->name, EM28XX_VERSION); @@ -2515,8 +2520,15 @@ int em28xx_register_analog_devices(struct em28xx *dev) /* Analog specific initialization */ dev->format = &format[0]; + + maxw = norm_maxw(dev); + /* MaxPacketSize for em2800 is too small to capture at full resolution + * use half of maxw as the scaler can only scale to 50% */ + if (dev->board.is_em2800) + maxw /= 2; + em28xx_set_video_format(dev, format[0].fourcc, - norm_maxw(dev), norm_maxh(dev)); + maxw, norm_maxh(dev)); video_mux(dev, dev->ctl_input); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 2a2cb7ed0014..22e252bcc41e 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -38,6 +38,7 @@ #include <media/videobuf-dvb.h> #endif #include "tuner-xc2028.h" +#include "xc5000.h" #include "em28xx-reg.h" /* Boards supported by driver */ @@ -121,6 +122,9 @@ #define EM28174_BOARD_PCTV_290E 78 #define EM2884_BOARD_TERRATEC_H5 79 #define EM28174_BOARD_PCTV_460E 80 +#define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81 +#define EM2884_BOARD_CINERGY_HTC_STICK 82 +#define EM2860_BOARD_HT_VIDBOX_NW03 83 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -594,6 +598,8 @@ struct em28xx { int max_pkt_size; /* max packet size of isoc transaction */ int num_alt; /* Number of alternative settings */ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ + int dvb_alt; /* alternate for DVB */ + unsigned int dvb_max_pkt_size; /* wMaxPacketSize for DVB */ struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */ @@ -825,7 +831,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev) if (dev->board.is_webcam) return dev->sensor_xres; - if (dev->board.max_range_640_480 || dev->board.is_em2800) + if (dev->board.max_range_640_480) return 640; return 720; diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 40f214ab924f..5539f09440ac 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -76,8 +76,8 @@ MODULE_PARM_DESC(video_nr, "\none and for every other camera." "\n"); -static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = - ET61X251_FORCE_MUNMAP}; +static bool force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = + ET61X251_FORCE_MUNMAP}; module_param_array(force_munmap, bool, NULL, 0444); MODULE_PARM_DESC(force_munmap, "\n<0|1[,...]> Force the application to unmap previously" diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c index 27cb197d0bd6..27e3e0c0b219 100644 --- a/drivers/media/video/fsl-viu.c +++ b/drivers/media/video/fsl-viu.c @@ -1661,18 +1661,7 @@ static struct platform_driver viu_of_platform_driver = { }, }; -static int __init viu_init(void) -{ - return platform_driver_register(&viu_of_platform_driver); -} - -static void __exit viu_exit(void) -{ - platform_driver_unregister(&viu_of_platform_driver); -} - -module_init(viu_init); -module_exit(viu_exit); +module_platform_driver(viu_of_platform_driver); MODULE_DESCRIPTION("Freescale Video-In(VIU)"); MODULE_AUTHOR("Hongjun Chen"); diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 103af3fe5aa0..dfe268bfa4f8 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -77,6 +77,16 @@ config USB_GSPCA_JEILINJ To compile this driver as a module, choose M here: the module will be called gspca_jeilinj. +config USB_GSPCA_JL2005BCD + tristate "JL2005B/C/D USB V4L2 driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based the + JL2005B, JL2005C, or JL2005D chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_jl2005bcd. + config USB_GSPCA_KINECT tristate "Kinect sensor device USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index f345f494d0f3..79ebe46e1ad7 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o +obj-$(CONFIG_USB_GSPCA_JL2005BCD) += gspca_jl2005bcd.o obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o @@ -49,6 +50,7 @@ gspca_cpia1-objs := cpia1.o gspca_etoms-objs := etoms.o gspca_finepix-objs := finepix.o gspca_jeilinj-objs := jeilinj.o +gspca_jl2005bcd-objs := jl2005bcd.o gspca_kinect-objs := kinect.o gspca_konica-objs := konica.o gspca_mars-objs := mars.o diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c index 636627b57dc9..9769f17915c0 100644 --- a/drivers/media/video/gspca/benq.c +++ b/drivers/media/video/gspca/benq.c @@ -76,7 +76,6 @@ static int sd_config(struct gspca_dev *gspca_dev, gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); gspca_dev->cam.no_urb_create = 1; - gspca_dev->cam.reverse_alts = 1; return 0; } @@ -135,13 +134,17 @@ static int sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { + struct usb_interface *intf; + reg_w(gspca_dev, 0x003c, 0x0003); reg_w(gspca_dev, 0x003c, 0x0004); reg_w(gspca_dev, 0x003c, 0x0005); reg_w(gspca_dev, 0x003c, 0x0006); reg_w(gspca_dev, 0x003c, 0x0007); + + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); usb_set_interface(gspca_dev->dev, gspca_dev->iface, - gspca_dev->nbalt - 1); + intf->num_altsetting - 1); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index a8f54c20e585..c84e26006fc3 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -337,7 +337,6 @@ static int sd_config(struct gspca_dev *gspca_dev, return -1; cam = &gspca_dev->cam; - gspca_dev->nbalt = 4; switch (sd->sensor) { case ID_MI1320: diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 2ca10dfec91f..ca5a2b139d0b 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -633,23 +633,32 @@ static u32 which_bandwidth(struct gspca_dev *gspca_dev) u32 bandwidth; int i; + /* get the (max) image size */ i = gspca_dev->curr_mode; bandwidth = gspca_dev->cam.cam_mode[i].sizeimage; - /* if the image is compressed, estimate the mean image size */ - if (bandwidth < gspca_dev->cam.cam_mode[i].width * + /* if the image is compressed, estimate its mean size */ + if (!gspca_dev->cam.needs_full_bandwidth && + bandwidth < gspca_dev->cam.cam_mode[i].width * gspca_dev->cam.cam_mode[i].height) - bandwidth /= 3; + bandwidth = bandwidth * 3 / 8; /* 0.375 */ /* estimate the frame rate */ if (gspca_dev->sd_desc->get_streamparm) { struct v4l2_streamparm parm; - parm.parm.capture.timeperframe.denominator = 15; gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm); bandwidth *= parm.parm.capture.timeperframe.denominator; + bandwidth /= parm.parm.capture.timeperframe.numerator; } else { - bandwidth *= 15; /* 15 fps */ + + /* don't hope more than 15 fps with USB 1.1 and + * image resolution >= 640x480 */ + if (gspca_dev->width >= 640 + && gspca_dev->dev->speed == USB_SPEED_FULL) + bandwidth *= 15; /* 15 fps */ + else + bandwidth *= 30; /* 30 fps */ } PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth); @@ -667,9 +676,8 @@ struct ep_tb_s { * build the table of the endpoints * and compute the minimum bandwidth for the image transfer */ -static int build_ep_tb(struct gspca_dev *gspca_dev, +static int build_isoc_ep_tb(struct gspca_dev *gspca_dev, struct usb_interface *intf, - int xfer, struct ep_tb_s *ep_tb) { struct usb_host_endpoint *ep; @@ -687,17 +695,21 @@ static int build_ep_tb(struct gspca_dev *gspca_dev, ep_tb->bandwidth = 2000 * 2000 * 120; found = 0; for (j = 0; j < nbalt; j++) { - ep = alt_xfer(&intf->altsetting[j], xfer); + ep = alt_xfer(&intf->altsetting[j], + USB_ENDPOINT_XFER_ISOC); if (ep == NULL) continue; + if (ep->desc.bInterval == 0) { + pr_err("alt %d iso endp with 0 interval\n", j); + continue; + } psize = le16_to_cpu(ep->desc.wMaxPacketSize); - if (!gspca_dev->cam.bulk) /* isoc */ - psize = (psize & 0x07ff) * - (1 + ((psize >> 11) & 3)); - bandwidth = psize * ep->desc.bInterval * 1000; + psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); + bandwidth = psize * 1000; if (gspca_dev->dev->speed == USB_SPEED_HIGH || gspca_dev->dev->speed == USB_SPEED_SUPER) bandwidth *= 8; + bandwidth /= 1 << (ep->desc.bInterval - 1); if (bandwidth <= last_bw) continue; if (bandwidth < ep_tb->bandwidth) { @@ -715,6 +727,23 @@ static int build_ep_tb(struct gspca_dev *gspca_dev, ep_tb++; } + /* + * If the camera: + * has a usb audio class interface (a built in usb mic); and + * is a usb 1 full speed device; and + * uses the max full speed iso bandwidth; and + * and has more than 1 alt setting + * then skip the highest alt setting to spare bandwidth for the mic + */ + if (gspca_dev->audio && + gspca_dev->dev->speed == USB_SPEED_FULL && + last_bw >= 1000000 && + i > 1) { + PDEBUG(D_STREAM, "dev has usb audio, skipping highest alt"); + i--; + ep_tb--; + } + /* get the requested bandwidth and start at the highest atlsetting */ bandwidth = which_bandwidth(gspca_dev); ep_tb--; @@ -790,10 +819,7 @@ static int create_urbs(struct gspca_dev *gspca_dev, ep->desc.bEndpointAddress); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - if (gspca_dev->dev->speed == USB_SPEED_LOW) - urb->interval = ep->desc.bInterval; - else - urb->interval = 1 << (ep->desc.bInterval - 1); + urb->interval = 1 << (ep->desc.bInterval - 1); urb->complete = isoc_irq; urb->number_of_packets = npkt; for (i = 0; i < npkt; i++) { @@ -848,7 +874,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK : USB_ENDPOINT_XFER_ISOC; - /* if the subdriver forced an altsetting, get the endpoint */ + /* if bulk or the subdriver forced an altsetting, get the endpoint */ if (gspca_dev->alt != 0) { gspca_dev->alt--; /* (previous version compatibility) */ ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer); @@ -863,7 +889,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) /* else, compute the minimum bandwidth * and build the endpoint table */ - alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb); + alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb); if (alt_idx <= 0) { pr_err("no transfer endpoint found\n"); ret = -EIO; @@ -880,7 +906,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) for (;;) { if (alt != gspca_dev->alt) { alt = gspca_dev->alt; - if (gspca_dev->nbalt > 1) { + if (intf->num_altsetting > 1) { ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, alt); @@ -2300,15 +2326,14 @@ int gspca_dev_probe2(struct usb_interface *intf, } gspca_dev->dev = dev; gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber; - gspca_dev->nbalt = intf->num_altsetting; /* check if any audio device */ - if (dev->config->desc.bNumInterfaces != 1) { + if (dev->actconfig->desc.bNumInterfaces != 1) { int i; struct usb_interface *intf2; - for (i = 0; i < dev->config->desc.bNumInterfaces; i++) { - intf2 = dev->config->interface[i]; + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { + intf2 = dev->actconfig->interface[i]; if (intf2 != NULL && intf2->altsetting != NULL && intf2->altsetting->desc.bInterfaceClass == @@ -2389,7 +2414,7 @@ int gspca_dev_probe(struct usb_interface *intf, } /* the USB video interface must be the first one */ - if (dev->config->desc.bNumInterfaces != 1 + if (dev->actconfig->desc.bNumInterfaces != 1 && intf->cur_altsetting->desc.bInterfaceNumber != 0) return -ENODEV; diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index e444f16e1497..589009f4496f 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -69,7 +69,9 @@ struct cam { u8 bulk; /* image transfer by 0:isoc / 1:bulk */ u8 npkt; /* number of packets in an ISOC message * 0 is the default value: 32 packets */ - u8 reverse_alts; /* Alt settings are in high to low order */ + u8 needs_full_bandwidth;/* Set this flag to notify the bandwidth calc. + * code that the cam fills all image buffers to + * the max, even when using compression. */ }; struct gspca_dev; @@ -208,7 +210,6 @@ struct gspca_dev { char memory; /* memory type (V4L2_MEMORY_xxx) */ __u8 iface; /* USB interface number */ __u8 alt; /* USB alternate setting */ - __u8 nbalt; /* number of USB alternate settings */ u8 audio; /* presence of audio device */ }; diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c new file mode 100644 index 000000000000..53f58ef367cf --- /dev/null +++ b/drivers/media/video/gspca/jl2005bcd.c @@ -0,0 +1,554 @@ +/* + * Jeilin JL2005B/C/D library + * + * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.edu> + * + * 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 + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "jl2005bcd" + +#include <linux/workqueue.h> +#include <linux/slab.h> +#include "gspca.h" + + +MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>"); +MODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* Default timeouts, in ms */ +#define JL2005C_CMD_TIMEOUT 500 +#define JL2005C_DATA_TIMEOUT 1000 + +/* Maximum transfer size to use. */ +#define JL2005C_MAX_TRANSFER 0x200 +#define FRAME_HEADER_LEN 16 + + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + unsigned char firmware_id[6]; + const struct v4l2_pix_format *cap_mode; + /* Driver stuff */ + struct work_struct work_struct; + struct workqueue_struct *work_thread; + u8 frame_brightness; + int block_size; /* block size of camera */ + int vga; /* 1 if vga cam, 0 if cif cam */ +}; + + +/* Camera has two resolution settings. What they are depends on model. */ +static const struct v4l2_pix_format cif_mode[] = { + {176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + {352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + {640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* + * cam uses endpoint 0x03 to send commands, 0x84 for read commands, + * and 0x82 for bulk data transfer. + */ + +/* All commands are two bytes only */ +static int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command) +{ + int retval; + + memcpy(gspca_dev->usb_buf, command, 2); + retval = usb_bulk_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 3), + gspca_dev->usb_buf, 2, NULL, 500); + if (retval < 0) + pr_err("command write [%02x] error %d\n", + gspca_dev->usb_buf[0], retval); + return retval; +} + +/* Response to a command is one byte in usb_buf[0], only if requested. */ +static int jl2005c_read1(struct gspca_dev *gspca_dev) +{ + int retval; + + retval = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x84), + gspca_dev->usb_buf, 1, NULL, 500); + if (retval < 0) + pr_err("read command [0x%02x] error %d\n", + gspca_dev->usb_buf[0], retval); + return retval; +} + +/* Response appears in gspca_dev->usb_buf[0] */ +static int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg) +{ + int retval; + + static u8 instruction[2] = {0x95, 0x00}; + /* put register to read in byte 1 */ + instruction[1] = reg; + /* Send the read request */ + retval = jl2005c_write2(gspca_dev, instruction); + if (retval < 0) + return retval; + retval = jl2005c_read1(gspca_dev); + + return retval; +} + +static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev) +{ + int i; + int retval; + int frame_brightness = 0; + + static u8 instruction[2] = {0x7f, 0x01}; + + retval = jl2005c_write2(gspca_dev, instruction); + if (retval < 0) + return retval; + + i = 0; + while (i < 20 && !frame_brightness) { + /* If we tried 20 times, give up. */ + retval = jl2005c_read_reg(gspca_dev, 0x7e); + if (retval < 0) + return retval; + frame_brightness = gspca_dev->usb_buf[0]; + retval = jl2005c_read_reg(gspca_dev, 0x7d); + if (retval < 0) + return retval; + i++; + } + PDEBUG(D_FRAM, "frame_brightness is 0x%02x", gspca_dev->usb_buf[0]); + return retval; +} + +static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg, + unsigned char value) +{ + int retval; + u8 instruction[2]; + + instruction[0] = reg; + instruction[1] = value; + + retval = jl2005c_write2(gspca_dev, instruction); + if (retval < 0) + return retval; + + return retval; +} + +static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + int i = 0; + int retval = -1; + unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f}; + + PDEBUG(D_PROBE, "Running jl2005c_get_firmware_id"); + /* Read the first ID byte once for warmup */ + retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]); + PDEBUG(D_PROBE, "response is %02x", gspca_dev->usb_buf[0]); + if (retval < 0) + return retval; + /* Now actually get the ID string */ + for (i = 0; i < 6; i++) { + retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]); + if (retval < 0) + return retval; + sd->firmware_id[i] = gspca_dev->usb_buf[0]; + } + PDEBUG(D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x", + sd->firmware_id[0], + sd->firmware_id[1], + sd->firmware_id[2], + sd->firmware_id[3], + sd->firmware_id[4], + sd->firmware_id[5]); + return 0; +} + +static int jl2005c_stream_start_vga_lg + (struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + static u8 instruction[][2] = { + {0x05, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x18}, + {0x02, 0x00}, + {0x01, 0x00}, + {0x04, 0x52}, + }; + + for (i = 0; i < ARRAY_SIZE(instruction); i++) { + msleep(60); + retval = jl2005c_write2(gspca_dev, instruction[i]); + if (retval < 0) + return retval; + } + msleep(60); + return retval; +} + +static int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + static u8 instruction[][2] = { + {0x06, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x1a}, + {0x02, 0x00}, + {0x01, 0x00}, + {0x04, 0x52}, + }; + + for (i = 0; i < ARRAY_SIZE(instruction); i++) { + msleep(60); + retval = jl2005c_write2(gspca_dev, instruction[i]); + if (retval < 0) + return retval; + } + msleep(60); + return retval; +} + +static int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + static u8 instruction[][2] = { + {0x05, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x30}, + {0x02, 0x00}, + {0x01, 0x00}, + {0x04, 0x42}, + }; + + for (i = 0; i < ARRAY_SIZE(instruction); i++) { + msleep(60); + retval = jl2005c_write2(gspca_dev, instruction[i]); + if (retval < 0) + return retval; + } + msleep(60); + return retval; +} + +static int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + static u8 instruction[][2] = { + {0x06, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x32}, + {0x02, 0x00}, + {0x01, 0x00}, + {0x04, 0x42}, + }; + + for (i = 0; i < ARRAY_SIZE(instruction); i++) { + msleep(60); + retval = jl2005c_write2(gspca_dev, instruction[i]); + if (retval < 0) + return retval; + } + msleep(60); + return retval; +} + + +static int jl2005c_stop(struct gspca_dev *gspca_dev) +{ + int retval; + + retval = jl2005c_write_reg(gspca_dev, 0x07, 0x00); + return retval; +} + +/* This function is called as a workqueue function and runs whenever the camera + * is streaming data. Because it is a workqueue function it is allowed to sleep + * so we can use synchronous USB calls. To avoid possible collisions with other + * threads attempting to use the camera's USB interface the gspca usb_lock is + * used when performing the one USB control operation inside the workqueue, + * which tells the camera to close the stream. In practice the only thing + * which needs to be protected against is the usb_set_interface call that + * gspca makes during stream_off. Otherwise the camera doesn't provide any + * controls that the user could try to change. + */ +static void jl2005c_dostream(struct work_struct *work) +{ + struct sd *dev = container_of(work, struct sd, work_struct); + struct gspca_dev *gspca_dev = &dev->gspca_dev; + int bytes_left = 0; /* bytes remaining in current frame. */ + int data_len; /* size to use for the next read. */ + int header_read = 0; + unsigned char header_sig[2] = {0x4a, 0x4c}; + int act_len; + int packet_type; + int ret; + u8 *buffer; + + buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); + if (!buffer) { + pr_err("Couldn't allocate USB buffer\n"); + goto quit_stream; + } + + while (gspca_dev->present && gspca_dev->streaming) { + /* Check if this is a new frame. If so, start the frame first */ + if (!header_read) { + mutex_lock(&gspca_dev->usb_lock); + ret = jl2005c_start_new_frame(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + if (ret < 0) + goto quit_stream; + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x82), + buffer, JL2005C_MAX_TRANSFER, &act_len, + JL2005C_DATA_TIMEOUT); + PDEBUG(D_PACK, + "Got %d bytes out of %d for header", + act_len, JL2005C_MAX_TRANSFER); + if (ret < 0 || act_len < JL2005C_MAX_TRANSFER) + goto quit_stream; + /* Check whether we actually got the first blodk */ + if (memcmp(header_sig, buffer, 2) != 0) { + pr_err("First block is not the first block\n"); + goto quit_stream; + } + /* total size to fetch is byte 7, times blocksize + * of which we already got act_len */ + bytes_left = buffer[0x07] * dev->block_size - act_len; + PDEBUG(D_PACK, "bytes_left = 0x%x", bytes_left); + /* We keep the header. It has other information, too.*/ + packet_type = FIRST_PACKET; + gspca_frame_add(gspca_dev, packet_type, + buffer, act_len); + header_read = 1; + } + while (bytes_left > 0 && gspca_dev->present) { + data_len = bytes_left > JL2005C_MAX_TRANSFER ? + JL2005C_MAX_TRANSFER : bytes_left; + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x82), + buffer, data_len, &act_len, + JL2005C_DATA_TIMEOUT); + if (ret < 0 || act_len < data_len) + goto quit_stream; + PDEBUG(D_PACK, + "Got %d bytes out of %d for frame", + data_len, bytes_left); + bytes_left -= data_len; + if (bytes_left == 0) { + packet_type = LAST_PACKET; + header_read = 0; + } else + packet_type = INTER_PACKET; + gspca_frame_add(gspca_dev, packet_type, + buffer, data_len); + } + } +quit_stream: + if (gspca_dev->present) { + mutex_lock(&gspca_dev->usb_lock); + jl2005c_stop(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + } + kfree(buffer); +} + + + + +/* This function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam; + struct sd *sd = (struct sd *) gspca_dev; + + cam = &gspca_dev->cam; + /* We don't use the buffer gspca allocates so make it small. */ + cam->bulk_size = 64; + cam->bulk = 1; + /* For the rest, the camera needs to be detected */ + jl2005c_get_firmware_id(gspca_dev); + /* Here are some known firmware IDs + * First some JL2005B cameras + * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2} Sakar KidzCam + * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2} No-name JL2005B + * JL2005C cameras + * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8} Argus DC-1512 + * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8} ICarly + * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4} Jazz + * + * Based upon this scanty evidence, we can detect a CIF camera by + * testing byte 0 for 0x4x. + */ + if ((sd->firmware_id[0] & 0xf0) == 0x40) { + cam->cam_mode = cif_mode; + cam->nmodes = ARRAY_SIZE(cif_mode); + sd->block_size = 0x80; + } else { + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + sd->block_size = 0x200; + } + + INIT_WORK(&sd->work_struct, jl2005c_dostream); + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + + struct sd *sd = (struct sd *) gspca_dev; + sd->cap_mode = gspca_dev->cam.cam_mode; + + switch (gspca_dev->width) { + case 640: + PDEBUG(D_STREAM, "Start streaming at vga resolution"); + jl2005c_stream_start_vga_lg(gspca_dev); + break; + case 320: + PDEBUG(D_STREAM, "Start streaming at qvga resolution"); + jl2005c_stream_start_vga_small(gspca_dev); + break; + case 352: + PDEBUG(D_STREAM, "Start streaming at cif resolution"); + jl2005c_stream_start_cif_lg(gspca_dev); + break; + case 176: + PDEBUG(D_STREAM, "Start streaming at qcif resolution"); + jl2005c_stream_start_cif_small(gspca_dev); + break; + default: + pr_err("Unknown resolution specified\n"); + return -1; + } + + /* Start the workqueue function to do the streaming */ + sd->work_thread = create_singlethread_workqueue(MODULE_NAME); + queue_work(sd->work_thread, &sd->work_struct); + + return 0; +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + + /* wait for the work queue to terminate */ + mutex_unlock(&gspca_dev->usb_lock); + /* This waits for sq905c_dostream to finish */ + destroy_workqueue(dev->work_thread); + dev->work_thread = NULL; + mutex_lock(&gspca_dev->usb_lock); +} + + + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + /* .ctrls = none have been detected */ + /* .nctrls = ARRAY_SIZE(sd_ctrls), */ + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, +}; + +/* -- module initialisation -- */ +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x0979, 0x0227)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + int ret; + + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c index b1da7f4096c8..f0c0d74dfe92 100644 --- a/drivers/media/video/gspca/konica.c +++ b/drivers/media/video/gspca/konica.c @@ -247,9 +247,6 @@ static int sd_config(struct gspca_dev *gspca_dev, gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); gspca_dev->cam.no_urb_create = 1; - /* The highest alt setting has an isoc packetsize of 0, so we - don't want to use it */ - gspca_dev->nbalt--; sd->brightness = BRIGHTNESS_DEFAULT; sd->contrast = CONTRAST_DEFAULT; diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index 9fe3816b2aa0..0c4493675438 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -27,8 +27,8 @@ /* Kernel module parameters */ int force_sensor; -static int dump_bridge; -int dump_sensor; +static bool dump_bridge; +bool dump_sensor; static const struct usb_device_id m5602_table[] = { {USB_DEVICE(0x0402, 0x5602)}, diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h index b1f0c492036a..8c672b5c8c6a 100644 --- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h +++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h @@ -106,7 +106,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int mt9m111_probe(struct sd *sd); int mt9m111_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h index 2efd607987ec..2b6a13b508f7 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov7660.h +++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h @@ -86,7 +86,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int ov7660_probe(struct sd *sd); int ov7660_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h index da9a129b739d..f7aa5bf68983 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.h +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h @@ -135,7 +135,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int ov9650_probe(struct sd *sd); int ov9650_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h index 338359596398..81a2bcb88fe3 100644 --- a/drivers/media/video/gspca/m5602/m5602_po1030.h +++ b/drivers/media/video/gspca/m5602/m5602_po1030.h @@ -147,7 +147,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int po1030_probe(struct sd *sd); int po1030_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h index 8cc7a3f6da72..8e0035e731c7 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h @@ -65,7 +65,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int s5k4aa_probe(struct sd *sd); int s5k4aa_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h index 80a63a236e24..79952247b534 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h +++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h @@ -41,7 +41,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int s5k83a_probe(struct sd *sd); int s5k83a_init(struct sd *sd); diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 5c2ea05c46b4..b0231465afae 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -263,7 +263,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_mode); cam->ctrls = sd->ctrls; sd->quality = QUALITY_DEF; - gspca_dev->nbalt = 9; /* use the altsetting 08 */ return 0; } diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index d4bec9321771..7167cac7359c 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -1763,8 +1763,8 @@ static int sd_config(struct gspca_dev *gspca_dev, if ((unsigned) webcam >= NWEBCAMS) webcam = 0; sd->webcam = webcam; - gspca_dev->cam.reverse_alts = 1; gspca_dev->cam.ctrls = sd->ctrls; + gspca_dev->cam.needs_full_bandwidth = 1; sd->ag_cnt = -1; /* diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 08b8ce1dee18..739e8a2a2d30 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -3348,7 +3348,6 @@ static int sd_config(struct gspca_dev *gspca_dev, case BRIDGE_W9968CF: cam->cam_mode = w9968cf_vga_mode; cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode); - cam->reverse_alts = 1; break; } @@ -3684,8 +3683,8 @@ static void ov511_mode_init_regs(struct sd *sd) /* Check if we have enough bandwidth to disable compression */ fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1; needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2; - /* 1400 is a conservative estimate of the max nr of isoc packets/sec */ - if (needed > 1400 * packet_size) { + /* 1000 isoc packets/sec */ + if (needed > 1000 * packet_size) { /* Enable Y and UV quantization and compression */ reg_w(sd, R511_COMP_EN, 0x07); reg_w(sd, R511_COMP_LUT_EN, 0x03); diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index f30060d50633..fbfa02affa13 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c @@ -71,6 +71,7 @@ struct sd { enum sensors { SENSOR_OV965x, /* ov9657 */ SENSOR_OV971x, /* ov9712 */ + SENSOR_OV562x, /* ov5621 */ NSENSORS }; @@ -207,6 +208,14 @@ static const struct v4l2_pix_format ov971x_mode[] = { } }; +static const struct v4l2_pix_format ov562x_mode[] = { + {2592, 1680, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 2592, + .sizeimage = 2592 * 1680, + .colorspace = V4L2_COLORSPACE_SRGB + } +}; + static const u8 bridge_init[][2] = { {0x88, 0xf8}, {0x89, 0xff}, @@ -830,6 +839,124 @@ static const u8 ov965x_start_2_sxga[][2] = { {0xa3, 0x41}, /* bd60 */ }; +static const u8 ov562x_init[][2] = { + {0x88, 0x20}, + {0x89, 0x0a}, + {0x8a, 0x90}, + {0x8b, 0x06}, + {0x8c, 0x01}, + {0x8d, 0x10}, + {0x1c, 0x00}, + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1c, 0x0a}, + {0x1d, 0x2e}, + {0x1d, 0x1e}, +}; + +static const u8 ov562x_init_2[][2] = { + {0x12, 0x80}, + {0x11, 0x41}, + {0x13, 0x00}, + {0x10, 0x1e}, + {0x3b, 0x07}, + {0x5b, 0x40}, + {0x39, 0x07}, + {0x53, 0x02}, + {0x54, 0x60}, + {0x04, 0x20}, + {0x27, 0x04}, + {0x3d, 0x40}, + {0x36, 0x00}, + {0xc5, 0x04}, + {0x4e, 0x00}, + {0x4f, 0x93}, + {0x50, 0x7b}, + {0xca, 0x0c}, + {0xcb, 0x0f}, + {0x39, 0x07}, + {0x4a, 0x10}, + {0x3e, 0x0a}, + {0x3d, 0x00}, + {0x0c, 0x38}, + {0x38, 0x90}, + {0x46, 0x30}, + {0x4f, 0x93}, + {0x50, 0x7b}, + {0xab, 0x00}, + {0xca, 0x0c}, + {0xcb, 0x0f}, + {0x37, 0x02}, + {0x44, 0x48}, + {0x8d, 0x44}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x32, 0x00}, + {0x38, 0x90}, + {0x53, 0x02}, + {0x54, 0x60}, + {0x12, 0x00}, + {0x17, 0x12}, + {0x18, 0xb4}, + {0x19, 0x0c}, + {0x1a, 0xf4}, + {0x03, 0x4a}, + {0x89, 0x20}, + {0x83, 0x80}, + {0xb7, 0x9d}, + {0xb6, 0x11}, + {0xb5, 0x55}, + {0xb4, 0x00}, + {0xa9, 0xf0}, + {0xa8, 0x0a}, + {0xb8, 0xf0}, + {0xb9, 0xf0}, + {0xba, 0xf0}, + {0x81, 0x07}, + {0x63, 0x44}, + {0x13, 0xc7}, + {0x14, 0x60}, + {0x33, 0x75}, + {0x2c, 0x00}, + {0x09, 0x00}, + {0x35, 0x30}, + {0x27, 0x04}, + {0x3c, 0x07}, + {0x3a, 0x0a}, + {0x3b, 0x07}, + {0x01, 0x40}, + {0x02, 0x40}, + {0x16, 0x40}, + {0x52, 0xb0}, + {0x51, 0x83}, + {0x21, 0xbb}, + {0x22, 0x10}, + {0x23, 0x03}, + {0x35, 0x38}, + {0x20, 0x90}, + {0x28, 0x30}, + {0x73, 0xe1}, + {0x6c, 0x00}, + {0x6d, 0x80}, + {0x6e, 0x00}, + {0x70, 0x04}, + {0x71, 0x00}, + {0x8d, 0x04}, + {0x64, 0x00}, + {0x65, 0x00}, + {0x66, 0x00}, + {0x67, 0x00}, + {0x68, 0x00}, + {0x69, 0x00}, + {0x6a, 0x00}, + {0x6b, 0x00}, + {0x71, 0x94}, + {0x74, 0x20}, + {0x80, 0x09}, + {0x85, 0xc0}, +}; + static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val) { struct usb_device *udev = gspca_dev->dev; @@ -1210,6 +1337,17 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x56, 0x1f); else reg_w(gspca_dev, 0x56, 0x17); + } else if ((sensor_id & 0xfff0) == 0x5620) { + sd->sensor = SENSOR_OV562x; + + gspca_dev->cam.cam_mode = ov562x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode); + + reg_w_array(gspca_dev, ov562x_init, + ARRAY_SIZE(ov562x_init)); + sccb_w_array(gspca_dev, ov562x_init_2, + ARRAY_SIZE(ov562x_init_2)); + reg_w(gspca_dev, 0xe0, 0x00); } else { err("Unknown sensor %04x", sensor_id); return -EINVAL; @@ -1222,7 +1360,7 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->sensor == SENSOR_OV971x) + if (sd->sensor == SENSOR_OV971x || sd->sensor == SENSOR_OV562x) return gspca_dev->usb_err; switch (gspca_dev->curr_mode) { case QVGA_MODE: /* 320x240 */ @@ -1409,6 +1547,7 @@ static const struct sd_desc sd_desc = { static const struct usb_device_id device_table[] = { {USB_DEVICE(0x05a9, 0x8065)}, {USB_DEVICE(0x06f8, 0x3003)}, + {USB_DEVICE(0x05a9, 0x1550)}, {} }; diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index ece8b1e82a13..3844c49f269c 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -41,14 +41,14 @@ MODULE_LICENSE("GPL"); #define PAC207_BRIGHTNESS_DEFAULT 46 #define PAC207_EXPOSURE_MIN 3 -#define PAC207_EXPOSURE_MAX 26 +#define PAC207_EXPOSURE_MAX 90 /* 1 sec expo time / 1 fps */ #define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */ -#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */ +#define PAC207_EXPOSURE_KNEE 9 /* fps: 90 / exposure -> 9: 10 fps */ #define PAC207_GAIN_MIN 0 #define PAC207_GAIN_MAX 31 -#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */ -#define PAC207_GAIN_KNEE 31 +#define PAC207_GAIN_DEFAULT 7 /* power on default: 9 */ +#define PAC207_GAIN_KNEE 15 #define PAC207_AUTOGAIN_DEADZONE 30 @@ -332,7 +332,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - 100, PAC207_AUTOGAIN_DEADZONE, + 90, PAC207_AUTOGAIN_DEADZONE, PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 2811195258c4..9db2b34d172c 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -1197,6 +1197,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x262a)}, {USB_DEVICE(0x093a, 0x262c)}, + {USB_DEVICE(0x145f, 0x013c)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c index 1494e1829d36..bb70092c2229 100644 --- a/drivers/media/video/gspca/se401.c +++ b/drivers/media/video/gspca/se401.c @@ -376,7 +376,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->bulk_size = BULK_SIZE; cam->bulk_nurbs = 4; cam->ctrls = sd->ctrls; - gspca_dev->nbalt = 1; /* Ignore the bogus isoc alt settings */ sd->resetlevel = 0x2d; /* Set initial resetlevel */ /* See if the camera supports brightness */ @@ -395,6 +394,14 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } +/* function called at start time before URB creation */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + gspca_dev->alt = 1; /* Ignore the bogus isoc alt settings */ + + return gspca_dev->usb_err; +} + /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { @@ -714,6 +721,7 @@ static const struct sd_desc sd_desc = { .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .dq_callback = sd_dq_callback, diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 33cabc342dcf..9e198b45c3c8 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -2048,6 +2048,7 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; + cam->needs_full_bandwidth = 1; sd->sensor = (id->driver_info >> 8) & 0xff; sd->i2c_addr = id->driver_info & 0xff; @@ -2233,6 +2234,42 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) } } +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct usb_interface *intf; + u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv; + + /* + * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth + * than our regular bandwidth calculations reserve, so we force the + * use of a specific altsetting when using the SN9C20X_I420 fmt. + */ + if (!(flags & (MODE_RAW | MODE_JPEG))) { + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + + if (intf->num_altsetting != 9) { + pr_warn("sn9c20x camera with unknown number of alt " + "settings (%d), please report!\n", + intf->num_altsetting); + gspca_dev->alt = intf->num_altsetting; + return 0; + } + + switch (gspca_dev->width) { + case 160: /* 160x120 */ + gspca_dev->alt = 2; + break; + case 320: /* 320x240 */ + gspca_dev->alt = 6; + break; + default: /* >= 640x480 */ + gspca_dev->alt = 9; + } + } + + return 0; +} + #define HW_WIN(mode, hstart, vstart) \ ((const u8 []){hstart, 0, vstart, 0, \ (mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \ @@ -2473,6 +2510,7 @@ static const struct sd_desc sd_desc = { .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index ddb392dc4f2d..6a1148d7fe92 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1079,20 +1079,23 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam->npkt = 36; /* 36 packets per ISOC message */ - if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { - sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN; - sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX; - sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF; - } - return 0; } /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; const __u8 stop = 0x09; /* Disable stream turn of LED */ + if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { + sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN; + sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX; + sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF; + if (sd->ctrls[EXPOSURE].val > COARSE_EXPOSURE_MAX) + sd->ctrls[EXPOSURE].val = COARSE_EXPOSURE_DEF; + } + reg_w(gspca_dev, 0x01, &stop, 1); return 0; diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index afa3186b8038..0c9e6ddabd2c 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1235,7 +1235,7 @@ static const u8 po2030n_sensor_param1[][8] = { {DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */ {0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10}, {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10}, + {0xd1, 0x6e, 0x16, 0x40, 0x40, 0x40, 0x40, 0x10}, /* RGBG gains */ /*param2*/ {0xa1, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10}, @@ -1779,10 +1779,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->ag_cnt = -1; sd->quality = QUALITY_DEF; - /* if USB 1.1, let some bandwidth for the audio device */ - if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) - gspca_dev->nbalt--; - INIT_WORK(&sd->work, qual_upd); return 0; @@ -2063,6 +2059,16 @@ static void setredblue(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (sd->sensor == SENSOR_PO2030N) { + u8 rg1b[] = /* red green1 blue (no g2) */ + {0xc1, 0x6e, 0x16, 0x00, 0x40, 0x00, 0x00, 0x10}; + + /* 0x40 = normal value = gain x 1 */ + rg1b[3] = sd->ctrls[RED].val * 2; + rg1b[5] = sd->ctrls[BLUE].val * 2; + i2c_w8(gspca_dev, rg1b); + return; + } reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val); /* reg_w1(gspca_dev, 0x07, 32); */ reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val); @@ -2397,7 +2403,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x17, reg17); reg01 &= ~S_PWR_DN; /* sensor power on */ reg_w1(gspca_dev, 0x01, reg01); - reg01 &= ~SYS_SEL_48M; + reg01 &= ~SCL_SEL_OD; /* remove open-drain mode */ reg_w1(gspca_dev, 0x01, reg01); switch (sd->sensor) { diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index 259a0c73c664..4a5f209ce719 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -451,7 +451,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ + cam->needs_full_bandwidth = 1; sd->chip_revision = id->driver_info; if (sd->chip_revision == Rev012A) { diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index 0ab425fbea9a..91d99b4cc57b 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -36,8 +36,8 @@ MODULE_AUTHOR("Erik AndrĂ©n"); MODULE_DESCRIPTION("STV06XX USB Camera Driver"); MODULE_LICENSE("GPL"); -static int dump_bridge; -static int dump_sensor; +static bool dump_bridge; +static bool dump_sensor; int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) { @@ -304,7 +304,7 @@ static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); @@ -317,7 +317,7 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) struct usb_host_interface *alt; struct sd *sd = (struct sd *) gspca_dev; - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; if (packet_size <= min_packet_size) diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index ea44deb66af4..9b9f85a8e60e 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -30,6 +30,7 @@ #define MODULE_NAME "t613" +#include <linux/input.h> #include <linux/slab.h> #include "gspca.h" @@ -57,6 +58,7 @@ struct sd { u8 effect; u8 sensor; + u8 button_pressed; }; enum sensors { SENSOR_OM6802, @@ -1095,15 +1097,35 @@ static void sd_stopN(struct gspca_dev *gspca_dev) msleep(20); reg_w(gspca_dev, 0x0309); } +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + /* If the last button state is pressed, release it now! */ + if (sd->button_pressed) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + sd->button_pressed = 0; + } +#endif } static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* isoc packet */ int len) /* iso packet length */ { + struct sd *sd = (struct sd *) gspca_dev; int pkt_type; if (data[0] == 0x5a) { +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + if (len > 20) { + u8 state = (data[20] & 0x80) ? 1 : 0; + if (sd->button_pressed != state) { + input_report_key(gspca_dev->input_dev, + KEY_CAMERA, state); + input_sync(gspca_dev->input_dev); + sd->button_pressed = state; + } + } +#endif /* Control Packet, after this came the header again, * but extra bytes came in the packet before this, * sometimes an EOF arrives, sometimes not... */ @@ -1410,6 +1432,9 @@ static const struct sd_desc sd_desc = { .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .other_input = 1, +#endif }; /* -- module initialisation -- */ diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c index b2695b1dc603..444d3c5b9079 100644 --- a/drivers/media/video/gspca/topro.c +++ b/drivers/media/video/gspca/topro.c @@ -3946,7 +3946,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev) /* 640x480 * 30 fps does not work */ if (i == 6 /* if 30 fps */ && gspca_dev->width == 640) - i = 0x86; /* 15 fps */ + i = 0x05; /* 15 fps */ } else { for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) { if (sd->framerate >= rates_6810[i]) diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c index d12ea1518ace..911152e169d6 100644 --- a/drivers/media/video/gspca/vicam.c +++ b/drivers/media/video/gspca/vicam.c @@ -324,7 +324,8 @@ static void sd_stop0(struct gspca_dev *gspca_dev) dev->work_thread = NULL; mutex_lock(&gspca_dev->usb_lock); - vicam_set_camera_power(gspca_dev, 0); + if (gspca_dev->present) + vicam_set_camera_power(gspca_dev, 0); } /* Table of supported USB devices */ diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c index fbb6ed25ec31..ecada178bceb 100644 --- a/drivers/media/video/gspca/xirlink_cit.c +++ b/drivers/media/video/gspca/xirlink_cit.c @@ -995,14 +995,12 @@ static int sd_config(struct gspca_dev *gspca_dev, case CIT_MODEL0: cam->cam_mode = model0_mode; cam->nmodes = ARRAY_SIZE(model0_mode); - cam->reverse_alts = 1; gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP)); sd->sof_len = 4; break; case CIT_MODEL1: cam->cam_mode = cif_yuv_mode; cam->nmodes = ARRAY_SIZE(cif_yuv_mode); - cam->reverse_alts = 1; gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP); sd->sof_len = 4; break; @@ -2791,7 +2789,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) } /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size); return 0; @@ -2814,7 +2812,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev) break; } - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); if (packet_size <= min_packet_size) return -EIO; diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 0202fead6b97..b9e15bb0328b 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -5381,12 +5381,12 @@ static const struct usb_action tas5130c_NoFlikerScale[] = { {} }; -static const struct usb_action gc0303_InitialScale[] = { +/* from usbvm305.inf 0ac8:305b 07/06/15 (3 - tas5130c) */ +static const struct usb_action gc0303_Initial[] = { {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc, - * 0<->10 */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ @@ -5405,29 +5405,22 @@ static const struct usb_action gc0303_InitialScale[] = { * 6<->8 */ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ - {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ - {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ - {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ - {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ - {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ -/*?? {0xaa, 0x01, 0x0000}, */ {0xaa, 0x01, 0x0000}, {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ + {0xaa, 0x1b, 0x0000}, {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ - {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ - {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ - {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ - {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ - {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ - {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ - {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ -/*?? {0xa0, 0x00, 0x0039}, - {0xa1, 0x01, 0x0037}, */ + {0xaa, 0x0a, 0x0002}, + {0xaa, 0x0b, 0x0000}, + {0xaa, 0x0c, 0x0002}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x0e, 0x0002}, + {0xaa, 0x0f, 0x0000}, + {0xaa, 0x10, 0x0002}, + {0xaa, 0x11, 0x0000}, {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ @@ -5442,17 +5435,18 @@ static const struct usb_action gc0303_InitialScale[] = { {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ + {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN}, {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ + {0xaa, 0x1b, 0x0000}, {} }; -static const struct usb_action gc0303_Initial[] = { +static const struct usb_action gc0303_InitialScale[] = { {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc, */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ @@ -5471,34 +5465,26 @@ static const struct usb_action gc0303_Initial[] = { * 8<->6 */ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ - {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ - {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ - {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ - {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ - {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ -/*?? {0xaa, 0x01, 0x0000}, */ {0xaa, 0x01, 0x0000}, {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ + {0xaa, 0x1b, 0x0000}, {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ - {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ - {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ - {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ - {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ - {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ - {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ - {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ -/*?? {0xa0, 0x00, 0x0039}, - {0xa1, 0x01, 0x0037}, */ + {0xaa, 0x0a, 0x0001}, + {0xaa, 0x0b, 0x0000}, + {0xaa, 0x0c, 0x0001}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x0e, 0x0001}, + {0xaa, 0x0f, 0x0000}, + {0xaa, 0x10, 0x0001}, + {0xaa, 0x11, 0x0000}, {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ {0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */ - {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */ @@ -5508,36 +5494,37 @@ static const struct usb_action gc0303_Initial[] = { {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ + {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN}, {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ + {0xaa, 0x1b, 0x0000}, {} }; -static const struct usb_action gc0303_50HZScale[] = { +static const struct usb_action gc0303_50HZ[] = { {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ - {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */ + {0xaa, 0x84, 0x0063}, {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */ {0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ - {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */ + {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP}, {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {0xa0, 0x7f, ZC3XX_R18D_YTARGET}, {} }; -static const struct usb_action gc0303_50HZ[] = { +static const struct usb_action gc0303_50HZScale[] = { {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0003}, /* 00,83,03,aa */ {0xaa, 0x84, 0x0054}, /* 00,84,54,aa */ @@ -5550,21 +5537,21 @@ static const struct usb_action gc0303_50HZ[] = { {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {0xa0, 0x7f, ZC3XX_R18D_YTARGET}, {} }; -static const struct usb_action gc0303_60HZScale[] = { +static const struct usb_action gc0303_60HZ[] = { {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ - {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */ + {0xaa, 0x83, 0x0000}, + {0xaa, 0x84, 0x003b}, {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ @@ -5581,14 +5568,14 @@ static const struct usb_action gc0303_60HZScale[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, {} }; -static const struct usb_action gc0303_60HZ[] = { +static const struct usb_action gc0303_60HZScale[] = { {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */ - {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */ + {0xaa, 0x83, 0x0000}, + {0xaa, 0x84, 0x0076}, {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,1,0b,cc, */ {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,2,10,cc, */ @@ -5605,18 +5592,18 @@ static const struct usb_action gc0303_60HZ[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,0,ff,cc, */ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,d,58,cc, */ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,d,78,cc */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, {} }; -static const struct usb_action gc0303_NoFlikerScale[] = { +static const struct usb_action gc0303_NoFliker[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,0,00,cc, */ - {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ - {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ + {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW}, {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ @@ -5631,14 +5618,14 @@ static const struct usb_action gc0303_NoFlikerScale[] = { {} }; -static const struct usb_action gc0303_NoFliker[] = { +static const struct usb_action gc0303_NoFlikerScale[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ - {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc, */ - {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc, */ + {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW}, {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ @@ -5809,7 +5796,7 @@ static void setmatrix(struct gspca_dev *gspca_dev) static const u8 tas5130c_matrix[9] = {0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68}; static const u8 gc0303_matrix[9] = - {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b}; + {0x6c, 0xea, 0xea, 0xea, 0x6c, 0xea, 0xea, 0xea, 0x6c}; static const u8 *matrix_tb[SENSOR_MAX] = { [SENSOR_ADCM2700] = adcm2700_matrix, [SENSOR_CS2102] = ov7620_matrix, @@ -6426,10 +6413,6 @@ static int sd_config(struct gspca_dev *gspca_dev, gspca_dev->cam.ctrls = sd->ctrls; sd->quality = QUALITY_DEF; - /* if USB 1.1, let some bandwidth for the audio device */ - if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) - gspca_dev->nbalt--; - return 0; } diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c index 3f1a5b1beeba..e5eb56a5b618 100644 --- a/drivers/media/video/hdpvr/hdpvr-core.c +++ b/drivers/media/video/hdpvr/hdpvr-core.c @@ -49,7 +49,7 @@ module_param(default_audio_input, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / " "1=RCA front / 2=S/PDIF"); -static int boost_audio; +static bool boost_audio; module_param(boost_audio, bool, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(boost_audio, "boost the audio signal"); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 3ab875d036e1..a7c41d32f414 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -244,7 +244,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, /* ----------------------------------------------------------------------- */ -static void ir_key_poll(struct IR_i2c *ir) +static int ir_key_poll(struct IR_i2c *ir) { static u32 ir_key, ir_raw; int rc; @@ -253,20 +253,28 @@ static void ir_key_poll(struct IR_i2c *ir) rc = ir->get_key(ir, &ir_key, &ir_raw); if (rc < 0) { dprintk(2,"error\n"); - return; + return rc; } if (rc) { dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key); rc_keydown(ir->rc, ir_key, 0); } + return 0; } static void ir_work(struct work_struct *work) { + int rc; struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); - ir_key_poll(ir); + rc = ir_key_poll(ir); + if (rc == -ENODEV) { + rc_unregister_device(ir->rc); + ir->rc = NULL; + return; + } + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); } @@ -446,7 +454,8 @@ static int ir_remove(struct i2c_client *client) cancel_delayed_work_sync(&ir->work); /* unregister device */ - rc_unregister_device(ir->rc); + if (ir->rc) + rc_unregister_device(ir->rc); /* free memory */ kfree(ir); @@ -489,11 +498,3 @@ static void __exit ir_fini(void) module_init(ir_init); module_exit(ir_fini); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 41108a9a195e..3949b7dc2368 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -99,7 +99,7 @@ static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, static unsigned int cardtype_c = 1; static unsigned int tuner_c = 1; -static unsigned int radio_c = 1; +static bool radio_c = 1; static unsigned int i2c_clock_period_c = 1; static char pal[] = "---"; static char secam[] = "--"; @@ -731,9 +731,6 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) init_kthread_work(&itv->irq_work, ivtv_irq_work_handler); - /* start counting open_id at 1 */ - itv->open_id = 1; - /* Initial settings */ itv->cxhdl.port = CX2341X_PORT_MEMORY; itv->cxhdl.capabilities = CX2341X_CAP_HAS_SLICED_VBI; diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8f9cc17b518e..06f3d78389bf 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -332,7 +332,7 @@ struct ivtv_stream { const char *name; /* name of the stream */ int type; /* stream type */ - u32 id; + struct v4l2_fh *fh; /* pointer to the streaming filehandle */ spinlock_t qlock; /* locks access to the queues */ unsigned long s_flags; /* status flags, see above */ int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ @@ -379,7 +379,6 @@ struct ivtv_stream { struct ivtv_open_id { struct v4l2_fh fh; - u32 open_id; /* unique ID for this file descriptor */ int type; /* stream type */ int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */ struct ivtv *itv; diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 38f052257f46..2cd6c89b7d91 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -50,16 +50,16 @@ static int ivtv_claim_stream(struct ivtv_open_id *id, int type) if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { /* someone already claimed this stream */ - if (s->id == id->open_id) { + if (s->fh == &id->fh) { /* yes, this file descriptor did. So that's OK. */ return 0; } - if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI || + if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI || type == IVTV_ENC_STREAM_TYPE_VBI)) { /* VBI is handled already internally, now also assign the file descriptor to this stream for external reading of the stream. */ - s->id = id->open_id; + s->fh = &id->fh; IVTV_DEBUG_INFO("Start Read VBI\n"); return 0; } @@ -67,7 +67,7 @@ static int ivtv_claim_stream(struct ivtv_open_id *id, int type) IVTV_DEBUG_INFO("Stream %d is busy\n", type); return -EBUSY; } - s->id = id->open_id; + s->fh = &id->fh; if (type == IVTV_DEC_STREAM_TYPE_VBI) { /* Enable reinsertion interrupt */ ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); @@ -104,7 +104,7 @@ void ivtv_release_stream(struct ivtv_stream *s) struct ivtv *itv = s->itv; struct ivtv_stream *s_vbi; - s->id = -1; + s->fh = NULL; if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { /* this stream is still in use internally */ @@ -136,7 +136,7 @@ void ivtv_release_stream(struct ivtv_stream *s) /* was already cleared */ return; } - if (s_vbi->id != -1) { + if (s_vbi->fh) { /* VBI stream still claimed by a file descriptor */ return; } @@ -268,11 +268,13 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, } /* wait for more data to arrive */ + mutex_unlock(&itv->serialize_lock); prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); /* New buffers might have become available before we were added to the waitqueue */ if (!s->q_full.buffers) schedule(); finish_wait(&s->waitq, &wait); + mutex_lock(&itv->serialize_lock); if (signal_pending(current)) { /* return if a signal was received */ IVTV_DEBUG_INFO("User stopped %s\n", s->name); @@ -357,7 +359,7 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co size_t tot_written = 0; int single_frame = 0; - if (atomic_read(&itv->capturing) == 0 && s->id == -1) { + if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) { /* shouldn't happen */ IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); return -EIO; @@ -507,9 +509,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); - mutex_lock(&itv->serialize_lock); rc = ivtv_start_capture(id); - mutex_unlock(&itv->serialize_lock); if (rc) return rc; return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); @@ -584,9 +584,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c set_bit(IVTV_F_S_APPL_IO, &s->s_flags); /* Start decoder (returns 0 if already started) */ - mutex_lock(&itv->serialize_lock); rc = ivtv_start_decoding(id, itv->speed); - mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); @@ -627,11 +625,13 @@ retry: break; if (filp->f_flags & O_NONBLOCK) return -EAGAIN; + mutex_unlock(&itv->serialize_lock); prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); /* New buffers might have become free before we were added to the waitqueue */ if (!s->q_free.buffers) schedule(); finish_wait(&s->waitq, &wait); + mutex_lock(&itv->serialize_lock); if (signal_pending(current)) { IVTV_DEBUG_INFO("User stopped %s\n", s->name); return -EINTR; @@ -686,12 +686,14 @@ retry: if (mode == OUT_YUV) ivtv_yuv_setup_stream_frame(itv); + mutex_unlock(&itv->serialize_lock); prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); while (!(got_sig = signal_pending(current)) && test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { schedule(); } finish_wait(&itv->dma_waitq, &wait); + mutex_lock(&itv->serialize_lock); if (got_sig) { IVTV_DEBUG_INFO("User interrupted %s\n", s->name); return -EINTR; @@ -756,9 +758,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { int rc; - mutex_lock(&itv->serialize_lock); rc = ivtv_start_capture(id); - mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", s->name, rc); @@ -808,7 +808,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) id->type == IVTV_ENC_STREAM_TYPE_VBI) && test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { /* Also used internally, don't stop capturing */ - s->id = -1; + s->fh = NULL; } else { ivtv_stop_v4l2_encode_stream(s, gop_end); @@ -861,20 +861,9 @@ int ivtv_v4l2_close(struct file *filp) IVTV_DEBUG_FILE("close %s\n", s->name); - v4l2_fh_del(fh); - v4l2_fh_exit(fh); - - /* Easy case first: this stream was never claimed by us */ - if (s->id != id->open_id) { - kfree(id); - return 0; - } - - /* 'Unclaim' this stream */ - /* Stop radio */ - mutex_lock(&itv->serialize_lock); - if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { + if (id->type == IVTV_ENC_STREAM_TYPE_RAD && + v4l2_fh_is_singular_file(filp)) { /* Closing radio device, return to TV mode */ ivtv_mute(itv); /* Mark that the radio is no longer in use */ @@ -890,13 +879,25 @@ int ivtv_v4l2_close(struct file *filp) if (atomic_read(&itv->capturing) > 0) { /* Undo video mute */ ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, - v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) | - (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); + v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) | + (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); } /* Done! Unmute and continue. */ ivtv_unmute(itv); - ivtv_release_stream(s); - } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { + } + + v4l2_fh_del(fh); + v4l2_fh_exit(fh); + + /* Easy case first: this stream was never claimed by us */ + if (s->fh != &id->fh) { + kfree(id); + return 0; + } + + /* 'Unclaim' this stream */ + + if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); @@ -911,21 +912,25 @@ int ivtv_v4l2_close(struct file *filp) ivtv_stop_capture(id, 0); } kfree(id); - mutex_unlock(&itv->serialize_lock); return 0; } -static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) +int ivtv_v4l2_open(struct file *filp) { -#ifdef CONFIG_VIDEO_ADV_DEBUG struct video_device *vdev = video_devdata(filp); -#endif + struct ivtv_stream *s = video_get_drvdata(vdev); struct ivtv *itv = s->itv; struct ivtv_open_id *item; int res = 0; IVTV_DEBUG_FILE("open %s\n", s->name); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on device %s\n", + video_device_node_name(vdev)); + return -ENXIO; + } + #ifdef CONFIG_VIDEO_ADV_DEBUG /* Unless ivtv_fw_debug is set, error out if firmware dead. */ if (ivtv_fw_debug) { @@ -966,31 +971,19 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) return -ENOMEM; } v4l2_fh_init(&item->fh, s->vdev); - if (res < 0) { - v4l2_fh_exit(&item->fh); - kfree(item); - return res; - } item->itv = itv; item->type = s->type; - item->open_id = itv->open_id++; filp->private_data = &item->fh; + v4l2_fh_add(&item->fh); - if (item->type == IVTV_ENC_STREAM_TYPE_RAD) { - /* Try to claim this stream */ - if (ivtv_claim_stream(item, item->type)) { - /* No, it's already in use */ - v4l2_fh_exit(&item->fh); - kfree(item); - return -EBUSY; - } - + if (item->type == IVTV_ENC_STREAM_TYPE_RAD && + v4l2_fh_is_singular_file(filp)) { if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { if (atomic_read(&itv->capturing) > 0) { /* switching to radio while capture is in progress is not polite */ - ivtv_release_stream(s); + v4l2_fh_del(&item->fh); v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; @@ -1022,32 +1015,9 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); itv->yuv_info.stream_size = 0; } - v4l2_fh_add(&item->fh); return 0; } -int ivtv_v4l2_open(struct file *filp) -{ - int res; - struct ivtv *itv = NULL; - struct ivtv_stream *s = NULL; - struct video_device *vdev = video_devdata(filp); - - s = video_get_drvdata(vdev); - itv = s->itv; - - mutex_lock(&itv->serialize_lock); - if (ivtv_init_on_first_open(itv)) { - IVTV_ERR("Failed to initialize on device %s\n", - video_device_node_name(vdev)); - mutex_unlock(&itv->serialize_lock); - return -ENXIO; - } - res = ivtv_serialized_open(s, filp); - mutex_unlock(&itv->serialize_lock); - return res; -} - void ivtv_mute(struct ivtv *itv) { if (atomic_read(&itv->capturing)) diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h index 9332920ca4ff..7b9ec1cfeb80 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.h +++ b/drivers/media/video/ivtv/ivtv-i2c.h @@ -25,7 +25,7 @@ struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv); int ivtv_i2c_register(struct ivtv *itv, unsigned idx); struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw); -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int init_ivtv_i2c(struct ivtv *itv); void exit_ivtv_i2c(struct ivtv *itv); diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index ecafa697326e..c4bc48143098 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -179,6 +179,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed) ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); /* Wait for any DMA to finish */ + mutex_unlock(&itv->serialize_lock); prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); while (test_bit(IVTV_F_I_DMA, &itv->i_flags)) { got_sig = signal_pending(current); @@ -188,6 +189,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed) schedule(); } finish_wait(&itv->dma_waitq, &wait); + mutex_lock(&itv->serialize_lock); if (got_sig) return -EINTR; @@ -1107,6 +1109,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std) * happens within the first 100 lines of the top field. * Make 4 attempts to sync to the decoder before giving up. */ + mutex_unlock(&itv->serialize_lock); for (f = 0; f < 4; f++) { prepare_to_wait(&itv->vsync_waitq, &wait, TASK_UNINTERRUPTIBLE); @@ -1115,6 +1118,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std) schedule_timeout(msecs_to_jiffies(25)); } finish_wait(&itv->vsync_waitq, &wait); + mutex_lock(&itv->serialize_lock); if (f == 4) IVTV_WARN("Mode change failed to sync to decoder\n"); @@ -1842,8 +1846,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio, return 0; } -static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp, - unsigned int cmd, unsigned long arg) +long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct video_device *vfd = video_devdata(filp); long ret; @@ -1855,21 +1858,6 @@ static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp, return ret; } -long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct ivtv_open_id *id = fh2id(filp->private_data); - struct ivtv *itv = id->itv; - long res; - - /* DQEVENT can block, so this should not run with the serialize lock */ - if (cmd == VIDIOC_DQEVENT) - return ivtv_serialized_ioctl(itv, filp, cmd, arg); - mutex_lock(&itv->serialize_lock); - res = ivtv_serialized_ioctl(itv, filp, cmd, arg); - mutex_unlock(&itv->serialize_lock); - return res; -} - static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { .vidioc_querycap = ivtv_querycap, .vidioc_s_audio = ivtv_s_audio, diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index 9c29e964d400..1b3b9578bf47 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -288,13 +288,13 @@ static void dma_post(struct ivtv_stream *s) ivtv_process_vbi_data(itv, buf, 0, s->type); s->q_dma.bytesused += buf->bytesused; } - if (s->id == -1) { + if (s->fh == NULL) { ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); return; } } ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused); - if (s->id != -1) + if (s->fh) wake_up(&s->waitq); } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index e7794dc1330e..c6e28b4ebbed 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -159,7 +159,6 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size; spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); - s->id = -1; s->sg_handle = IVTV_DMA_UNMAPPED; ivtv_queue_init(&s->q_free); ivtv_queue_init(&s->q_full); @@ -214,6 +213,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) s->vdev->fops = ivtv_stream_info[type].fops; s->vdev->release = video_device_release; s->vdev->tvnorms = V4L2_STD_ALL; + s->vdev->lock = &itv->serialize_lock; set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags); ivtv_set_funcs(s->vdev); return 0; diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index dcbab6ad4c26..2ad65eb29832 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -1149,23 +1149,37 @@ int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src) { struct yuv_playback_info *yi = &itv->yuv_info; struct ivtv_dma_frame dma_args; + int res; ivtv_yuv_setup_stream_frame(itv); /* We only need to supply source addresses for this */ dma_args.y_source = src; dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31); - return ivtv_yuv_udma_frame(itv, &dma_args); + /* Wait for frame DMA. Note that serialize_lock is locked, + so to allow other processes to access the driver while + we are waiting unlock first and later lock again. */ + mutex_unlock(&itv->serialize_lock); + res = ivtv_yuv_udma_frame(itv, &dma_args); + mutex_lock(&itv->serialize_lock); + return res; } /* IVTV_IOC_DMA_FRAME ioctl handler */ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) { -/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */ + int res; +/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */ ivtv_yuv_next_free(itv); ivtv_yuv_setup_frame(itv, args); - return ivtv_yuv_udma_frame(itv, args); + /* Wait for frame DMA. Note that serialize_lock is locked, + so to allow other processes to access the driver while + we are waiting unlock first and later lock again. */ + mutex_unlock(&itv->serialize_lock); + res = ivtv_yuv_udma_frame(itv, args); + mutex_lock(&itv->serialize_lock); + return res; } void ivtv_yuv_close(struct ivtv *itv) @@ -1174,7 +1188,9 @@ void ivtv_yuv_close(struct ivtv *itv) int h_filter, v_filter_1, v_filter_2; IVTV_DEBUG_YUV("ivtv_yuv_close\n"); + mutex_unlock(&itv->serialize_lock); ivtv_waitq(&itv->vsync_waitq); + mutex_lock(&itv->serialize_lock); yi->running = 0; atomic_set(&yi->next_dma_frame, -1); diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 6b7c9c823330..d0fbfcf7133d 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -58,7 +58,7 @@ /* card parameters */ static int ivtvfb_card_id = -1; static int ivtvfb_debug = 0; -static int osd_laced; +static bool osd_laced; static int osd_depth; static int osd_upper; static int osd_left; diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h index 82c8817bd32d..4b021e1ee5f2 100644 --- a/drivers/media/video/m5mols/m5mols.h +++ b/drivers/media/video/m5mols/m5mols.h @@ -163,7 +163,6 @@ struct m5mols_version { * @ffmt: current fmt according to resolution type * @res_type: current resolution type * @irq_waitq: waitqueue for the capture - * @work_irq: workqueue for the IRQ * @flags: state variable for the interrupt handler * @handle: control handler * @autoexposure: Auto Exposure control @@ -175,14 +174,12 @@ struct m5mols_version { * @ver: information of the version * @cap: the capture mode attributes * @power: current sensor's power status - * @ctrl_sync: true means all controls of the sensor are initialized - * @int_capture: true means the capture interrupt is issued once + * @isp_ready: 1 when the ISP controller has completed booting + * @ctrl_sync: 1 when the control handler state is restored in H/W * @lock_ae: true means the Auto Exposure is locked * @lock_awb: true means the Aut WhiteBalance is locked * @resolution: register value for current resolution - * @interrupt: register value for current interrupt status * @mode: register value for current operation mode - * @mode_save: register value for current operation mode for saving * @set_power: optional power callback to the board code */ struct m5mols_info { @@ -191,16 +188,16 @@ struct m5mols_info { struct media_pad pad; struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; int res_type; + wait_queue_head_t irq_waitq; - struct work_struct work_irq; - unsigned long flags; + atomic_t irq_done; struct v4l2_ctrl_handler handle; + /* Autoexposure/exposure control cluster */ - struct { - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - }; + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *autowb; struct v4l2_ctrl *colorfx; struct v4l2_ctrl *saturation; @@ -208,21 +205,19 @@ struct m5mols_info { struct m5mols_version ver; struct m5mols_capture cap; - bool power; - bool ctrl_sync; + + unsigned int isp_ready:1; + unsigned int power:1; + unsigned int ctrl_sync:1; + bool lock_ae; bool lock_awb; u8 resolution; - u8 interrupt; u8 mode; - u8 mode_save; + int (*set_power)(struct device *dev, int on); }; -#define ST_CAPT_IRQ 0 - -#define is_powered(__info) (__info->power) -#define is_ctrl_synced(__info) (__info->ctrl_sync) #define is_available_af(__info) (__info->ver.af) #define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) #define is_manufacturer(__info, __manufacturer) \ @@ -257,7 +252,15 @@ int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val); int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val); int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); -int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value); + +int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, + int timeout); + +/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */ +#define M5MOLS_I2C_RDY_WAIT_FL (1 << 16) +/* ISP state transition timeout, in ms */ +#define M5MOLS_MODE_CHANGE_TIMEOUT 200 +#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT 250 /* * Mode operation of the M-5MOLS @@ -282,7 +285,8 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value); int m5mols_mode(struct m5mols_info *info, u8 mode); int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); -int m5mols_sync_controls(struct m5mols_info *info); +int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout); +int m5mols_restore_controls(struct m5mols_info *info); int m5mols_start_capture(struct m5mols_info *info); int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); int m5mols_lock_3a(struct m5mols_info *info, bool lock); diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c index 3248ac805711..ba25e8e2ba4c 100644 --- a/drivers/media/video/m5mols/m5mols_capture.c +++ b/drivers/media/video/m5mols/m5mols_capture.c @@ -1,3 +1,4 @@ + /* * The Capture code for Fujitsu M-5MOLS ISP * @@ -25,26 +26,11 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include <media/m5mols.h> +#include <media/s5p_fimc.h> #include "m5mols.h" #include "m5mols_reg.h" -static int m5mols_capture_error_handler(struct m5mols_info *info, - int timeout) -{ - int ret; - - /* Disable all interrupts and clear relevant interrupt staus bits */ - ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE, - info->interrupt & ~(REG_INT_CAPTURE)); - if (ret) - return ret; - - if (timeout == 0) - return -ETIMEDOUT; - - return 0; -} /** * m5mols_read_rational - I2C read of a rational number * @@ -121,69 +107,54 @@ int m5mols_start_capture(struct m5mols_info *info) { struct v4l2_subdev *sd = &info->sd; u8 resolution = info->resolution; - int timeout; int ret; /* - * Preparing capture. Setting control & interrupt before entering - * capture mode - * - * 1) change to MONITOR mode for operating control & interrupt - * 2) set controls (considering v4l2_control value & lock 3A) - * 3) set interrupt - * 4) change to CAPTURE mode + * Synchronize the controls, set the capture frame resolution and color + * format. The frame capture is initiated during switching from Monitor + * to Capture mode. */ ret = m5mols_mode(info, REG_MONITOR); if (!ret) - ret = m5mols_sync_controls(info); + ret = m5mols_restore_controls(info); if (!ret) - ret = m5mols_lock_3a(info, true); + ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); + if (!ret) + ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution); if (!ret) - ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); + ret = m5mols_lock_3a(info, true); if (!ret) ret = m5mols_mode(info, REG_CAPTURE); - if (!ret) { - /* Wait for capture interrupt, after changing capture mode */ - timeout = wait_event_interruptible_timeout(info->irq_waitq, - test_bit(ST_CAPT_IRQ, &info->flags), - msecs_to_jiffies(2000)); - if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) - ret = m5mols_capture_error_handler(info, timeout); - } + if (!ret) + /* Wait until a frame is captured to ISP internal memory */ + ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); if (!ret) ret = m5mols_lock_3a(info, false); if (ret) return ret; + /* - * Starting capture. Setting capture frame count and resolution and - * the format(available format: JPEG, Bayer RAW, YUV). - * - * 1) select single or multi(enable to 25), format, size - * 2) set interrupt - * 3) start capture(for main image, now) - * 4) get information - * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device) + * Initiate the captured data transfer to a MIPI-CSI receiver. */ ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); if (!ret) - ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); - if (!ret) - ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution); - if (!ret) - ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); - if (!ret) ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); if (!ret) { + bool captured = false; + unsigned int size; + /* Wait for the capture completion interrupt */ - timeout = wait_event_interruptible_timeout(info->irq_waitq, - test_bit(ST_CAPT_IRQ, &info->flags), - msecs_to_jiffies(2000)); - if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) { + ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); + if (!ret) { + captured = true; ret = m5mols_capture_info(info); - if (!ret) - v4l2_subdev_notify(sd, 0, &info->cap.total); } + size = captured ? info->cap.main : 0; + v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n", + __func__, size, info->cap.thumb); + + v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size); } - return m5mols_capture_error_handler(info, timeout); + return ret; } diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index e0f09e531800..93d768db9f33 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -135,10 +135,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length) * @reg: combination of size, category and command for the I2C packet * @size: desired size of I2C packet * @val: read value + * + * Returns 0 on success, or else negative errno. */ static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct m5mols_info *info = to_m5mols(sd); u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; u8 category = I2C_CATEGORY(reg); u8 cmd = I2C_COMMAND(reg); @@ -168,15 +171,17 @@ static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) usleep_range(200, 200); ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) { - v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", - size, category, cmd, ret); - return ret; + + if (ret == 2) { + *val = m5mols_swap_byte(&rbuf[1], size); + return 0; } - *val = m5mols_swap_byte(&rbuf[1], size); + if (info->isp_ready) + v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", + size, category, cmd, ret); - return 0; + return ret < 0 ? ret : -EIO; } int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) @@ -229,10 +234,13 @@ int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) * m5mols_write - I2C command write function * @reg: combination of size, category and command for the I2C packet * @val: value to write + * + * Returns 0 on success, or else negative errno. */ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct m5mols_info *info = to_m5mols(sd); u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; u8 category = I2C_CATEGORY(reg); u8 cmd = I2C_COMMAND(reg); @@ -263,28 +271,45 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) usleep_range(200, 200); ret = i2c_transfer(client->adapter, msg, 1); - if (ret < 0) { - v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n", - size, category, cmd, ret); - return ret; - } + if (ret == 1) + return 0; - return 0; + if (info->isp_ready) + v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n", + category, cmd, ret); + + return ret < 0 ? ret : -EIO; } -int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask) +/** + * m5mols_busy_wait - Busy waiting with I2C register polling + * @reg: the I2C_REG() address of an 8-bit status register to check + * @value: expected status register value + * @mask: bit mask for the read status register value + * @timeout: timeout in miliseconds, or -1 for default timeout + * + * The @reg register value is ORed with @mask before comparing with @value. + * + * Return: 0 if the requested condition became true within less than + * @timeout ms, or else negative errno. + */ +int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, + int timeout) { - u8 busy; - int i; - int ret; + int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout; + unsigned long end = jiffies + msecs_to_jiffies(ms); + u8 status; - for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { - ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy); - if (ret < 0) + do { + int ret = m5mols_read_u8(sd, reg, &status); + + if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL)) return ret; - if ((busy & mask) == mask) + if (!ret && (status & mask & 0xff) == (value & 0xff)) return 0; - } + usleep_range(100, 250); + } while (ms > 0 && time_is_after_jiffies(end)); + return -EBUSY; } @@ -307,6 +332,20 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) return ret; } +int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout) +{ + struct m5mols_info *info = to_m5mols(sd); + + int ret = wait_event_interruptible_timeout(info->irq_waitq, + atomic_add_unless(&info->irq_done, -1, 0), + msecs_to_jiffies(timeout)); + if (ret <= 0) + return ret ? ret : -ETIMEDOUT; + + return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask, + M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1); +} + /** * m5mols_reg_mode - Write the mode and check busy status * @@ -316,8 +355,10 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) { int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); - - return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode); + if (ret < 0) + return ret; + return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff, + M5MOLS_MODE_CHANGE_TIMEOUT); } /** @@ -338,13 +379,13 @@ int m5mols_mode(struct m5mols_info *info, u8 mode) return ret; ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); - if ((!ret && reg == mode) || ret) + if (ret || reg == mode) return ret; switch (reg) { case REG_PARAMETER: ret = m5mols_reg_mode(sd, REG_MONITOR); - if (!ret && mode == REG_MONITOR) + if (mode == REG_MONITOR) break; if (!ret) ret = m5mols_reg_mode(sd, REG_CAPTURE); @@ -361,7 +402,7 @@ int m5mols_mode(struct m5mols_info *info, u8 mode) case REG_CAPTURE: ret = m5mols_reg_mode(sd, REG_MONITOR); - if (!ret && mode == REG_MONITOR) + if (mode == REG_MONITOR) break; if (!ret) ret = m5mols_reg_mode(sd, REG_PARAMETER); @@ -570,26 +611,25 @@ static struct v4l2_subdev_pad_ops m5mols_pad_ops = { }; /** - * m5mols_sync_controls - Apply default scene mode and the current controls + * m5mols_restore_controls - Apply current control values to the registers * - * This is used only streaming for syncing between v4l2_ctrl framework and - * m5mols's controls. First, do the scenemode to the sensor, then call - * v4l2_ctrl_handler_setup. It can be same between some commands and - * the scenemode's in the default v4l2_ctrls. But, such commands of control - * should be prior to the scenemode's one. + * m5mols_do_scenemode() handles all parameters for which there is yet no + * individual control. It should be replaced at some point by setting each + * control individually, in required register set up order. */ -int m5mols_sync_controls(struct m5mols_info *info) +int m5mols_restore_controls(struct m5mols_info *info) { - int ret = -EINVAL; + int ret; - if (!is_ctrl_synced(info)) { - ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); - if (ret) - return ret; + if (info->ctrl_sync) + return 0; - v4l2_ctrl_handler_setup(&info->handle); - info->ctrl_sync = true; - } + ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); + if (ret) + return ret; + + ret = v4l2_ctrl_handler_setup(&info->handle); + info->ctrl_sync = !ret; return ret; } @@ -613,7 +653,7 @@ static int m5mols_start_monitor(struct m5mols_info *info) if (!ret) ret = m5mols_mode(info, REG_MONITOR); if (!ret) - ret = m5mols_sync_controls(info); + ret = m5mols_restore_controls(info); return ret; } @@ -645,17 +685,25 @@ static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); struct m5mols_info *info = to_m5mols(sd); + int ispstate = info->mode; int ret; - info->mode_save = info->mode; + /* + * If needed, defer restoring the controls until + * the device is fully initialized. + */ + if (!info->isp_ready) { + info->ctrl_sync = 0; + return 0; + } ret = m5mols_mode(info, REG_PARAMETER); - if (!ret) - ret = m5mols_set_ctrl(ctrl); - if (!ret) - ret = m5mols_mode(info, info->mode_save); - - return ret; + if (ret < 0) + return ret; + ret = m5mols_set_ctrl(ctrl); + if (ret < 0) + return ret; + return m5mols_mode(info, ispstate); } static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { @@ -669,10 +717,10 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable) const struct m5mols_platform_data *pdata = info->pdata; int ret; - if (enable) { - if (is_powered(info)) - return 0; + if (info->power == enable) + return 0; + if (enable) { if (info->set_power) { ret = info->set_power(&client->dev, 1); if (ret) @@ -686,15 +734,11 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable) } gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); - usleep_range(1000, 1000); - info->power = true; + info->power = 1; return ret; } - if (!is_powered(info)) - return 0; - ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); if (ret) return ret; @@ -703,8 +747,9 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable) info->set_power(&client->dev, 0); gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); - usleep_range(1000, 1000); - info->power = false; + + info->isp_ready = 0; + info->power = 0; return ret; } @@ -717,21 +762,29 @@ int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, } /** - * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core. + * m5mols_fw_start - M-5MOLS internal ARM controller initialization * - * Booting internal ARM core makes the M-5MOLS is ready for getting commands - * with I2C. It's the first thing to be done after it powered up. It must wait - * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting. + * Execute the M-5MOLS internal ARM controller initialization sequence. + * This function should be called after the supply voltage has been + * applied and before any requests to the device are made. */ -static int m5mols_sensor_armboot(struct v4l2_subdev *sd) +static int m5mols_fw_start(struct v4l2_subdev *sd) { + struct m5mols_info *info = to_m5mols(sd); int ret; - ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); + atomic_set(&info->irq_done, 0); + /* Wait until I2C slave is initialized in Flash Writer mode */ + ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE, + M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1); + if (!ret) + ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); + if (!ret) + ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000); if (ret < 0) return ret; - msleep(520); + info->isp_ready = 1; ret = m5mols_get_version(sd); if (!ret) @@ -743,7 +796,8 @@ static int m5mols_sensor_armboot(struct v4l2_subdev *sd) ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); if (!ret) - ret = m5mols_enable_interrupt(sd, REG_INT_AF); + ret = m5mols_enable_interrupt(sd, + REG_INT_AF | REG_INT_CAPTURE); return ret; } @@ -780,7 +834,7 @@ static int m5mols_init_controls(struct m5mols_info *info) 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE); info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, - 1, 0, V4L2_EXPOSURE_MANUAL); + 1, 0, V4L2_EXPOSURE_AUTO); sd->ctrl_handler = &info->handle; if (info->handle.error) { @@ -809,16 +863,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on) if (on) { ret = m5mols_sensor_power(info, true); if (!ret) - ret = m5mols_sensor_armboot(sd); - if (!ret) - ret = m5mols_init_controls(info); - if (ret) - return ret; - - info->ffmt[M5MOLS_RESTYPE_MONITOR] = - m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR]; - info->ffmt[M5MOLS_RESTYPE_CAPTURE] = - m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE]; + ret = m5mols_fw_start(sd); return ret; } @@ -829,17 +874,14 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on) if (!ret) ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); if (!ret) - ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS, - REG_AF_IDLE); - if (!ret) - v4l2_info(sd, "Success soft-landing lens\n"); + ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE, + 0xff, -1); + if (ret < 0) + v4l2_warn(sd, "Soft landing lens failed\n"); } ret = m5mols_sensor_power(info, false); - if (!ret) { - v4l2_ctrl_handler_free(&info->handle); - info->ctrl_sync = false; - } + info->ctrl_sync = 0; return ret; } @@ -865,52 +907,33 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = { .log_status = m5mols_log_status, }; +/* + * V4L2 subdev internal operations + */ +static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + + *format = m5mols_default_ffmt[0]; + return 0; +} + +static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = { + .open = m5mols_open, +}; + static const struct v4l2_subdev_ops m5mols_ops = { .core = &m5mols_core_ops, .pad = &m5mols_pad_ops, .video = &m5mols_video_ops, }; -static void m5mols_irq_work(struct work_struct *work) -{ - struct m5mols_info *info = - container_of(work, struct m5mols_info, work_irq); - struct v4l2_subdev *sd = &info->sd; - u8 reg; - int ret; - - if (!is_powered(info) || - m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt)) - return; - - switch (info->interrupt & REG_INT_MASK) { - case REG_INT_AF: - if (!is_available_af(info)) - break; - ret = m5mols_read_u8(sd, AF_STATUS, ®); - v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", - reg == REG_AF_FAIL ? "Failed" : - reg == REG_AF_SUCCESS ? "Success" : - reg == REG_AF_IDLE ? "Idle" : "Busy"); - break; - case REG_INT_CAPTURE: - if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) - wake_up_interruptible(&info->irq_waitq); - - v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); - break; - default: - v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); - break; - }; -} - static irqreturn_t m5mols_irq_handler(int irq, void *data) { - struct v4l2_subdev *sd = data; - struct m5mols_info *info = to_m5mols(sd); + struct m5mols_info *info = to_m5mols(data); - schedule_work(&info->work_irq); + atomic_set(&info->irq_done, 1); + wake_up_interruptible(&info->irq_waitq); return IRQ_HANDLED; } @@ -961,7 +984,9 @@ static int __devinit m5mols_probe(struct i2c_client *client, sd = &info->sd; strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); v4l2_i2c_subdev_init(sd, client, &m5mols_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->internal_ops = &m5mols_subdev_internal_ops; info->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&sd->entity, 1, &info->pad, 0); if (ret < 0) @@ -969,7 +994,6 @@ static int __devinit m5mols_probe(struct i2c_client *client, sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; init_waitqueue_head(&info->irq_waitq); - INIT_WORK(&info->work_irq, m5mols_irq_work); ret = request_irq(client->irq, m5mols_irq_handler, IRQF_TRIGGER_RISING, MODULE_NAME, sd); if (ret) { @@ -977,7 +1001,20 @@ static int __devinit m5mols_probe(struct i2c_client *client, goto out_me; } info->res_type = M5MOLS_RESTYPE_MONITOR; - return 0; + info->ffmt[0] = m5mols_default_ffmt[0]; + info->ffmt[1] = m5mols_default_ffmt[1]; + + ret = m5mols_sensor_power(info, true); + if (ret) + goto out_me; + + ret = m5mols_fw_start(sd); + if (!ret) + ret = m5mols_init_controls(info); + + m5mols_sensor_power(info, false); + if (!ret) + return 0; out_me: media_entity_cleanup(&sd->entity); out_reg: @@ -995,6 +1032,7 @@ static int __devexit m5mols_remove(struct i2c_client *client) struct m5mols_info *info = to_m5mols(sd); v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(sd->ctrl_handler); free_irq(client->irq, sd); regulator_bulk_free(ARRAY_SIZE(supplies), supplies); diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h index c755bd6edfe9..ae4aced0f9b2 100644 --- a/drivers/media/video/m5mols/m5mols_reg.h +++ b/drivers/media/video/m5mols/m5mols_reg.h @@ -55,39 +55,31 @@ * There is many registers between customer version address and awb one. For * more specific contents, see definition if file m5mols.h. */ -#define CAT0_VER_CUSTOMER 0x00 /* customer version */ -#define CAT0_VER_PROJECT 0x01 /* project version */ -#define CAT0_VER_FIRMWARE 0x02 /* Firmware version */ -#define CAT0_VER_HARDWARE 0x04 /* Hardware version */ -#define CAT0_VER_PARAMETER 0x06 /* Parameter version */ -#define CAT0_VER_AWB 0x08 /* Auto WB version */ -#define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ -#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ -#define CAT0_STATUS 0x0c /* SYSTEM mode status register */ -#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ -#define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ - -#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1) -#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1) -#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2) -#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2) -#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2) -#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2) - -#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) +#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, 0x00, 1) +#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, 0x01, 1) +#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, 0x02, 2) +#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, 0x04, 2) +#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, 0x06, 2) +#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, 0x08, 2) + +#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, 0x0b, 1) #define REG_SYSINIT 0x00 /* SYSTEM mode */ #define REG_PARAMETER 0x01 /* PARAMETER mode */ #define REG_MONITOR 0x02 /* MONITOR mode */ #define REG_CAPTURE 0x03 /* CAPTURE mode */ #define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) -#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1) +#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, 0x0a, 1) #define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ #define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ #define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ +/* SYSTEM mode status */ +#define SYSTEM_STATUS I2C_REG(CAT_SYSTEM, 0x0c, 1) -#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1) -#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1) +/* Interrupt pending register */ +#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, 0x10, 1) +/* interrupt enable register */ +#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, 0x11, 1) #define REG_INT_MODE (1 << 0) #define REG_INT_AF (1 << 1) #define REG_INT_ZOOM (1 << 2) @@ -105,20 +97,20 @@ * can handle with preview(MONITOR) resolution size/frame per second/interface * between the sensor and the Application Processor/even the image effect. */ -#define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */ -#define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */ -#define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */ -#define CAT1_EFFECT 0x0b /* image effects */ -#define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1) +/* Resolution in the MONITOR mode */ +#define PARM_MON_SIZE I2C_REG(CAT_PARAM, 0x01, 1) -#define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1) +/* Frame rate */ +#define PARM_MON_FPS I2C_REG(CAT_PARAM, 0x02, 1) #define REG_FPS_30 0x02 -#define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1) +/* Video bus between the sensor and a host processor */ +#define PARM_INTERFACE I2C_REG(CAT_PARAM, 0x00, 1) #define REG_INTERFACE_MIPI 0x02 -#define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1) +/* Image effects */ +#define PARM_EFFECT I2C_REG(CAT_PARAM, 0x0b, 1) #define REG_EFFECT_OFF 0x00 #define REG_EFFECT_NEGA 0x01 #define REG_EFFECT_EMBOSS 0x06 @@ -135,39 +127,37 @@ * another options like zoom/color effect(different with effect in PARAMETER * mode)/anti hand shaking algorithm. */ -#define CAT2_ZOOM 0x01 /* set the zoom position & execute */ -#define CAT2_ZOOM_STEP 0x03 /* set the zoom step */ -#define CAT2_CFIXB 0x09 /* CB value for color effect */ -#define CAT2_CFIXR 0x0a /* CR value for color effect */ -#define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */ -#define CAT2_CHROMA_LVL 0x0f /* set chroma level */ -#define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */ -#define CAT2_EDGE_LVL 0x11 /* set sharpness level */ -#define CAT2_EDGE_EN 0x12 /* set on/off sharpness */ -#define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */ - -#define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1) - -#define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1) -#define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1) + +/* Target digital zoom position */ +#define MON_ZOOM I2C_REG(CAT_MONITOR, 0x01, 1) + +/* CR value for color effect */ +#define MON_CFIXR I2C_REG(CAT_MONITOR, 0x0a, 1) +/* CB value for color effect */ +#define MON_CFIXB I2C_REG(CAT_MONITOR, 0x09, 1) #define REG_CFIXB_SEPIA 0xd8 #define REG_CFIXR_SEPIA 0x18 -#define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1) +#define MON_EFFECT I2C_REG(CAT_MONITOR, 0x0b, 1) #define REG_COLOR_EFFECT_OFF 0x00 #define REG_COLOR_EFFECT_ON 0x01 -#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1) -#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1) +/* Chroma enable */ +#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, 0x10, 1) +/* Chroma level */ +#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, 0x0f, 1) #define REG_CHROMA_OFF 0x00 #define REG_CHROMA_ON 0x01 -#define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1) -#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1) +/* Sharpness on/off */ +#define MON_EDGE_EN I2C_REG(CAT_MONITOR, 0x12, 1) +/* Sharpness level */ +#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, 0x11, 1) #define REG_EDGE_OFF 0x00 #define REG_EDGE_ON 0x01 -#define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1) +/* Set color tone (contrast) */ +#define MON_TONE_CTL I2C_REG(CAT_MONITOR, 0x25, 1) /* * Category 3 - Auto Exposure @@ -179,27 +169,20 @@ * different. So, this category also provide getting the max/min values. And, * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. */ -#define CAT3_AE_LOCK 0x00 /* locking Auto exposure */ -#define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */ -#define CAT3_ISO 0x05 /* set ISO */ -#define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */ -#define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */ -#define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */ -#define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */ -#define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */ -#define CAT3_AE_INDEX 0x38 /* AE index */ - -#define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1) + +/* Auto Exposure locking */ +#define AE_LOCK I2C_REG(CAT_AE, 0x00, 1) #define REG_AE_UNLOCK 0x00 #define REG_AE_LOCK 0x01 -#define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1) +/* Auto Exposure algorithm mode */ +#define AE_MODE I2C_REG(CAT_AE, 0x01, 1) #define REG_AE_OFF 0x00 /* AE off */ #define REG_AE_ALL 0x01 /* calc AE in all block integral */ #define REG_AE_CENTER 0x03 /* calc AE in center weighted */ #define REG_AE_SPOT 0x06 /* calc AE in specific spot */ -#define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1) +#define AE_ISO I2C_REG(CAT_AE, 0x05, 1) #define REG_ISO_AUTO 0x00 #define REG_ISO_50 0x01 #define REG_ISO_100 0x02 @@ -207,8 +190,10 @@ #define REG_ISO_400 0x04 #define REG_ISO_800 0x05 -#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1) -#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1) +/* EV (scenemode) preset for MONITOR */ +#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, 0x0a, 1) +/* EV (scenemode) preset for CAPTURE */ +#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, 0x0b, 1) #define REG_SCENE_NORMAL 0x00 #define REG_SCENE_PORTRAIT 0x01 #define REG_SCENE_LANDSCAPE 0x02 @@ -224,11 +209,14 @@ #define REG_SCENE_TEXT 0x0c #define REG_SCENE_CANDLE 0x0d -#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2) -#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2) -#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2) +/* Manual gain in MONITOR mode */ +#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, 0x12, 2) +/* Maximum gain in MONITOR mode */ +#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, 0x1a, 2) +/* Manual gain in CAPTURE mode */ +#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, 0x26, 2) -#define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1) +#define AE_INDEX I2C_REG(CAT_AE, 0x38, 1) #define REG_AE_INDEX_20_NEG 0x00 #define REG_AE_INDEX_15_NEG 0x01 #define REG_AE_INDEX_10_NEG 0x02 @@ -241,22 +229,19 @@ /* * Category 6 - White Balance - * - * This category provide AWB locking/mode/preset/speed/gain bias, etc. */ -#define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */ -#define CAT6_AWB_MODE 0x02 /* set Auto or Manual */ -#define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */ -#define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1) +/* Auto Whitebalance locking */ +#define AWB_LOCK I2C_REG(CAT_WB, 0x00, 1) #define REG_AWB_UNLOCK 0x00 #define REG_AWB_LOCK 0x01 -#define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1) +#define AWB_MODE I2C_REG(CAT_WB, 0x02, 1) #define REG_AWB_AUTO 0x01 /* AWB off */ #define REG_AWB_PRESET 0x02 /* AWB preset */ -#define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1) +/* Manual WB (preset) */ +#define AWB_MANUAL I2C_REG(CAT_WB, 0x03, 1) #define REG_AWB_INCANDESCENT 0x01 #define REG_AWB_FLUORESCENT_1 0x02 #define REG_AWB_FLUORESCENT_2 0x03 @@ -269,42 +254,25 @@ /* * Category 7 - EXIF information */ -#define CAT7_INFO_EXPTIME_NU 0x00 -#define CAT7_INFO_EXPTIME_DE 0x04 -#define CAT7_INFO_TV_NU 0x08 -#define CAT7_INFO_TV_DE 0x0c -#define CAT7_INFO_AV_NU 0x10 -#define CAT7_INFO_AV_DE 0x14 -#define CAT7_INFO_BV_NU 0x18 -#define CAT7_INFO_BV_DE 0x1c -#define CAT7_INFO_EBV_NU 0x20 -#define CAT7_INFO_EBV_DE 0x24 -#define CAT7_INFO_ISO 0x28 -#define CAT7_INFO_FLASH 0x2a -#define CAT7_INFO_SDR 0x2c -#define CAT7_INFO_QVAL 0x2e - -#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4) -#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4) -#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4) -#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4) -#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4) -#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4) -#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4) -#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4) -#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4) -#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4) -#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2) -#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2) -#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2) -#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2) +#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, 0x00, 4) +#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, 0x04, 4) +#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, 0x08, 4) +#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, 0x0c, 4) +#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, 0x10, 4) +#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, 0x14, 4) +#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, 0x18, 4) +#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, 0x1c, 4) +#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, 0x20, 4) +#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, 0x24, 4) +#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, 0x28, 2) +#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, 0x2a, 2) +#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, 0x2c, 2) +#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, 0x2e, 2) /* * Category 9 - Face Detection */ -#define CAT9_FD_CTL 0x00 - -#define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1) +#define FD_CTL I2C_REG(CAT_FD, 0x00, 1) #define BIT_FD_EN 0 #define BIT_FD_DRAW_FACE_FRAME 4 #define BIT_FD_DRAW_SMILE_LVL 6 @@ -314,62 +282,50 @@ /* * Category A - Lens Parameter */ -#define CATA_AF_MODE 0x01 -#define CATA_AF_EXECUTE 0x02 -#define CATA_AF_STATUS 0x03 -#define CATA_AF_VERSION 0x0a - -#define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1) +#define AF_MODE I2C_REG(CAT_LENS, 0x01, 1) #define REG_AF_NORMAL 0x00 /* Normal AF, one time */ #define REG_AF_MACRO 0x01 /* Macro AF, one time */ #define REG_AF_POWEROFF 0x07 -#define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1) +#define AF_EXECUTE I2C_REG(CAT_LENS, 0x02, 1) #define REG_AF_STOP 0x00 #define REG_AF_EXE_AUTO 0x01 #define REG_AF_EXE_CAF 0x02 -#define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1) +#define AF_STATUS I2C_REG(CAT_LENS, 0x03, 1) #define REG_AF_FAIL 0x00 #define REG_AF_SUCCESS 0x02 #define REG_AF_IDLE 0x04 #define REG_AF_BUSY 0x05 -#define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1) +#define AF_VERSION I2C_REG(CAT_LENS, 0x0a, 1) /* * Category B - CAPTURE Parameter */ -#define CATB_YUVOUT_MAIN 0x00 -#define CATB_MAIN_IMAGE_SIZE 0x01 -#define CATB_MCC_MODE 0x1d -#define CATB_WDR_EN 0x2c -#define CATB_LIGHT_CTRL 0x40 -#define CATB_FLASH_CTRL 0x41 - -#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1) +#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, 0x00, 1) #define REG_YUV422 0x00 #define REG_BAYER10 0x05 #define REG_BAYER8 0x06 #define REG_JPEG 0x10 -#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1) +#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1) -#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1) +#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1) #define REG_MCC_OFF 0x00 #define REG_MCC_NORMAL 0x01 -#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1) +#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, 0x2c, 1) #define REG_WDR_OFF 0x00 #define REG_WDR_ON 0x01 #define REG_WDR_AUTO 0x02 -#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1) +#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, 0x40, 1) #define REG_LIGHT_OFF 0x00 #define REG_LIGHT_ON 0x01 #define REG_LIGHT_AUTO 0x02 -#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1) +#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, 0x41, 1) #define REG_FLASH_OFF 0x00 #define REG_FLASH_ON 0x01 #define REG_FLASH_AUTO 0x02 @@ -377,34 +333,29 @@ /* * Category C - CAPTURE Control */ -#define CATC_CAP_MODE 0x00 -#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */ -#define CATC_CAP_START 0x09 -#define CATC_CAP_IMAGE_SIZE 0x0d -#define CATC_CAP_THUMB_SIZE 0x11 - -#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1) +#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, 0x00, 1) #define REG_CAP_NONE 0x00 #define REG_CAP_ANTI_SHAKE 0x02 -#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1) +/* Select single- or multi-shot capture */ +#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, 0x06, 1) -#define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1) +#define CAPC_START I2C_REG(CAT_CAPT_CTRL, 0x09, 1) #define REG_CAP_START_MAIN 0x01 #define REG_CAP_START_THUMB 0x03 -#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4) -#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4) +#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, 0x0d, 4) +#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, 0x11, 4) /* * Category F - Flash * * This mode provides functions about internal flash stuff and system startup. */ -#define CATF_CAM_START 0x12 /* It starts internal ARM core booting - * after power-up */ -#define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1) -#define REG_START_ARM_BOOT 0x01 +/* Starts internal ARM core booting after power-up */ +#define FLASH_CAM_START I2C_REG(CAT_FLASH, 0x12, 1) +#define REG_START_ARM_BOOT 0x01 /* write value */ +#define REG_IN_FLASH_MODE 0x00 /* read value */ #endif /* M5MOLS_REG_H */ diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 80ec64d2d6d8..37d20e73908a 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c @@ -51,7 +51,7 @@ static int delivered; * sense. */ -static int alloc_bufs_at_read; +static bool alloc_bufs_at_read; module_param(alloc_bufs_at_read, bool, 0444); MODULE_PARM_DESC(alloc_bufs_at_read, "Non-zero value causes DMA buffers to be allocated when the " @@ -73,11 +73,11 @@ MODULE_PARM_DESC(dma_buf_size, "parameters require larger buffers, an attempt to reallocate " "will be made."); #else /* MCAM_MODE_VMALLOC */ -static const int alloc_bufs_at_read = 0; +static const bool alloc_bufs_at_read = 0; static const int n_dma_bufs = 3; /* Used by S/G_PARM */ #endif /* MCAM_MODE_VMALLOC */ -static int flip; +static bool flip; module_param(flip, bool, 0444); MODULE_PARM_DESC(flip, "If set, the sensor will be instructed to flip the image " @@ -522,6 +522,15 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam) */ static void mcam_ctlr_dma_sg(struct mcam_camera *cam) { + /* + * The list-empty condition can hit us at resume time + * if the buffer list was empty when the system was suspended. + */ + if (list_empty(&cam->buffers)) { + set_bit(CF_SG_RESTART, &cam->flags); + return; + } + mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); mcam_sg_next_buffer(cam); mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); @@ -566,6 +575,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame) } else { set_bit(CF_SG_RESTART, &cam->flags); singles++; + cam->vb_bufs[0] = NULL; } /* * Now we can give the completed frame back to user space. @@ -661,10 +671,10 @@ static int mcam_ctlr_configure(struct mcam_camera *cam) unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); + clear_bit(CF_SG_RESTART, &cam->flags); cam->dma_setup(cam); mcam_ctlr_image(cam); mcam_set_config_needed(cam, 0); - clear_bit(CF_SG_RESTART, &cam->flags); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0; } @@ -873,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam) mcam_reset_buffers(cam); mcam_ctlr_irq_enable(cam); cam->state = S_STREAMING; - mcam_ctlr_start(cam); + if (!test_bit(CF_SG_RESTART, &cam->flags)) + mcam_ctlr_start(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0; } @@ -1818,11 +1829,15 @@ void mccic_shutdown(struct mcam_camera *cam) void mccic_suspend(struct mcam_camera *cam) { - enum mcam_state cstate = cam->state; + mutex_lock(&cam->s_mutex); + if (cam->users > 0) { + enum mcam_state cstate = cam->state; - mcam_ctlr_stop_dma(cam); - mcam_ctlr_power_down(cam); - cam->state = cstate; + mcam_ctlr_stop_dma(cam); + mcam_ctlr_power_down(cam); + cam->state = cstate; + } + mutex_unlock(&cam->s_mutex); } int mccic_resume(struct mcam_camera *cam) @@ -1839,8 +1854,15 @@ int mccic_resume(struct mcam_camera *cam) mutex_unlock(&cam->s_mutex); set_bit(CF_CONFIG_NEEDED, &cam->flags); - if (cam->state == S_STREAMING) + if (cam->state == S_STREAMING) { + /* + * If there was a buffer in the DMA engine at suspend + * time, put it back on the queue or we'll forget about it. + */ + if (cam->buffer_mode == B_DMA_sg && cam->vb_bufs[0]) + list_add(&cam->vb_bufs[0]->queue, &cam->buffers); ret = mcam_read_setup(cam); + } return ret; } #endif /* CONFIG_PM */ diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c index fb0b124b35f3..0d64e2d7474a 100644 --- a/drivers/media/video/marvell-ccic/mmp-driver.c +++ b/drivers/media/video/marvell-ccic/mmp-driver.c @@ -26,6 +26,7 @@ #include <linux/io.h> #include <linux/delay.h> #include <linux/list.h> +#include <linux/pm.h> #include "mcam-core.h" @@ -310,10 +311,44 @@ static int mmpcam_platform_remove(struct platform_device *pdev) return mmpcam_remove(cam); } +/* + * Suspend/resume support. + */ +#ifdef CONFIG_PM + +static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct mmp_camera *cam = mmpcam_find_device(pdev); + + if (state.event != PM_EVENT_SUSPEND) + return 0; + mccic_suspend(&cam->mcam); + return 0; +} + +static int mmpcam_resume(struct platform_device *pdev) +{ + struct mmp_camera *cam = mmpcam_find_device(pdev); + + /* + * Power up unconditionally just in case the core tries to + * touch a register even if nothing was active before; trust + * me, it's better this way. + */ + mmpcam_power_up(&cam->mcam); + return mccic_resume(&cam->mcam); +} + +#endif + static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, .remove = mmpcam_platform_remove, +#ifdef CONFIG_PM + .suspend = mmpcam_suspend, + .resume = mmpcam_resume, +#endif .driver = { .name = "mmp-camera", .owner = THIS_MODULE diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index d0f538857285..d7cd0f633f63 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -69,12 +69,12 @@ MODULE_LICENSE("GPL"); /* module parameters */ static int opmode = OPMODE_AUTO; int msp_debug; /* msp_debug output */ -int msp_once; /* no continuous stereo monitoring */ -int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), +bool msp_once; /* no continuous stereo monitoring */ +bool msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), the autoscan seems work well only with FM... */ int msp_standard = 1; /* Override auto detect of audio msp_standard, if needed. */ -int msp_dolby; +bool msp_dolby; int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual (msp34xxg only) 0x00a0-0x03c0 */ diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h index 831e8db4368c..fbe5e0715f93 100644 --- a/drivers/media/video/msp3400-driver.h +++ b/drivers/media/video/msp3400-driver.h @@ -44,10 +44,10 @@ /* module parameters */ extern int msp_debug; -extern int msp_once; -extern int msp_amsound; +extern bool msp_once; +extern bool msp_amsound; extern int msp_standard; -extern int msp_dolby; +extern bool msp_dolby; extern int msp_stereo_thresh; struct msp_state { diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index e2b1029b16cd..097c9d3d04a8 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -109,14 +109,13 @@ static struct mt9m001 *to_mt9m001(const struct i2c_client *client) static int reg_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); + return i2c_smbus_read_word_swapped(client, reg); } static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - return i2c_smbus_write_word_data(client, reg, swab16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int reg_set(struct i2c_client *client, const u8 reg, diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 398f96ffd35e..bee65bff46e8 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -139,25 +139,52 @@ #define MT9M111_MAX_HEIGHT 1024 #define MT9M111_MAX_WIDTH 1280 +struct mt9m111_context { + u16 read_mode; + u16 blanking_h; + u16 blanking_v; + u16 reducer_xzoom; + u16 reducer_yzoom; + u16 reducer_xsize; + u16 reducer_ysize; + u16 output_fmt_ctrl2; + u16 control; +}; + +static struct mt9m111_context context_a = { + .read_mode = MT9M111_READ_MODE_A, + .blanking_h = MT9M111_HORIZONTAL_BLANKING_A, + .blanking_v = MT9M111_VERTICAL_BLANKING_A, + .reducer_xzoom = MT9M111_REDUCER_XZOOM_A, + .reducer_yzoom = MT9M111_REDUCER_YZOOM_A, + .reducer_xsize = MT9M111_REDUCER_XSIZE_A, + .reducer_ysize = MT9M111_REDUCER_YSIZE_A, + .output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_A, + .control = MT9M111_CTXT_CTRL_RESTART, +}; + +static struct mt9m111_context context_b = { + .read_mode = MT9M111_READ_MODE_B, + .blanking_h = MT9M111_HORIZONTAL_BLANKING_B, + .blanking_v = MT9M111_VERTICAL_BLANKING_B, + .reducer_xzoom = MT9M111_REDUCER_XZOOM_B, + .reducer_yzoom = MT9M111_REDUCER_YZOOM_B, + .reducer_xsize = MT9M111_REDUCER_XSIZE_B, + .reducer_ysize = MT9M111_REDUCER_YSIZE_B, + .output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_B, + .control = MT9M111_CTXT_CTRL_RESTART | + MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B | + MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B | + MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B | + MT9M111_CTXT_CTRL_HBLANK_SEL_B, +}; + /* MT9M111 has only one fixed colorspace per pixelcode */ struct mt9m111_datafmt { enum v4l2_mbus_pixelcode code; enum v4l2_colorspace colorspace; }; -/* Find a data format by a pixel code in an array */ -static const struct mt9m111_datafmt *mt9m111_find_datafmt( - enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG}, @@ -173,27 +200,35 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, }; -enum mt9m111_context { - HIGHPOWER = 0, - LOWPOWER, -}; - struct mt9m111 { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; struct v4l2_ctrl *gain; int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code * from v4l2-chip-ident.h */ - enum mt9m111_context context; - struct v4l2_rect rect; + struct mt9m111_context *ctx; + struct v4l2_rect rect; /* cropping rectangle */ + int width; /* output */ + int height; /* sizes */ struct mutex power_lock; /* lock to protect power_count */ int power_count; const struct mt9m111_datafmt *fmt; int lastpage; /* PageMap cache value */ unsigned char datawidth; - unsigned int powered:1; }; +/* Find a data format by a pixel code */ +static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111, + enum v4l2_mbus_pixelcode code) +{ + int i; + for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++) + if (mt9m111_colour_fmts[i].code == code) + return mt9m111_colour_fmts + i; + + return mt9m111->fmt; +} + static struct mt9m111 *to_mt9m111(const struct i2c_client *client) { return container_of(i2c_get_clientdata(client), struct mt9m111, subdev); @@ -211,7 +246,7 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg) if (page > 2) return -EINVAL; - ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page)); + ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page); if (!ret) mt9m111->lastpage = page; return ret; @@ -223,7 +258,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg) ret = reg_page_map_set(client, reg); if (!ret) - ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff)); + ret = i2c_smbus_read_word_swapped(client, reg & 0xff); dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); return ret; @@ -236,8 +271,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg, ret = reg_page_map_set(client, reg); if (!ret) - ret = i2c_smbus_write_word_data(client, reg & 0xff, - swab16(data)); + ret = i2c_smbus_write_word_swapped(client, reg & 0xff, data); dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); return ret; } @@ -276,76 +310,63 @@ static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg, } static int mt9m111_set_context(struct mt9m111 *mt9m111, - enum mt9m111_context ctxt) + struct mt9m111_context *ctx) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B - | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B - | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B - | MT9M111_CTXT_CTRL_VBLANK_SEL_B - | MT9M111_CTXT_CTRL_HBLANK_SEL_B; - int valA = MT9M111_CTXT_CTRL_RESTART; - - if (ctxt == HIGHPOWER) - return reg_write(CONTEXT_CONTROL, valB); - else - return reg_write(CONTEXT_CONTROL, valA); + return reg_write(CONTEXT_CONTROL, ctx->control); } -static int mt9m111_setup_rect(struct mt9m111 *mt9m111, - struct v4l2_rect *rect) +static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111, + struct mt9m111_context *ctx, struct v4l2_rect *rect, + unsigned int width, unsigned int height) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int ret, is_raw_format; - int width = rect->width; - int height = rect->height; + int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, rect->width); + if (!ret) + ret = mt9m111_reg_write(client, ctx->reducer_yzoom, rect->height); + if (!ret) + ret = mt9m111_reg_write(client, ctx->reducer_xsize, width); + if (!ret) + ret = mt9m111_reg_write(client, ctx->reducer_ysize, height); + return ret; +} - if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || - mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) - is_raw_format = 1; - else - is_raw_format = 0; +static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect, + int width, int height, enum v4l2_mbus_pixelcode code) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); + int ret; ret = reg_write(COLUMN_START, rect->left); if (!ret) ret = reg_write(ROW_START, rect->top); - if (is_raw_format) { - if (!ret) - ret = reg_write(WINDOW_WIDTH, width); - if (!ret) - ret = reg_write(WINDOW_HEIGHT, height); - } else { - if (!ret) - ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH); - if (!ret) - ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT); - if (!ret) - ret = reg_write(REDUCER_XSIZE_B, width); - if (!ret) - ret = reg_write(REDUCER_YSIZE_B, height); - if (!ret) - ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH); - if (!ret) - ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT); + if (!ret) + ret = reg_write(WINDOW_WIDTH, rect->width); + if (!ret) + ret = reg_write(WINDOW_HEIGHT, rect->height); + + if (code != V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { + /* IFP in use, down-scaling possible */ if (!ret) - ret = reg_write(REDUCER_XSIZE_A, width); + ret = mt9m111_setup_rect_ctx(mt9m111, &context_b, + rect, width, height); if (!ret) - ret = reg_write(REDUCER_YSIZE_A, height); + ret = mt9m111_setup_rect_ctx(mt9m111, &context_a, + rect, width, height); } + dev_dbg(&client->dev, "%s(%x): %ux%u@%u:%u -> %ux%u = %d\n", + __func__, code, rect->width, rect->height, rect->left, rect->top, + width, height, ret); + return ret; } static int mt9m111_enable(struct mt9m111 *mt9m111) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int ret; - - ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); - if (!ret) - mt9m111->powered = 1; - return ret; + return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE); } static int mt9m111_reset(struct mt9m111 *mt9m111) @@ -363,43 +384,41 @@ static int mt9m111_reset(struct mt9m111 *mt9m111) return ret; } -static int mt9m111_make_rect(struct mt9m111 *mt9m111, - struct v4l2_rect *rect) +static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { + struct v4l2_rect rect = a->c; + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + int width, height; + int ret; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { /* Bayer format - even size lengths */ - rect->width = ALIGN(rect->width, 2); - rect->height = ALIGN(rect->height, 2); + rect.width = ALIGN(rect.width, 2); + rect.height = ALIGN(rect.height, 2); /* Let the user play with the starting pixel */ } /* FIXME: the datasheet doesn't specify minimum sizes */ - soc_camera_limit_side(&rect->left, &rect->width, + soc_camera_limit_side(&rect.left, &rect.width, MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH); - soc_camera_limit_side(&rect->top, &rect->height, + soc_camera_limit_side(&rect.top, &rect.height, MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT); - return mt9m111_setup_rect(mt9m111, rect); -} - -static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct v4l2_rect rect = a->c; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - int ret; - - dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n", - __func__, rect.left, rect.top, rect.width, rect.height); + width = min(mt9m111->width, rect.width); + height = min(mt9m111->height, rect.height); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - ret = mt9m111_make_rect(mt9m111, &rect); - if (!ret) + ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code); + if (!ret) { mt9m111->rect = rect; + mt9m111->width = width; + mt9m111->height = height; + } + return ret; } @@ -434,8 +453,8 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd, { struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - mf->width = mt9m111->rect.width; - mf->height = mt9m111->rect.height; + mf->width = mt9m111->width; + mf->height = mt9m111->height; mf->code = mt9m111->fmt->code; mf->colorspace = mt9m111->fmt->colorspace; mf->field = V4L2_FIELD_NONE; @@ -504,46 +523,11 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111, return -EINVAL; } - ret = reg_mask(OUTPUT_FORMAT_CTRL2_A, data_outfmt2, - mask_outfmt2); + ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2, + data_outfmt2, mask_outfmt2); if (!ret) - ret = reg_mask(OUTPUT_FORMAT_CTRL2_B, data_outfmt2, - mask_outfmt2); - - return ret; -} - -static int mt9m111_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct mt9m111_datafmt *fmt; - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - struct v4l2_rect rect = { - .left = mt9m111->rect.left, - .top = mt9m111->rect.top, - .width = mf->width, - .height = mf->height, - }; - int ret; - - fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, - ARRAY_SIZE(mt9m111_colour_fmts)); - if (!fmt) - return -EINVAL; - - dev_dbg(&client->dev, - "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__, - mf->code, rect.left, rect.top, rect.width, rect.height); - - ret = mt9m111_make_rect(mt9m111, &rect); - if (!ret) - ret = mt9m111_set_pixfmt(mt9m111, mf->code); - if (!ret) { - mt9m111->rect = rect; - mt9m111->fmt = fmt; - mf->colorspace = fmt->colorspace; - } + ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2, + data_outfmt2, mask_outfmt2); return ret; } @@ -551,42 +535,71 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd, static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { + struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); const struct mt9m111_datafmt *fmt; - bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || - mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; - - fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, - ARRAY_SIZE(mt9m111_colour_fmts)); - if (!fmt) { - fmt = mt9m111->fmt; - mf->code = fmt->code; - } + struct v4l2_rect *rect = &mt9m111->rect; + bool bayer; + + fmt = mt9m111_find_datafmt(mt9m111, mf->code); + + bayer = fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; /* * With Bayer format enforce even side lengths, but let the user play * with the starting pixel */ + if (bayer) { + rect->width = ALIGN(rect->width, 2); + rect->height = ALIGN(rect->height, 2); + } - if (mf->height > MT9M111_MAX_HEIGHT) - mf->height = MT9M111_MAX_HEIGHT; - else if (mf->height < 2) - mf->height = 2; - else if (bayer) - mf->height = ALIGN(mf->height, 2); + if (fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { + /* IFP bypass mode, no scaling */ + mf->width = rect->width; + mf->height = rect->height; + } else { + /* No upscaling */ + if (mf->width > rect->width) + mf->width = rect->width; + if (mf->height > rect->height) + mf->height = rect->height; + } - if (mf->width > MT9M111_MAX_WIDTH) - mf->width = MT9M111_MAX_WIDTH; - else if (mf->width < 2) - mf->width = 2; - else if (bayer) - mf->width = ALIGN(mf->width, 2); + dev_dbg(&client->dev, "%s(): %ux%u, code=%x\n", __func__, + mf->width, mf->height, fmt->code); + mf->code = fmt->code; mf->colorspace = fmt->colorspace; return 0; } +static int mt9m111_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + const struct mt9m111_datafmt *fmt; + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + struct v4l2_rect *rect = &mt9m111->rect; + int ret; + + mt9m111_try_fmt(sd, mf); + fmt = mt9m111_find_datafmt(mt9m111, mf->code); + /* try_fmt() guarantees fmt != NULL && fmt->code == mf->code */ + + ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code); + if (!ret) + ret = mt9m111_set_pixfmt(mt9m111, mf->code); + if (!ret) { + mt9m111->width = mf->width; + mt9m111->height = mf->height; + mt9m111->fmt = fmt; + } + + return ret; +} + static int mt9m111_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) { @@ -650,17 +663,10 @@ static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; - if (mt9m111->context == HIGHPOWER) { - if (flip) - ret = reg_set(READ_MODE_B, mask); - else - ret = reg_clear(READ_MODE_B, mask); - } else { - if (flip) - ret = reg_set(READ_MODE_A, mask); - else - ret = reg_clear(READ_MODE_A, mask); - } + if (flip) + ret = mt9m111_reg_set(client, mt9m111->ctx->read_mode, mask); + else + ret = mt9m111_reg_clear(client, mt9m111->ctx->read_mode, mask); return ret; } @@ -738,30 +744,39 @@ static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) static int mt9m111_suspend(struct mt9m111 *mt9m111) { + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); + int ret; + v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111)); - return 0; + ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); + if (!ret) + ret = reg_set(RESET, MT9M111_RESET_RESET_SOC | + MT9M111_RESET_OUTPUT_DISABLE | + MT9M111_RESET_ANALOG_STANDBY); + if (!ret) + ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE); + + return ret; } static void mt9m111_restore_state(struct mt9m111 *mt9m111) { - mt9m111_set_context(mt9m111, mt9m111->context); + mt9m111_set_context(mt9m111, mt9m111->ctx); mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); - mt9m111_setup_rect(mt9m111, &mt9m111->rect); + mt9m111_setup_geometry(mt9m111, &mt9m111->rect, + mt9m111->width, mt9m111->height, mt9m111->fmt->code); v4l2_ctrl_handler_setup(&mt9m111->hdl); } static int mt9m111_resume(struct mt9m111 *mt9m111) { - int ret = 0; + int ret = mt9m111_enable(mt9m111); + if (!ret) + ret = mt9m111_reset(mt9m111); + if (!ret) + mt9m111_restore_state(mt9m111); - if (mt9m111->powered) { - ret = mt9m111_enable(mt9m111); - if (!ret) - ret = mt9m111_reset(mt9m111); - if (!ret) - mt9m111_restore_state(mt9m111); - } return ret; } @@ -770,12 +785,13 @@ static int mt9m111_init(struct mt9m111 *mt9m111) struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; - mt9m111->context = HIGHPOWER; + /* Default HIGHPOWER context */ + mt9m111->ctx = &context_b; ret = mt9m111_enable(mt9m111); if (!ret) ret = mt9m111_reset(mt9m111); if (!ret) - ret = mt9m111_set_context(mt9m111, mt9m111->context); + ret = mt9m111_set_context(mt9m111, mt9m111->ctx); if (ret) dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); return ret; diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c index 73c068993f05..93c3ec7426e8 100644 --- a/drivers/media/video/mt9p031.c +++ b/drivers/media/video/mt9p031.c @@ -132,13 +132,12 @@ static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd) static int mt9p031_read(struct i2c_client *client, u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : be16_to_cpu(data); + return i2c_smbus_read_word_swapped(client, reg); } static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data) { - return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear, diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c index 08074b8a2736..cd81d04a529e 100644 --- a/drivers/media/video/mt9t001.c +++ b/drivers/media/video/mt9t001.c @@ -133,13 +133,12 @@ static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd) static int mt9t001_read(struct i2c_client *client, u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : be16_to_cpu(data); + return i2c_smbus_read_word_swapped(client, reg); } static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data) { - return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear, diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 0e78477452ff..84add1aef139 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -90,14 +90,13 @@ static struct mt9t031 *to_mt9t031(const struct i2c_client *client) static int reg_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); + return i2c_smbus_read_word_swapped(client, reg); } static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - return i2c_smbus_write_word_data(client, reg, swab16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int reg_set(struct i2c_client *client, const u8 reg, diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 690ee0d42eeb..944940758fa3 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -130,14 +130,13 @@ static struct mt9v022 *to_mt9v022(const struct i2c_client *client) static int reg_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); + return i2c_smbus_read_word_swapped(client, reg); } static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - return i2c_smbus_write_word_data(client, reg, swab16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int reg_set(struct i2c_client *client, const u8 reg, diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c index f080c162123f..d90b982cc218 100644 --- a/drivers/media/video/mt9v032.c +++ b/drivers/media/video/mt9v032.c @@ -139,10 +139,10 @@ static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd) static int mt9v032_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); + s32 data = i2c_smbus_read_word_swapped(client, reg); dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__, - swab16(data), reg); - return data < 0 ? data : swab16(data); + data, reg); + return data; } static int mt9v032_write(struct i2c_client *client, const u8 reg, @@ -150,7 +150,7 @@ static int mt9v032_write(struct i2c_client *client, const u8 reg, { dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__, data, reg); - return i2c_smbus_write_word_data(client, reg, swab16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set) diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 18e94c7d2be8..055d11ddb038 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -487,7 +487,7 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd, return v4l2_subdev_call(sd, video, s_crop, a); } -static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +static int mx1_camera_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index a803d9ea8fd6..04aab0c538aa 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c @@ -210,6 +210,22 @@ #define MAX_VIDEO_MEM 16 +struct mx2_prp_cfg { + int channel; + u32 in_fmt; + u32 out_fmt; + u32 src_pixel; + u32 ch1_pixel; + u32 irq_flags; +}; + +/* prp configuration for a client-host fmt pair */ +struct mx2_fmt_cfg { + enum v4l2_mbus_pixelcode in_fmt; + u32 out_fmt; + struct mx2_prp_cfg cfg; +}; + struct mx2_camera_dev { struct device *dev; struct soc_camera_host soc_host; @@ -241,6 +257,8 @@ struct mx2_camera_dev { void *discard_buffer; dma_addr_t discard_buffer_dma; size_t discard_size; + struct mx2_fmt_cfg *emma_prp; + u32 frame_count; }; /* buffer for one video frame */ @@ -253,6 +271,59 @@ struct mx2_buffer { int bufnum; }; +static struct mx2_fmt_cfg mx27_emma_prp_table[] = { + /* + * This is a generic configuration which is valid for most + * prp input-output format combinations. + * We set the incomming and outgoing pixelformat to a + * 16 Bit wide format and adjust the bytesperline + * accordingly. With this configuration the inputdata + * will not be changed by the emma and could be any type + * of 16 Bit Pixelformat. + */ + { + .in_fmt = 0, + .out_fmt = 0, + .cfg = { + .channel = 1, + .in_fmt = PRP_CNTL_DATA_IN_RGB16, + .out_fmt = PRP_CNTL_CH1_OUT_RGB16, + .src_pixel = 0x2ca00565, /* RGB565 */ + .ch1_pixel = 0x2ca00565, /* RGB565 */ + .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | + PRP_INTR_CH1FC | PRP_INTR_LBOVF, + } + }, + { + .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8, + .out_fmt = V4L2_PIX_FMT_YUV420, + .cfg = { + .channel = 2, + .in_fmt = PRP_CNTL_DATA_IN_YUV422, + .out_fmt = PRP_CNTL_CH2_OUT_YUV420, + .src_pixel = 0x22000888, /* YUV422 (YUYV) */ + .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | + PRP_INTR_CH2FC | PRP_INTR_LBOVF | + PRP_INTR_CH2OVF, + } + }, +}; + +static struct mx2_fmt_cfg *mx27_emma_prp_get_format( + enum v4l2_mbus_pixelcode in_fmt, + u32 out_fmt) +{ + int i; + + for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++) + if ((mx27_emma_prp_table[i].in_fmt == in_fmt) && + (mx27_emma_prp_table[i].out_fmt == out_fmt)) { + return &mx27_emma_prp_table[i]; + } + /* If no match return the most generic configuration */ + return &mx27_emma_prp_table[0]; +}; + static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) { unsigned long flags; @@ -301,6 +372,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd) writel(pcdev->csicr1, pcdev->base_csi + CSICR1); pcdev->icd = icd; + pcdev->frame_count = 0; dev_info(icd->parent, "Camera driver attached to camera %d\n", icd->devnum); @@ -719,55 +791,77 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_fmt_cfg *prp = pcdev->emma_prp; + u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; + + if (prp->cfg.channel == 1) { + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_RGB1_PTR); + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_RGB2_PTR); + + writel(PRP_CNTL_CH1EN | + PRP_CNTL_CSIEN | + prp->cfg.in_fmt | + prp->cfg.out_fmt | + PRP_CNTL_CH1_LEN | + PRP_CNTL_CH1BYP | + PRP_CNTL_CH1_TSKIP(0) | + PRP_CNTL_IN_TSKIP(0), + pcdev->base_emma + PRP_CNTL); + + writel((icd->user_width << 16) | icd->user_height, + pcdev->base_emma + PRP_SRC_FRAME_SIZE); + writel((icd->user_width << 16) | icd->user_height, + pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); + writel(bytesperline, + pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); + writel(prp->cfg.src_pixel, + pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); + writel(prp->cfg.ch1_pixel, + pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); + } else { /* channel 2 */ + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_Y_PTR); + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_SOURCE_Y_PTR); + + if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { + writel(pcdev->discard_buffer_dma + imgsize, + pcdev->base_emma + PRP_DEST_CB_PTR); + writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), + pcdev->base_emma + PRP_DEST_CR_PTR); + writel(pcdev->discard_buffer_dma + imgsize, + pcdev->base_emma + PRP_SOURCE_CB_PTR); + writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), + pcdev->base_emma + PRP_SOURCE_CR_PTR); + } - writel(pcdev->discard_buffer_dma, - pcdev->base_emma + PRP_DEST_RGB1_PTR); - writel(pcdev->discard_buffer_dma, - pcdev->base_emma + PRP_DEST_RGB2_PTR); - - /* - * We only use the EMMA engine to get rid of the broken - * DMA Engine. No color space consversion at the moment. - * We set the incomming and outgoing pixelformat to an - * 16 Bit wide format and adjust the bytesperline - * accordingly. With this configuration the inputdata - * will not be changed by the emma and could be any type - * of 16 Bit Pixelformat. - */ - writel(PRP_CNTL_CH1EN | + writel(PRP_CNTL_CH2EN | PRP_CNTL_CSIEN | - PRP_CNTL_DATA_IN_RGB16 | - PRP_CNTL_CH1_OUT_RGB16 | - PRP_CNTL_CH1_LEN | - PRP_CNTL_CH1BYP | - PRP_CNTL_CH1_TSKIP(0) | + prp->cfg.in_fmt | + prp->cfg.out_fmt | + PRP_CNTL_CH2_LEN | + PRP_CNTL_CH2_TSKIP(0) | PRP_CNTL_IN_TSKIP(0), pcdev->base_emma + PRP_CNTL); - writel(((bytesperline >> 1) << 16) | icd->user_height, + writel((icd->user_width << 16) | icd->user_height, pcdev->base_emma + PRP_SRC_FRAME_SIZE); - writel(((bytesperline >> 1) << 16) | icd->user_height, - pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); - writel(bytesperline, - pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); - writel(0x2ca00565, /* RGB565 */ + + writel((icd->user_width << 16) | icd->user_height, + pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); + + writel(prp->cfg.src_pixel, pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); - writel(0x2ca00565, /* RGB565 */ - pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); + + } /* Enable interrupts */ - writel(PRP_INTR_RDERR | - PRP_INTR_CH1WERR | - PRP_INTR_CH2WERR | - PRP_INTR_CH1FC | - PRP_INTR_CH2FC | - PRP_INTR_LBOVF | - PRP_INTR_CH2OVF, - pcdev->base_emma + PRP_INTR_CNTL); + writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); } -static int mx2_camera_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) +static int mx2_camera_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); @@ -911,9 +1005,58 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd, return ret; } +static int mx2_camera_get_formats(struct soc_camera_device *icd, + unsigned int idx, + struct soc_camera_format_xlate *xlate) +{ + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_mbus_pixelfmt *fmt; + struct device *dev = icd->parent; + enum v4l2_mbus_pixelcode code; + int ret, formats = 0; + + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + if (ret < 0) + /* no more formats */ + return 0; + + fmt = soc_mbus_get_fmtdesc(code); + if (!fmt) { + dev_err(dev, "Invalid format code #%u: %d\n", idx, code); + return 0; + } + + if (code == V4L2_MBUS_FMT_YUYV8_2X8) { + formats++; + if (xlate) { + /* + * CH2 can output YUV420 which is a standard format in + * soc_mediabus.c + */ + xlate->host_fmt = + soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8); + xlate->code = code; + dev_dbg(dev, "Providing host format %s for sensor code %d\n", + xlate->host_fmt->name, code); + xlate++; + } + } + + /* Generic pass-trough */ + formats++; + if (xlate) { + xlate->host_fmt = fmt; + xlate->code = code; + xlate++; + } + return formats; +} + static int mx2_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct mx2_camera_dev *pcdev = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; @@ -946,6 +1089,10 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, pix->colorspace = mf.colorspace; icd->current_fmt = xlate; + if (mx27_camera_emma(pcdev)) + pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, + xlate->host_fmt->fourcc); + return 0; } @@ -1011,7 +1158,12 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, if (mf.field == V4L2_FIELD_ANY) mf.field = V4L2_FIELD_NONE; - if (mf.field != V4L2_FIELD_NONE) { + /* + * Driver supports interlaced images provided they have + * both fields so that they can be processed as if they + * were progressive. + */ + if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) { dev_err(icd->parent, "Field type %d unsupported.\n", mf.field); return -EINVAL; @@ -1173,6 +1325,7 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = { .remove = mx2_camera_remove_device, .set_fmt = mx2_camera_set_fmt, .set_crop = mx2_camera_set_crop, + .get_formats = mx2_camera_get_formats, .try_fmt = mx2_camera_try_fmt, .init_videobuf = mx2_camera_init_videobuf, .reqbufs = mx2_camera_reqbufs, @@ -1184,6 +1337,8 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = { static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, int bufnum, int state) { + u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; + struct mx2_fmt_cfg *prp = pcdev->emma_prp; struct mx2_buffer *buf; struct videobuf_buffer *vb; unsigned long phys; @@ -1197,12 +1352,22 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, vb = &buf->vb; #ifdef DEBUG phys = videobuf_to_dma_contig(vb); - if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum) - != phys) { - dev_err(pcdev->dev, "%p != %p\n", phys, - readl(pcdev->base_emma + - PRP_DEST_RGB1_PTR + - 4 * bufnum)); + if (prp->cfg.channel == 1) { + if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + + 4 * bufnum) != phys) { + dev_err(pcdev->dev, "%p != %p\n", phys, + readl(pcdev->base_emma + + PRP_DEST_RGB1_PTR + + 4 * bufnum)); + } + } else { + if (readl(pcdev->base_emma + PRP_DEST_Y_PTR - + 0x14 * bufnum) != phys) { + dev_err(pcdev->dev, "%p != %p\n", phys, + readl(pcdev->base_emma + + PRP_DEST_Y_PTR - + 0x14 * bufnum)); + } } #endif dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, @@ -1211,14 +1376,29 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, list_del(&vb->queue); vb->state = state; do_gettimeofday(&vb->ts); - vb->field_count++; + vb->field_count = pcdev->frame_count * 2; + pcdev->frame_count++; wake_up(&vb->done); } if (list_empty(&pcdev->capture)) { - writel(pcdev->discard_buffer_dma, pcdev->base_emma + - PRP_DEST_RGB1_PTR + 4 * bufnum); + if (prp->cfg.channel == 1) { + writel(pcdev->discard_buffer_dma, pcdev->base_emma + + PRP_DEST_RGB1_PTR + 4 * bufnum); + } else { + writel(pcdev->discard_buffer_dma, pcdev->base_emma + + PRP_DEST_Y_PTR - + 0x14 * bufnum); + if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { + writel(pcdev->discard_buffer_dma + imgsize, + pcdev->base_emma + PRP_DEST_CB_PTR - + 0x14 * bufnum); + writel(pcdev->discard_buffer_dma + + ((5 * imgsize) / 4), pcdev->base_emma + + PRP_DEST_CR_PTR - 0x14 * bufnum); + } + } return; } @@ -1233,7 +1413,18 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, vb->state = VIDEOBUF_ACTIVE; phys = videobuf_to_dma_contig(vb); - writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); + if (prp->cfg.channel == 1) { + writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); + } else { + writel(phys, pcdev->base_emma + + PRP_DEST_Y_PTR - 0x14 * bufnum); + if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { + writel(phys + imgsize, pcdev->base_emma + + PRP_DEST_CB_PTR - 0x14 * bufnum); + writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + + PRP_DEST_CR_PTR - 0x14 * bufnum); + } + } } static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) @@ -1253,10 +1444,12 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) * the next one. */ cntl = readl(pcdev->base_emma + PRP_CNTL); - writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL); + writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN), + pcdev->base_emma + PRP_CNTL); writel(cntl, pcdev->base_emma + PRP_CNTL); } - if ((status & (3 << 5)) == (3 << 5) + if ((((status & (3 << 5)) == (3 << 5)) || + ((status & (3 << 3)) == (3 << 3))) && !list_empty(&pcdev->active_bufs)) { /* * Both buffers have triggered, process the one we're expecting @@ -1267,9 +1460,9 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ } - if (status & (1 << 6)) + if ((status & (1 << 6)) || (status & (1 << 4))) mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); - if (status & (1 << 5)) + if ((status & (1 << 5)) || (status & (1 << 3))) mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); writel(status, pcdev->base_emma + PRP_INTRSTATUS); diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index f96f92f00f92..74522773e934 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -287,7 +287,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) sg_dma_len(sg) = new_size; txd = ichan->dma_chan.device->device_prep_slave_sg( - &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, + &ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (!txd) goto error; @@ -982,12 +982,13 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, return 0; } -static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +static int mx3_camera_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + u32 pixfmt = icd->current_fmt->host_fmt->fourcc; unsigned long bus_flags, common_flags; u32 dw, sens_conf; const struct soc_mbus_pixelfmt *fmt; @@ -1285,19 +1286,7 @@ static struct platform_driver mx3_camera_driver = { .remove = __devexit_p(mx3_camera_remove), }; - -static int __init mx3_camera_init(void) -{ - return platform_driver_register(&mx3_camera_driver); -} - -static void __exit mx3_camera_exit(void) -{ - platform_driver_unregister(&mx3_camera_driver); -} - -module_init(mx3_camera_init); -module_exit(mx3_camera_exit); +module_platform_driver(mx3_camera_driver); MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>"); diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index ee0d0b39cd17..1fb7d5bd5ec2 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -70,9 +70,9 @@ static u32 video1_numbuffers = 3; static u32 video2_numbuffers = 3; static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE; static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE; -static u32 vid1_static_vrfb_alloc; -static u32 vid2_static_vrfb_alloc; -static int debug; +static bool vid1_static_vrfb_alloc; +static bool vid2_static_vrfb_alloc; +static bool debug; /* Module parameters */ module_param(video1_numbuffers, uint, S_IRUGO); @@ -424,7 +424,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout, "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n" "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n" "out_height=%d rotation_type=%d screen_width=%d\n", - __func__, info.enabled, info.paddr, info.width, info.height, + __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height, info.color_mode, info.rotation, info.mirror, info.pos_x, info.pos_y, info.out_width, info.out_height, info.rotation_type, info.screen_width); @@ -524,10 +524,50 @@ static int omapvid_apply_changes(struct omap_vout_device *vout) return 0; } +static int omapvid_handle_interlace_display(struct omap_vout_device *vout, + unsigned int irqstatus, struct timeval timevalue) +{ + u32 fid; + + if (vout->first_int) { + vout->first_int = 0; + goto err; + } + + if (irqstatus & DISPC_IRQ_EVSYNC_ODD) + fid = 1; + else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) + fid = 0; + else + goto err; + + vout->field_id ^= 1; + if (fid != vout->field_id) { + if (fid == 0) + vout->field_id = fid; + } else if (0 == fid) { + if (vout->cur_frm == vout->next_frm) + goto err; + + vout->cur_frm->ts = timevalue; + vout->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&vout->cur_frm->done); + vout->cur_frm = vout->next_frm; + } else { + if (list_empty(&vout->dma_queue) || + (vout->cur_frm != vout->next_frm)) + goto err; + } + + return vout->field_id; +err: + return 0; +} + static void omap_vout_isr(void *arg, unsigned int irqstatus) { - int ret; - u32 addr, fid; + int ret, fid, mgr_id; + u32 addr, irq; struct omap_overlay *ovl; struct timeval timevalue; struct omapvideo_info *ovid; @@ -543,112 +583,73 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) if (!ovl->manager || !ovl->manager->device) return; + mgr_id = ovl->manager->id; cur_display = ovl->manager->device; spin_lock(&vout->vbq_lock); do_gettimeofday(&timevalue); - if (cur_display->type != OMAP_DISPLAY_TYPE_VENC) { - switch (cur_display->type) { - case OMAP_DISPLAY_TYPE_DPI: - if (!(irqstatus & (DISPC_IRQ_VSYNC | DISPC_IRQ_VSYNC2))) - goto vout_isr_err; - break; - case OMAP_DISPLAY_TYPE_HDMI: - if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN)) - goto vout_isr_err; - break; - default: - goto vout_isr_err; - } - if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { - vout->cur_frm->ts = timevalue; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); - vout->cur_frm = vout->next_frm; - } - vout->first_int = 0; - if (list_empty(&vout->dma_queue)) + switch (cur_display->type) { + case OMAP_DISPLAY_TYPE_DSI: + case OMAP_DISPLAY_TYPE_DPI: + if (mgr_id == OMAP_DSS_CHANNEL_LCD) + irq = DISPC_IRQ_VSYNC; + else if (mgr_id == OMAP_DSS_CHANNEL_LCD2) + irq = DISPC_IRQ_VSYNC2; + else goto vout_isr_err; - vout->next_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vout->next_frm->queue); - - vout->next_frm->state = VIDEOBUF_ACTIVE; + if (!(irqstatus & irq)) + goto vout_isr_err; + break; + case OMAP_DISPLAY_TYPE_VENC: + fid = omapvid_handle_interlace_display(vout, irqstatus, + timevalue); + if (!fid) + goto vout_isr_err; + break; + case OMAP_DISPLAY_TYPE_HDMI: + if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN)) + goto vout_isr_err; + break; + default: + goto vout_isr_err; + } - addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i] - + vout->cropped_offset; + if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { + vout->cur_frm->ts = timevalue; + vout->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&vout->cur_frm->done); + vout->cur_frm = vout->next_frm; + } - /* First save the configuration in ovelray structure */ - ret = omapvid_init(vout, addr); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to set overlay info\n"); - /* Enable the pipeline and set the Go bit */ - ret = omapvid_apply_changes(vout); - if (ret) - printk(KERN_ERR VOUT_NAME "failed to change mode\n"); - } else { + vout->first_int = 0; + if (list_empty(&vout->dma_queue)) + goto vout_isr_err; - if (vout->first_int) { - vout->first_int = 0; - goto vout_isr_err; - } - if (irqstatus & DISPC_IRQ_EVSYNC_ODD) - fid = 1; - else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) - fid = 0; - else - goto vout_isr_err; + vout->next_frm = list_entry(vout->dma_queue.next, + struct videobuf_buffer, queue); + list_del(&vout->next_frm->queue); - vout->field_id ^= 1; - if (fid != vout->field_id) { - if (0 == fid) - vout->field_id = fid; + vout->next_frm->state = VIDEOBUF_ACTIVE; - goto vout_isr_err; - } - if (0 == fid) { - if (vout->cur_frm == vout->next_frm) - goto vout_isr_err; - - vout->cur_frm->ts = timevalue; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); - vout->cur_frm = vout->next_frm; - } else if (1 == fid) { - if (list_empty(&vout->dma_queue) || - (vout->cur_frm != vout->next_frm)) - goto vout_isr_err; - - vout->next_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vout->next_frm->queue); - - vout->next_frm->state = VIDEOBUF_ACTIVE; - addr = (unsigned long) - vout->queued_buf_addr[vout->next_frm->i] + - vout->cropped_offset; - /* First save the configuration in ovelray structure */ - ret = omapvid_init(vout, addr); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to set overlay info\n"); - /* Enable the pipeline and set the Go bit */ - ret = omapvid_apply_changes(vout); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to change mode\n"); - } + addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i] + + vout->cropped_offset; - } + /* First save the configuration in ovelray structure */ + ret = omapvid_init(vout, addr); + if (ret) + printk(KERN_ERR VOUT_NAME + "failed to set overlay info\n"); + /* Enable the pipeline and set the Go bit */ + ret = omapvid_apply_changes(vout); + if (ret) + printk(KERN_ERR VOUT_NAME "failed to change mode\n"); vout_isr_err: spin_unlock(&vout->vbq_lock); } - /* Video buffer call backs */ /* @@ -664,10 +665,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, u32 phy_addr = 0, virt_addr = 0; struct omap_vout_device *vout = q->priv_data; struct omapvideo_info *ovid = &vout->vid_info; + int vid_max_buf_size; if (!vout) return -EINVAL; + vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize : + video2_bufsize; + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) return -EINVAL; @@ -690,7 +695,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, video1_numbuffers : video2_numbuffers; /* Check the size of the buffer */ - if (*size > vout->buffer_size) { + if (*size > vid_max_buf_size) { v4l2_err(&vout->vid_dev->v4l2_dev, "buffer allocation mismatch [%u] [%u]\n", *size, vout->buffer_size); @@ -943,12 +948,8 @@ 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_overlay_info info; - ovl->get_overlay_info(ovl, &info); - info.enabled = 0; - ovl->set_overlay_info(ovl, &info); - } + if (ovl->manager && ovl->manager->device) + ovl->disable(ovl); } /* Turn off the pipeline */ ret = omapvid_apply_changes(vout); @@ -1041,7 +1042,8 @@ static int vidioc_querycap(struct file *file, void *fh, strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver)); strlcpy(cap->card, vout->vfd->name, sizeof(cap->card)); cap->bus_info[0] = '\0'; - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT; + cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; return 0; } @@ -1668,7 +1670,6 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) if (ovl->manager && ovl->manager->device) { struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); - info.enabled = 1; info.paddr = addr; if (ovl->set_overlay_info(ovl, &info)) { ret = -EINVAL; @@ -1687,6 +1688,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) if (ret) v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); + for (j = 0; j < ovid->num_overlays; j++) { + struct omap_overlay *ovl = ovid->overlays[j]; + + if (ovl->manager && ovl->manager->device) { + ret = ovl->enable(ovl); + if (ret) + goto streamon_err1; + } + } + ret = 0; streamon_err1: @@ -1716,16 +1727,8 @@ 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]; - if (ovl->manager && ovl->manager->device) { - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - info.enabled = 0; - ret = ovl->set_overlay_info(ovl, &info); - if (ret) - v4l2_err(&vout->vid_dev->v4l2_dev, - "failed to update overlay info in streamoff\n"); - } + if (ovl->manager && ovl->manager->device) + ovl->disable(ovl); } /* Turn of the pipeline */ @@ -1823,7 +1826,9 @@ static int vidioc_g_fbuf(struct file *file, void *fh, ovid = &vout->vid_info; ovl = ovid->overlays[0]; - a->flags = 0x0; + /* The video overlay must stay within the framebuffer and can't be + positioned independently. */ + a->flags = V4L2_FBUF_FLAG_OVERLAY; a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY | V4L2_FBUF_CAP_SRC_CHROMAKEY; diff --git a/drivers/media/video/omap/omap_vout_vrfb.c b/drivers/media/video/omap/omap_vout_vrfb.c index ebebcac49225..4be26abf6cea 100644 --- a/drivers/media/video/omap/omap_vout_vrfb.c +++ b/drivers/media/video/omap/omap_vout_vrfb.c @@ -84,7 +84,7 @@ void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) } int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, - u32 static_vrfb_allocation) + bool static_vrfb_allocation) { int ret = 0, i, j; struct omap_vout_device *vout; diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h index d793501cafcc..27a95d23b913 100644 --- a/drivers/media/video/omap/omap_voutdef.h +++ b/drivers/media/video/omap/omap_voutdef.h @@ -25,7 +25,7 @@ #define MAC_VRFB_CTXS 4 #define MAX_VOUT_DEV 2 #define MAX_OVLS 3 -#define MAX_DISPLAYS 3 +#define MAX_DISPLAYS 10 #define MAX_MANAGERS 3 #define QQVGA_WIDTH 160 diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index 6a6cf388bae4..c20f5ecd6790 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c @@ -1436,13 +1436,13 @@ static int omap1_cam_querycap(struct soc_camera_host *ici, return 0; } -static int omap1_cam_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) +static int omap1_cam_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct omap1_cam_dev *pcdev = ici->priv; + u32 pixfmt = icd->current_fmt->host_fmt->fourcc; const struct soc_camera_format_xlate *xlate; const struct soc_mbus_pixelfmt *fmt; struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; @@ -1713,17 +1713,7 @@ static struct platform_driver omap1_cam_driver = { .remove = __exit_p(omap1_cam_remove), }; -static int __init omap1_cam_init(void) -{ - return platform_driver_register(&omap1_cam_driver); -} -module_init(omap1_cam_init); - -static void __exit omap1_cam_exit(void) -{ - platform_driver_unregister(&omap1_cam_driver); -} -module_exit(omap1_cam_exit); +module_platform_driver(omap1_cam_driver); module_param(sg_mode, bool, 0644); MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg"); diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index 45522e603185..7d3864144368 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c @@ -1868,21 +1868,7 @@ static struct platform_driver omap24xxcam_driver = { }, }; -/* - * - * Module initialisation and deinitialisation - * - */ - -static int __init omap24xxcam_init(void) -{ - return platform_driver_register(&omap24xxcam_driver); -} - -static void __exit omap24xxcam_cleanup(void) -{ - platform_driver_unregister(&omap24xxcam_driver); -} +module_platform_driver(omap24xxcam_driver); MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>"); MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver"); @@ -1894,6 +1880,3 @@ MODULE_PARM_DESC(video_nr, module_param(capture_mem, int, 0); MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture " "buffers (default 4800kiB)"); - -module_init(omap24xxcam_init); -module_exit(omap24xxcam_cleanup); diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index d4c48ef227fb..12d5f923e1d0 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -403,6 +403,7 @@ static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus) static void isp_isr_sbl(struct isp_device *isp) { struct device *dev = isp->dev; + struct isp_pipeline *pipe; u32 sbl_pcr; /* @@ -416,27 +417,38 @@ static void isp_isr_sbl(struct isp_device *isp) if (sbl_pcr) dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr); - if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF - | ISPSBL_PCR_CSIB_WBL_OVF)) { - isp->isp_ccdc.error = 1; - if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW) - isp->isp_prev.error = 1; - if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER) - isp->isp_res.error = 1; + if (sbl_pcr & ISPSBL_PCR_CSIB_WBL_OVF) { + pipe = to_isp_pipeline(&isp->isp_ccp2.subdev.entity); + if (pipe != NULL) + pipe->error = true; + } + + if (sbl_pcr & ISPSBL_PCR_CSIA_WBL_OVF) { + pipe = to_isp_pipeline(&isp->isp_csi2a.subdev.entity); + if (pipe != NULL) + pipe->error = true; + } + + if (sbl_pcr & ISPSBL_PCR_CCDC_WBL_OVF) { + pipe = to_isp_pipeline(&isp->isp_ccdc.subdev.entity); + if (pipe != NULL) + pipe->error = true; } if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) { - isp->isp_prev.error = 1; - if (isp->isp_res.input == RESIZER_INPUT_VP && - !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)) - isp->isp_res.error = 1; + pipe = to_isp_pipeline(&isp->isp_prev.subdev.entity); + if (pipe != NULL) + pipe->error = true; } if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF | ISPSBL_PCR_RSZ2_WBL_OVF | ISPSBL_PCR_RSZ3_WBL_OVF - | ISPSBL_PCR_RSZ4_WBL_OVF)) - isp->isp_res.error = 1; + | ISPSBL_PCR_RSZ4_WBL_OVF)) { + pipe = to_isp_pipeline(&isp->isp_res.subdev.entity); + if (pipe != NULL) + pipe->error = true; + } if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF) omap3isp_stat_sbl_overflow(&isp->isp_af); @@ -464,24 +476,17 @@ static irqreturn_t isp_isr(int irq, void *_isp) IRQ0STATUS_HS_VS_IRQ; struct isp_device *isp = _isp; u32 irqstatus; - int ret; irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_isr_sbl(isp); - if (irqstatus & IRQ0STATUS_CSIA_IRQ) { - ret = omap3isp_csi2_isr(&isp->isp_csi2a); - if (ret) - isp->isp_ccdc.error = 1; - } + if (irqstatus & IRQ0STATUS_CSIA_IRQ) + omap3isp_csi2_isr(&isp->isp_csi2a); - if (irqstatus & IRQ0STATUS_CSIB_IRQ) { - ret = omap3isp_ccp2_isr(&isp->isp_ccp2); - if (ret) - isp->isp_ccdc.error = 1; - } + if (irqstatus & IRQ0STATUS_CSIB_IRQ) + omap3isp_ccp2_isr(&isp->isp_ccp2); if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) { if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW) @@ -2222,24 +2227,7 @@ static struct platform_driver omap3isp_driver = { }, }; -/* - * isp_init - ISP module initialization. - */ -static int __init isp_init(void) -{ - return platform_driver_register(&omap3isp_driver); -} - -/* - * isp_cleanup - ISP module cleanup. - */ -static void __exit isp_cleanup(void) -{ - platform_driver_unregister(&omap3isp_driver); -} - -module_init(isp_init); -module_exit(isp_cleanup); +module_platform_driver(omap3isp_driver); MODULE_AUTHOR("Nokia Corporation"); MODULE_DESCRIPTION("TI OMAP3 ISP driver"); diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index d341ba12593f..a74a79701d34 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1406,9 +1406,8 @@ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) { - struct isp_pipeline *pipe = - to_isp_pipeline(&ccdc->video_out.video.entity); - struct video_device *vdev = ccdc->subdev.devnode; + struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); + struct video_device *vdev = &ccdc->subdev.devnode; struct v4l2_event event; memset(&event, 0, sizeof(event)); @@ -1428,8 +1427,11 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events) unsigned long flags; if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) { + struct isp_pipeline *pipe = + to_isp_pipeline(&ccdc->subdev.entity); + ccdc_lsc_error_handler(ccdc); - ccdc->error = 1; + pipe->error = true; dev_dbg(to_device(ccdc), "lsc prefetch error\n"); } @@ -1504,7 +1506,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) goto done; } - buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error); + buffer = omap3isp_video_buffer_next(&ccdc->video_out); if (buffer != NULL) { ccdc_set_outaddr(ccdc, buffer->isp_addr); restart = 1; @@ -1518,7 +1520,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) ISP_PIPELINE_STREAM_SINGLESHOT); done: - ccdc->error = 0; return restart; } @@ -1744,7 +1745,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) */ ccdc_config_vp(ccdc); ccdc_enable_vp(ccdc, 1); - ccdc->error = 0; ccdc_print_status(ccdc); } diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h index 483a19cac1ad..6d0264bab75b 100644 --- a/drivers/media/video/omap3isp/ispccdc.h +++ b/drivers/media/video/omap3isp/ispccdc.h @@ -150,7 +150,6 @@ struct ispccdc_lsc { * @input: Active input * @output: Active outputs * @video_out: Output video node - * @error: A hardware error occurred during capture * @alaw: A-law compression enabled (1) or disabled (0) * @lpf: Low pass filter enabled (1) or disabled (0) * @obclamp: Optical-black clamp enabled (1) or disabled (0) @@ -178,7 +177,6 @@ struct isp_ccdc_device { enum ccdc_input_entity input; unsigned int output; struct isp_video video_out; - unsigned int error; unsigned int alaw:1, lpf:1, diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index 904ca8c8b17f..70ddbf35b223 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -556,7 +556,7 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); struct isp_buffer *buffer; - buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error); + buffer = omap3isp_video_buffer_next(&ccp2->video_in); if (buffer != NULL) ccp2_set_inaddr(ccp2, buffer->isp_addr); @@ -567,8 +567,6 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_SINGLESHOT); } - - ccp2->error = 0; } /* @@ -576,13 +574,11 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) * @ccp2: Pointer to ISP CCP2 device * * This will handle the CCP2 interrupts - * - * Returns -EIO in case of error, or 0 on success. */ -int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) +void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) { + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); struct isp_device *isp = to_isp_device(ccp2); - int ret = 0; static const u32 ISPCCP2_LC01_ERROR = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | @@ -604,19 +600,18 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) ISPCCP2_LCM_IRQSTATUS); /* Errors */ if (lcx_irqstatus & ISPCCP2_LC01_ERROR) { - ccp2->error = 1; + pipe->error = true; dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus); - return -EIO; + return; } if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) { - ccp2->error = 1; + pipe->error = true; dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus); - ret = -EIO; } if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping)) - return 0; + return; /* Frame number propagation */ if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) { @@ -629,8 +624,6 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) /* Handle queued buffers on frame end interrupts */ if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ) ccp2_isr_buffer(ccp2); - - return ret; } /* ----------------------------------------------------------------------------- @@ -867,7 +860,6 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable) if (enable == ISP_PIPELINE_STREAM_STOPPED) return 0; atomic_set(&ccp2->stopping, 0); - ccp2->error = 0; } switch (enable) { diff --git a/drivers/media/video/omap3isp/ispccp2.h b/drivers/media/video/omap3isp/ispccp2.h index 6674e9de2cd7..76d65f4576ef 100644 --- a/drivers/media/video/omap3isp/ispccp2.h +++ b/drivers/media/video/omap3isp/ispccp2.h @@ -82,7 +82,6 @@ struct isp_ccp2_device { struct isp_video video_in; struct isp_csiphy *phy; struct regulator *vdds_csib; - unsigned int error; enum isp_pipeline_stream_state state; wait_queue_head_t wait; atomic_t stopping; @@ -94,6 +93,6 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp); int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, struct v4l2_device *vdev); void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2); -int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2); +void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2); #endif /* OMAP3_ISP_CCP2_H */ diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 0c5f1cb9d99d..fcb5168996a7 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -667,7 +667,7 @@ static void csi2_isr_buffer(struct isp_csi2_device *csi2) csi2_ctx_enable(isp, csi2, 0, 0); - buffer = omap3isp_video_buffer_next(&csi2->video_out, 0); + buffer = omap3isp_video_buffer_next(&csi2->video_out); /* * Let video queue operation restart engine if there is an underrun @@ -727,17 +727,15 @@ static void csi2_isr_ctx(struct isp_csi2_device *csi2, /* * omap3isp_csi2_isr - CSI2 interrupt handling. - * - * Return -EIO on Transmission error */ -int omap3isp_csi2_isr(struct isp_csi2_device *csi2) +void omap3isp_csi2_isr(struct isp_csi2_device *csi2) { + struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); u32 csi2_irqstatus, cpxio1_irqstatus; struct isp_device *isp = csi2->isp; - int retval = 0; if (!csi2->available) - return -ENODEV; + return; csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS); isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS); @@ -750,7 +748,7 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2) csi2->regs1, ISPCSI2_PHY_IRQSTATUS); dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ " "%x\n", cpxio1_irqstatus); - retval = -EIO; + pipe->error = true; } if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | @@ -775,11 +773,11 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2) ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0); - retval = -EIO; + pipe->error = true; } if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) - return 0; + return; /* Successful cases */ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) @@ -787,8 +785,6 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2) if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) dev_dbg(isp->dev, "CSI2: ECC correction done\n"); - - return retval; } /* ----------------------------------------------------------------------------- diff --git a/drivers/media/video/omap3isp/ispcsi2.h b/drivers/media/video/omap3isp/ispcsi2.h index 456fb7fb8a0f..885ad79a7678 100644 --- a/drivers/media/video/omap3isp/ispcsi2.h +++ b/drivers/media/video/omap3isp/ispcsi2.h @@ -156,7 +156,7 @@ struct isp_csi2_device { atomic_t stopping; }; -int omap3isp_csi2_isr(struct isp_csi2_device *csi2); +void omap3isp_csi2_isr(struct isp_csi2_device *csi2); int omap3isp_csi2_reset(struct isp_csi2_device *csi2); int omap3isp_csi2_init(struct isp_device *isp); void omap3isp_csi2_cleanup(struct isp_device *isp); diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index ccb876fe023f..6d0fb2c8c26d 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -116,11 +116,11 @@ static struct omap3isp_prev_csc flr_prev_csc = { #define PREV_MIN_IN_HEIGHT 8 #define PREV_MAX_IN_HEIGHT 16384 -#define PREV_MIN_OUT_WIDTH 0 -#define PREV_MIN_OUT_HEIGHT 0 -#define PREV_MAX_OUT_WIDTH 1280 -#define PREV_MAX_OUT_WIDTH_ES2 3300 -#define PREV_MAX_OUT_WIDTH_3630 4096 +#define PREV_MIN_OUT_WIDTH 0 +#define PREV_MIN_OUT_HEIGHT 0 +#define PREV_MAX_OUT_WIDTH_REV_1 1280 +#define PREV_MAX_OUT_WIDTH_REV_2 3300 +#define PREV_MAX_OUT_WIDTH_REV_15 4096 /* * Coeficient Tables for the submodules in Preview. @@ -1306,14 +1306,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) switch (isp->revision) { case ISP_REVISION_1_0: - return PREV_MAX_OUT_WIDTH; + return PREV_MAX_OUT_WIDTH_REV_1; case ISP_REVISION_2_0: default: - return PREV_MAX_OUT_WIDTH_ES2; + return PREV_MAX_OUT_WIDTH_REV_2; case ISP_REVISION_15_0: - return PREV_MAX_OUT_WIDTH_3630; + return PREV_MAX_OUT_WIDTH_REV_15; } } @@ -1404,16 +1404,14 @@ static void preview_isr_buffer(struct isp_prev_device *prev) int restart = 0; if (prev->input == PREVIEW_INPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&prev->video_in, - prev->error); + buffer = omap3isp_video_buffer_next(&prev->video_in); if (buffer != NULL) preview_set_inaddr(prev, buffer->isp_addr); pipe->state |= ISP_PIPELINE_IDLE_INPUT; } if (prev->output & PREVIEW_OUTPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&prev->video_out, - prev->error); + buffer = omap3isp_video_buffer_next(&prev->video_out); if (buffer != NULL) { preview_set_outaddr(prev, buffer->isp_addr); restart = 1; @@ -1440,8 +1438,6 @@ static void preview_isr_buffer(struct isp_prev_device *prev) default: return; } - - prev->error = 0; } /* @@ -1565,7 +1561,6 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable) omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW); preview_configure(prev); atomic_set(&prev->stopping, 0); - prev->error = 0; preview_print_status(prev); } diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index f54e775c2df4..09686607973c 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h @@ -157,7 +157,6 @@ struct isptables_update { * @output: Bitmask of the active output * @video_in: Input video entity * @video_out: Output video entity - * @error: A hardware error occurred during capture * @params: Module configuration data * @shadow_update: If set, update the hardware configured in the next interrupt * @underrun: Whether the preview entity has queued buffers on the output @@ -179,7 +178,6 @@ struct isp_prev_device { unsigned int output; struct isp_video video_in; struct isp_video video_out; - unsigned int error; struct prev_params params; unsigned int shadow_update:1; diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 50e593bfcfaf..6958a9e3dc22 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1038,7 +1038,7 @@ static void resizer_isr_buffer(struct isp_res_device *res) /* Complete the output buffer and, if reading from memory, the input * buffer. */ - buffer = omap3isp_video_buffer_next(&res->video_out, res->error); + buffer = omap3isp_video_buffer_next(&res->video_out); if (buffer != NULL) { resizer_set_outaddr(res, buffer->isp_addr); restart = 1; @@ -1047,7 +1047,7 @@ static void resizer_isr_buffer(struct isp_res_device *res) pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; if (res->input == RESIZER_INPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&res->video_in, 0); + buffer = omap3isp_video_buffer_next(&res->video_in); if (buffer != NULL) resizer_set_inaddr(res, buffer->isp_addr); pipe->state |= ISP_PIPELINE_IDLE_INPUT; @@ -1064,8 +1064,6 @@ static void resizer_isr_buffer(struct isp_res_device *res) if (restart) resizer_enable_oneshot(res); } - - res->error = 0; } /* @@ -1154,7 +1152,6 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable) omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER); resizer_configure(res); - res->error = 0; resizer_print_status(res); } diff --git a/drivers/media/video/omap3isp/ispresizer.h b/drivers/media/video/omap3isp/ispresizer.h index 76abc2e42126..70c1c0e1bbdf 100644 --- a/drivers/media/video/omap3isp/ispresizer.h +++ b/drivers/media/video/omap3isp/ispresizer.h @@ -107,7 +107,6 @@ struct isp_res_device { enum resizer_input_entity input; struct isp_video video_in; struct isp_video video_out; - unsigned int error; u32 addr_base; /* stored source buffer address in memory mode */ u32 crop_offset; /* additional offset for crop in memory mode */ diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index bd3aebafafa0..b02070057724 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -211,14 +211,14 @@ static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix, mbus->width = pix->width; mbus->height = pix->height; - for (i = 0; i < ARRAY_SIZE(formats); ++i) { + /* Skip the last format in the loop so that it will be selected if no + * match is found. + */ + for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) { if (formats[i].pixelformat == pix->pixelformat) break; } - if (WARN_ON(i == ARRAY_SIZE(formats))) - return; - mbus->code = formats[i].code; mbus->colorspace = pix->colorspace; mbus->field = pix->field; @@ -581,21 +581,20 @@ static const struct isp_video_queue_operations isp_video_queue_ops = { /* * omap3isp_video_buffer_next - Complete the current buffer and return the next * @video: ISP video object - * @error: Whether an error occurred during capture * * Remove the current video buffer from the DMA queue and fill its timestamp, * field count and state fields before waking up its completion handler. * - * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0) - * or VIDEOBUF_ERROR otherwise (@error is non-zero). + * For capture video nodes the buffer state is set to ISP_BUF_STATE_DONE if no + * error has been flagged in the pipeline, or to ISP_BUF_STATE_ERROR otherwise. + * For video output nodes the buffer state is always set to ISP_BUF_STATE_DONE. * * The DMA queue is expected to contain at least one buffer. * * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is * empty. */ -struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, - unsigned int error) +struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) { struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); struct isp_video_queue *queue = video->queue; @@ -630,7 +629,13 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, else buf->vbuf.sequence = atomic_read(&pipe->frame_number); - buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE; + /* Report pipeline errors to userspace on the capture device side. */ + if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) { + buf->state = ISP_BUF_STATE_ERROR; + pipe->error = false; + } else { + buf->state = ISP_BUF_STATE_DONE; + } wake_up(&buf->wait); @@ -1016,6 +1021,8 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) if (ret < 0) goto error; + pipe->error = false; + spin_lock_irqsave(&pipe->lock, flags); pipe->state &= ~ISP_PIPELINE_STREAM; pipe->state |= state; diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 08cbfa144e6e..d91bdb919be0 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -85,6 +85,10 @@ enum isp_pipeline_state { ISP_PIPELINE_STREAM = 64, }; +/* + * struct isp_pipeline - An ISP hardware pipeline + * @error: A hardware error occurred during capture + */ struct isp_pipeline { struct media_pipeline pipe; spinlock_t lock; /* Pipeline state and queue flags */ @@ -96,6 +100,7 @@ struct isp_pipeline { unsigned int max_rate; atomic_t frame_number; bool do_propagation; /* of frame number */ + bool error; struct v4l2_fract max_timeperframe; }; @@ -194,8 +199,7 @@ void omap3isp_video_cleanup(struct isp_video *video); int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev); void omap3isp_video_unregister(struct isp_video *video); -struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, - unsigned int error); +struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video); void omap3isp_video_resume(struct isp_video *video, int continuous); struct media_pad *omap3isp_video_remote_pad(struct isp_video *video); diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 8aa058531280..6a564964853a 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -25,7 +25,7 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 122b45760f0d..ebc2c7e39233 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2546,8 +2546,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, } /* Define and configure additional controls from cx2341x module. */ - hdw->mpeg_ctrl_info = kzalloc( - sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL); + hdw->mpeg_ctrl_info = kcalloc(MPEGDEF_COUNT, + sizeof(*(hdw->mpeg_ctrl_info)), + GFP_KERNEL); if (!hdw->mpeg_ctrl_info) goto fail; for (idx = 0; idx < MPEGDEF_COUNT; idx++) { cptr = hdw->controls + idx + CTRLDEF_COUNT; diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 3977addf3ba8..1f506fde97d0 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -102,52 +102,18 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = #include "pwc-nala.h" }; -static void pwc_set_image_buffer_size(struct pwc_device *pdev); - /****************************************************************************/ -static int _send_control_msg(struct pwc_device *pdev, - u8 request, u16 value, int index, void *buf, int buflen) -{ - int rc; - void *kbuf = NULL; - - if (buflen) { - kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */ - if (kbuf == NULL) - return -ENOMEM; - memcpy(kbuf, buf, buflen); - } - - rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - kbuf, buflen, USB_CTRL_SET_TIMEOUT); - - kfree(kbuf); - return rc; -} - static int recv_control_msg(struct pwc_device *pdev, - u8 request, u16 value, void *buf, int buflen) + u8 request, u16 value, int recv_count) { int rc; - void *kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */ - - if (kbuf == NULL) - return -ENOMEM; rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), request, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - pdev->vcinterface, - kbuf, buflen, USB_CTRL_GET_TIMEOUT); - memcpy(buf, kbuf, buflen); - kfree(kbuf); - + value, pdev->vcinterface, + pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT); if (rc < 0) PWC_ERROR("recv_control_msg error %d req %02x val %04x\n", rc, request, value); @@ -155,26 +121,39 @@ static int recv_control_msg(struct pwc_device *pdev, } static inline int send_video_command(struct pwc_device *pdev, - int index, void *buf, int buflen) + int index, const unsigned char *buf, int buflen) { - return _send_control_msg(pdev, - SET_EP_STREAM_CTL, - VIDEO_OUTPUT_CONTROL_FORMATTER, - index, - buf, buflen); + int rc; + + memcpy(pdev->ctrl_buf, buf, buflen); + + rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + SET_EP_STREAM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + VIDEO_OUTPUT_CONTROL_FORMATTER, index, + pdev->ctrl_buf, buflen, USB_CTRL_SET_TIMEOUT); + if (rc >= 0) + memcpy(pdev->cmd_buf, buf, buflen); + else + PWC_ERROR("send_video_command error %d\n", rc); + + return rc; } int send_control_msg(struct pwc_device *pdev, u8 request, u16 value, void *buf, int buflen) { - return _send_control_msg(pdev, - request, value, pdev->vcinterface, buf, buflen); + return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, pdev->vcinterface, + buf, buflen, USB_CTRL_SET_TIMEOUT); } -static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) +static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt, + int frames, int *compression, int send_to_cam) { - unsigned char buf[3]; - int ret, fps; + int fps, ret = 0; struct Nala_table_entry *pEntry; int frames2frames[31] = { /* closest match of framerate */ @@ -196,35 +175,34 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) 7 /* 30 */ }; - if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) + if (size < 0 || size > PSZ_CIF) return -EINVAL; + if (frames < 4) + frames = 4; + else if (frames > 25) + frames = 25; frames = frames2frames[frames]; fps = frames2table[frames]; pEntry = &Nala_table[size][fps]; if (pEntry->alternate == 0) return -EINVAL; - memcpy(buf, pEntry->mode, 3); - ret = send_video_command(pdev, pdev->vendpoint, buf, 3); - if (ret < 0) { - PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret); + if (send_to_cam) + ret = send_video_command(pdev, pdev->vendpoint, + pEntry->mode, 3); + if (ret < 0) return ret; - } - if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - ret = pwc_dec1_init(pdev, pdev->type, pdev->release, buf); - if (ret < 0) - return ret; - } - pdev->cmd_len = 3; - memcpy(pdev->cmd_buf, buf, 3); + if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420) + pwc_dec1_init(pdev, pEntry->mode); /* Set various parameters */ + pdev->pixfmt = pixfmt; pdev->vframes = frames; - pdev->vsize = size; pdev->valternate = pEntry->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; + pdev->width = pwc_image_sizes[size][0]; + pdev->height = pwc_image_sizes[size][1]; + pdev->frame_size = (pdev->width * pdev->height * 3) / 2; if (pEntry->compressed) { if (pdev->release < 5) { /* 4 fold compression */ pdev->vbandlength = 528; @@ -237,183 +215,142 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) } else pdev->vbandlength = 0; + + /* Let pwc-if.c:isoc_init know we don't support higher compression */ + *compression = 3; + return 0; } -static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, + int frames, int *compression, int send_to_cam) { - unsigned char buf[13]; const struct Timon_table_entry *pChoose; - int ret, fps; + int fps, ret = 0; - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) + if (size >= PSZ_MAX || *compression < 0 || *compression > 3) return -EINVAL; + if (frames < 5) + frames = 5; + else if (size == PSZ_VGA && frames > 15) + frames = 15; + else if (frames > 30) + frames = 30; fps = (frames / 5) - 1; - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - */ + /* Find a supported framerate with progressively higher compression */ pChoose = NULL; - while (compression <= 3) { - pChoose = &Timon_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; + while (*compression <= 3) { + pChoose = &Timon_table[size][fps][*compression]; + if (pChoose->alternate != 0) + break; + (*compression)++; } if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ - memcpy(buf, pChoose->mode, 13); - if (snapshot) - buf[0] |= 0x80; - ret = send_video_command(pdev, pdev->vendpoint, buf, 13); + if (send_to_cam) + ret = send_video_command(pdev, pdev->vendpoint, + pChoose->mode, 13); if (ret < 0) return ret; - if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - ret = pwc_dec23_init(pdev, pdev->type, buf); - if (ret < 0) - return ret; - } - - pdev->cmd_len = 13; - memcpy(pdev->cmd_buf, buf, 13); + if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) + pwc_dec23_init(pdev, pChoose->mode); /* Set various parameters */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; + pdev->pixfmt = pixfmt; + pdev->vframes = (fps + 1) * 5; pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; + pdev->width = pwc_image_sizes[size][0]; + pdev->height = pwc_image_sizes[size][1]; pdev->vbandlength = pChoose->bandlength; if (pChoose->bandlength > 0) - pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; + pdev->frame_size = (pChoose->bandlength * pdev->height) / 4; else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; + pdev->frame_size = (pdev->width * pdev->height * 12) / 8; return 0; } -static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, + int frames, int *compression, int send_to_cam) { const struct Kiara_table_entry *pChoose = NULL; - int fps, ret; - unsigned char buf[12]; - struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; + int fps, ret = 0; - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) + if (size >= PSZ_MAX || *compression < 0 || *compression > 3) return -EINVAL; + if (frames < 5) + frames = 5; + else if (size == PSZ_VGA && frames > 15) + frames = 15; + else if (frames > 30) + frames = 30; fps = (frames / 5) - 1; - /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ - if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420) - { - /* Only available in case the raw palette is selected or - we have the decompressor available. This mode is - only available in compressed form - */ - PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n"); - pChoose = &RawEntry; - } - else - { - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - Skip this step when using RAW modes. - */ - snapshot = 0; - while (compression <= 3) { - pChoose = &Kiara_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; - } + /* Find a supported framerate with progressively higher compression */ + while (*compression <= 3) { + pChoose = &Kiara_table[size][fps][*compression]; + if (pChoose->alternate != 0) + break; + (*compression)++; } if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ - PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate); - - /* usb_control_msg won't take staticly allocated arrays as argument?? */ - memcpy(buf, pChoose->mode, 12); - if (snapshot) - buf[0] |= 0x80; - /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ - ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12); + if (send_to_cam) + ret = send_video_command(pdev, 4, pChoose->mode, 12); if (ret < 0) return ret; - if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - ret = pwc_dec23_init(pdev, pdev->type, buf); - if (ret < 0) - return ret; - } + if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) + pwc_dec23_init(pdev, pChoose->mode); - pdev->cmd_len = 12; - memcpy(pdev->cmd_buf, buf, 12); /* All set and go */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; + pdev->pixfmt = pixfmt; + pdev->vframes = (fps + 1) * 5; pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; + pdev->width = pwc_image_sizes[size][0]; + pdev->height = pwc_image_sizes[size][1]; pdev->vbandlength = pChoose->bandlength; if (pdev->vbandlength > 0) - pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; + pdev->frame_size = (pdev->vbandlength * pdev->height) / 4; else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n", - pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength); + pdev->frame_size = (pdev->width * pdev->height * 12) / 8; + PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n", + pdev->frame_size, pdev->vframes, size, pdev->vbandlength); return 0; } - - -/** - @pdev: device structure - @width: viewport width - @height: viewport height - @frame: framerate, in fps - @compression: preferred compression ratio - @snapshot: snapshot mode or streaming - */ -int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) +int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, + int pixfmt, int frames, int *compression, int send_to_cam) { int ret, size; - PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt); - size = pwc_decode_size(pdev, width, height); - if (size < 0) { - PWC_DEBUG_MODULE("Could not find suitable size.\n"); - return -ERANGE; - } + PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", + width, height, frames, pixfmt); + size = pwc_get_size(pdev, width, height); PWC_TRACE("decode_size = %d.\n", size); if (DEVICE_USE_CODEC1(pdev->type)) { - ret = set_video_mode_Nala(pdev, size, frames); - + ret = set_video_mode_Nala(pdev, size, pixfmt, frames, + compression, send_to_cam); } else if (DEVICE_USE_CODEC3(pdev->type)) { - ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); - + ret = set_video_mode_Kiara(pdev, size, pixfmt, frames, + compression, send_to_cam); } else { - ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); + ret = set_video_mode_Timon(pdev, size, pixfmt, frames, + compression, send_to_cam); } if (ret < 0) { PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); return ret; } - pdev->view.x = width; - pdev->view.y = height; - pdev->vcompression = compression; pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; - pwc_set_image_buffer_size(pdev); - PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); + PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height); return 0; } @@ -470,44 +407,15 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i return ret; } -static void pwc_set_image_buffer_size(struct pwc_device *pdev) -{ - int factor = 0; - - /* for V4L2_PIX_FMT_YUV420 */ - switch (pdev->pixfmt) { - case V4L2_PIX_FMT_YUV420: - factor = 6; - break; - case V4L2_PIX_FMT_PWC1: - case V4L2_PIX_FMT_PWC2: - factor = 6; /* can be uncompressed YUV420P */ - break; - } - - /* Set sizes in bytes */ - pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; - pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; - - /* Align offset, or you'll get some very weird results in - YUV420 mode... x must be multiple of 4 (to get the Y's in - place), and y even (or you'll mixup U & V). This is less of a - problem for YUV420P. - */ - pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; - pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; -} - int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) { int ret; - u8 buf; - ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf)); + ret = recv_control_msg(pdev, request, value, 1); if (ret < 0) return ret; - *data = buf; + *data = pdev->ctrl_buf[0]; return 0; } @@ -515,7 +423,8 @@ int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) { int ret; - ret = send_control_msg(pdev, request, value, &data, sizeof(data)); + pdev->ctrl_buf[0] = data; + ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1); if (ret < 0) return ret; @@ -525,37 +434,34 @@ int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) { int ret; - s8 buf; - ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf)); + ret = recv_control_msg(pdev, request, value, 1); if (ret < 0) return ret; - *data = buf; + *data = ((s8 *)pdev->ctrl_buf)[0]; return 0; } int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) { int ret; - u8 buf[2]; - ret = recv_control_msg(pdev, request, value, buf, sizeof(buf)); + ret = recv_control_msg(pdev, request, value, 2); if (ret < 0) return ret; - *data = (buf[1] << 8) | buf[0]; + *data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0]; return 0; } int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data) { int ret; - u8 buf[2]; - buf[0] = data & 0xff; - buf[1] = data >> 8; - ret = send_control_msg(pdev, request, value, buf, sizeof(buf)); + pdev->ctrl_buf[0] = data & 0xff; + pdev->ctrl_buf[1] = data >> 8; + ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2); if (ret < 0) return ret; @@ -576,7 +482,6 @@ int pwc_button_ctrl(struct pwc_device *pdev, u16 value) /* POWER */ void pwc_camera_power(struct pwc_device *pdev, int power) { - char buf; int r; if (!pdev->power_save) @@ -586,69 +491,18 @@ void pwc_camera_power(struct pwc_device *pdev, int power) return; /* Not supported by Nala or Timon < release 6 */ if (power) - buf = 0x00; /* active */ + pdev->ctrl_buf[0] = 0x00; /* active */ else - buf = 0xFF; /* power save */ - r = send_control_msg(pdev, - SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, - &buf, sizeof(buf)); - + pdev->ctrl_buf[0] = 0xFF; /* power save */ + r = send_control_msg(pdev, SET_STATUS_CTL, + SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1); if (r < 0) PWC_ERROR("Failed to power %s camera (%d)\n", power ? "on" : "off", r); } -static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) -{ - unsigned char buf; - - /* useful range is 0x01..0x20 */ - buf = speed / 0x7f0; - return send_control_msg(pdev, - SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf)); -} - -static int pwc_get_wb_speed(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf * 0x7f0; - return 0; -} - - -static int pwc_set_wb_delay(struct pwc_device *pdev, int delay) -{ - unsigned char buf; - - /* useful range is 0x01..0x3F */ - buf = (delay >> 10); - return send_control_msg(pdev, - SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf)); -} - -static int pwc_get_wb_delay(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf << 10; - return 0; -} - - int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) { - unsigned char buf[2]; int r; if (pdev->type < 730) @@ -664,123 +518,20 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) if (off_value > 0xff) off_value = 0xff; - buf[0] = on_value; - buf[1] = off_value; + pdev->ctrl_buf[0] = on_value; + pdev->ctrl_buf[1] = off_value; r = send_control_msg(pdev, - SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); + SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2); if (r < 0) PWC_ERROR("Failed to set LED on/off time (%d)\n", r); return r; } -static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) -{ - unsigned char buf[2]; - int ret; - - if (pdev->type < 730) { - *on_value = -1; - *off_value = -1; - return 0; - } - - ret = recv_control_msg(pdev, - GET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *on_value = buf[0] * 100; - *off_value = buf[1] * 100; - return 0; -} - -static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) -{ - unsigned char buf; - - buf = flags & 0x03; // only lower two bits are currently used - return send_control_msg(pdev, - SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, &buf, sizeof(buf)); -} - -int pwc_mpt_reset(struct pwc_device *pdev, int flags) -{ - int ret; - ret = _pwc_mpt_reset(pdev, flags); - if (ret >= 0) { - pdev->pan_angle = 0; - pdev->tilt_angle = 0; - } - return ret; -} - -static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) -{ - unsigned char buf[4]; - - /* set new relative angle; angles are expressed in degrees * 100, - but cam as .5 degree resolution, hence divide by 200. Also - the angle must be multiplied by 64 before it's send to - the cam (??) - */ - pan = 64 * pan / 100; - tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ - buf[0] = pan & 0xFF; - buf[1] = (pan >> 8) & 0xFF; - buf[2] = tilt & 0xFF; - buf[3] = (tilt >> 8) & 0xFF; - return send_control_msg(pdev, - SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, &buf, sizeof(buf)); -} - -int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) -{ - int ret; - - /* check absolute ranges */ - if (pan < pdev->angle_range.pan_min || - pan > pdev->angle_range.pan_max || - tilt < pdev->angle_range.tilt_min || - tilt > pdev->angle_range.tilt_max) - return -ERANGE; - - /* go to relative range, check again */ - pan -= pdev->pan_angle; - tilt -= pdev->tilt_angle; - /* angles are specified in degrees * 100, thus the limit = 36000 */ - if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000) - return -ERANGE; - - ret = _pwc_mpt_set_angle(pdev, pan, tilt); - if (ret >= 0) { - pdev->pan_angle += pan; - pdev->tilt_angle += tilt; - } - if (ret == -EPIPE) /* stall -> out of range */ - ret = -ERANGE; - return ret; -} - -static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) -{ - int ret; - unsigned char buf[5]; - - ret = recv_control_msg(pdev, - GET_MPT_CTL, PT_STATUS_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - status->status = buf[0] & 0x7; // 3 bits are used for reporting - status->time_pan = (buf[1] << 8) + buf[2]; - status->time_tilt = (buf[3] << 8) + buf[4]; - return 0; -} - #ifdef CONFIG_USB_PWC_DEBUG int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) { - unsigned char buf; int ret = -1, request; if (pdev->type < 675) @@ -790,431 +541,13 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) else request = SENSOR_TYPE_FORMATTER2; - ret = recv_control_msg(pdev, - GET_STATUS_CTL, request, &buf, sizeof(buf)); + ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1); if (ret < 0) return ret; if (pdev->type < 675) - *sensor = buf | 0x100; + *sensor = pdev->ctrl_buf[0] | 0x100; else - *sensor = buf; + *sensor = pdev->ctrl_buf[0]; return 0; } #endif - - /* End of Add-Ons */ - /* ************************************************* */ - -/* Linux 2.5.something and 2.6 pass direct pointers to arguments of - ioctl() calls. With 2.4, you have to do tedious copy_from_user() - and copy_to_user() calls. With these macros we circumvent this, - and let me maintain only one source file. The functionality is - exactly the same otherwise. - */ - -/* define local variable for arg */ -#define ARG_DEF(ARG_type, ARG_name)\ - ARG_type *ARG_name = arg; -/* copy arg to local variable */ -#define ARG_IN(ARG_name) /* nothing */ -/* argument itself (referenced) */ -#define ARGR(ARG_name) (*ARG_name) -/* argument address */ -#define ARGA(ARG_name) ARG_name -/* copy local variable to arg */ -#define ARG_OUT(ARG_name) /* nothing */ - -/* - * Our ctrls use native values, but the old custom pwc ioctl interface expects - * values from 0 - 65535, define 2 helper functions to scale things. */ -static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl) -{ - return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum; -} - -static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val) -{ - return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535); -} - -long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) -{ - long ret = 0; - - switch(cmd) { - case VIDIOCPWCRUSER: - ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER); - break; - - case VIDIOCPWCSUSER: - ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER); - break; - - case VIDIOCPWCFACTORY: - ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER); - break; - - case VIDIOCPWCSCQUAL: - { - ARG_DEF(int, qual) - - if (vb2_is_streaming(&pdev->vb_queue)) { - ret = -EBUSY; - break; - } - - ARG_IN(qual) - if (ARGR(qual) < 0 || ARGR(qual) > 3) - ret = -EINVAL; - else - ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); - break; - } - - case VIDIOCPWCGCQUAL: - { - ARG_DEF(int, qual) - - ARGR(qual) = pdev->vcompression; - ARG_OUT(qual) - break; - } - - case VIDIOCPWCPROBE: - { - ARG_DEF(struct pwc_probe, probe) - - strcpy(ARGR(probe).name, pdev->vdev.name); - ARGR(probe).type = pdev->type; - ARG_OUT(probe) - break; - } - - case VIDIOCPWCGSERIAL: - { - ARG_DEF(struct pwc_serial, serial) - - strcpy(ARGR(serial).serial, pdev->serial); - ARG_OUT(serial) - break; - } - - case VIDIOCPWCSAGC: - { - ARG_DEF(int, agc) - ARG_IN(agc) - ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0); - if (ret == 0 && ARGR(agc) >= 0) - ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc)); - break; - } - - case VIDIOCPWCGAGC: - { - ARG_DEF(int, agc) - if (v4l2_ctrl_g_ctrl(pdev->autogain)) - ARGR(agc) = -1; - else - ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain); - ARG_OUT(agc) - break; - } - - case VIDIOCPWCSSHUTTER: - { - ARG_DEF(int, shutter) - ARG_IN(shutter) - ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto, - /* Menu idx 0 = auto, idx 1 = manual */ - ARGR(shutter) >= 0); - if (ret == 0 && ARGR(shutter) >= 0) - ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter)); - break; - } - - case VIDIOCPWCSAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - ARG_IN(wb) - ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance, - ARGR(wb).mode); - if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) - ret = pwc_ioctl_s_ctrl(pdev->red_balance, - ARGR(wb).manual_red); - if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) - ret = pwc_ioctl_s_ctrl(pdev->blue_balance, - ARGR(wb).manual_blue); - break; - } - - case VIDIOCPWCGAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance); - ARGR(wb).manual_red = ARGR(wb).read_red = - pwc_ioctl_g_ctrl(pdev->red_balance); - ARGR(wb).manual_blue = ARGR(wb).read_blue = - pwc_ioctl_g_ctrl(pdev->blue_balance); - ARG_OUT(wb) - break; - } - - case VIDIOCPWCSAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - if (ARGR(wbs).control_speed > 0) { - ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); - } - if (ARGR(wbs).control_delay > 0) { - ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); - } - break; - } - - case VIDIOCPWCGAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); - if (ret < 0) - break; - ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); - if (ret < 0) - break; - ARG_OUT(wbs) - break; - } - - case VIDIOCPWCSLED: - { - ARG_DEF(struct pwc_leds, leds) - - ARG_IN(leds) - ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); - break; - } - - - case VIDIOCPWCGLED: - { - ARG_DEF(struct pwc_leds, leds) - - ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); - ARG_OUT(leds) - break; - } - - case VIDIOCPWCSCONTOUR: - { - ARG_DEF(int, contour) - ARG_IN(contour) - ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0); - if (ret == 0 && ARGR(contour) >= 0) - ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour)); - break; - } - - case VIDIOCPWCGCONTOUR: - { - ARG_DEF(int, contour) - if (v4l2_ctrl_g_ctrl(pdev->autocontour)) - ARGR(contour) = -1; - else - ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour); - ARG_OUT(contour) - break; - } - - case VIDIOCPWCSBACKLIGHT: - { - ARG_DEF(int, backlight) - ARG_IN(backlight) - ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight)); - break; - } - - case VIDIOCPWCGBACKLIGHT: - { - ARG_DEF(int, backlight) - ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight); - ARG_OUT(backlight) - break; - } - - case VIDIOCPWCSFLICKER: - { - ARG_DEF(int, flicker) - ARG_IN(flicker) - ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker)); - break; - } - - case VIDIOCPWCGFLICKER: - { - ARG_DEF(int, flicker) - ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker); - ARG_OUT(flicker) - break; - } - - case VIDIOCPWCSDYNNOISE: - { - ARG_DEF(int, dynnoise) - ARG_IN(dynnoise) - ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise)); - break; - } - - case VIDIOCPWCGDYNNOISE: - { - ARG_DEF(int, dynnoise) - ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction); - ARG_OUT(dynnoise); - break; - } - - case VIDIOCPWCGREALSIZE: - { - ARG_DEF(struct pwc_imagesize, size) - - ARGR(size).width = pdev->image.x; - ARGR(size).height = pdev->image.y; - ARG_OUT(size) - break; - } - - case VIDIOCPWCMPTRESET: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(int, flags) - - ARG_IN(flags) - ret = pwc_mpt_reset(pdev, ARGR(flags)); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGRANGE: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_range, range) - - ARGR(range) = pdev->angle_range; - ARG_OUT(range) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSANGLE: - { - int new_pan, new_tilt; - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARG_IN(angles) - /* The camera can only set relative angles, so - do some calculations when getting an absolute angle . - */ - if (ARGR(angles).absolute) - { - new_pan = ARGR(angles).pan; - new_tilt = ARGR(angles).tilt; - } - else - { - new_pan = pdev->pan_angle + ARGR(angles).pan; - new_tilt = pdev->tilt_angle + ARGR(angles).tilt; - } - ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGANGLE: - { - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARGR(angles).absolute = 1; - ARGR(angles).pan = pdev->pan_angle; - ARGR(angles).tilt = pdev->tilt_angle; - ARG_OUT(angles) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSTATUS: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_status, status) - - ret = pwc_mpt_get_status(pdev, ARGA(status)); - ARG_OUT(status) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCGVIDCMD: - { - ARG_DEF(struct pwc_video_command, vcmd); - - ARGR(vcmd).type = pdev->type; - ARGR(vcmd).release = pdev->release; - ARGR(vcmd).command_len = pdev->cmd_len; - memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len); - ARGR(vcmd).bandlength = pdev->vbandlength; - ARGR(vcmd).frame_size = pdev->frame_size; - ARG_OUT(vcmd) - break; - } - /* - case VIDIOCPWCGVIDTABLE: - { - ARG_DEF(struct pwc_table_init_buffer, table); - ARGR(table).len = pdev->cmd_len; - memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); - ARG_OUT(table) - break; - } - */ - - default: - ret = -ENOIOCTLCMD; - break; - } - - if (ret > 0) - return 0; - return ret; -} - - -/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c index be0e02cb487f..e899036aadf4 100644 --- a/drivers/media/video/pwc/pwc-dec1.c +++ b/drivers/media/video/pwc/pwc-dec1.c @@ -22,19 +22,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "pwc-dec1.h" +#include "pwc.h" -int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer) +void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd) { - struct pwc_dec1_private *pdec; + struct pwc_dec1_private *pdec = &pdev->dec1; - if (pwc->decompress_data == NULL) { - pdec = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL); - if (pdec == NULL) - return -ENOMEM; - pwc->decompress_data = pdec; - } - pdec = pwc->decompress_data; - - return 0; + pdec->version = pdev->release; } diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h index a57d8601080b..c565ef8f52fb 100644 --- a/drivers/media/video/pwc/pwc-dec1.h +++ b/drivers/media/video/pwc/pwc-dec1.h @@ -25,13 +25,15 @@ #ifndef PWC_DEC1_H #define PWC_DEC1_H -#include "pwc.h" +#include <linux/mutex.h> + +struct pwc_device; struct pwc_dec1_private { int version; }; -int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer); +void pwc_dec1_init(struct pwc_device *pdev, const unsigned char *cmd); #endif diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c index 06a4e877ba40..3792fedff951 100644 --- a/drivers/media/video/pwc/pwc-dec23.c +++ b/drivers/media/video/pwc/pwc-dec23.c @@ -27,7 +27,6 @@ #include "pwc-timon.h" #include "pwc-kiara.h" #include "pwc-dec23.h" -#include <media/pwc-ioctl.h> #include <linux/string.h> #include <linux/slab.h> @@ -51,13 +50,6 @@ # define USE_LOOKUP_TABLE_TO_CLAMP 1 #endif -/* - * ENABLE_BAYER_DECODER - * 0: bayer decoder is not build (save some space) - * 1: bayer decoder is build and can be used - */ -#define ENABLE_BAYER_DECODER 0 - static void build_subblock_pattern(struct pwc_dec23_private *pdec) { static const unsigned int initial_values[12] = { @@ -302,20 +294,17 @@ static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE]; /* If the type or the command change, we rebuild the lookup table */ -int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd) +void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd) { int flags, version, shift, i; - struct pwc_dec23_private *pdec; + struct pwc_dec23_private *pdec = &pdev->dec23; - if (pwc->decompress_data == NULL) { - pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); - if (pdec == NULL) - return -ENOMEM; - pwc->decompress_data = pdec; - } - pdec = pwc->decompress_data; + mutex_init(&pdec->lock); - if (DEVICE_USE_CODEC3(type)) { + if (pdec->last_cmd_valid && pdec->last_cmd == cmd[2]) + return; + + if (DEVICE_USE_CODEC3(pdev->type)) { flags = cmd[2] & 0x18; if (flags == 8) pdec->nbits = 7; /* More bits, mean more bits to encode the stream, but better quality */ @@ -362,7 +351,8 @@ int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd) pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255; #endif - return 0; + pdec->last_cmd = cmd[2]; + pdec->last_cmd_valid = 1; } /* @@ -467,123 +457,6 @@ static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned i #endif } -#if ENABLE_BAYER_DECODER -/* - * Format: 8x2 pixels - * . G . G . G . G . G . G . G - * . . . . . . . . . . . . . . - * . G . G . G . G . G . G . G - * . . . . . . . . . . . . . . - * or - * . . . . . . . . . . . . . . - * G . G . G . G . G . G . G . - * . . . . . . . . . . . . . . - * G . G . G . G . G . G . G . -*/ -static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) -{ -#if UNROLL_LOOP_FOR_COPY - /* Unroll all loops */ - const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; - unsigned char *d = dst; - const int *c = src; - - d[0] = cm[c[0] >> scalebits]; - d[2] = cm[c[1] >> scalebits]; - d[4] = cm[c[2] >> scalebits]; - d[6] = cm[c[3] >> scalebits]; - d[8] = cm[c[4] >> scalebits]; - d[10] = cm[c[5] >> scalebits]; - d[12] = cm[c[6] >> scalebits]; - d[14] = cm[c[7] >> scalebits]; - - d = dst + bytes_per_line; - d[0] = cm[c[8] >> scalebits]; - d[2] = cm[c[9] >> scalebits]; - d[4] = cm[c[10] >> scalebits]; - d[6] = cm[c[11] >> scalebits]; - d[8] = cm[c[12] >> scalebits]; - d[10] = cm[c[13] >> scalebits]; - d[12] = cm[c[14] >> scalebits]; - d[14] = cm[c[15] >> scalebits]; -#else - int i; - unsigned char *d; - const int *c = src; - - d = dst; - for (i = 0; i < 8; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line; - for (i = 0; i < 8; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); -#endif -} -#endif - -#if ENABLE_BAYER_DECODER -/* - * Format: 4x4 pixels - * R . R . R . R - * . B . B . B . - * R . R . R . R - * . B . B . B . - */ -static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) -{ -#if UNROLL_LOOP_FOR_COPY - /* Unroll all loops */ - const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; - unsigned char *d = dst; - const int *c = src; - - d[0] = cm[c[0] >> scalebits]; - d[2] = cm[c[1] >> scalebits]; - d[4] = cm[c[2] >> scalebits]; - d[6] = cm[c[3] >> scalebits]; - - d = dst + bytes_per_line; - d[1] = cm[c[4] >> scalebits]; - d[3] = cm[c[5] >> scalebits]; - d[5] = cm[c[6] >> scalebits]; - d[7] = cm[c[7] >> scalebits]; - - d = dst + bytes_per_line*2; - d[0] = cm[c[8] >> scalebits]; - d[2] = cm[c[9] >> scalebits]; - d[4] = cm[c[10] >> scalebits]; - d[6] = cm[c[11] >> scalebits]; - - d = dst + bytes_per_line*3; - d[1] = cm[c[12] >> scalebits]; - d[3] = cm[c[13] >> scalebits]; - d[5] = cm[c[14] >> scalebits]; - d[7] = cm[c[15] >> scalebits]; -#else - int i; - unsigned char *d; - const int *c = src; - - d = dst; - for (i = 0; i < 4; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line; - for (i = 0; i < 4; i++, c++) - d[i*2+1] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line*2; - for (i = 0; i < 4; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line*3; - for (i = 0; i < 4; i++, c++) - d[i*2+1] = CLAMP((*c) >> scalebits); -#endif -} -#endif - /* * To manage the stream, we keep bits in a 32 bits register. * fill_nbits(n): fill the reservoir with at least n bits @@ -775,146 +648,44 @@ static void DecompressBand23(struct pwc_dec23_private *pdec, } -#if ENABLE_BAYER_DECODER -/* - * Size need to be a multiple of 8 in width - * - * Return a block of four line encoded like this: - * - * G R G R G R G R G R G R G R G R - * B G B G B G B G B G B G B G B G - * G R G R G R G R G R G R G R G R - * B G B G B G B G B G B G B G B G - * - */ -static void DecompressBandBayer(struct pwc_dec23_private *pdec, - const unsigned char *rawyuv, - unsigned char *rgbbayer, - unsigned int compressed_image_width, - unsigned int real_image_width) -{ - int compression_index, nblocks; - const unsigned char *ptable0004; - const unsigned char *ptable8004; - unsigned char *dest; - - pdec->reservoir = 0; - pdec->nbits_in_reservoir = 0; - pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */ - - get_nbits(pdec, 4, compression_index); - - /* pass 1: uncompress RB component */ - nblocks = compressed_image_width / 4; - - ptable0004 = pdec->table_0004_pass1[compression_index]; - ptable8004 = pdec->table_8004_pass1[compression_index]; - dest = rgbbayer; - - /* Each block decode a square of 4x4 */ - while (nblocks) { - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits); - dest += 8; - nblocks--; - } - - /* pass 2: uncompress G component */ - nblocks = compressed_image_width / 8; - - ptable0004 = pdec->table_0004_pass2[compression_index]; - ptable8004 = pdec->table_8004_pass2[compression_index]; - - /* Each block decode a square of 4x4 */ - while (nblocks) { - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits); - - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits); - - rgbbayer += 16; - nblocks -= 2; - } -} -#endif - - /** * * Uncompress a pwc23 buffer. * - * pwc.view: size of the image wanted - * pwc.image: size of the image returned by the camera - * pwc.offset: (x,y) to displayer image in the view - * * src: raw data * dst: image output - * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER */ -void pwc_dec23_decompress(const struct pwc_device *pwc, +void pwc_dec23_decompress(struct pwc_device *pdev, const void *src, - void *dst, - int flags) + void *dst) { - int bandlines_left, stride, bytes_per_block; - - bandlines_left = pwc->image.y / 4; - bytes_per_block = pwc->view.x * 4; - - if (flags & PWCX_FLAG_BAYER) { -#if ENABLE_BAYER_DECODER - /* RGB Bayer format */ - unsigned char *rgbout; - - stride = pwc->view.x * pwc->offset.y; - rgbout = dst + stride + pwc->offset.x; - - - while (bandlines_left--) { - - DecompressBandBayer(pwc->decompress_data, - src, - rgbout, - pwc->image.x, pwc->view.x); - - src += pwc->vbandlength; - rgbout += bytes_per_block; - - } -#else - memset(dst, 0, pwc->view.x * pwc->view.y); -#endif - - } else { - /* YUV420P image format */ - unsigned char *pout_planar_y; - unsigned char *pout_planar_u; - unsigned char *pout_planar_v; - unsigned int plane_size; - - plane_size = pwc->view.x * pwc->view.y; - - /* offset in Y plane */ - stride = pwc->view.x * pwc->offset.y; - pout_planar_y = dst + stride + pwc->offset.x; - - /* offsets in U/V planes */ - stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2; - pout_planar_u = dst + plane_size + stride; - pout_planar_v = dst + plane_size + plane_size / 4 + stride; - - while (bandlines_left--) { - - DecompressBand23(pwc->decompress_data, - src, - pout_planar_y, pout_planar_u, pout_planar_v, - pwc->image.x, pwc->view.x); - src += pwc->vbandlength; - pout_planar_y += bytes_per_block; - pout_planar_u += pwc->view.x; - pout_planar_v += pwc->view.x; - - } + int bandlines_left, bytes_per_block; + struct pwc_dec23_private *pdec = &pdev->dec23; + + /* YUV420P image format */ + unsigned char *pout_planar_y; + unsigned char *pout_planar_u; + unsigned char *pout_planar_v; + unsigned int plane_size; + + mutex_lock(&pdec->lock); + + bandlines_left = pdev->height / 4; + bytes_per_block = pdev->width * 4; + plane_size = pdev->height * pdev->width; + + pout_planar_y = dst; + pout_planar_u = dst + plane_size; + pout_planar_v = dst + plane_size + plane_size / 4; + + while (bandlines_left--) { + DecompressBand23(pdec, src, + pout_planar_y, pout_planar_u, pout_planar_v, + pdev->width, pdev->width); + src += pdev->vbandlength; + pout_planar_y += bytes_per_block; + pout_planar_u += pdev->width; + pout_planar_v += pdev->width; } + mutex_unlock(&pdec->lock); } diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h index a0ac4f3dff81..c655b1c1e6a9 100644 --- a/drivers/media/video/pwc/pwc-dec23.h +++ b/drivers/media/video/pwc/pwc-dec23.h @@ -25,15 +25,20 @@ #ifndef PWC_DEC23_H #define PWC_DEC23_H -#include "pwc.h" +struct pwc_device; struct pwc_dec23_private { + struct mutex lock; + + unsigned char last_cmd, last_cmd_valid; + unsigned int scalebits; unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */ unsigned int reservoir; unsigned int nbits_in_reservoir; + const unsigned char *stream; int temp_colors[16]; @@ -49,9 +54,8 @@ struct pwc_dec23_private }; -int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd); -void pwc_dec23_decompress(const struct pwc_device *pwc, +void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd); +void pwc_dec23_decompress(struct pwc_device *pdev, const void *src, - void *dst, - int flags); + void *dst); #endif diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 01ff643e682d..122fbd0081eb 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -128,33 +128,23 @@ static struct usb_driver pwc_driver = { #define MAX_DEV_HINTS 20 #define MAX_ISOC_ERRORS 20 -static int default_fps = 10; #ifdef CONFIG_USB_PWC_DEBUG int pwc_trace = PWC_DEBUG_LEVEL; #endif static int power_save = -1; -static int led_on = 100, led_off; /* defaults to LED that is on while in use */ -static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */ -static struct { - int type; - char serial_number[30]; - int device_node; - struct pwc_device *pdev; -} device_hint[MAX_DEV_HINTS]; +static int leds[2] = { 100, 0 }; /***/ -static int pwc_video_open(struct file *file); static int pwc_video_close(struct file *file); static ssize_t pwc_video_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); -static void pwc_video_release(struct video_device *vfd); static const struct v4l2_file_operations pwc_fops = { .owner = THIS_MODULE, - .open = pwc_video_open, + .open = v4l2_fh_open, .release = pwc_video_close, .read = pwc_video_read, .poll = pwc_video_poll, @@ -163,7 +153,7 @@ static const struct v4l2_file_operations pwc_fops = { }; static struct video_device pwc_template = { .name = "Philips Webcam", /* Filled in later */ - .release = pwc_video_release, + .release = video_device_release_empty, .fops = &pwc_fops, .ioctl_ops = &pwc_ioctl_ops, }; @@ -191,7 +181,6 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down) { if (down) { PWC_TRACE("Snapshot button pressed.\n"); - pdev->snapshot_button_status = 1; } else { PWC_TRACE("Snapshot button released.\n"); } @@ -375,6 +364,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) int i, j, ret; struct usb_interface *intf; struct usb_host_interface *idesc = NULL; + int compression = 0; /* 0..3 = uncompressed..high */ if (pdev->iso_init) return 0; @@ -386,6 +376,12 @@ static int pwc_isoc_init(struct pwc_device *pdev) pdev->visoc_errors = 0; udev = pdev->udev; +retry: + /* We first try with low compression and then retry with a higher + compression setting if there is not enough bandwidth. */ + ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt, + pdev->vframes, &compression, 1); + /* Get the current alternate interface, adjust packet size */ intf = usb_ifnum_to_if(udev, 0); if (intf) @@ -408,9 +404,12 @@ static int pwc_isoc_init(struct pwc_device *pdev) } /* Set alternate interface */ - ret = 0; PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate); ret = usb_set_interface(pdev->udev, 0, pdev->valternate); + if (ret == -ENOSPC && compression < 3) { + compression++; + goto retry; + } if (ret < 0) return ret; @@ -454,6 +453,12 @@ static int pwc_isoc_init(struct pwc_device *pdev) /* link */ for (i = 0; i < MAX_ISO_BUFS; i++) { ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL); + if (ret == -ENOSPC && compression < 3) { + compression++; + pdev->iso_init = 1; + pwc_isoc_cleanup(pdev); + goto retry; + } if (ret) { PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret); pdev->iso_init = 1; @@ -517,12 +522,11 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev) PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n"); } -/* - * Release all queued buffers, no need to take queued_bufs_lock, since all - * iso urbs have been killed when we're called so pwc_isoc_handler won't run. - */ static void pwc_cleanup_queued_bufs(struct pwc_device *pdev) { + unsigned long flags = 0; + + spin_lock_irqsave(&pdev->queued_bufs_lock, flags); while (!list_empty(&pdev->queued_bufs)) { struct pwc_frame_buf *buf; @@ -531,84 +535,7 @@ static void pwc_cleanup_queued_bufs(struct pwc_device *pdev) list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } -} - -/********* - * sysfs - *********/ -static struct pwc_device *cd_to_pwc(struct device *cd) -{ - struct video_device *vdev = to_video_device(cd); - return video_get_drvdata(vdev); -} - -static ssize_t show_pan_tilt(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle); -} - -static ssize_t store_pan_tilt(struct device *class_dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - int pan, tilt; - int ret = -EINVAL; - - if (strncmp(buf, "reset", 5) == 0) - ret = pwc_mpt_reset(pdev, 0x3); - - else if (sscanf(buf, "%d %d", &pan, &tilt) > 0) - ret = pwc_mpt_set_angle(pdev, pan, tilt); - - if (ret < 0) - return ret; - return strlen(buf); -} -static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); - -static ssize_t show_snapshot_button_status(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - int status = pdev->snapshot_button_status; - pdev->snapshot_button_status = 0; - return sprintf(buf, "%d\n", status); -} - -static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, - NULL); - -static int pwc_create_sysfs_files(struct pwc_device *pdev) -{ - int rc; - - rc = device_create_file(&pdev->vdev.dev, &dev_attr_button); - if (rc) - goto err; - if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt); - if (rc) - goto err_button; - } - - return 0; - -err_button: - device_remove_file(&pdev->vdev.dev, &dev_attr_button); -err: - PWC_ERROR("Could not create sysfs files.\n"); - return rc; -} - -static void pwc_remove_sysfs_files(struct pwc_device *pdev) -{ - if (pdev->features & FEATURE_MOTOR_PANTILT) - device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt); - device_remove_file(&pdev->vdev.dev, &dev_attr_button); + spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); } #ifdef CONFIG_USB_PWC_DEBUG @@ -644,85 +571,60 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type) /***************************************************************************/ /* Video4Linux functions */ -static int pwc_video_open(struct file *file) +int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file) { - struct video_device *vdev = video_devdata(file); - struct pwc_device *pdev; - - PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); - - pdev = video_get_drvdata(vdev); - if (!pdev->udev) - return -ENODEV; + int r = 0; - file->private_data = vdev; - PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); - return 0; + mutex_lock(&pdev->capt_file_lock); + if (pdev->capt_file != NULL && + pdev->capt_file != file) { + r = -EBUSY; + goto leave; + } + pdev->capt_file = file; +leave: + mutex_unlock(&pdev->capt_file_lock); + return r; } -static void pwc_video_release(struct video_device *vfd) +static void pwc_video_release(struct v4l2_device *v) { - struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev); - int hint; - - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - - /* Free intermediate decompression buffer & tables */ - if (pdev->decompress_data != NULL) { - PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", - pdev->decompress_data); - kfree(pdev->decompress_data); - pdev->decompress_data = NULL; - } + struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); v4l2_ctrl_handler_free(&pdev->ctrl_handler); - + kfree(pdev->ctrl_buf); kfree(pdev); } static int pwc_video_close(struct file *file) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - - PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); + struct pwc_device *pdev = video_drvdata(file); - pdev = video_get_drvdata(vdev); if (pdev->capt_file == file) { vb2_queue_release(&pdev->vb_queue); pdev->capt_file = NULL; } - - PWC_DEBUG_OPEN("<< video_close()\n"); - return 0; + return v4l2_fh_release(file); } static ssize_t pwc_video_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev = video_get_drvdata(vdev); + struct pwc_device *pdev = video_drvdata(file); if (!pdev->udev) return -ENODEV; - if (pdev->capt_file != NULL && - pdev->capt_file != file) + if (pwc_test_n_set_capt_file(pdev, file)) return -EBUSY; - pdev->capt_file = file; - return vb2_read(&pdev->vb_queue, buf, count, ppos, file->f_flags & O_NONBLOCK); } static unsigned int pwc_video_poll(struct file *file, poll_table *wait) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev = video_get_drvdata(vdev); + struct pwc_device *pdev = video_drvdata(file); if (!pdev->udev) return POLL_ERR; @@ -732,8 +634,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev = video_get_drvdata(vdev); + struct pwc_device *pdev = video_drvdata(file); if (pdev->capt_file != file) return -EBUSY; @@ -749,6 +650,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int sizes[], void *alloc_ctxs[]) { struct pwc_device *pdev = vb2_get_drv_priv(vq); + int size; if (*nbuffers < MIN_FRAMES) *nbuffers = MIN_FRAMES; @@ -757,7 +659,9 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, *nplanes = 1; - sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2); + size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT); + sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] * + pwc_image_sizes[size][1] * 3 / 2); return 0; } @@ -812,56 +716,59 @@ static void buffer_queue(struct vb2_buffer *vb) unsigned long flags = 0; spin_lock_irqsave(&pdev->queued_bufs_lock, flags); - list_add_tail(&buf->list, &pdev->queued_bufs); + /* Check the device has not disconnected between prep and queuing */ + if (pdev->udev) + list_add_tail(&buf->list, &pdev->queued_bufs); + else + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); } static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct pwc_device *pdev = vb2_get_drv_priv(vq); + int r; - if (!pdev->udev) - return -ENODEV; + mutex_lock(&pdev->udevlock); + if (!pdev->udev) { + r = -ENODEV; + goto leave; + } /* Turn on camera and set LEDS on */ pwc_camera_power(pdev, 1); - if (pdev->power_save) { - /* Restore video mode */ - pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, - pdev->vframes, pdev->vcompression, - pdev->vsnapshot); - } - pwc_set_leds(pdev, led_on, led_off); + pwc_set_leds(pdev, leds[0], leds[1]); - return pwc_isoc_init(pdev); + r = pwc_isoc_init(pdev); + if (r) { + /* If we failed turn camera and LEDS back off */ + pwc_set_leds(pdev, 0, 0); + pwc_camera_power(pdev, 0); + /* And cleanup any queued bufs!! */ + pwc_cleanup_queued_bufs(pdev); + } +leave: + mutex_unlock(&pdev->udevlock); + return r; } static int stop_streaming(struct vb2_queue *vq) { struct pwc_device *pdev = vb2_get_drv_priv(vq); + mutex_lock(&pdev->udevlock); if (pdev->udev) { pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); pwc_isoc_cleanup(pdev); } + mutex_unlock(&pdev->udevlock); + pwc_cleanup_queued_bufs(pdev); return 0; } -static void pwc_lock(struct vb2_queue *vq) -{ - struct pwc_device *pdev = vb2_get_drv_priv(vq); - mutex_lock(&pdev->modlock); -} - -static void pwc_unlock(struct vb2_queue *vq) -{ - struct pwc_device *pdev = vb2_get_drv_priv(vq); - mutex_unlock(&pdev->modlock); -} - static struct vb2_ops pwc_vb_queue_ops = { .queue_setup = queue_setup, .buf_init = buffer_init, @@ -871,8 +778,6 @@ static struct vb2_ops pwc_vb_queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = pwc_unlock, - .wait_finish = pwc_lock, }; /***************************************************************************/ @@ -887,9 +792,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id struct usb_device *udev = interface_to_usbdev(intf); struct pwc_device *pdev = NULL; int vendor_id, product_id, type_id; - int hint, rc; + int rc; int features = 0; - int video_nr = -1; /* default: use next available device */ + int compression = 0; int my_power_save = power_save; char serial_number[30], *name; @@ -1149,28 +1054,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id return -ENOMEM; } pdev->type = type_id; - pdev->vframes = default_fps; - strcpy(pdev->serial, serial_number); pdev->features = features; - if (vendor_id == 0x046D && product_id == 0x08B5) { - /* Logitech QuickCam Orbit - The ranges have been determined experimentally; they may differ from cam to cam. - Also, the exact ranges left-right and up-down are different for my cam - */ - pdev->angle_range.pan_min = -7000; - pdev->angle_range.pan_max = 7000; - pdev->angle_range.tilt_min = -3000; - pdev->angle_range.tilt_max = 2500; - } pwc_construct(pdev); /* set min/max sizes correct */ - mutex_init(&pdev->modlock); + mutex_init(&pdev->capt_file_lock); mutex_init(&pdev->udevlock); spin_lock_init(&pdev->queued_bufs_lock); INIT_LIST_HEAD(&pdev->queued_bufs); pdev->udev = udev; - pdev->vcompression = pwc_preferred_compression; pdev->power_save = my_power_save; /* Init videobuf2 queue structure */ @@ -1185,35 +1077,21 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id /* Init video_device structure */ memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev.parent = &intf->dev; - pdev->vdev.lock = &pdev->modlock; strcpy(pdev->vdev.name, name); + set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags); video_set_drvdata(&pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); - /* Now search device_hint[] table for a match, so we can hint a node number. */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) { - if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && - (device_hint[hint].pdev == NULL)) { - /* so far, so good... try serial number */ - if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { - /* match! */ - video_nr = device_hint[hint].device_node; - PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr); - break; - } - } + /* Allocate USB command buffers */ + pdev->ctrl_buf = kmalloc(sizeof(pdev->cmd_buf), GFP_KERNEL); + if (!pdev->ctrl_buf) { + PWC_ERROR("Oops, could not allocate memory for pwc_device.\n"); + rc = -ENOMEM; + goto err_free_mem; } - /* occupy slot */ - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = pdev; - - PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); - usb_set_intfdata(intf, pdev); - #ifdef CONFIG_USB_PWC_DEBUG /* Query sensor type */ if (pwc_get_cmos_sensor(pdev, &rc) >= 0) { @@ -1227,8 +1105,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pwc_set_leds(pdev, 0, 0); /* Setup intial videomode */ - rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y, - pdev->vframes, pdev->vcompression, 0); + rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT, + V4L2_PIX_FMT_YUV420, 30, &compression, 1); if (rc) goto err_free_mem; @@ -1239,20 +1117,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id goto err_free_mem; } - pdev->vdev.ctrl_handler = &pdev->ctrl_handler; - /* And powerdown the camera until streaming starts */ pwc_camera_power(pdev, 0); - rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); - if (rc < 0) { - PWC_ERROR("Failed to register as video device (%d).\n", rc); + /* Register the v4l2_device structure */ + pdev->v4l2_dev.release = pwc_video_release; + rc = v4l2_device_register(&intf->dev, &pdev->v4l2_dev); + if (rc) { + PWC_ERROR("Failed to register v4l2-device (%d).\n", rc); goto err_free_controls; } - rc = pwc_create_sysfs_files(pdev); - if (rc) - goto err_video_unreg; + pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler; + pdev->vdev.v4l2_dev = &pdev->v4l2_dev; + + rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1); + if (rc < 0) { + PWC_ERROR("Failed to register as video device (%d).\n", rc); + goto err_unregister_v4l2_dev; + } PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev)); #ifdef CONFIG_USB_PWC_INPUT_EVDEV @@ -1261,7 +1144,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (!pdev->button_dev) { PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); rc = -ENOMEM; - pwc_remove_sysfs_files(pdev); goto err_video_unreg; } @@ -1279,7 +1161,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (rc) { input_free_device(pdev->button_dev); pdev->button_dev = NULL; - pwc_remove_sysfs_files(pdev); goto err_video_unreg; } #endif @@ -1287,13 +1168,13 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id return 0; err_video_unreg: - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = NULL; video_unregister_device(&pdev->vdev); +err_unregister_v4l2_dev: + v4l2_device_unregister(&pdev->v4l2_dev); err_free_controls: v4l2_ctrl_handler_free(&pdev->ctrl_handler); err_free_mem: - usb_set_intfdata(intf, NULL); + kfree(pdev->ctrl_buf); kfree(pdev); return rc; } @@ -1301,27 +1182,26 @@ err_free_mem: /* The user yanked out the cable... */ static void usb_pwc_disconnect(struct usb_interface *intf) { - struct pwc_device *pdev = usb_get_intfdata(intf); + struct v4l2_device *v = usb_get_intfdata(intf); + struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); mutex_lock(&pdev->udevlock); - mutex_lock(&pdev->modlock); - - usb_set_intfdata(intf, NULL); /* No need to keep the urbs around after disconnection */ pwc_isoc_cleanup(pdev); - pwc_cleanup_queued_bufs(pdev); pdev->udev = NULL; - - mutex_unlock(&pdev->modlock); mutex_unlock(&pdev->udevlock); - pwc_remove_sysfs_files(pdev); + pwc_cleanup_queued_bufs(pdev); + video_unregister_device(&pdev->vdev); + v4l2_device_unregister(&pdev->v4l2_dev); #ifdef CONFIG_USB_PWC_INPUT_EVDEV if (pdev->button_dev) input_unregister_device(pdev->button_dev); #endif + + v4l2_device_put(&pdev->v4l2_dev); } @@ -1329,30 +1209,19 @@ static void usb_pwc_disconnect(struct usb_interface *intf) * Initialization code & module stuff */ -static int fps; -static int compression = -1; -static int leds[2] = { -1, -1 }; static unsigned int leds_nargs; -static char *dev_hint[MAX_DEV_HINTS]; -static unsigned int dev_hint_nargs; -module_param(fps, int, 0444); #ifdef CONFIG_USB_PWC_DEBUG module_param_named(trace, pwc_trace, int, 0644); #endif module_param(power_save, int, 0644); -module_param(compression, int, 0444); module_param_array(leds, int, &leds_nargs, 0444); -module_param_array(dev_hint, charp, &dev_hint_nargs, 0444); -MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); #ifdef CONFIG_USB_PWC_DEBUG MODULE_PARM_DESC(trace, "For debugging purposes"); #endif MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off"); -MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); -MODULE_PARM_DESC(dev_hint, "Device node hints"); MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); MODULE_AUTHOR("Luc Saillard <luc@saillard.org>"); @@ -1362,122 +1231,13 @@ MODULE_VERSION( PWC_VERSION ); static int __init usb_pwc_init(void) { - int i; - -#ifdef CONFIG_USB_PWC_DEBUG - PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n"); - PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); - PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); - PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); - - if (pwc_trace >= 0) { - PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace); - } -#endif - - if (fps) { - if (fps < 4 || fps > 30) { - PWC_ERROR("Framerate out of bounds (4-30).\n"); - return -EINVAL; - } - default_fps = fps; - PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps); - } - - if (compression >= 0) { - if (compression > 3) { - PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); - return -EINVAL; - } - pwc_preferred_compression = compression; - PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression); - } - if (leds[0] >= 0) - led_on = leds[0]; - if (leds[1] >= 0) - led_off = leds[1]; - - /* Big device node whoopla. Basically, it allows you to assign a - device node (/dev/videoX) to a camera, based on its type - & serial number. The format is [type[.serialnumber]:]node. - - Any camera that isn't matched by these rules gets the next - available free device node. - */ - for (i = 0; i < MAX_DEV_HINTS; i++) { - char *s, *colon, *dot; - - /* This loop also initializes the array */ - device_hint[i].pdev = NULL; - s = dev_hint[i]; - if (s != NULL && *s != '\0') { - device_hint[i].type = -1; /* wildcard */ - strcpy(device_hint[i].serial_number, "*"); - - /* parse string: chop at ':' & '/' */ - colon = dot = s; - while (*colon != '\0' && *colon != ':') - colon++; - while (*dot != '\0' && *dot != '.') - dot++; - /* Few sanity checks */ - if (*dot != '\0' && dot > colon) { - PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n"); - return -EINVAL; - } - - if (*colon == '\0') { - /* No colon */ - if (*dot != '\0') { - PWC_ERROR("Malformed camera hint: no colon + device node given.\n"); - return -EINVAL; - } - else { - /* No type or serial number specified, just a number. */ - device_hint[i].device_node = - simple_strtol(s, NULL, 10); - } - } - else { - /* There's a colon, so we have at least a type and a device node */ - device_hint[i].type = - simple_strtol(s, NULL, 10); - device_hint[i].device_node = - simple_strtol(colon + 1, NULL, 10); - if (*dot != '\0') { - /* There's a serial number as well */ - int k; - - dot++; - k = 0; - while (*dot != ':' && k < 29) { - device_hint[i].serial_number[k++] = *dot; - dot++; - } - device_hint[i].serial_number[k] = '\0'; - } - } - PWC_TRACE("device_hint[%d]:\n", i); - PWC_TRACE(" type : %d\n", device_hint[i].type); - PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number); - PWC_TRACE(" node : %d\n", device_hint[i].device_node); - } - else - device_hint[i].type = 0; /* not filled */ - } /* ..for MAX_DEV_HINTS */ - - PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver); return usb_register(&pwc_driver); } static void __exit usb_pwc_exit(void) { - PWC_DEBUG_MODULE("Deregistering driver.\n"); usb_deregister(&pwc_driver); - PWC_INFO("Philips webcam module removed.\n"); } module_init(usb_pwc_init); module_exit(usb_pwc_exit); - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h index 047dad8c15f7..8e02b7ac2139 100644 --- a/drivers/media/video/pwc/pwc-kiara.h +++ b/drivers/media/video/pwc/pwc-kiara.h @@ -27,7 +27,7 @@ #ifndef PWC_KIARA_H #define PWC_KIARA_H -#include <media/pwc-ioctl.h> +#include "pwc.h" #define PWC_FPS_MAX_KIARA 6 diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c index 0b031336eab8..9be5adffa874 100644 --- a/drivers/media/video/pwc/pwc-misc.c +++ b/drivers/media/video/pwc/pwc-misc.c @@ -27,67 +27,47 @@ #include "pwc.h" -const struct pwc_coord pwc_image_sizes[PSZ_MAX] = +const int pwc_image_sizes[PSZ_MAX][2] = { - { 128, 96, 0 }, /* sqcif */ - { 160, 120, 0 }, /* qsif */ - { 176, 144, 0 }, /* qcif */ - { 320, 240, 0 }, /* sif */ - { 352, 288, 0 }, /* cif */ - { 640, 480, 0 }, /* vga */ + { 128, 96 }, /* sqcif */ + { 160, 120 }, /* qsif */ + { 176, 144 }, /* qcif */ + { 320, 240 }, /* sif */ + { 352, 288 }, /* cif */ + { 640, 480 }, /* vga */ }; /* x,y -> PSZ_ */ -int pwc_decode_size(struct pwc_device *pdev, int width, int height) +int pwc_get_size(struct pwc_device *pdev, int width, int height) { - int i, find; - - /* Make sure we don't go beyond our max size. - NB: we have different limits for RAW and normal modes. In case - you don't have the decompressor loaded or use RAW mode, - the maximum viewable size is smaller. - */ - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - { - if (width > pdev->abs_max.x || height > pdev->abs_max.y) - { - PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); - return -1; - } - } - else - { - if (width > pdev->view_max.x || height > pdev->view_max.y) - { - PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n"); - return -1; - } - } + int i; /* Find the largest size supported by the camera that fits into the - requested size. - */ - find = -1; + requested size. */ + for (i = PSZ_MAX - 1; i >= 0; i--) { + if (!(pdev->image_mask & (1 << i))) + continue; + + if (pwc_image_sizes[i][0] <= width && + pwc_image_sizes[i][1] <= height) + return i; + } + + /* No mode found, return the smallest mode we have */ for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1 << i)) { - if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) - find = i; - } + if (pdev->image_mask & (1 << i)) + return i; } - return find; + + /* Never reached there always is atleast one supported mode */ + return 0; } -/* initialize variables depending on type and decompressor*/ +/* initialize variables depending on type and decompressor */ void pwc_construct(struct pwc_device *pdev) { if (DEVICE_USE_CODEC1(pdev->type)) { - pdev->view_min.x = 128; - pdev->view_min.y = 96; - pdev->view_max.x = 352; - pdev->view_max.y = 288; - pdev->abs_max.x = 352; - pdev->abs_max.y = 288; pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; pdev->vcinterface = 2; pdev->vendpoint = 4; @@ -96,13 +76,7 @@ void pwc_construct(struct pwc_device *pdev) } else if (DEVICE_USE_CODEC3(pdev->type)) { - pdev->view_min.x = 160; - pdev->view_min.y = 120; - pdev->view_max.x = 640; - pdev->view_max.y = 480; pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; pdev->vcinterface = 3; pdev->vendpoint = 5; pdev->frame_header_size = TOUCAM_HEADER_SIZE; @@ -110,20 +84,10 @@ void pwc_construct(struct pwc_device *pdev) } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ { - pdev->view_min.x = 128; - pdev->view_min.y = 96; - /* Anthill bug #38: PWC always reports max size, even without PWCX */ - pdev->view_max.x = 640; - pdev->view_max.y = 480; pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; pdev->vcinterface = 3; pdev->vendpoint = 4; pdev->frame_header_size = 0; pdev->frame_trailer_size = 0; } - pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ - pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; - pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; } diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h index a6e22224c95f..270c5b9010f6 100644 --- a/drivers/media/video/pwc/pwc-timon.h +++ b/drivers/media/video/pwc/pwc-timon.h @@ -42,7 +42,7 @@ #ifndef PWC_TIMON_H #define PWC_TIMON_H -#include <media/pwc-ioctl.h> +#include "pwc.h" #define PWC_FPS_MAX_TIMON 6 diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c index 51265092bd31..b65903fbcf0d 100644 --- a/drivers/media/video/pwc/pwc-uncompress.c +++ b/drivers/media/video/pwc/pwc-uncompress.c @@ -35,7 +35,7 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) { - int n, line, col, stride; + int n, line, col; void *yuv, *image; u16 *src; u16 *dsty, *dstu, *dstv; @@ -60,35 +60,23 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) return 0; } - vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size); + vb2_set_plane_payload(&fbuf->vb, 0, + pdev->width * pdev->height * 3 / 2); if (pdev->vbandlength == 0) { /* Uncompressed mode. - * We copy the data into the output buffer, using the viewport - * size (which may be larger than the image size). - * Unfortunately we have to do a bit of byte stuffing to get - * the desired output format/size. * * We do some byte shuffling here to go from the * native format to YUV420P. */ src = (u16 *)yuv; - n = pdev->view.x * pdev->view.y; + n = pdev->width * pdev->height; + dsty = (u16 *)(image); + dstu = (u16 *)(image + n); + dstv = (u16 *)(image + n + n / 4); - /* offset in Y plane */ - stride = pdev->view.x * pdev->offset.y + pdev->offset.x; - dsty = (u16 *)(image + stride); - - /* offsets in U/V planes */ - stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; - dstu = (u16 *)(image + n + stride); - dstv = (u16 *)(image + n + n / 4 + stride); - - /* increment after each line */ - stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ - - for (line = 0; line < pdev->image.y; line++) { - for (col = 0; col < pdev->image.x; col += 4) { + for (line = 0; line < pdev->height; line++) { + for (col = 0; col < pdev->width; col += 4) { *dsty++ = *src++; *dsty++ = *src++; if (line & 1) @@ -96,11 +84,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) else *dstu++ = *src++; } - dsty += stride; - if (line & 1) - dstv += (stride >> 1); - else - dstu += (stride >> 1); } return 0; @@ -111,12 +94,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) * the decompressor routines will write the data in planar format * immediately. */ - if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) { - PWC_ERROR("Mode Bayer is not supported for now\n"); - /* flags |= PWCX_FLAG_BAYER; */ - return -ENXIO; /* No such device or address: missing decompressor */ - } - if (DEVICE_USE_CODEC1(pdev->type)) { /* TODO & FIXME */ @@ -124,10 +101,7 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) return -ENXIO; /* No such device or address: missing decompressor */ } else { - pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR); + pwc_dec23_decompress(pdev, yuv, image); } return 0; } - - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index a10ff6b64acf..f495eeb5403a 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -49,6 +49,7 @@ static const struct v4l2_ctrl_ops pwc_ctrl_ops = { enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto }; enum { custom_autocontour, custom_contour, custom_noise_reduction, + custom_awb_speed, custom_awb_delay, custom_save_user, custom_restore_user, custom_restore_factory }; const char * const pwc_auto_whitebal_qmenu[] = { @@ -138,6 +139,26 @@ static const struct v4l2_ctrl_config pwc_restore_factory_cfg = { .name = "Restore Factory Settings", }; +static const struct v4l2_ctrl_config pwc_awb_speed_cfg = { + .ops = &pwc_ctrl_ops, + .id = PWC_CID_CUSTOM(awb_speed), + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Auto White Balance Speed", + .min = 1, + .max = 32, + .step = 1, +}; + +static const struct v4l2_ctrl_config pwc_awb_delay_cfg = { + .ops = &pwc_ctrl_ops, + .id = PWC_CID_CUSTOM(awb_delay), + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Auto White Balance Delay", + .min = 0, + .max = 63, + .step = 1, +}; + int pwc_init_controls(struct pwc_device *pdev) { struct v4l2_ctrl_handler *hdl; @@ -338,6 +359,23 @@ int pwc_init_controls(struct pwc_device *pdev) if (pdev->restore_factory) pdev->restore_factory->flags |= V4L2_CTRL_FLAG_UPDATE; + /* Auto White Balance speed & delay */ + r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, + AWB_CONTROL_SPEED_FORMATTER, &def); + if (r || def < 1 || def > 32) + def = 1; + cfg = pwc_awb_speed_cfg; + cfg.def = def; + pdev->awb_speed = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + + r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, + AWB_CONTROL_DELAY_FORMATTER, &def); + if (r || def > 63) + def = 0; + cfg = pwc_awb_delay_cfg; + cfg.def = def; + pdev->awb_delay = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + if (!(pdev->features & FEATURE_MOTOR_PANTILT)) return hdl->error; @@ -357,25 +395,16 @@ int pwc_init_controls(struct pwc_device *pdev) return hdl->error; } -static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) +static void pwc_vidioc_fill_fmt(struct v4l2_format *f, + int width, int height, u32 pixfmt) { memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); - f->fmt.pix.width = pdev->view.x; - f->fmt.pix.height = pdev->view.y; + f->fmt.pix.width = width; + f->fmt.pix.height = height; f->fmt.pix.field = V4L2_FIELD_NONE; - if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; - f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - } else { - /* vbandlength contains 4 lines ... */ - f->fmt.pix.bytesperline = pdev->vbandlength/4; - f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame); - if (DEVICE_USE_CODEC1(pdev->type)) - f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1; - else - f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2; - } + f->fmt.pix.pixelformat = pixfmt; + f->fmt.pix.bytesperline = f->fmt.pix.width; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.width * 3 / 2; PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() " "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n", f->fmt.pix.width, @@ -391,6 +420,8 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma /* ioctl(VIDIOC_TRY_FMT) */ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) { + int size; + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); return -EINVAL; @@ -417,15 +448,11 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) } - if (f->fmt.pix.width > pdev->view_max.x) - f->fmt.pix.width = pdev->view_max.x; - else if (f->fmt.pix.width < pdev->view_min.x) - f->fmt.pix.width = pdev->view_min.x; - - if (f->fmt.pix.height > pdev->view_max.y) - f->fmt.pix.height = pdev->view_max.y; - else if (f->fmt.pix.height < pdev->view_min.y) - f->fmt.pix.height = pdev->view_min.y; + size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height); + pwc_vidioc_fill_fmt(f, + pwc_image_sizes[size][0], + pwc_image_sizes[size][1], + f->fmt.pix.pixelformat); return 0; } @@ -435,68 +462,45 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { struct pwc_device *pdev = video_drvdata(file); - int ret, fps, snapshot, compression, pixelformat; - - if (!pdev->udev) - return -ENODEV; + int ret, pixelformat, compression = 0; - if (pdev->capt_file != NULL && - pdev->capt_file != file) + if (pwc_test_n_set_capt_file(pdev, file)) return -EBUSY; - pdev->capt_file = file; - ret = pwc_vidioc_try_fmt(pdev, f); - if (ret<0) + if (ret < 0) return ret; pixelformat = f->fmt.pix.pixelformat; - compression = pdev->vcompression; - snapshot = 0; - fps = pdev->vframes; - if (f->fmt.pix.priv) { - compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT; - snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT); - fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; - if (fps == 0) - fps = pdev->vframes; - } - if (pixelformat != V4L2_PIX_FMT_YUV420 && - pixelformat != V4L2_PIX_FMT_PWC1 && - pixelformat != V4L2_PIX_FMT_PWC2) - return -EINVAL; + mutex_lock(&pdev->udevlock); + if (!pdev->udev) { + ret = -ENODEV; + goto leave; + } - if (vb2_is_streaming(&pdev->vb_queue)) - return -EBUSY; + if (pdev->iso_init) { + ret = -EBUSY; + goto leave; + } PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d " - "compression=%d snapshot=%d format=%c%c%c%c\n", - f->fmt.pix.width, f->fmt.pix.height, fps, - compression, snapshot, + "format=%c%c%c%c\n", + f->fmt.pix.width, f->fmt.pix.height, pdev->vframes, (pixelformat)&255, (pixelformat>>8)&255, (pixelformat>>16)&255, (pixelformat>>24)&255); - ret = pwc_set_video_mode(pdev, - f->fmt.pix.width, - f->fmt.pix.height, - fps, - compression, - snapshot); + ret = pwc_set_video_mode(pdev, f->fmt.pix.width, f->fmt.pix.height, + pixelformat, 30, &compression, 0); PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret); - if (ret) - return ret; - - pdev->pixfmt = pixelformat; - - pwc_vidioc_fill_fmt(pdev, f); - - return 0; - + pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt); +leave: + mutex_unlock(&pdev->udevlock); + return ret; } static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) @@ -536,30 +540,14 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i) return i ? -EINVAL : 0; } -static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +static int pwc_g_volatile_ctrl_unlocked(struct v4l2_ctrl *ctrl) { struct pwc_device *pdev = container_of(ctrl->handler, struct pwc_device, ctrl_handler); int ret = 0; - /* - * Sometimes it can take quite long for the pwc to complete usb control - * transfers, so release the modlock to give streaming by another - * process / thread the chance to continue with a dqbuf. - */ - mutex_unlock(&pdev->modlock); - - /* - * Take the udev-lock to protect against the disconnect handler - * completing and setting dev->udev to NULL underneath us. Other code - * does not need to do this since it is protected by the modlock. - */ - mutex_lock(&pdev->udevlock); - - if (!pdev->udev) { - ret = -ENODEV; - goto leave; - } + if (!pdev->udev) + return -ENODEV; switch (ctrl->id) { case V4L2_CID_AUTO_WHITE_BALANCE: @@ -624,9 +612,18 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) if (ret) PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret); -leave: + return ret; +} + +static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct pwc_device *pdev = + container_of(ctrl->handler, struct pwc_device, ctrl_handler); + int ret; + + mutex_lock(&pdev->udevlock); + ret = pwc_g_volatile_ctrl_unlocked(ctrl); mutex_unlock(&pdev->udevlock); - mutex_lock(&pdev->modlock); return ret; } @@ -643,6 +640,15 @@ static int pwc_set_awb(struct pwc_device *pdev) if (pdev->auto_white_balance->val != awb_manual) pdev->color_bal_valid = false; /* Force cache update */ + + /* + * If this is a preset, update our red / blue balance values + * so that events get generated for the new preset values + */ + if (pdev->auto_white_balance->val == awb_indoor || + pdev->auto_white_balance->val == awb_outdoor || + pdev->auto_white_balance->val == awb_fl) + pwc_g_volatile_ctrl_unlocked(pdev->auto_white_balance); } if (pdev->auto_white_balance->val != awb_manual) return 0; @@ -766,33 +772,33 @@ static int pwc_set_autogain_expo(struct pwc_device *pdev) static int pwc_set_motor(struct pwc_device *pdev) { int ret; - u8 buf[4]; - buf[0] = 0; + pdev->ctrl_buf[0] = 0; if (pdev->motor_pan_reset->is_new) - buf[0] |= 0x01; + pdev->ctrl_buf[0] |= 0x01; if (pdev->motor_tilt_reset->is_new) - buf[0] |= 0x02; + pdev->ctrl_buf[0] |= 0x02; if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) { ret = send_control_msg(pdev, SET_MPT_CTL, - PT_RESET_CONTROL_FORMATTER, buf, 1); + PT_RESET_CONTROL_FORMATTER, + pdev->ctrl_buf, 1); if (ret < 0) return ret; } - memset(buf, 0, sizeof(buf)); + memset(pdev->ctrl_buf, 0, 4); if (pdev->motor_pan->is_new) { - buf[0] = pdev->motor_pan->val & 0xFF; - buf[1] = (pdev->motor_pan->val >> 8); + pdev->ctrl_buf[0] = pdev->motor_pan->val & 0xFF; + pdev->ctrl_buf[1] = (pdev->motor_pan->val >> 8); } if (pdev->motor_tilt->is_new) { - buf[2] = pdev->motor_tilt->val & 0xFF; - buf[3] = (pdev->motor_tilt->val >> 8); + pdev->ctrl_buf[2] = pdev->motor_tilt->val & 0xFF; + pdev->ctrl_buf[3] = (pdev->motor_tilt->val >> 8); } if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) { ret = send_control_msg(pdev, SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, - buf, sizeof(buf)); + pdev->ctrl_buf, 4); if (ret < 0) return ret; } @@ -806,8 +812,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) container_of(ctrl->handler, struct pwc_device, ctrl_handler); int ret = 0; - /* See the comments on locking in pwc_g_volatile_ctrl */ - mutex_unlock(&pdev->modlock); mutex_lock(&pdev->udevlock); if (!pdev->udev) { @@ -891,6 +895,16 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER); break; + case PWC_CID_CUSTOM(awb_speed): + ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, + AWB_CONTROL_SPEED_FORMATTER, + ctrl->val); + break; + case PWC_CID_CUSTOM(awb_delay): + ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, + AWB_CONTROL_DELAY_FORMATTER, + ctrl->val); + break; case V4L2_CID_PAN_RELATIVE: ret = pwc_set_motor(pdev); break; @@ -903,7 +917,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) leave: mutex_unlock(&pdev->udevlock); - mutex_lock(&pdev->modlock); return ret; } @@ -933,9 +946,14 @@ static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { struct pwc_device *pdev = video_drvdata(file); + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */ PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n", - pdev->image.x, pdev->image.y); - pwc_vidioc_fill_fmt(pdev, f); + pdev->width, pdev->height); + pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt); + mutex_unlock(&pdev->udevlock); return 0; } @@ -951,12 +969,9 @@ static int pwc_reqbufs(struct file *file, void *fh, { struct pwc_device *pdev = video_drvdata(file); - if (pdev->capt_file != NULL && - pdev->capt_file != file) + if (pwc_test_n_set_capt_file(pdev, file)) return -EBUSY; - pdev->capt_file = file; - return vb2_reqbufs(&pdev->vb_queue, rb); } @@ -1025,25 +1040,21 @@ static int pwc_enum_framesizes(struct file *file, void *fh, struct pwc_device *pdev = video_drvdata(file); unsigned int i = 0, index = fsize->index; - if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { + if (fsize->pixel_format == V4L2_PIX_FMT_YUV420 || + (fsize->pixel_format == V4L2_PIX_FMT_PWC1 && + DEVICE_USE_CODEC1(pdev->type)) || + (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && + DEVICE_USE_CODEC23(pdev->type))) { for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1UL << i)) { - if (!index--) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pwc_image_sizes[i].x; - fsize->discrete.height = pwc_image_sizes[i].y; - return 0; - } + if (!(pdev->image_mask & (1UL << i))) + continue; + if (!index--) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = pwc_image_sizes[i][0]; + fsize->discrete.height = pwc_image_sizes[i][1]; + return 0; } } - } else if (fsize->index == 0 && - ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || - (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pdev->abs_max.x; - fsize->discrete.height = pdev->abs_max.y; - return 0; } return -EINVAL; } @@ -1056,8 +1067,8 @@ static int pwc_enum_frameintervals(struct file *file, void *fh, unsigned int i; for (i = 0; i < PSZ_MAX; i++) { - if (pwc_image_sizes[i].x == fival->width && - pwc_image_sizes[i].y == fival->height) { + if (pwc_image_sizes[i][0] == fival->width && + pwc_image_sizes[i][1] == fival->height) { size = i; break; } @@ -1078,20 +1089,69 @@ static int pwc_enum_frameintervals(struct file *file, void *fh, return 0; } -static int pwc_log_status(struct file *file, void *priv) +static int pwc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) { struct pwc_device *pdev = video_drvdata(file); - v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME); + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(parm, 0, sizeof(*parm)); + + parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + parm->parm.capture.readbuffers = MIN_FRAMES; + parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe.denominator = pdev->vframes; + parm->parm.capture.timeperframe.numerator = 1; + return 0; } -static long pwc_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) +static int pwc_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) { struct pwc_device *pdev = video_drvdata(file); + int compression = 0; + int ret, fps; - return pwc_ioctl(pdev, cmd, arg); + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + parm->parm.capture.timeperframe.numerator == 0) + return -EINVAL; + + if (pwc_test_n_set_capt_file(pdev, file)) + return -EBUSY; + + fps = parm->parm.capture.timeperframe.denominator / + parm->parm.capture.timeperframe.numerator; + + mutex_lock(&pdev->udevlock); + if (!pdev->udev) { + ret = -ENODEV; + goto leave; + } + + if (pdev->iso_init) { + ret = -EBUSY; + goto leave; + } + + ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt, + fps, &compression, 0); + + pwc_g_parm(file, fh, parm); + +leave: + mutex_unlock(&pdev->udevlock); + return ret; +} + +static int pwc_log_status(struct file *file, void *priv) +{ + struct pwc_device *pdev = video_drvdata(file); + + v4l2_ctrl_handler_log_status(&pdev->ctrl_handler, PWC_NAME); + return 0; } const struct v4l2_ioctl_ops pwc_ioctl_ops = { @@ -1112,8 +1172,6 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = { .vidioc_log_status = pwc_log_status, .vidioc_enum_framesizes = pwc_enum_framesizes, .vidioc_enum_frameintervals = pwc_enum_frameintervals, - .vidioc_default = pwc_default, + .vidioc_g_parm = pwc_g_parm, + .vidioc_s_parm = pwc_s_parm, }; - - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 0e4e2d7b7872..e4d4d711dd1f 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -35,14 +35,17 @@ #include <asm/errno.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-event.h> #include <media/videobuf2-vmalloc.h> #ifdef CONFIG_USB_PWC_INPUT_EVDEV #include <linux/input.h> #endif - -#include <media/pwc-ioctl.h> +#include "pwc-dec1.h" +#include "pwc-dec23.h" /* Version block */ #define PWC_VERSION "10.0.15" @@ -106,6 +109,9 @@ #define FEATURE_CODEC1 0x0002 #define FEATURE_CODEC2 0x0004 +#define MAX_WIDTH 640 +#define MAX_HEIGHT 480 + /* Ignore errors in the first N frames, to allow for startup delays */ #define FRAME_LOWMARK 5 @@ -128,9 +134,6 @@ #define DEVICE_USE_CODEC3(x) ((x)>=700) #define DEVICE_USE_CODEC23(x) ((x)>=675) -/* from pwc-dec.h */ -#define PWCX_FLAG_PLANAR 0x0001 - /* Request types: video */ #define SET_LUM_CTL 0x01 #define GET_LUM_CTL 0x02 @@ -186,6 +189,24 @@ #define PT_RESET_CONTROL_FORMATTER 0x02 #define PT_STATUS_FORMATTER 0x03 +/* Enumeration of image sizes */ +#define PSZ_SQCIF 0x00 +#define PSZ_QSIF 0x01 +#define PSZ_QCIF 0x02 +#define PSZ_SIF 0x03 +#define PSZ_CIF 0x04 +#define PSZ_VGA 0x05 +#define PSZ_MAX 6 + +struct pwc_raw_frame { + __le16 type; /* type of the webcam */ + __le16 vbandlength; /* Size of 4 lines compressed (used by the + decompressor) */ + __u8 cmd[4]; /* the four byte of the command (in case of + nala, only the first 3 bytes is filled) */ + __u8 rawframe[0]; /* frame_size = H / 4 * vbandlength */ +} __packed; + /* intermediate buffers with raw data from the USB cam */ struct pwc_frame_buf { @@ -198,39 +219,36 @@ struct pwc_frame_buf struct pwc_device { struct video_device vdev; - struct mutex modlock; + struct v4l2_device v4l2_dev; /* Pointer to our usb_device, may be NULL after unplug */ struct usb_device *udev; - /* Protects the setting of udev to NULL by our disconnect handler */ struct mutex udevlock; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ int type; int release; /* release number */ int features; /* feature bits */ - char serial[30]; /* serial number (string) */ /*** Video data ***/ struct file *capt_file; /* file doing video capture */ + struct mutex capt_file_lock; int vendpoint; /* video isoc endpoint */ int vcinterface; /* video control interface */ int valternate; /* alternate interface needed */ - int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ + int vframes; /* frames-per-second */ int pixfmt; /* pixelformat: V4L2_PIX_FMT_YUV420 or _PWCX */ int vframe_count; /* received frames */ int vmax_packet_size; /* USB maxpacket size */ int vlast_packet_size; /* for frame synchronisation */ int visoc_errors; /* number of contiguous ISOC errors */ - int vcompression; /* desired compression factor */ int vbandlength; /* compressed band length; 0 is uncompressed */ - char vsnapshot; /* snapshot mode */ char vsync; /* used by isoc handler */ char vmirror; /* for ToUCaM series */ char power_save; /* Do powersaving for this cam */ - int cmd_len; unsigned char cmd_buf[13]; + unsigned char *ctrl_buf; struct urb *urbs[MAX_ISO_BUFS]; char iso_init; @@ -253,7 +271,10 @@ struct pwc_device int frame_total_size; /* including header & trailer */ int drop_frames; - void *decompress_data; /* private data for decompression engine */ + union { /* private data for decompression engine */ + struct pwc_dec1_private dec1; + struct pwc_dec23_private dec23; + }; /* * We have an 'image' and a 'view', where 'image' is the fixed-size img @@ -262,21 +283,8 @@ struct pwc_device * a gray or black border. view_min <= image <= view <= view_max; */ int image_mask; /* supported sizes */ - struct pwc_coord view_min, view_max; /* minimum and maximum view */ - struct pwc_coord abs_max; /* maximum supported size */ - struct pwc_coord image, view; /* image and viewport size */ - struct pwc_coord offset; /* offset of the viewport */ + int width, height; /* current resolution */ - /*** motorized pan/tilt feature */ - struct pwc_mpt_range angle_range; - int pan_angle; /* in degrees * 100 */ - int tilt_angle; /* absolute angle; 0,0 is home */ - - /* - * Set to 1 when the user push the button, reset to 0 - * when this value is read from sysfs. - */ - int snapshot_button_status; #ifdef CONFIG_USB_PWC_INPUT_EVDEV struct input_dev *button_dev; /* webcam snapshot button input */ char button_phys[64]; @@ -328,6 +336,8 @@ struct pwc_device struct v4l2_ctrl *save_user; struct v4l2_ctrl *restore_user; struct v4l2_ctrl *restore_factory; + struct v4l2_ctrl *awb_speed; + struct v4l2_ctrl *awb_delay; struct { /* motor control cluster */ struct v4l2_ctrl *motor_pan; @@ -344,19 +354,20 @@ struct pwc_device extern int pwc_trace; #endif +int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file); + /** Functions in pwc-misc.c */ /* sizes in pixels */ -extern const struct pwc_coord pwc_image_sizes[PSZ_MAX]; +extern const int pwc_image_sizes[PSZ_MAX][2]; -int pwc_decode_size(struct pwc_device *pdev, int width, int height); +int pwc_get_size(struct pwc_device *pdev, int width, int height); void pwc_construct(struct pwc_device *pdev); /** Functions in pwc-ctrl.c */ /* Request a certain video mode. Returns < 0 if not possible */ -extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); +extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, + int pixfmt, int frames, int *compression, int send_to_cam); extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); -extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); -extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); extern int send_control_msg(struct pwc_device *pdev, @@ -375,9 +386,6 @@ int pwc_init_controls(struct pwc_device *pdev); /* Power down or up the camera; not supported by all models */ extern void pwc_camera_power(struct pwc_device *pdev, int power); -/* Private ioctl()s; see pwc-ioctl.h */ -extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); - extern const struct v4l2_ioctl_ops pwc_ioctl_ops; /** pwc-uncompress.c */ diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 79fb22c89ae9..0bd7da26d018 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -1133,12 +1133,13 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, __raw_writel(cicr0, pcdev->base + CICR0); } -static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +static int pxa_camera_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct pxa_camera_dev *pcdev = ici->priv; struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; + u32 pixfmt = icd->current_fmt->host_fmt->fourcc; unsigned long bus_flags, common_flags; int ret; struct pxa_cam *cam = icd->host_priv; @@ -1851,19 +1852,7 @@ static struct platform_driver pxa_camera_driver = { .remove = __devexit_p(pxa_camera_remove), }; - -static int __init pxa_camera_init(void) -{ - return platform_driver_register(&pxa_camera_driver); -} - -static void __exit pxa_camera_exit(void) -{ - platform_driver_unregister(&pxa_camera_driver); -} - -module_init(pxa_camera_init); -module_exit(pxa_camera_exit); +module_platform_driver(pxa_camera_driver); MODULE_DESCRIPTION("PXA27x SoC Camera Host driver"); MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 2cc3b9166724..a9e9653beeb4 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -63,6 +63,8 @@ static int fimc_init_capture(struct fimc_dev *fimc) fimc_hw_set_effect(ctx, false); fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); + if (fimc->variant->has_alpha) + fimc_hw_set_rgb_alpha(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock_irqrestore(&fimc->slock, flags); @@ -154,6 +156,8 @@ int fimc_capture_config_update(struct fimc_ctx *ctx) fimc_hw_set_rotation(ctx); fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_hw_set_out_dma(ctx); + if (fimc->variant->has_alpha) + fimc_hw_set_rgb_alpha(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock(&ctx->slock); @@ -689,7 +693,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, mf->code = 0; continue; } - if (mf->width != tfmt->width || mf->width != tfmt->width) { + if (mf->width != tfmt->width || mf->height != tfmt->height) { u32 fcc = ffmt->fourcc; tfmt->width = mf->width; tfmt->height = mf->height; @@ -698,7 +702,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, NULL, &fcc, FIMC_SD_PAD_SOURCE); if (ffmt && ffmt->mbus_code) mf->code = ffmt->mbus_code; - if (mf->width != tfmt->width || mf->width != tfmt->width) + if (mf->width != tfmt->width || + mf->height != tfmt->height) continue; tfmt->code = mf->code; } @@ -706,7 +711,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, ret = v4l2_subdev_call(csis, pad, set_fmt, NULL, &sfmt); if (mf->code == tfmt->code && - mf->width == tfmt->width && mf->width == tfmt->width) + mf->width == tfmt->width && mf->height == tfmt->height) break; } @@ -812,6 +817,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) FIMC_SD_PAD_SOURCE); if (!ff->fmt) return -EINVAL; + + /* Update RGB Alpha control state and value range */ + fimc_alpha_ctrl_update(ctx); + /* Try to match format at the host and the sensor */ if (!fimc->vid_cap.user_subdev_api) { mf->code = ff->fmt->mbus_code; @@ -1235,6 +1244,9 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, *mf = fmt->format; return 0; } + /* 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)); ff = fmt->pad == FIMC_SD_PAD_SINK ? diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 07c6254faee3..81bcbb9492ea 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -52,13 +52,29 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M, }, { - .name = "XRGB-8-8-8-8, 32 bpp", + .name = "ARGB8888, 32 bpp", .fourcc = V4L2_PIX_FMT_RGB32, .depth = { 32 }, .color = S5P_FIMC_RGB888, .memplanes = 1, .colplanes = 1, - .flags = FMT_FLAGS_M2M, + .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA, + }, { + .name = "ARGB1555", + .fourcc = V4L2_PIX_FMT_RGB555, + .depth = { 16 }, + .color = S5P_FIMC_RGB555, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, + }, { + .name = "ARGB4444", + .fourcc = V4L2_PIX_FMT_RGB444, + .depth = { 16 }, + .color = S5P_FIMC_RGB444, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, }, { .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, @@ -171,6 +187,14 @@ static struct fimc_fmt fimc_formats[] = { }, }; +static unsigned int get_m2m_fmt_flags(unsigned int stream_type) +{ + if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return FMT_FLAGS_M2M_IN; + else + return FMT_FLAGS_M2M_OUT; +} + int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, int dw, int dh, int rotation) { @@ -652,8 +676,11 @@ static void fimc_dma_run(void *priv) if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS)) fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1); - if (ctx->state & FIMC_PARAMS) + if (ctx->state & FIMC_PARAMS) { fimc_hw_set_out_dma(ctx); + if (fimc->variant->has_alpha) + fimc_hw_set_rgb_alpha(ctx); + } fimc_activate_capture(ctx); @@ -750,12 +777,11 @@ static struct vb2_ops fimc_qops = { #define ctrl_to_ctx(__ctrl) \ container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler) -static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) +static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl) { - struct fimc_ctx *ctx = ctrl_to_ctx(ctrl); struct fimc_dev *fimc = ctx->fimc_dev; struct samsung_fimc_variant *variant = fimc->variant; - unsigned long flags; + unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT; int ret = 0; if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) @@ -763,59 +789,77 @@ static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_HFLIP: - spin_lock_irqsave(&ctx->slock, flags); ctx->hflip = ctrl->val; break; case V4L2_CID_VFLIP: - spin_lock_irqsave(&ctx->slock, flags); ctx->vflip = ctrl->val; break; case V4L2_CID_ROTATE: if (fimc_capture_pending(fimc) || - fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { + (ctx->state & flags) == flags) { ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, ctx->s_frame.height, ctx->d_frame.width, ctx->d_frame.height, ctrl->val); - } - if (ret) { - v4l2_err(fimc->m2m.vfd, "Out of scaler range\n"); - return -EINVAL; + if (ret) + return -EINVAL; } if ((ctrl->val == 90 || ctrl->val == 270) && !variant->has_out_rot) return -EINVAL; - spin_lock_irqsave(&ctx->slock, flags); + ctx->rotation = ctrl->val; break; - default: - v4l2_err(fimc->v4l2_dev, "Invalid control: 0x%X\n", ctrl->id); - return -EINVAL; + case V4L2_CID_ALPHA_COMPONENT: + ctx->d_frame.alpha = ctrl->val; + break; } ctx->state |= FIMC_PARAMS; set_bit(ST_CAPT_APPLY_CFG, &fimc->state); - spin_unlock_irqrestore(&ctx->slock, flags); return 0; } +static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fimc_ctx *ctx = ctrl_to_ctx(ctrl); + unsigned long flags; + int ret; + + spin_lock_irqsave(&ctx->slock, flags); + ret = __fimc_s_ctrl(ctx, ctrl); + spin_unlock_irqrestore(&ctx->slock, flags); + + return ret; +} + static const struct v4l2_ctrl_ops fimc_ctrl_ops = { .s_ctrl = fimc_s_ctrl, }; int fimc_ctrls_create(struct fimc_ctx *ctx) { + struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; + unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt); + if (ctx->ctrls_rdy) return 0; - v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4); ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); + V4L2_CID_ROTATE, 0, 270, 90, 0); ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); + V4L2_CID_HFLIP, 0, 1, 1, 0); ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, - V4L2_CID_ROTATE, 0, 270, 90, 0); + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (variant->has_alpha) + ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, + 0, max_alpha, 1, 0); + else + ctx->ctrl_alpha = NULL; + ctx->ctrls_rdy = ctx->ctrl_handler.error == 0; return ctx->ctrl_handler.error; @@ -826,11 +870,14 @@ void fimc_ctrls_delete(struct fimc_ctx *ctx) if (ctx->ctrls_rdy) { v4l2_ctrl_handler_free(&ctx->ctrl_handler); ctx->ctrls_rdy = false; + ctx->ctrl_alpha = NULL; } } void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) { + unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA; + if (!ctx->ctrls_rdy) return; @@ -838,6 +885,8 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) v4l2_ctrl_activate(ctx->ctrl_rotate, active); v4l2_ctrl_activate(ctx->ctrl_hflip, active); v4l2_ctrl_activate(ctx->ctrl_vflip, active); + if (ctx->ctrl_alpha) + v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha); if (active) { ctx->rotation = ctx->ctrl_rotate->val; @@ -851,6 +900,24 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) mutex_unlock(&ctx->ctrl_handler.lock); } +/* Update maximum value of the alpha color control */ +void fimc_alpha_ctrl_update(struct fimc_ctx *ctx) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_ctrl *ctrl = ctx->ctrl_alpha; + + if (ctrl == NULL || !fimc->variant->has_alpha) + return; + + v4l2_ctrl_lock(ctrl); + ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt); + + if (ctrl->cur.val > ctrl->maximum) + ctrl->cur.val = ctrl->maximum; + + v4l2_ctrl_unlock(ctrl); +} + /* * V4L2 ioctl handlers */ @@ -874,7 +941,8 @@ static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, { struct fimc_fmt *fmt; - fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_M2M, f->index); + fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type), + f->index); if (!fmt) return -EINVAL; @@ -938,6 +1006,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, pix->colorspace = V4L2_COLORSPACE_JPEG; pix->field = V4L2_FIELD_NONE; pix->num_planes = fmt->memplanes; + pix->pixelformat = fmt->fourcc; pix->height = height; pix->width = width; @@ -1017,7 +1086,8 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) dbg("w: %d, h: %d", pix->width, pix->height); - fmt = fimc_find_format(&pix->pixelformat, NULL, FMT_FLAGS_M2M, 0); + fmt = fimc_find_format(&pix->pixelformat, NULL, + get_m2m_fmt_flags(f->type), 0); if (WARN(fmt == NULL, "Pixel format lookup failed")) return -EINVAL; @@ -1087,10 +1157,13 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, pix = &f->fmt.pix_mp; frame->fmt = fimc_find_format(&pix->pixelformat, NULL, - FMT_FLAGS_M2M, 0); + get_m2m_fmt_flags(f->type), 0); if (!frame->fmt) return -EINVAL; + /* Update RGB Alpha control state and value range */ + fimc_alpha_ctrl_update(ctx); + for (i = 0; i < frame->fmt->colplanes; i++) { frame->payload[i] = (pix->width * pix->height * frame->fmt->depth[i]) / 8; @@ -1374,6 +1447,12 @@ static int fimc_m2m_open(struct file *file) if (!ctx) return -ENOMEM; v4l2_fh_init(&ctx->fh, fimc->m2m.vfd); + ctx->fimc_dev = fimc; + + /* Default color format */ + ctx->s_frame.fmt = &fimc_formats[0]; + ctx->d_frame.fmt = &fimc_formats[0]; + ret = fimc_ctrls_create(ctx); if (ret) goto error_fh; @@ -1383,10 +1462,6 @@ static int fimc_m2m_open(struct file *file) file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); - ctx->fimc_dev = fimc; - /* Default color format */ - ctx->s_frame.fmt = &fimc_formats[0]; - ctx->d_frame.fmt = &fimc_formats[0]; /* Setup the device context for memory-to-memory mode */ ctx->state = FIMC_CTX_M2M; ctx->flags = 0; @@ -1709,9 +1784,8 @@ static int fimc_runtime_resume(struct device *dev) /* Resume the capture or mem-to-mem device */ if (fimc_capture_busy(fimc)) return fimc_capture_resume(fimc); - else if (fimc_m2m_pending(fimc)) - return fimc_m2m_resume(fimc); - return 0; + + return fimc_m2m_resume(fimc); } static int fimc_runtime_suspend(struct device *dev) @@ -1893,6 +1967,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = { .has_cam_if = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, + .has_alpha = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, @@ -1906,6 +1981,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = { .has_cam_if = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, + .has_alpha = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index c7f01c47b20f..4e20560c73d4 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -85,7 +85,9 @@ enum fimc_datapath { }; enum fimc_color_fmt { - S5P_FIMC_RGB565 = 0x10, + S5P_FIMC_RGB444 = 0x10, + S5P_FIMC_RGB555, + S5P_FIMC_RGB565, S5P_FIMC_RGB666, S5P_FIMC_RGB888, S5P_FIMC_RGB30_LOCAL, @@ -160,8 +162,11 @@ struct fimc_fmt { u16 colplanes; u8 depth[VIDEO_MAX_PLANES]; u16 flags; -#define FMT_FLAGS_CAM (1 << 0) -#define FMT_FLAGS_M2M (1 << 1) +#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) }; /** @@ -283,6 +288,7 @@ struct fimc_frame { struct fimc_addr paddr; struct fimc_dma_offset dma_offset; struct fimc_fmt *fmt; + u8 alpha; }; /** @@ -387,6 +393,7 @@ struct samsung_fimc_variant { unsigned int has_cistatus2:1; unsigned int has_mainscaler_ext:1; unsigned int has_cam_if:1; + unsigned int has_alpha:1; struct fimc_pix_limit *pix_limit; u16 min_inp_pixsize; u16 min_out_pixsize; @@ -482,7 +489,8 @@ struct fimc_dev { * @ctrl_handler: v4l2 controls handler * @ctrl_rotate image rotation control * @ctrl_hflip horizontal flip control - * @ctrl_vflip vartical flip control + * @ctrl_vflip vertical flip control + * @ctrl_alpha RGB alpha control * @ctrls_rdy: true if the control handler is initialized */ struct fimc_ctx { @@ -509,6 +517,7 @@ struct fimc_ctx { struct v4l2_ctrl *ctrl_rotate; struct v4l2_ctrl *ctrl_hflip; struct v4l2_ctrl *ctrl_vflip; + struct v4l2_ctrl *ctrl_alpha; bool ctrls_rdy; }; @@ -578,6 +587,17 @@ static inline int tiled_fmt(struct fimc_fmt *fmt) return fmt->fourcc == V4L2_PIX_FMT_NV12MT; } +/* Return the alpha component bit mask */ +static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt) +{ + switch (fmt->color) { + case S5P_FIMC_RGB444: return 0x0f; + case S5P_FIMC_RGB555: return 0x01; + case S5P_FIMC_RGB888: return 0xff; + default: return 0; + }; +} + static inline void fimc_hw_clear_irq(struct fimc_dev *dev) { u32 cfg = readl(dev->regs + S5P_CIGCTRL); @@ -674,6 +694,7 @@ void fimc_hw_set_prescaler(struct fimc_ctx *ctx); void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); void fimc_hw_en_capture(struct fimc_ctx *ctx); void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active); +void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx); void fimc_hw_set_in_dma(struct fimc_ctx *ctx); void fimc_hw_set_input_path(struct fimc_ctx *ctx); void fimc_hw_set_output_path(struct fimc_ctx *ctx); @@ -695,6 +716,7 @@ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, int fimc_ctrls_create(struct fimc_ctx *ctx); void fimc_ctrls_delete(struct fimc_ctx *ctx); void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); +void fimc_alpha_ctrl_update(struct fimc_ctx *ctx); int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f); void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, struct v4l2_pix_format_mplane *pix); diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index 615c862f0360..8ea4ee116e46 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -21,7 +21,6 @@ #include <linux/pm_runtime.h> #include <linux/types.h> #include <linux/slab.h> -#include <linux/version.h> #include <media/v4l2-ctrls.h> #include <media/media-device.h> diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 44f5c2d1920b..15466d0529c1 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -117,7 +117,7 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx) S5P_CITRGFMT_VSIZE_MASK); switch (frame->fmt->color) { - case S5P_FIMC_RGB565...S5P_FIMC_RGB888: + case S5P_FIMC_RGB444...S5P_FIMC_RGB888: cfg |= S5P_CITRGFMT_RGB; break; case S5P_FIMC_YCBCR420: @@ -175,6 +175,7 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx) struct fimc_dev *dev = ctx->fimc_dev; struct fimc_frame *frame = &ctx->d_frame; struct fimc_dma_offset *offset = &frame->dma_offset; + struct fimc_fmt *fmt = frame->fmt; /* Set the input dma offsets. */ cfg = 0; @@ -198,15 +199,22 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx) cfg = readl(dev->regs + S5P_CIOCTRL); cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK | - S5P_CIOCTRL_YCBCR_PLANE_MASK); + S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK); - if (frame->fmt->colplanes == 1) + if (fmt->colplanes == 1) cfg |= ctx->out_order_1p; - else if (frame->fmt->colplanes == 2) + else if (fmt->colplanes == 2) cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE; - else if (frame->fmt->colplanes == 3) + else if (fmt->colplanes == 3) cfg |= S5P_CIOCTRL_YCBCR_3PLANE; + if (fmt->color == S5P_FIMC_RGB565) + cfg |= S5P_CIOCTRL_RGB565; + else if (fmt->color == S5P_FIMC_RGB555) + cfg |= S5P_CIOCTRL_ARGB1555; + else if (fmt->color == S5P_FIMC_RGB444) + cfg |= S5P_CIOCTRL_ARGB4444; + writel(cfg, dev->regs + S5P_CIOCTRL); } @@ -278,22 +286,28 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx) if (sc->copy_mode) cfg |= S5P_CISCCTRL_ONE2ONE; - if (ctx->in_path == FIMC_DMA) { - if (src_frame->fmt->color == S5P_FIMC_RGB565) + switch (src_frame->fmt->color) { + case S5P_FIMC_RGB565: cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565; - else if (src_frame->fmt->color == S5P_FIMC_RGB666) + break; + case S5P_FIMC_RGB666: cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666; - else if (src_frame->fmt->color == S5P_FIMC_RGB888) + break; + case S5P_FIMC_RGB888: cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888; + break; + } } if (ctx->out_path == FIMC_DMA) { - if (dst_frame->fmt->color == S5P_FIMC_RGB565) + u32 color = dst_frame->fmt->color; + + if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565) cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565; - else if (dst_frame->fmt->color == S5P_FIMC_RGB666) + else if (color == S5P_FIMC_RGB666) cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666; - else if (dst_frame->fmt->color == S5P_FIMC_RGB888) + else if (color == S5P_FIMC_RGB888) cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; } else { cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; @@ -379,6 +393,21 @@ void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active) writel(cfg, dev->regs + S5P_CIIMGEFF); } +void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_frame *frame = &ctx->d_frame; + u32 cfg; + + if (!(frame->fmt->flags & FMT_HAS_ALPHA)) + return; + + cfg = readl(dev->regs + S5P_CIOCTRL); + cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK; + cfg |= (frame->alpha << 4); + writel(cfg, dev->regs + S5P_CIOCTRL); +} + static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c index 59d79bc2f58a..130335cf62fd 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.c +++ b/drivers/media/video/s5p-fimc/mipi-csis.c @@ -427,6 +427,23 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } +static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + + format->colorspace = V4L2_COLORSPACE_JPEG; + format->code = s5pcsis_formats[0].code; + format->width = S5PCSIS_DEF_PIX_WIDTH; + format->height = S5PCSIS_DEF_PIX_HEIGHT; + format->field = V4L2_FIELD_NONE; + + return 0; +} + +static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = { + .open = s5pcsis_open, +}; + static struct v4l2_subdev_core_ops s5pcsis_core_ops = { .s_power = s5pcsis_s_power, }; @@ -544,8 +561,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); state->sd.owner = THIS_MODULE; strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name)); + state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; state->csis_fmt = &s5pcsis_formats[0]; + state->format.code = s5pcsis_formats[0].code; + state->format.width = S5PCSIS_DEF_PIX_WIDTH; + state->format.height = S5PCSIS_DEF_PIX_HEIGHT; + state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&state->sd.entity, diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/video/s5p-fimc/mipi-csis.h index f5691336dd5c..2709286396e1 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.h +++ b/drivers/media/video/s5p-fimc/mipi-csis.h @@ -19,4 +19,7 @@ #define CSIS_PAD_SOURCE 1 #define CSIS_PADS_NUM 2 +#define S5PCSIS_DEF_PIX_WIDTH 640 +#define S5PCSIS_DEF_PIX_HEIGHT 480 + #endif diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index c8e3b94bd91d..c7a5bc51d571 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -107,6 +107,11 @@ #define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3) #define S5P_CIOCTRL_YCBCR_2PLANE (1 << 3) #define S5P_CIOCTRL_YCBCR_PLANE_MASK (1 << 3) +#define S5P_CIOCTRL_ALPHA_OUT_MASK (0xff << 4) +#define S5P_CIOCTRL_RGB16FMT_MASK (3 << 16) +#define S5P_CIOCTRL_RGB565 (0 << 16) +#define S5P_CIOCTRL_ARGB1555 (1 << 16) +#define S5P_CIOCTRL_ARGB4444 (2 << 16) #define S5P_CIOCTRL_ORDER2P_SHIFT (24) #define S5P_CIOCTRL_ORDER2P_MASK (3 << 24) #define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24) diff --git a/drivers/media/video/s5p-g2d/Makefile b/drivers/media/video/s5p-g2d/Makefile new file mode 100644 index 000000000000..2c48c416a804 --- /dev/null +++ b/drivers/media/video/s5p-g2d/Makefile @@ -0,0 +1,3 @@ +s5p-g2d-objs := g2d.o g2d-hw.o + +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d.o diff --git a/drivers/media/video/s5p-g2d/g2d-hw.c b/drivers/media/video/s5p-g2d/g2d-hw.c new file mode 100644 index 000000000000..39937cf03c88 --- /dev/null +++ b/drivers/media/video/s5p-g2d/g2d-hw.c @@ -0,0 +1,104 @@ +/* + * Samsung S5P G2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@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 <linux/io.h> + +#include "g2d.h" +#include "g2d-regs.h" + +#define w(x, a) writel((x), d->regs + (a)) +#define r(a) readl(d->regs + (a)) + +/* g2d_reset clears all g2d registers */ +void g2d_reset(struct g2d_dev *d) +{ + w(1, SOFT_RESET_REG); +} + +void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f) +{ + u32 n; + + w(f->stride & 0xFFFF, SRC_STRIDE_REG); + + n = f->o_height & 0xFFF; + n <<= 16; + n |= f->o_width & 0xFFF; + w(n, SRC_LEFT_TOP_REG); + + n = f->bottom & 0xFFF; + n <<= 16; + n |= f->right & 0xFFF; + w(n, SRC_RIGHT_BOTTOM_REG); + + w(f->fmt->hw, SRC_COLOR_MODE_REG); +} + +void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a) +{ + w(a, SRC_BASE_ADDR_REG); +} + +void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f) +{ + u32 n; + + w(f->stride & 0xFFFF, DST_STRIDE_REG); + + n = f->o_height & 0xFFF; + n <<= 16; + n |= f->o_width & 0xFFF; + w(n, DST_LEFT_TOP_REG); + + n = f->bottom & 0xFFF; + n <<= 16; + n |= f->right & 0xFFF; + w(n, DST_RIGHT_BOTTOM_REG); + + w(f->fmt->hw, DST_COLOR_MODE_REG); +} + +void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a) +{ + w(a, DST_BASE_ADDR_REG); +} + +void g2d_set_rop4(struct g2d_dev *d, u32 r) +{ + w(r, ROP4_REG); +} + +u32 g2d_cmd_stretch(u32 e) +{ + e &= 1; + return e << 4; +} + +void g2d_set_cmd(struct g2d_dev *d, u32 c) +{ + w(c, BITBLT_COMMAND_REG); +} + +void g2d_start(struct g2d_dev *d) +{ + /* Clear cache */ + w(0x7, CACHECTL_REG); + /* Enable interrupt */ + w(1, INTEN_REG); + /* Start G2D engine */ + w(1, BITBLT_START_REG); +} + +void g2d_clear_int(struct g2d_dev *d) +{ + w(1, INTC_PEND_REG); +} diff --git a/drivers/media/video/s5p-g2d/g2d-regs.h b/drivers/media/video/s5p-g2d/g2d-regs.h new file mode 100644 index 000000000000..02e1cf50da4e --- /dev/null +++ b/drivers/media/video/s5p-g2d/g2d-regs.h @@ -0,0 +1,115 @@ +/* + * Samsung S5P G2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@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 + */ + +/* General Registers */ +#define SOFT_RESET_REG 0x0000 /* Software reset reg */ +#define INTEN_REG 0x0004 /* Interrupt Enable reg */ +#define INTC_PEND_REG 0x000C /* Interrupt Control Pending reg */ +#define FIFO_STAT_REG 0x0010 /* Command FIFO Status reg */ +#define AXI_ID_MODE_REG 0x0014 /* AXI Read ID Mode reg */ +#define CACHECTL_REG 0x0018 /* Cache & Buffer clear reg */ +#define AXI_MODE_REG 0x001C /* AXI Mode reg */ + +/* Command Registers */ +#define BITBLT_START_REG 0x0100 /* BitBLT Start reg */ +#define BITBLT_COMMAND_REG 0x0104 /* Command reg for BitBLT */ + +/* Parameter Setting Registers (Rotate & Direction) */ +#define ROTATE_REG 0x0200 /* Rotation reg */ +#define SRC_MSK_DIRECT_REG 0x0204 /* Src and Mask Direction reg */ +#define DST_PAT_DIRECT_REG 0x0208 /* Dest and Pattern Direction reg */ + +/* Parameter Setting Registers (Src) */ +#define SRC_SELECT_REG 0x0300 /* Src Image Selection reg */ +#define SRC_BASE_ADDR_REG 0x0304 /* Src Image Base Address reg */ +#define SRC_STRIDE_REG 0x0308 /* Src Stride reg */ +#define SRC_COLOR_MODE_REG 0x030C /* Src Image Color Mode reg */ +#define SRC_LEFT_TOP_REG 0x0310 /* Src Left Top Coordinate reg */ +#define SRC_RIGHT_BOTTOM_REG 0x0314 /* Src Right Bottom Coordinate reg */ + +/* Parameter Setting Registers (Dest) */ +#define DST_SELECT_REG 0x0400 /* Dest Image Selection reg */ +#define DST_BASE_ADDR_REG 0x0404 /* Dest Image Base Address reg */ +#define DST_STRIDE_REG 0x0408 /* Dest Stride reg */ +#define DST_COLOR_MODE_REG 0x040C /* Dest Image Color Mode reg */ +#define DST_LEFT_TOP_REG 0x0410 /* Dest Left Top Coordinate reg */ +#define DST_RIGHT_BOTTOM_REG 0x0414 /* Dest Right Bottom Coordinate reg */ + +/* Parameter Setting Registers (Pattern) */ +#define PAT_BASE_ADDR_REG 0x0500 /* Pattern Image Base Address reg */ +#define PAT_SIZE_REG 0x0504 /* Pattern Image Size reg */ +#define PAT_COLOR_MODE_REG 0x0508 /* Pattern Image Color Mode reg */ +#define PAT_OFFSET_REG 0x050C /* Pattern Left Top Coordinate reg */ +#define PAT_STRIDE_REG 0x0510 /* Pattern Stride reg */ + +/* Parameter Setting Registers (Mask) */ +#define MASK_BASE_ADDR_REG 0x0520 /* Mask Base Address reg */ +#define MASK_STRIDE_REG 0x0524 /* Mask Stride reg */ + +/* Parameter Setting Registers (Clipping Window) */ +#define CW_LT_REG 0x0600 /* LeftTop coordinates of Clip Window */ +#define CW_RB_REG 0x0604 /* RightBottom coordinates of Clip + Window */ + +/* Parameter Setting Registers (ROP & Alpha Setting) */ +#define THIRD_OPERAND_REG 0x0610 /* Third Operand Selection reg */ +#define ROP4_REG 0x0614 /* Raster Operation reg */ +#define ALPHA_REG 0x0618 /* Alpha value, Fading offset value */ + +/* Parameter Setting Registers (Color) */ +#define FG_COLOR_REG 0x0700 /* Foreground Color reg */ +#define BG_COLOR_REG 0x0704 /* Background Color reg */ +#define BS_COLOR_REG 0x0708 /* Blue Screen Color reg */ + +/* Parameter Setting Registers (Color Key) */ +#define SRC_COLORKEY_CTRL_REG 0x0710 /* Src Colorkey control reg */ +#define SRC_COLORKEY_DR_MIN_REG 0x0714 /* Src Colorkey Decision Reference + Min reg */ +#define SRC_COLORKEY_DR_MAX_REG 0x0718 /* Src Colorkey Decision Reference + Max reg */ +#define DST_COLORKEY_CTRL_REG 0x071C /* Dest Colorkey control reg */ +#define DST_COLORKEY_DR_MIN_REG 0x0720 /* Dest Colorkey Decision Reference + Min reg */ +#define DST_COLORKEY_DR_MAX_REG 0x0724 /* Dest Colorkey Decision Reference + Max reg */ + +/* Color mode values */ + +#define ORDER_XRGB 0 +#define ORDER_RGBX 1 +#define ORDER_XBGR 2 +#define ORDER_BGRX 3 + +#define MODE_XRGB_8888 0 +#define MODE_ARGB_8888 1 +#define MODE_RGB_565 2 +#define MODE_XRGB_1555 3 +#define MODE_ARGB_1555 4 +#define MODE_XRGB_4444 5 +#define MODE_ARGB_4444 6 +#define MODE_PACKED_RGB_888 7 + +#define COLOR_MODE(o, m) (((o) << 4) | (m)) + +/* ROP4 operation values */ +#define ROP4_COPY 0xCCCC +#define ROP4_INVERT 0x3333 + +/* Hardware limits */ +#define MAX_WIDTH 8000 +#define MAX_HEIGHT 8000 + +#define G2D_TIMEOUT 500 + +#define DEFAULT_WIDTH 100 +#define DEFAULT_HEIGHT 100 + diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c new file mode 100644 index 000000000000..febaa673d363 --- /dev/null +++ b/drivers/media/video/s5p-g2d/g2d.c @@ -0,0 +1,811 @@ +/* + * Samsung S5P G2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@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 <linux/module.h> +#include <linux/fs.h> +#include <linux/version.h> +#include <linux/timer.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/interrupt.h> + +#include <linux/platform_device.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "g2d.h" +#include "g2d-regs.h" + +#define fh2ctx(__fh) container_of(__fh, struct g2d_ctx, fh) + +static struct g2d_fmt formats[] = { + { + .name = "XRGB_8888", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = 32, + .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_8888), + }, + { + .name = "RGB_565", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = 16, + .hw = COLOR_MODE(ORDER_XRGB, MODE_RGB_565), + }, + { + .name = "XRGB_1555", + .fourcc = V4L2_PIX_FMT_RGB555X, + .depth = 16, + .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_1555), + }, + { + .name = "XRGB_4444", + .fourcc = V4L2_PIX_FMT_RGB444, + .depth = 16, + .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_4444), + }, + { + .name = "PACKED_RGB_888", + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, + .hw = COLOR_MODE(ORDER_XRGB, MODE_PACKED_RGB_888), + }, +}; +#define NUM_FORMATS ARRAY_SIZE(formats) + +struct g2d_frame def_frame = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .c_width = DEFAULT_WIDTH, + .c_height = DEFAULT_HEIGHT, + .o_width = 0, + .o_height = 0, + .fmt = &formats[0], + .right = DEFAULT_WIDTH, + .bottom = DEFAULT_HEIGHT, +}; + +struct g2d_fmt *find_fmt(struct v4l2_format *f) +{ + unsigned int i; + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].fourcc == f->fmt.pix.pixelformat) + return &formats[i]; + } + return NULL; +} + + +static struct g2d_frame *get_frame(struct g2d_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &ctx->in; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &ctx->out; + default: + return ERR_PTR(-EINVAL); + } +} + +static int g2d_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct g2d_ctx *ctx = vb2_get_drv_priv(vq); + struct g2d_frame *f = get_frame(ctx, vq->type); + + if (IS_ERR(f)) + return PTR_ERR(f); + + sizes[0] = f->size; + *nplanes = 1; + alloc_ctxs[0] = ctx->dev->alloc_ctx; + + if (*nbuffers == 0) + *nbuffers = 1; + + return 0; +} + +static int g2d_buf_prepare(struct vb2_buffer *vb) +{ + struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct g2d_frame *f = get_frame(ctx, vb->vb2_queue->type); + + if (IS_ERR(f)) + return PTR_ERR(f); + vb2_set_plane_payload(vb, 0, f->size); + return 0; +} + +static void g2d_buf_queue(struct vb2_buffer *vb) +{ + struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} + + +static struct vb2_ops g2d_qops = { + .queue_setup = g2d_queue_setup, + .buf_prepare = g2d_buf_prepare, + .buf_queue = g2d_buf_queue, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct g2d_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->drv_priv = ctx; + src_vq->ops = &g2d_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->drv_priv = ctx; + dst_vq->ops = &g2d_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + + return vb2_queue_init(dst_vq); +} + +static int g2d_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx, + ctrl_handler); + switch (ctrl->id) { + case V4L2_CID_COLORFX: + if (ctrl->val == V4L2_COLORFX_NEGATIVE) + ctx->rop = ROP4_INVERT; + else + ctx->rop = ROP4_COPY; + break; + default: + v4l2_err(&ctx->dev->v4l2_dev, "unknown control\n"); + return -EINVAL; + } + return 0; +} + +static const struct v4l2_ctrl_ops g2d_ctrl_ops = { + .s_ctrl = g2d_s_ctrl, +}; + +int g2d_setup_ctrls(struct g2d_ctx *ctx) +{ + struct g2d_dev *dev = ctx->dev; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1); + if (ctx->ctrl_handler.error) { + v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_handler.error; + } + + v4l2_ctrl_new_std_menu( + &ctx->ctrl_handler, + &g2d_ctrl_ops, + V4L2_CID_COLORFX, + V4L2_COLORFX_NEGATIVE, + ~((1 << V4L2_COLORFX_NONE) | (1 << V4L2_COLORFX_NEGATIVE)), + V4L2_COLORFX_NONE); + + if (ctx->ctrl_handler.error) { + v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_handler.error; + } + + return 0; +} + +static int g2d_open(struct file *file) +{ + struct g2d_dev *dev = video_drvdata(file); + struct g2d_ctx *ctx = NULL; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->dev = dev; + /* Set default formats */ + ctx->in = def_frame; + ctx->out = def_frame; + + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + ret = PTR_ERR(ctx->m2m_ctx); + kfree(ctx); + return ret; + } + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + g2d_setup_ctrls(ctx); + + /* Write the default values to the ctx struct */ + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + + v4l2_info(&dev->v4l2_dev, "instance opened\n"); + return 0; +} + +static int g2d_release(struct file *file) +{ + struct g2d_dev *dev = video_drvdata(file); + struct g2d_ctx *ctx = fh2ctx(file->private_data); + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + v4l2_info(&dev->v4l2_dev, "instance closed\n"); + return 0; +} + + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1); + strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1); + cap->bus_info[0] = 0; + cap->version = KERNEL_VERSION(1, 0, 0); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING; + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +{ + struct g2d_fmt *fmt; + if (f->index >= NUM_FORMATS) + return -EINVAL; + fmt = &formats[f->index]; + f->pixelformat = fmt->fourcc; + strncpy(f->description, fmt->name, sizeof(f->description) - 1); + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct g2d_ctx *ctx = prv; + struct vb2_queue *vq; + struct g2d_frame *frm; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + frm = get_frame(ctx, f->type); + if (IS_ERR(frm)) + return PTR_ERR(frm); + + f->fmt.pix.width = frm->width; + f->fmt.pix.height = frm->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = frm->fmt->fourcc; + f->fmt.pix.bytesperline = (frm->width * frm->fmt->depth) >> 3; + f->fmt.pix.sizeimage = frm->size; + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct g2d_fmt *fmt; + enum v4l2_field *field; + + fmt = find_fmt(f); + if (!fmt) + return -EINVAL; + + field = &f->fmt.pix.field; + if (*field == V4L2_FIELD_ANY) + *field = V4L2_FIELD_NONE; + else if (*field != V4L2_FIELD_NONE) + return -EINVAL; + + if (f->fmt.pix.width > MAX_WIDTH) + f->fmt.pix.width = MAX_WIDTH; + if (f->fmt.pix.height > MAX_HEIGHT) + f->fmt.pix.height = MAX_HEIGHT; + + if (f->fmt.pix.width < 1) + f->fmt.pix.width = 1; + if (f->fmt.pix.height < 1) + f->fmt.pix.height = 1; + + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + struct vb2_queue *vq; + struct g2d_frame *frm; + struct g2d_fmt *fmt; + int ret = 0; + + /* Adjust all values accordingly to the hardware capabilities + * and chosen format. */ + ret = vidioc_try_fmt(file, prv, f); + if (ret) + return ret; + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (vb2_is_busy(vq)) { + v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); + return -EBUSY; + } + frm = get_frame(ctx, f->type); + if (IS_ERR(frm)) + return PTR_ERR(frm); + fmt = find_fmt(f); + if (!fmt) + return -EINVAL; + frm->width = f->fmt.pix.width; + frm->height = f->fmt.pix.height; + frm->size = f->fmt.pix.sizeimage; + /* Reset crop settings */ + frm->o_width = 0; + frm->o_height = 0; + frm->c_width = frm->width; + frm->c_height = frm->height; + frm->right = frm->width; + frm->bottom = frm->height; + frm->fmt = fmt; + frm->stride = f->fmt.pix.bytesperline; + return 0; +} + +static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait) +{ + struct g2d_ctx *ctx = fh2ctx(file->private_data); + return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); +} + +static int g2d_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct g2d_ctx *ctx = fh2ctx(file->private_data); + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); +} + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cr) +{ + struct g2d_ctx *ctx = priv; + struct g2d_frame *f; + + f = get_frame(ctx, cr->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + cr->bounds.left = 0; + cr->bounds.top = 0; + cr->bounds.width = f->width; + cr->bounds.height = f->height; + cr->defrect = cr->bounds; + return 0; +} + +static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr) +{ + struct g2d_ctx *ctx = prv; + struct g2d_frame *f; + + f = get_frame(ctx, cr->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + cr->c.left = f->o_height; + cr->c.top = f->o_width; + cr->c.width = f->c_width; + cr->c.height = f->c_height; + return 0; +} + +static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + struct g2d_frame *f; + + f = get_frame(ctx, cr->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + if (cr->c.top < 0 || cr->c.left < 0) { + v4l2_err(&dev->v4l2_dev, + "doesn't support negative values for top & left\n"); + return -EINVAL; + } + + return 0; +} + +static int vidioc_s_crop(struct file *file, void *prv, struct v4l2_crop *cr) +{ + struct g2d_ctx *ctx = prv; + struct g2d_frame *f; + int ret; + + ret = vidioc_try_crop(file, prv, cr); + if (ret) + return ret; + f = get_frame(ctx, cr->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + f->c_width = cr->c.width; + f->c_height = cr->c.height; + f->o_width = cr->c.left; + f->o_height = cr->c.top; + f->bottom = f->o_height + f->c_height; + f->right = f->o_width + f->c_width; + return 0; +} + +static void g2d_lock(void *prv) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + mutex_lock(&dev->mutex); +} + +static void g2d_unlock(void *prv) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + mutex_unlock(&dev->mutex); +} + +static void job_abort(void *prv) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + int ret; + + if (dev->curr == 0) /* No job currently running */ + return; + + ret = wait_event_timeout(dev->irq_queue, + dev->curr == 0, + msecs_to_jiffies(G2D_TIMEOUT)); +} + +static void device_run(void *prv) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + struct vb2_buffer *src, *dst; + u32 cmd = 0; + + dev->curr = ctx; + + src = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + + clk_enable(dev->gate); + g2d_reset(dev); + + g2d_set_src_size(dev, &ctx->in); + g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0)); + + g2d_set_dst_size(dev, &ctx->out); + g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0)); + + g2d_set_rop4(dev, ctx->rop); + if (ctx->in.c_width != ctx->out.c_width || + ctx->in.c_height != ctx->out.c_height) + cmd |= g2d_cmd_stretch(1); + g2d_set_cmd(dev, cmd); + g2d_start(dev); +} + +static irqreturn_t g2d_isr(int irq, void *prv) +{ + struct g2d_dev *dev = prv; + struct g2d_ctx *ctx = dev->curr; + struct vb2_buffer *src, *dst; + + g2d_clear_int(dev); + clk_disable(dev->gate); + + BUG_ON(ctx == 0); + + src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + + BUG_ON(src == 0); + BUG_ON(dst == 0); + + v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); + + dev->curr = 0; + wake_up(&dev->irq_queue); + return IRQ_HANDLED; +} + +static const struct v4l2_file_operations g2d_fops = { + .owner = THIS_MODULE, + .open = g2d_open, + .release = g2d_release, + .poll = g2d_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = g2d_mmap, +}; + +static const struct v4l2_ioctl_ops g2d_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt, + .vidioc_s_fmt_vid_out = vidioc_s_fmt, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + + .vidioc_g_crop = vidioc_g_crop, + .vidioc_s_crop = vidioc_s_crop, + .vidioc_cropcap = vidioc_cropcap, +}; + +static struct video_device g2d_videodev = { + .name = G2D_NAME, + .fops = &g2d_fops, + .ioctl_ops = &g2d_ioctl_ops, + .minor = -1, + .release = video_device_release, +}; + +static struct v4l2_m2m_ops g2d_m2m_ops = { + .device_run = device_run, + .job_abort = job_abort, + .lock = g2d_lock, + .unlock = g2d_unlock, +}; + +static int g2d_probe(struct platform_device *pdev) +{ + struct g2d_dev *dev; + struct video_device *vfd; + struct resource *res; + int ret = 0; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + spin_lock_init(&dev->irqlock); + mutex_init(&dev->mutex); + atomic_set(&dev->num_inst, 0); + init_waitqueue_head(&dev->irq_queue); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to find registers\n"); + ret = -ENOENT; + goto free_dev; + } + + dev->res_regs = request_mem_region(res->start, resource_size(res), + dev_name(&pdev->dev)); + + if (!dev->res_regs) { + dev_err(&pdev->dev, "failed to obtain register region\n"); + ret = -ENOENT; + goto free_dev; + } + + dev->regs = ioremap(res->start, resource_size(res)); + if (!dev->regs) { + dev_err(&pdev->dev, "failed to map registers\n"); + ret = -ENOENT; + goto rel_res_regs; + } + + dev->clk = clk_get(&pdev->dev, "sclk_fimg2d"); + if (IS_ERR_OR_NULL(dev->clk)) { + dev_err(&pdev->dev, "failed to get g2d clock\n"); + ret = -ENXIO; + goto unmap_regs; + } + + dev->gate = clk_get(&pdev->dev, "fimg2d"); + if (IS_ERR_OR_NULL(dev->gate)) { + dev_err(&pdev->dev, "failed to get g2d clock gate\n"); + ret = -ENXIO; + goto put_clk; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "failed to find IRQ\n"); + ret = -ENXIO; + goto put_clk_gate; + } + + dev->irq = res->start; + + ret = request_irq(dev->irq, g2d_isr, 0, pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, "failed to install IRQ\n"); + goto put_clk_gate; + } + + dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(dev->alloc_ctx)) { + ret = PTR_ERR(dev->alloc_ctx); + goto rel_irq; + } + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + goto alloc_ctx_cleanup; + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto unreg_v4l2_dev; + } + *vfd = g2d_videodev; + vfd->lock = &dev->mutex; + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto rel_vdev; + } + video_set_drvdata(vfd, dev); + snprintf(vfd->name, sizeof(vfd->name), "%s", g2d_videodev.name); + dev->vfd = vfd; + v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", + vfd->num); + platform_set_drvdata(pdev, dev); + dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(dev->m2m_dev); + goto unreg_video_dev; + } + + def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; + + return 0; + +unreg_video_dev: + video_unregister_device(dev->vfd); +rel_vdev: + video_device_release(vfd); +unreg_v4l2_dev: + v4l2_device_unregister(&dev->v4l2_dev); +alloc_ctx_cleanup: + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); +rel_irq: + free_irq(dev->irq, dev); +put_clk_gate: + clk_put(dev->gate); +put_clk: + clk_put(dev->clk); +unmap_regs: + iounmap(dev->regs); +rel_res_regs: + release_resource(dev->res_regs); +free_dev: + kfree(dev); + return ret; +} + +static int g2d_remove(struct platform_device *pdev) +{ + struct g2d_dev *dev = (struct g2d_dev *)platform_get_drvdata(pdev); + + v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME); + v4l2_m2m_release(dev->m2m_dev); + video_unregister_device(dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); + free_irq(dev->irq, dev); + clk_put(dev->gate); + clk_put(dev->clk); + iounmap(dev->regs); + release_resource(dev->res_regs); + kfree(dev); + return 0; +} + +static struct platform_driver g2d_pdrv = { + .probe = g2d_probe, + .remove = g2d_remove, + .driver = { + .name = G2D_NAME, + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(g2d_pdrv); + +MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); +MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p-g2d/g2d.h new file mode 100644 index 000000000000..5eae90107bf8 --- /dev/null +++ b/drivers/media/video/s5p-g2d/g2d.h @@ -0,0 +1,83 @@ +/* + * Samsung S5P G2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@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 <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> + +#define G2D_NAME "s5p-g2d" + +struct g2d_dev { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *vfd; + struct mutex mutex; + spinlock_t irqlock; + atomic_t num_inst; + struct vb2_alloc_ctx *alloc_ctx; + struct resource *res_regs; + void __iomem *regs; + struct clk *clk; + struct clk *gate; + struct g2d_ctx *curr; + int irq; + wait_queue_head_t irq_queue; +}; + +struct g2d_frame { + /* Original dimensions */ + u32 width; + u32 height; + /* Crop size */ + u32 c_width; + u32 c_height; + /* Offset */ + u32 o_width; + u32 o_height; + /* Image format */ + struct g2d_fmt *fmt; + /* Variables that can calculated once and reused */ + u32 stride; + u32 bottom; + u32 right; + u32 size; +}; + +struct g2d_ctx { + struct v4l2_fh fh; + struct g2d_dev *dev; + struct v4l2_m2m_ctx *m2m_ctx; + struct g2d_frame in; + struct g2d_frame out; + struct v4l2_ctrl_handler ctrl_handler; + u32 rop; +}; + +struct g2d_fmt { + char *name; + u32 fourcc; + int depth; + u32 hw; +}; + + +void g2d_reset(struct g2d_dev *d); +void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f); +void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a); +void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f); +void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a); +void g2d_start(struct g2d_dev *d); +void g2d_clear_int(struct g2d_dev *d); +void g2d_set_rop4(struct g2d_dev *d, u32 r); +u32 g2d_cmd_stretch(u32 e); +void g2d_set_cmd(struct g2d_dev *d, u32 c); + + diff --git a/drivers/media/video/s5p-jpeg/Makefile b/drivers/media/video/s5p-jpeg/Makefile new file mode 100644 index 000000000000..ddc2900d88a2 --- /dev/null +++ b/drivers/media/video/s5p-jpeg/Makefile @@ -0,0 +1,2 @@ +s5p-jpeg-objs := jpeg-core.o +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c new file mode 100644 index 000000000000..1105a8749c8b --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-core.c @@ -0,0 +1,1482 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-core.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@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 <linux/clk.h> +#include <linux/err.h> +#include <linux/gfp.h> +#include <linux/interrupt.h> +#include <linux/io.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> +#include <linux/string.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "jpeg-core.h" +#include "jpeg-hw.h" + +static struct s5p_jpeg_fmt formats_enc[] = { + { + .name = "YUV 4:2:0 planar, YCbCr", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 12, + .colplanes = 3, + .types = MEM2MEM_CAPTURE, + }, + { + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .colplanes = 1, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, + { + .name = "RGB565", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, + .colplanes = 1, + .types = MEM2MEM_OUTPUT, + }, +}; +#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc) + +static struct s5p_jpeg_fmt formats_dec[] = { + { + .name = "YUV 4:2:0 planar, YCbCr", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 12, + .colplanes = 3, + .h_align = 4, + .v_align = 4, + .types = MEM2MEM_CAPTURE, + }, + { + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .colplanes = 1, + .h_align = 4, + .v_align = 3, + .types = MEM2MEM_CAPTURE, + }, + { + .name = "JPEG JFIF", + .fourcc = V4L2_PIX_FMT_JPEG, + .colplanes = 1, + .types = MEM2MEM_OUTPUT, + }, +}; +#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec) + +static const unsigned char qtbl_luminance[4][64] = { + {/* level 1 - high quality */ + 8, 6, 6, 8, 12, 14, 16, 17, + 6, 6, 6, 8, 10, 13, 12, 15, + 6, 6, 7, 8, 13, 14, 18, 24, + 8, 8, 8, 14, 13, 19, 24, 35, + 12, 10, 13, 13, 20, 26, 34, 39, + 14, 13, 14, 19, 26, 34, 39, 39, + 16, 12, 18, 24, 34, 39, 39, 39, + 17, 15, 24, 35, 39, 39, 39, 39 + }, + {/* level 2 */ + 12, 8, 8, 12, 17, 21, 24, 23, + 8, 9, 9, 11, 15, 19, 18, 23, + 8, 9, 10, 12, 19, 20, 27, 36, + 12, 11, 12, 21, 20, 28, 36, 53, + 17, 15, 19, 20, 30, 39, 51, 59, + 21, 19, 20, 28, 39, 51, 59, 59, + 24, 18, 27, 36, 51, 59, 59, 59, + 23, 23, 36, 53, 59, 59, 59, 59 + }, + {/* level 3 */ + 16, 11, 11, 16, 23, 27, 31, 30, + 11, 12, 12, 15, 20, 23, 23, 30, + 11, 12, 13, 16, 23, 26, 35, 47, + 16, 15, 16, 23, 26, 37, 47, 64, + 23, 20, 23, 26, 39, 51, 64, 64, + 27, 23, 26, 37, 51, 64, 64, 64, + 31, 23, 35, 47, 64, 64, 64, 64, + 30, 30, 47, 64, 64, 64, 64, 64 + }, + {/*level 4 - low quality */ + 20, 16, 25, 39, 50, 46, 62, 68, + 16, 18, 23, 38, 38, 53, 65, 68, + 25, 23, 31, 38, 53, 65, 68, 68, + 39, 38, 38, 53, 65, 68, 68, 68, + 50, 38, 53, 65, 68, 68, 68, 68, + 46, 53, 65, 68, 68, 68, 68, 68, + 62, 65, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 + } +}; + +static const unsigned char qtbl_chrominance[4][64] = { + {/* level 1 - high quality */ + 9, 8, 9, 11, 14, 17, 19, 24, + 8, 10, 9, 11, 14, 13, 17, 22, + 9, 9, 13, 14, 13, 15, 23, 26, + 11, 11, 14, 14, 15, 20, 26, 33, + 14, 14, 13, 15, 20, 24, 33, 39, + 17, 13, 15, 20, 24, 32, 39, 39, + 19, 17, 23, 26, 33, 39, 39, 39, + 24, 22, 26, 33, 39, 39, 39, 39 + }, + {/* level 2 */ + 13, 11, 13, 16, 20, 20, 29, 37, + 11, 14, 14, 14, 16, 20, 26, 32, + 13, 14, 15, 17, 20, 23, 35, 40, + 16, 14, 17, 21, 23, 30, 40, 50, + 20, 16, 20, 23, 30, 37, 50, 59, + 20, 20, 23, 30, 37, 48, 59, 59, + 29, 26, 35, 40, 50, 59, 59, 59, + 37, 32, 40, 50, 59, 59, 59, 59 + }, + {/* level 3 */ + 17, 15, 17, 21, 20, 26, 38, 48, + 15, 19, 18, 17, 20, 26, 35, 43, + 17, 18, 20, 22, 26, 30, 46, 53, + 21, 17, 22, 28, 30, 39, 53, 64, + 20, 20, 26, 30, 39, 48, 64, 64, + 26, 26, 30, 39, 48, 63, 64, 64, + 38, 35, 46, 53, 64, 64, 64, 64, + 48, 43, 53, 64, 64, 64, 64, 64 + }, + {/*level 4 - low quality */ + 21, 25, 32, 38, 54, 68, 68, 68, + 25, 28, 24, 38, 54, 68, 68, 68, + 32, 24, 32, 43, 66, 68, 68, 68, + 38, 38, 43, 53, 68, 68, 68, 68, + 54, 54, 66, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 + } +}; + +static const unsigned char hdctbl0[16] = { + 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 +}; + +static const unsigned char hdctblg0[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb +}; +static const unsigned char hactbl0[16] = { + 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d +}; +static const unsigned char hactblg0[162] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, + unsigned long tab, int len) +{ + int i; + + for (i = 0; i < len; i++) + writel((unsigned int)qtbl[i], regs + tab + (i * 0x04)); +} + +static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality) +{ + /* this driver fills quantisation table 0 with data for luma */ + jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0), + ARRAY_SIZE(qtbl_luminance[quality])); +} + +static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality) +{ + /* this driver fills quantisation table 1 with data for chroma */ + jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1), + ARRAY_SIZE(qtbl_chrominance[quality])); +} + +static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl, + unsigned long tab, int len) +{ + int i; + + for (i = 0; i < len; i++) + writel((unsigned int)htbl[i], regs + tab + (i * 0x04)); +} + +static inline void jpeg_set_hdctbl(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0)); +} + +static inline void jpeg_set_hdctblg(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0)); +} + +static inline void jpeg_set_hactbl(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0)); +} + +static inline void jpeg_set_hactblg(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0)); +} + +/* + * ============================================================================ + * Device file operations + * ============================================================================ + */ + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); +static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, + __u32 pixelformat); + +static int s5p_jpeg_open(struct file *file) +{ + struct s5p_jpeg *jpeg = video_drvdata(file); + struct video_device *vfd = video_devdata(file); + struct s5p_jpeg_ctx *ctx; + struct s5p_jpeg_fmt *out_fmt; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + file->private_data = ctx; + ctx->jpeg = jpeg; + if (vfd == jpeg->vfd_encoder) { + ctx->mode = S5P_JPEG_ENCODE; + out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565); + } else { + ctx->mode = S5P_JPEG_DECODE; + out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); + } + + ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + int err = PTR_ERR(ctx->m2m_ctx); + kfree(ctx); + return err; + } + + ctx->out_q.fmt = out_fmt; + ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); + + return 0; +} + +static int s5p_jpeg_release(struct file *file) +{ + struct s5p_jpeg_ctx *ctx = file->private_data; + + v4l2_m2m_ctx_release(ctx->m2m_ctx); + kfree(ctx); + + return 0; +} + +static unsigned int s5p_jpeg_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct s5p_jpeg_ctx *ctx = file->private_data; + + return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); +} + +static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct s5p_jpeg_ctx *ctx = file->private_data; + + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); +} + +static const struct v4l2_file_operations s5p_jpeg_fops = { + .owner = THIS_MODULE, + .open = s5p_jpeg_open, + .release = s5p_jpeg_release, + .poll = s5p_jpeg_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = s5p_jpeg_mmap, +}; + +/* + * ============================================================================ + * video ioctl operations + * ============================================================================ + */ + +static int get_byte(struct s5p_jpeg_buffer *buf) +{ + if (buf->curr >= buf->size) + return -1; + + return ((unsigned char *)buf->data)[buf->curr++]; +} + +static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word) +{ + unsigned int temp; + int byte; + + byte = get_byte(buf); + if (byte == -1) + return -1; + temp = byte << 8; + byte = get_byte(buf); + if (byte == -1) + return -1; + *word = (unsigned int)byte | temp; + return 0; +} + +static void skip(struct s5p_jpeg_buffer *buf, long len) +{ + if (len <= 0) + return; + + while (len--) + get_byte(buf); +} + +static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, + unsigned long buffer, unsigned long size) +{ + int c, components, notfound; + unsigned int height, width, word; + long length; + struct s5p_jpeg_buffer jpeg_buffer; + + jpeg_buffer.size = size; + jpeg_buffer.data = buffer; + jpeg_buffer.curr = 0; + + notfound = 1; + while (notfound) { + c = get_byte(&jpeg_buffer); + if (c == -1) + break; + if (c != 0xff) + continue; + do + c = get_byte(&jpeg_buffer); + while (c == 0xff); + if (c == -1) + break; + if (c == 0) + continue; + length = 0; + switch (c) { + /* SOF0: baseline JPEG */ + case SOF0: + if (get_word_be(&jpeg_buffer, &word)) + break; + if (get_byte(&jpeg_buffer) == -1) + break; + if (get_word_be(&jpeg_buffer, &height)) + break; + if (get_word_be(&jpeg_buffer, &width)) + break; + components = get_byte(&jpeg_buffer); + if (components == -1) + break; + notfound = 0; + + skip(&jpeg_buffer, components * 3); + break; + + /* skip payload-less markers */ + case RST ... RST + 7: + case SOI: + case EOI: + case TEM: + break; + + /* skip uninteresting payload markers */ + default: + if (get_word_be(&jpeg_buffer, &word)) + break; + length = (long)word - 2; + skip(&jpeg_buffer, length); + break; + } + } + result->w = width; + result->h = height; + result->size = components; + return !notfound; +} + +static int s5p_jpeg_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (ctx->mode == S5P_JPEG_ENCODE) { + strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder", + sizeof(cap->driver)); + strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder", + sizeof(cap->card)); + } else { + strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder", + sizeof(cap->driver)); + strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder", + sizeof(cap->card)); + } + cap->bus_info[0] = 0; + cap->capabilities = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OUTPUT; + return 0; +} + +static int enum_fmt(struct s5p_jpeg_fmt *formats, int n, + struct v4l2_fmtdesc *f, u32 type) +{ + int i, num = 0; + + for (i = 0; i < n; ++i) { + if (formats[i].types & type) { + /* index-th format of type type found ? */ + if (num == f->index) + break; + /* Correct type but haven't reached our index yet, + * just increment per-type index */ + ++num; + } + } + + /* Format not found */ + if (i >= n) + return -EINVAL; + + strlcpy(f->description, formats[i].name, sizeof(f->description)); + f->pixelformat = formats[i].fourcc; + + return 0; +} + +static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct s5p_jpeg_ctx *ctx; + + ctx = priv; + + if (ctx->mode == S5P_JPEG_ENCODE) + return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, + MEM2MEM_CAPTURE); + + return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE); +} + +static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct s5p_jpeg_ctx *ctx; + + ctx = priv; + + if (ctx->mode == S5P_JPEG_ENCODE) + return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, + MEM2MEM_OUTPUT); + + return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT); +} + +static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx, + enum v4l2_buf_type type) +{ + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + return &ctx->out_q; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return &ctx->cap_q; + + return NULL; +} + +static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct s5p_jpeg_q_data *q_data = NULL; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct s5p_jpeg_ctx *ct = priv; + + vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed) + return -EINVAL; + q_data = get_q_data(ct, f->type); + BUG_ON(q_data == NULL); + + pix->width = q_data->w; + pix->height = q_data->h; + pix->field = V4L2_FIELD_NONE; + pix->pixelformat = q_data->fmt->fourcc; + pix->bytesperline = 0; + if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) { + u32 bpl = q_data->w; + if (q_data->fmt->colplanes == 1) + bpl = (bpl * q_data->fmt->depth) >> 3; + pix->bytesperline = bpl; + } + pix->sizeimage = q_data->size; + + return 0; +} + +static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, + u32 pixelformat) +{ + unsigned int k; + struct s5p_jpeg_fmt *formats; + int n; + + if (mode == S5P_JPEG_ENCODE) { + formats = formats_enc; + n = NUM_FORMATS_ENC; + } else { + formats = formats_dec; + n = NUM_FORMATS_DEC; + } + + for (k = 0; k < n; k++) { + struct s5p_jpeg_fmt *fmt = &formats[k]; + if (fmt->fourcc == pixelformat) + return fmt; + } + + return NULL; + +} + +static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, + unsigned int walign, + u32 *h, unsigned int hmin, unsigned int hmax, + unsigned int halign) +{ + int width, height, w_step, h_step; + + width = *w; + height = *h; + + w_step = 1 << walign; + h_step = 1 << halign; + v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0); + + if (*w < width && (*w + w_step) < wmax) + *w += w_step; + if (*h < height && (*h + h_step) < hmax) + *h += h_step; + +} + +static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt, + struct s5p_jpeg_ctx *ctx, int q_type) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + + if (pix->field == V4L2_FIELD_ANY) + pix->field = V4L2_FIELD_NONE; + else if (pix->field != V4L2_FIELD_NONE) + return -EINVAL; + + /* V4L2 specification suggests the driver corrects the format struct + * if any of the dimensions is unsupported */ + if (q_type == MEM2MEM_OUTPUT) + jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH, + S5P_JPEG_MAX_WIDTH, 0, + &pix->height, S5P_JPEG_MIN_HEIGHT, + S5P_JPEG_MAX_HEIGHT, 0); + else + jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH, + S5P_JPEG_MAX_WIDTH, fmt->h_align, + &pix->height, S5P_JPEG_MIN_HEIGHT, + S5P_JPEG_MAX_HEIGHT, fmt->v_align); + + if (fmt->fourcc == V4L2_PIX_FMT_JPEG) { + if (pix->sizeimage <= 0) + pix->sizeimage = PAGE_SIZE; + pix->bytesperline = 0; + } else { + u32 bpl = pix->bytesperline; + + if (fmt->colplanes > 1 && bpl < pix->width) + bpl = pix->width; /* planar */ + + if (fmt->colplanes == 1 && /* packed */ + (bpl << 3) * fmt->depth < pix->width) + bpl = (pix->width * fmt->depth) >> 3; + + pix->bytesperline = bpl; + pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3; + } + + return 0; +} + +static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct s5p_jpeg_fmt *fmt; + struct s5p_jpeg_ctx *ctx = priv; + + fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); + if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { + v4l2_err(&ctx->jpeg->v4l2_dev, + "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE); +} + +static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct s5p_jpeg_fmt *fmt; + struct s5p_jpeg_ctx *ctx = priv; + + fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); + if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { + v4l2_err(&ctx->jpeg->v4l2_dev, + "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT); +} + +static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct s5p_jpeg_q_data *q_data = NULL; + struct v4l2_pix_format *pix = &f->fmt.pix; + + vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ct, f->type); + BUG_ON(q_data == NULL); + + if (vb2_is_busy(vq)) { + v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat); + q_data->w = pix->width; + q_data->h = pix->height; + if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) + q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3; + else + q_data->size = pix->sizeimage; + + return 0; +} + +static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + return s5p_jpeg_s_fmt(priv, f); +} + +static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = s5p_jpeg_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + return s5p_jpeg_s_fmt(priv, f); +} + +static int s5p_jpeg_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int s5p_jpeg_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); +} + +static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int s5p_jpeg_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + +static int s5p_jpeg_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static int s5p_jpeg_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); +} + +int s5p_jpeg_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + /* For JPEG blob active == default == bounds */ + switch (s->target) { + case V4L2_SEL_TGT_CROP_ACTIVE: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r.width = ctx->out_q.w; + s->r.height = ctx->out_q.h; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + s->r.width = ctx->cap_q.w; + s->r.height = ctx->cap_q.h; + break; + default: + return -EINVAL; + } + s->r.left = 0; + s->r.top = 0; + return 0; +} + +static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *compr) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (ctx->mode == S5P_JPEG_DECODE) + return -ENOTTY; + + memset(compr, 0, sizeof(*compr)); + compr->quality = ctx->compr_quality; + + return 0; +} + +static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *compr) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (ctx->mode == S5P_JPEG_DECODE) + return -ENOTTY; + + compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST, + S5P_JPEG_COMPR_QUAL_WORST); + + ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality; + + return 0; +} + +static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = { + .vidioc_querycap = s5p_jpeg_querycap, + + .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out, + + .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt, + .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt, + + .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap, + .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out, + + .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap, + .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out, + + .vidioc_reqbufs = s5p_jpeg_reqbufs, + .vidioc_querybuf = s5p_jpeg_querybuf, + + .vidioc_qbuf = s5p_jpeg_qbuf, + .vidioc_dqbuf = s5p_jpeg_dqbuf, + + .vidioc_streamon = s5p_jpeg_streamon, + .vidioc_streamoff = s5p_jpeg_streamoff, + + .vidioc_g_selection = s5p_jpeg_g_selection, + + .vidioc_g_jpegcomp = s5p_jpeg_g_jpegcomp, + .vidioc_s_jpegcomp = s5p_jpeg_s_jpegcomp, +}; + +/* + * ============================================================================ + * mem2mem callbacks + * ============================================================================ + */ + +static void s5p_jpeg_device_run(void *priv) +{ + struct s5p_jpeg_ctx *ctx = priv; + struct s5p_jpeg *jpeg = ctx->jpeg; + struct vb2_buffer *src_buf, *dst_buf; + unsigned long src_addr, dst_addr; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + + jpeg_reset(jpeg->regs); + jpeg_poweron(jpeg->regs); + jpeg_proc_mode(jpeg->regs, ctx->mode); + if (ctx->mode == S5P_JPEG_ENCODE) { + if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565) + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); + else + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); + if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) + jpeg_subsampling_mode(jpeg->regs, + S5P_JPEG_SUBSAMPLING_422); + else + jpeg_subsampling_mode(jpeg->regs, + S5P_JPEG_SUBSAMPLING_420); + jpeg_dri(jpeg->regs, 0); + jpeg_x(jpeg->regs, ctx->out_q.w); + jpeg_y(jpeg->regs, ctx->out_q.h); + jpeg_imgadr(jpeg->regs, src_addr); + jpeg_jpgadr(jpeg->regs, dst_addr); + + /* ultimately comes from sizeimage from userspace */ + jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size); + + /* JPEG RGB to YCbCr conversion matrix */ + jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11); + jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12); + jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13); + jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21); + jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22); + jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23); + jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31); + jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32); + jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33); + + /* + * JPEG IP allows storing 4 quantization tables + * We fill table 0 for luma and table 1 for chroma + */ + jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality); + jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality); + /* use table 0 for Y */ + jpeg_qtbl(jpeg->regs, 1, 0); + /* use table 1 for Cb and Cr*/ + jpeg_qtbl(jpeg->regs, 2, 1); + jpeg_qtbl(jpeg->regs, 3, 1); + + /* Y, Cb, Cr use Huffman table 0 */ + jpeg_htbl_ac(jpeg->regs, 1); + jpeg_htbl_dc(jpeg->regs, 1); + jpeg_htbl_ac(jpeg->regs, 2); + jpeg_htbl_dc(jpeg->regs, 2); + jpeg_htbl_ac(jpeg->regs, 3); + jpeg_htbl_dc(jpeg->regs, 3); + } else { + jpeg_rst_int_enable(jpeg->regs, true); + jpeg_data_num_int_enable(jpeg->regs, true); + jpeg_final_mcu_num_int_enable(jpeg->regs, true); + jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); + jpeg_jpgadr(jpeg->regs, src_addr); + jpeg_imgadr(jpeg->regs, dst_addr); + } + jpeg_start(jpeg->regs); +} + +static int s5p_jpeg_job_ready(void *priv) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (ctx->mode == S5P_JPEG_DECODE) + return ctx->hdr_parsed; + return 1; +} + +static void s5p_jpeg_job_abort(void *priv) +{ +} + +static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = { + .device_run = s5p_jpeg_device_run, + .job_ready = s5p_jpeg_job_ready, + .job_abort = s5p_jpeg_job_abort, +}; + +/* + * ============================================================================ + * Queue operations + * ============================================================================ + */ + +static int s5p_jpeg_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); + struct s5p_jpeg_q_data *q_data = NULL; + unsigned int size, count = *nbuffers; + + q_data = get_q_data(ctx, vq->type); + BUG_ON(q_data == NULL); + + size = q_data->size; + + /* + * header is parsed during decoding and parsed information stored + * in the context so we do not allow another buffer to overwrite it + */ + if (ctx->mode == S5P_JPEG_DECODE) + count = 1; + + *nbuffers = count; + *nplanes = 1; + sizes[0] = size; + alloc_ctxs[0] = ctx->jpeg->alloc_ctx; + + return 0; +} + +static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct s5p_jpeg_q_data *q_data = NULL; + + q_data = get_q_data(ctx, vb->vb2_queue->type); + BUG_ON(q_data == NULL); + + if (vb2_plane_size(vb, 0) < q_data->size) { + pr_err("%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, q_data->size); + + return 0; +} + +static void s5p_jpeg_buf_queue(struct vb2_buffer *vb) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + if (ctx->mode == S5P_JPEG_DECODE && + vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct s5p_jpeg_q_data tmp, *q_data; + ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp, + (unsigned long)vb2_plane_vaddr(vb, 0), + min((unsigned long)ctx->out_q.size, + vb2_get_plane_payload(vb, 0))); + if (!ctx->hdr_parsed) { + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + return; + } + + q_data = &ctx->out_q; + q_data->w = tmp.w; + q_data->h = tmp.h; + + q_data = &ctx->cap_q; + q_data->w = tmp.w; + q_data->h = tmp.h; + + jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH, + S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align, + &q_data->h, S5P_JPEG_MIN_HEIGHT, + S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align + ); + q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3; + } + if (ctx->m2m_ctx) + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} + +static void s5p_jpeg_wait_prepare(struct vb2_queue *vq) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); + + mutex_unlock(&ctx->jpeg->lock); +} + +static void s5p_jpeg_wait_finish(struct vb2_queue *vq) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); + + mutex_lock(&ctx->jpeg->lock); +} + +static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q); + int ret; + + ret = pm_runtime_get_sync(ctx->jpeg->dev); + + return ret > 0 ? 0 : ret; +} + +static int s5p_jpeg_stop_streaming(struct vb2_queue *q) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q); + + pm_runtime_put(ctx->jpeg->dev); + + return 0; +} + +static struct vb2_ops s5p_jpeg_qops = { + .queue_setup = s5p_jpeg_queue_setup, + .buf_prepare = s5p_jpeg_buf_prepare, + .buf_queue = s5p_jpeg_buf_queue, + .wait_prepare = s5p_jpeg_wait_prepare, + .wait_finish = s5p_jpeg_wait_finish, + .start_streaming = s5p_jpeg_start_streaming, + .stop_streaming = s5p_jpeg_stop_streaming, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct s5p_jpeg_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &s5p_jpeg_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &s5p_jpeg_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return vb2_queue_init(dst_vq); +} + +/* + * ============================================================================ + * ISR + * ============================================================================ + */ + +static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) +{ + struct s5p_jpeg *jpeg = dev_id; + struct s5p_jpeg_ctx *curr_ctx; + struct vb2_buffer *src_buf, *dst_buf; + unsigned long payload_size = 0; + enum vb2_buffer_state state = VB2_BUF_STATE_DONE; + bool enc_jpeg_too_large = false; + bool timer_elapsed = false; + bool op_completed = false; + + curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); + + src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + + if (curr_ctx->mode == S5P_JPEG_ENCODE) + enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs); + timer_elapsed = jpeg_timer_stat(jpeg->regs); + op_completed = jpeg_result_stat_ok(jpeg->regs); + if (curr_ctx->mode == S5P_JPEG_DECODE) + op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs); + + if (enc_jpeg_too_large) { + state = VB2_BUF_STATE_ERROR; + jpeg_clear_enc_stream_stat(jpeg->regs); + } else if (timer_elapsed) { + state = VB2_BUF_STATE_ERROR; + jpeg_clear_timer_stat(jpeg->regs); + } else if (!op_completed) { + state = VB2_BUF_STATE_ERROR; + } else { + payload_size = jpeg_compressed_size(jpeg->regs); + } + + v4l2_m2m_buf_done(src_buf, state); + if (curr_ctx->mode == S5P_JPEG_ENCODE) + vb2_set_plane_payload(dst_buf, 0, payload_size); + v4l2_m2m_buf_done(dst_buf, state); + v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); + + jpeg_clear_int(jpeg->regs); + + return IRQ_HANDLED; +} + +/* + * ============================================================================ + * Driver basic infrastructure + * ============================================================================ + */ + +static int s5p_jpeg_probe(struct platform_device *pdev) +{ + struct s5p_jpeg *jpeg; + struct resource *res; + int ret; + + /* JPEG IP abstraction struct */ + jpeg = kzalloc(sizeof(struct s5p_jpeg), GFP_KERNEL); + if (!jpeg) + return -ENOMEM; + + mutex_init(&jpeg->lock); + jpeg->dev = &pdev->dev; + + /* memory-mapped registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "cannot find IO resource\n"); + ret = -ENOENT; + goto jpeg_alloc_rollback; + } + + jpeg->ioarea = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!jpeg->ioarea) { + dev_err(&pdev->dev, "cannot request IO\n"); + ret = -ENXIO; + goto jpeg_alloc_rollback; + } + + jpeg->regs = ioremap(res->start, resource_size(res)); + if (!jpeg->regs) { + dev_err(&pdev->dev, "cannot map IO\n"); + ret = -ENXIO; + goto mem_region_rollback; + } + + dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", + jpeg->regs, jpeg->ioarea, res); + + /* interrupt service routine registration */ + jpeg->irq = ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "cannot find IRQ\n"); + goto ioremap_rollback; + } + + ret = request_irq(jpeg->irq, s5p_jpeg_irq, 0, + dev_name(&pdev->dev), jpeg); + + if (ret) { + dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq); + goto ioremap_rollback; + } + + /* clocks */ + jpeg->clk = clk_get(&pdev->dev, "jpeg"); + if (IS_ERR(jpeg->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + ret = PTR_ERR(jpeg->clk); + goto request_irq_rollback; + } + dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk); + clk_enable(jpeg->clk); + + /* v4l2 device */ + ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register v4l2 device\n"); + goto clk_get_rollback; + } + + /* mem2mem device */ + jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops); + if (IS_ERR(jpeg->m2m_dev)) { + v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(jpeg->m2m_dev); + goto device_register_rollback; + } + + jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(jpeg->alloc_ctx)) { + v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n"); + ret = PTR_ERR(jpeg->alloc_ctx); + goto m2m_init_rollback; + } + + /* JPEG encoder /dev/videoX node */ + jpeg->vfd_encoder = video_device_alloc(); + if (!jpeg->vfd_encoder) { + v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto vb2_allocator_rollback; + } + strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME, + sizeof(jpeg->vfd_encoder->name)); + jpeg->vfd_encoder->fops = &s5p_jpeg_fops; + jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops; + jpeg->vfd_encoder->minor = -1; + jpeg->vfd_encoder->release = video_device_release; + jpeg->vfd_encoder->lock = &jpeg->lock; + jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev; + + ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); + goto enc_vdev_alloc_rollback; + } + + video_set_drvdata(jpeg->vfd_encoder, jpeg); + v4l2_info(&jpeg->v4l2_dev, + "encoder device registered as /dev/video%d\n", + jpeg->vfd_encoder->num); + + /* JPEG decoder /dev/videoX node */ + jpeg->vfd_decoder = video_device_alloc(); + if (!jpeg->vfd_decoder) { + v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto enc_vdev_register_rollback; + } + strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME, + sizeof(jpeg->vfd_decoder->name)); + jpeg->vfd_decoder->fops = &s5p_jpeg_fops; + jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops; + jpeg->vfd_decoder->minor = -1; + jpeg->vfd_decoder->release = video_device_release; + jpeg->vfd_decoder->lock = &jpeg->lock; + jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev; + + ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); + goto dec_vdev_alloc_rollback; + } + + video_set_drvdata(jpeg->vfd_decoder, jpeg); + v4l2_info(&jpeg->v4l2_dev, + "decoder device registered as /dev/video%d\n", + jpeg->vfd_decoder->num); + + /* final statements & power management */ + platform_set_drvdata(pdev, jpeg); + + pm_runtime_enable(&pdev->dev); + + v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n"); + + return 0; + +dec_vdev_alloc_rollback: + video_device_release(jpeg->vfd_decoder); + +enc_vdev_register_rollback: + video_unregister_device(jpeg->vfd_encoder); + +enc_vdev_alloc_rollback: + video_device_release(jpeg->vfd_encoder); + +vb2_allocator_rollback: + vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx); + +m2m_init_rollback: + v4l2_m2m_release(jpeg->m2m_dev); + +device_register_rollback: + v4l2_device_unregister(&jpeg->v4l2_dev); + +clk_get_rollback: + clk_disable(jpeg->clk); + clk_put(jpeg->clk); + +request_irq_rollback: + free_irq(jpeg->irq, jpeg); + +ioremap_rollback: + iounmap(jpeg->regs); + +mem_region_rollback: + release_resource(jpeg->ioarea); + release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea)); + +jpeg_alloc_rollback: + kfree(jpeg); + return ret; +} + +static int s5p_jpeg_remove(struct platform_device *pdev) +{ + struct s5p_jpeg *jpeg = platform_get_drvdata(pdev); + + pm_runtime_disable(jpeg->dev); + + video_unregister_device(jpeg->vfd_decoder); + video_device_release(jpeg->vfd_decoder); + video_unregister_device(jpeg->vfd_encoder); + video_device_release(jpeg->vfd_encoder); + vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx); + v4l2_m2m_release(jpeg->m2m_dev); + v4l2_device_unregister(&jpeg->v4l2_dev); + + clk_disable(jpeg->clk); + clk_put(jpeg->clk); + + free_irq(jpeg->irq, jpeg); + + iounmap(jpeg->regs); + + release_resource(jpeg->ioarea); + release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea)); + kfree(jpeg); + + return 0; +} + +static int s5p_jpeg_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int s5p_jpeg_runtime_resume(struct device *dev) +{ + struct s5p_jpeg *jpeg = dev_get_drvdata(dev); + /* + * JPEG IP allows storing two Huffman tables for each component + * We fill table 0 for each component + */ + jpeg_set_hdctbl(jpeg->regs); + jpeg_set_hdctblg(jpeg->regs); + jpeg_set_hactbl(jpeg->regs); + jpeg_set_hactblg(jpeg->regs); + return 0; +} + +static const struct dev_pm_ops s5p_jpeg_pm_ops = { + .runtime_suspend = s5p_jpeg_runtime_suspend, + .runtime_resume = s5p_jpeg_runtime_resume, +}; + +static struct platform_driver s5p_jpeg_driver = { + .probe = s5p_jpeg_probe, + .remove = s5p_jpeg_remove, + .driver = { + .owner = THIS_MODULE, + .name = S5P_JPEG_M2M_NAME, + .pm = &s5p_jpeg_pm_ops, + }, +}; + +static int __init +s5p_jpeg_register(void) +{ + int ret; + + pr_info("S5P JPEG V4L2 Driver, (c) 2011 Samsung Electronics\n"); + + ret = platform_driver_register(&s5p_jpeg_driver); + + if (ret) + pr_err("%s: failed to register jpeg driver\n", __func__); + + return ret; +} + +static void __exit +s5p_jpeg_unregister(void) +{ + platform_driver_unregister(&s5p_jpeg_driver); +} + +module_init(s5p_jpeg_register); +module_exit(s5p_jpeg_unregister); + +MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>"); +MODULE_DESCRIPTION("Samsung JPEG codec driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h new file mode 100644 index 000000000000..facad6114f5e --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-core.h @@ -0,0 +1,143 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-core.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@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 JPEG_CORE_H_ +#define JPEG_CORE_H_ + +#include <media/v4l2-device.h> + +#define S5P_JPEG_M2M_NAME "s5p-jpeg" + +/* JPEG compression quality setting */ +#define S5P_JPEG_COMPR_QUAL_BEST 0 +#define S5P_JPEG_COMPR_QUAL_WORST 3 + +/* JPEG RGB to YCbCr conversion matrix coefficients */ +#define S5P_JPEG_COEF11 0x4d +#define S5P_JPEG_COEF12 0x97 +#define S5P_JPEG_COEF13 0x1e +#define S5P_JPEG_COEF21 0x2c +#define S5P_JPEG_COEF22 0x57 +#define S5P_JPEG_COEF23 0x83 +#define S5P_JPEG_COEF31 0x83 +#define S5P_JPEG_COEF32 0x6e +#define S5P_JPEG_COEF33 0x13 + +/* a selection of JPEG markers */ +#define TEM 0x01 +#define SOF0 0xc0 +#define RST 0xd0 +#define SOI 0xd8 +#define EOI 0xd9 +#define DHP 0xde + +/* Flags that indicate a format can be used for capture/output */ +#define MEM2MEM_CAPTURE (1 << 0) +#define MEM2MEM_OUTPUT (1 << 1) + +/** + * struct s5p_jpeg - JPEG IP abstraction + * @lock: the mutex protecting this structure + * @v4l2_dev: v4l2 device for mem2mem mode + * @vfd_encoder: video device node for encoder mem2mem mode + * @vfd_decoder: video device node for decoder mem2mem mode + * @m2m_dev: v4l2 mem2mem device data + * @ioarea: JPEG IP memory region + * @regs: JPEG IP registers mapping + * @irq: JPEG IP irq + * @clk: JPEG IP clock + * @dev: JPEG IP struct device + * @alloc_ctx: videobuf2 memory allocator's context + */ +struct s5p_jpeg { + struct mutex lock; + + struct v4l2_device v4l2_dev; + struct video_device *vfd_encoder; + struct video_device *vfd_decoder; + struct v4l2_m2m_dev *m2m_dev; + + struct resource *ioarea; + void __iomem *regs; + unsigned int irq; + struct clk *clk; + struct device *dev; + void *alloc_ctx; +}; + +/** + * struct jpeg_fmt - driver's internal color format data + * @name: format descritpion + * @fourcc: the fourcc code, 0 if not applicable + * @depth: number of bits per pixel + * @colplanes: number of color planes (1 for packed formats) + * @h_align: horizontal alignment order (align to 2^h_align) + * @v_align: vertical alignment order (align to 2^v_align) + * @types: types of queue this format is applicable to + */ +struct s5p_jpeg_fmt { + char *name; + u32 fourcc; + int depth; + int colplanes; + int h_align; + int v_align; + u32 types; +}; + +/** + * s5p_jpeg_q_data - parameters of one queue + * @fmt: driver-specific format of this queue + * @w: image width + * @h: image height + * @size: image buffer size in bytes + */ +struct s5p_jpeg_q_data { + struct s5p_jpeg_fmt *fmt; + u32 w; + u32 h; + u32 size; +}; + +/** + * s5p_jpeg_ctx - the device context data + * @jpeg: JPEG IP device for this context + * @mode: compression (encode) operation or decompression (decode) + * @compr_quality: destination image quality in compression (encode) mode + * @m2m_ctx: mem2mem device context + * @out_q: source (output) queue information + * @cap_fmt: destination (capture) queue queue information + * @hdr_parsed: set if header has been parsed during decompression + */ +struct s5p_jpeg_ctx { + struct s5p_jpeg *jpeg; + unsigned int mode; + unsigned int compr_quality; + struct v4l2_m2m_ctx *m2m_ctx; + struct s5p_jpeg_q_data out_q; + struct s5p_jpeg_q_data cap_q; + bool hdr_parsed; +}; + +/** + * s5p_jpeg_buffer - description of memory containing input JPEG data + * @size: buffer size + * @curr: current position in the buffer + * @data: pointer to the data + */ +struct s5p_jpeg_buffer { + unsigned long size; + unsigned long curr; + unsigned long data; +}; + +#endif /* JPEG_CORE_H */ diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw.h b/drivers/media/video/s5p-jpeg/jpeg-hw.h new file mode 100644 index 000000000000..e10c744e9f23 --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-hw.h @@ -0,0 +1,353 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-hw.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@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 JPEG_HW_H_ +#define JPEG_HW_H_ + +#include <linux/io.h> + +#include "jpeg-hw.h" +#include "jpeg-regs.h" + +#define S5P_JPEG_MIN_WIDTH 32 +#define S5P_JPEG_MIN_HEIGHT 32 +#define S5P_JPEG_MAX_WIDTH 8192 +#define S5P_JPEG_MAX_HEIGHT 8192 +#define S5P_JPEG_ENCODE 0 +#define S5P_JPEG_DECODE 1 +#define S5P_JPEG_RAW_IN_565 0 +#define S5P_JPEG_RAW_IN_422 1 +#define S5P_JPEG_SUBSAMPLING_422 0 +#define S5P_JPEG_SUBSAMPLING_420 1 +#define S5P_JPEG_RAW_OUT_422 0 +#define S5P_JPEG_RAW_OUT_420 1 + +static inline void jpeg_reset(void __iomem *regs) +{ + unsigned long reg; + + writel(1, regs + S5P_JPG_SW_RESET); + reg = readl(regs + S5P_JPG_SW_RESET); + /* no other way but polling for when JPEG IP becomes operational */ + while (reg != 0) { + cpu_relax(); + reg = readl(regs + S5P_JPG_SW_RESET); + } +} + +static inline void jpeg_poweron(void __iomem *regs) +{ + writel(S5P_POWER_ON, regs + S5P_JPGCLKCON); +} + +static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) +{ + unsigned long reg, m; + + m = S5P_MOD_SEL_565; + if (mode == S5P_JPEG_RAW_IN_565) + m = S5P_MOD_SEL_565; + else if (mode == S5P_JPEG_RAW_IN_422) + m = S5P_MOD_SEL_422; + + reg = readl(regs + S5P_JPGCMOD); + reg &= ~S5P_MOD_SEL_MASK; + reg |= m; + writel(reg, regs + S5P_JPGCMOD); +} + +static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGCMOD); + if (y16) + reg |= S5P_MODE_Y16; + else + reg &= ~S5P_MODE_Y16_MASK; + writel(reg, regs + S5P_JPGCMOD); +} + +static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode) +{ + unsigned long reg, m; + + m = S5P_PROC_MODE_DECOMPR; + if (mode == S5P_JPEG_ENCODE) + m = S5P_PROC_MODE_COMPR; + else + m = S5P_PROC_MODE_DECOMPR; + reg = readl(regs + S5P_JPGMOD); + reg &= ~S5P_PROC_MODE_MASK; + reg |= m; + writel(reg, regs + S5P_JPGMOD); +} + +static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode) +{ + unsigned long reg, m; + + m = S5P_SUBSAMPLING_MODE_422; + if (mode == S5P_JPEG_SUBSAMPLING_422) + m = S5P_SUBSAMPLING_MODE_422; + else if (mode == S5P_JPEG_SUBSAMPLING_420) + m = S5P_SUBSAMPLING_MODE_420; + reg = readl(regs + S5P_JPGMOD); + reg &= ~S5P_SUBSAMPLING_MODE_MASK; + reg |= m; + writel(reg, regs + S5P_JPGMOD); +} + +static inline void jpeg_dri(void __iomem *regs, unsigned int dri) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGDRI_U); + reg &= ~0xff; + reg |= (dri >> 8) & 0xff; + writel(reg, regs + S5P_JPGDRI_U); + + reg = readl(regs + S5P_JPGDRI_L); + reg &= ~0xff; + reg |= dri & 0xff; + writel(reg, regs + S5P_JPGDRI_L); +} + +static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_QTBL); + reg &= ~S5P_QT_NUMt_MASK(t); + reg |= (n << S5P_QT_NUMt_SHIFT(t)) & S5P_QT_NUMt_MASK(t); + writel(reg, regs + S5P_JPG_QTBL); +} + +static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_HTBL); + reg &= ~S5P_HT_NUMt_AC_MASK(t); + /* this driver uses table 0 for all color components */ + reg |= (0 << S5P_HT_NUMt_AC_SHIFT(t)) & S5P_HT_NUMt_AC_MASK(t); + writel(reg, regs + S5P_JPG_HTBL); +} + +static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_HTBL); + reg &= ~S5P_HT_NUMt_DC_MASK(t); + /* this driver uses table 0 for all color components */ + reg |= (0 << S5P_HT_NUMt_DC_SHIFT(t)) & S5P_HT_NUMt_DC_MASK(t); + writel(reg, regs + S5P_JPG_HTBL); +} + +static inline void jpeg_y(void __iomem *regs, unsigned int y) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGY_U); + reg &= ~0xff; + reg |= (y >> 8) & 0xff; + writel(reg, regs + S5P_JPGY_U); + + reg = readl(regs + S5P_JPGY_L); + reg &= ~0xff; + reg |= y & 0xff; + writel(reg, regs + S5P_JPGY_L); +} + +static inline void jpeg_x(void __iomem *regs, unsigned int x) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGX_U); + reg &= ~0xff; + reg |= (x >> 8) & 0xff; + writel(reg, regs + S5P_JPGX_U); + + reg = readl(regs + S5P_JPGX_L); + reg &= ~0xff; + reg |= x & 0xff; + writel(reg, regs + S5P_JPGX_L); +} + +static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGINTSE); + reg &= ~S5P_RSTm_INT_EN_MASK; + if (enable) + reg |= S5P_RSTm_INT_EN; + writel(reg, regs + S5P_JPGINTSE); +} + +static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGINTSE); + reg &= ~S5P_DATA_NUM_INT_EN_MASK; + if (enable) + reg |= S5P_DATA_NUM_INT_EN; + writel(reg, regs + S5P_JPGINTSE); +} + +static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGINTSE); + reg &= ~S5P_FINAL_MCU_NUM_INT_EN_MASK; + if (enbl) + reg |= S5P_FINAL_MCU_NUM_INT_EN; + writel(reg, regs + S5P_JPGINTSE); +} + +static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_TIMER_SE); + reg |= S5P_TIMER_INT_EN; + reg &= ~S5P_TIMER_INIT_MASK; + reg |= val & S5P_TIMER_INIT_MASK; + writel(reg, regs + S5P_JPG_TIMER_SE); +} + +static inline void jpeg_timer_disable(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_TIMER_SE); + reg &= ~S5P_TIMER_INT_EN_MASK; + writel(reg, regs + S5P_JPG_TIMER_SE); +} + +static inline int jpeg_timer_stat(void __iomem *regs) +{ + return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK) + >> S5P_TIMER_INT_STAT_SHIFT); +} + +static inline void jpeg_clear_timer_stat(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_TIMER_SE); + reg &= ~S5P_TIMER_INT_STAT_MASK; + writel(reg, regs + S5P_JPG_TIMER_SE); +} + +static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE); + reg &= ~S5P_ENC_STREAM_BOUND_MASK; + reg |= S5P_ENC_STREAM_INT_EN; + reg |= size & S5P_ENC_STREAM_BOUND_MASK; + writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE); +} + +static inline int jpeg_enc_stream_stat(void __iomem *regs) +{ + return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) & + S5P_ENC_STREAM_INT_STAT_MASK); +} + +static inline void jpeg_clear_enc_stream_stat(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE); + reg &= ~S5P_ENC_STREAM_INT_MASK; + writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE); +} + +static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format) +{ + unsigned long reg, f; + + f = S5P_DEC_OUT_FORMAT_422; + if (format == S5P_JPEG_RAW_OUT_422) + f = S5P_DEC_OUT_FORMAT_422; + else if (format == S5P_JPEG_RAW_OUT_420) + f = S5P_DEC_OUT_FORMAT_420; + reg = readl(regs + S5P_JPG_OUTFORM); + reg &= ~S5P_DEC_OUT_FORMAT_MASK; + reg |= f; + writel(reg, regs + S5P_JPG_OUTFORM); +} + +static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr) +{ + writel(addr, regs + S5P_JPG_JPGADR); +} + +static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr) +{ + writel(addr, regs + S5P_JPG_IMGADR); +} + +static inline void jpeg_coef(void __iomem *regs, unsigned int i, + unsigned int j, unsigned int coef) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_COEF(i)); + reg &= ~S5P_COEFn_MASK(j); + reg |= (coef << S5P_COEFn_SHIFT(j)) & S5P_COEFn_MASK(j); + writel(reg, regs + S5P_JPG_COEF(i)); +} + +static inline void jpeg_start(void __iomem *regs) +{ + writel(1, regs + S5P_JSTART); +} + +static inline int jpeg_result_stat_ok(void __iomem *regs) +{ + return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK) + >> S5P_RESULT_STAT_SHIFT); +} + +static inline int jpeg_stream_stat_ok(void __iomem *regs) +{ + return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK) + >> S5P_STREAM_STAT_SHIFT); +} + +static inline void jpeg_clear_int(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGINTST); + writel(S5P_INT_RELEASE, regs + S5P_JPGCOM); + reg = readl(regs + S5P_JPGOPR); +} + +static inline unsigned int jpeg_compressed_size(void __iomem *regs) +{ + unsigned long jpeg_size = 0; + + jpeg_size |= (readl(regs + S5P_JPGCNT_U) & 0xff) << 16; + jpeg_size |= (readl(regs + S5P_JPGCNT_M) & 0xff) << 8; + jpeg_size |= (readl(regs + S5P_JPGCNT_L) & 0xff); + + return (unsigned int)jpeg_size; +} + +#endif /* JPEG_HW_H_ */ diff --git a/drivers/media/video/s5p-jpeg/jpeg-regs.h b/drivers/media/video/s5p-jpeg/jpeg-regs.h new file mode 100644 index 000000000000..91f4dd5f86dd --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-regs.h @@ -0,0 +1,170 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-regs.h + * + * Register definition file for Samsung JPEG codec driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@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 JPEG_REGS_H_ +#define JPEG_REGS_H_ + +/* JPEG mode register */ +#define S5P_JPGMOD 0x00 +#define S5P_PROC_MODE_MASK (0x1 << 3) +#define S5P_PROC_MODE_DECOMPR (0x1 << 3) +#define S5P_PROC_MODE_COMPR (0x0 << 3) +#define S5P_SUBSAMPLING_MODE_MASK 0x7 +#define S5P_SUBSAMPLING_MODE_444 (0x0 << 0) +#define S5P_SUBSAMPLING_MODE_422 (0x1 << 0) +#define S5P_SUBSAMPLING_MODE_420 (0x2 << 0) +#define S5P_SUBSAMPLING_MODE_GRAY (0x3 << 0) + +/* JPEG operation status register */ +#define S5P_JPGOPR 0x04 + +/* Quantization tables*/ +#define S5P_JPG_QTBL 0x08 +#define S5P_QT_NUMt_SHIFT(t) (((t) - 1) << 1) +#define S5P_QT_NUMt_MASK(t) (0x3 << S5P_QT_NUMt_SHIFT(t)) + +/* Huffman tables */ +#define S5P_JPG_HTBL 0x0c +#define S5P_HT_NUMt_AC_SHIFT(t) (((t) << 1) - 1) +#define S5P_HT_NUMt_AC_MASK(t) (0x1 << S5P_HT_NUMt_AC_SHIFT(t)) + +#define S5P_HT_NUMt_DC_SHIFT(t) (((t) - 1) << 1) +#define S5P_HT_NUMt_DC_MASK(t) (0x1 << S5P_HT_NUMt_DC_SHIFT(t)) + +/* JPEG restart interval register upper byte */ +#define S5P_JPGDRI_U 0x10 + +/* JPEG restart interval register lower byte */ +#define S5P_JPGDRI_L 0x14 + +/* JPEG vertical resolution register upper byte */ +#define S5P_JPGY_U 0x18 + +/* JPEG vertical resolution register lower byte */ +#define S5P_JPGY_L 0x1c + +/* JPEG horizontal resolution register upper byte */ +#define S5P_JPGX_U 0x20 + +/* JPEG horizontal resolution register lower byte */ +#define S5P_JPGX_L 0x24 + +/* JPEG byte count register upper byte */ +#define S5P_JPGCNT_U 0x28 + +/* JPEG byte count register middle byte */ +#define S5P_JPGCNT_M 0x2c + +/* JPEG byte count register lower byte */ +#define S5P_JPGCNT_L 0x30 + +/* JPEG interrupt setting register */ +#define S5P_JPGINTSE 0x34 +#define S5P_RSTm_INT_EN_MASK (0x1 << 7) +#define S5P_RSTm_INT_EN (0x1 << 7) +#define S5P_DATA_NUM_INT_EN_MASK (0x1 << 6) +#define S5P_DATA_NUM_INT_EN (0x1 << 6) +#define S5P_FINAL_MCU_NUM_INT_EN_MASK (0x1 << 5) +#define S5P_FINAL_MCU_NUM_INT_EN (0x1 << 5) + +/* JPEG interrupt status register */ +#define S5P_JPGINTST 0x38 +#define S5P_RESULT_STAT_SHIFT 6 +#define S5P_RESULT_STAT_MASK (0x1 << S5P_RESULT_STAT_SHIFT) +#define S5P_STREAM_STAT_SHIFT 5 +#define S5P_STREAM_STAT_MASK (0x1 << S5P_STREAM_STAT_SHIFT) + +/* JPEG command register */ +#define S5P_JPGCOM 0x4c +#define S5P_INT_RELEASE (0x1 << 2) + +/* Raw image data r/w address register */ +#define S5P_JPG_IMGADR 0x50 + +/* JPEG file r/w address register */ +#define S5P_JPG_JPGADR 0x58 + +/* Coefficient for RGB-to-YCbCr converter register */ +#define S5P_JPG_COEF(n) (0x5c + (((n) - 1) << 2)) +#define S5P_COEFn_SHIFT(j) ((3 - (j)) << 3) +#define S5P_COEFn_MASK(j) (0xff << S5P_COEFn_SHIFT(j)) + +/* JPEG color mode register */ +#define S5P_JPGCMOD 0x68 +#define S5P_MOD_SEL_MASK (0x7 << 5) +#define S5P_MOD_SEL_422 (0x1 << 5) +#define S5P_MOD_SEL_565 (0x2 << 5) +#define S5P_MODE_Y16_MASK (0x1 << 1) +#define S5P_MODE_Y16 (0x1 << 1) + +/* JPEG clock control register */ +#define S5P_JPGCLKCON 0x6c +#define S5P_CLK_DOWN_READY (0x1 << 1) +#define S5P_POWER_ON (0x1 << 0) + +/* JPEG start register */ +#define S5P_JSTART 0x70 + +/* JPEG SW reset register */ +#define S5P_JPG_SW_RESET 0x78 + +/* JPEG timer setting register */ +#define S5P_JPG_TIMER_SE 0x7c +#define S5P_TIMER_INT_EN_MASK (0x1 << 31) +#define S5P_TIMER_INT_EN (0x1 << 31) +#define S5P_TIMER_INIT_MASK 0x7fffffff + +/* JPEG timer status register */ +#define S5P_JPG_TIMER_ST 0x80 +#define S5P_TIMER_INT_STAT_SHIFT 31 +#define S5P_TIMER_INT_STAT_MASK (0x1 << S5P_TIMER_INT_STAT_SHIFT) +#define S5P_TIMER_CNT_SHIFT 0 +#define S5P_TIMER_CNT_MASK 0x7fffffff + +/* JPEG decompression output format register */ +#define S5P_JPG_OUTFORM 0x88 +#define S5P_DEC_OUT_FORMAT_MASK (0x1 << 0) +#define S5P_DEC_OUT_FORMAT_422 (0x0 << 0) +#define S5P_DEC_OUT_FORMAT_420 (0x1 << 0) + +/* JPEG version register */ +#define S5P_JPG_VERSION 0x8c + +/* JPEG compressed stream size interrupt setting register */ +#define S5P_JPG_ENC_STREAM_INTSE 0x98 +#define S5P_ENC_STREAM_INT_MASK (0x1 << 24) +#define S5P_ENC_STREAM_INT_EN (0x1 << 24) +#define S5P_ENC_STREAM_BOUND_MASK 0xffffff + +/* JPEG compressed stream size interrupt status register */ +#define S5P_JPG_ENC_STREAM_INTST 0x9c +#define S5P_ENC_STREAM_INT_STAT_MASK 0x1 + +/* JPEG quantizer table register */ +#define S5P_JPG_QTBL_CONTENT(n) (0x400 + (n) * 0x100) + +/* JPEG DC Huffman table register */ +#define S5P_JPG_HDCTBL(n) (0x800 + (n) * 0x400) + +/* JPEG DC Huffman table register */ +#define S5P_JPG_HDCTBLG(n) (0x840 + (n) * 0x400) + +/* JPEG AC Huffman table register */ +#define S5P_JPG_HACTBL(n) (0x880 + (n) * 0x400) + +/* JPEG AC Huffman table register */ +#define S5P_JPG_HACTBLG(n) (0x8c0 + (n) * 0x400) + +#endif /* JPEG_REGS_H_ */ + diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c index 8be8b54eb749..83fe461af263 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc.c @@ -18,7 +18,6 @@ #include <linux/platform_device.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/version.h> #include <linux/videodev2.h> #include <linux/workqueue.h> #include <media/videobuf2-core.h> @@ -475,7 +474,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, ctx->mv_size = 0; } ctx->dpb_count = s5p_mfc_get_dpb_count(); - if (ctx->img_width == 0 || ctx->img_width == 0) + if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; else ctx->state = MFCINST_HEAD_PARSED; @@ -1245,27 +1244,7 @@ static struct platform_driver s5p_mfc_driver = { }, }; -static char banner[] __initdata = - "S5P MFC V4L2 Driver, (C) 2011 Samsung Electronics\n"; - -static int __init s5p_mfc_init(void) -{ - int ret; - - pr_info("%s", banner); - ret = platform_driver_register(&s5p_mfc_driver); - if (ret) - pr_err("Platform device registration failed.\n"); - return ret; -} - -static void __exit s5p_mfc_exit(void) -{ - platform_driver_unregister(&s5p_mfc_driver); -} - -module_init(s5p_mfc_init); -module_exit(s5p_mfc_exit); +module_platform_driver(s5p_mfc_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index 844a4d7797bc..c25ec022d267 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -165,7 +165,7 @@ static struct mfc_control controls[] = { .maximum = 32, .step = 1, .default_value = 1, - .flags = V4L2_CTRL_FLAG_VOLATILE, + .is_volatile = 1, }, }; diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c index 0279e6e89feb..8b41a0410ab1 100644 --- a/drivers/media/video/s5p-tv/hdmi_drv.c +++ b/drivers/media/video/s5p-tv/hdmi_drv.c @@ -838,8 +838,8 @@ static int hdmi_resources_init(struct hdmi_device *hdev) dev_err(dev, "failed to get clock 'hdmiphy'\n"); goto fail; } - res->regul_bulk = kzalloc(ARRAY_SIZE(supply) * - sizeof res->regul_bulk[0], GFP_KERNEL); + res->regul_bulk = kcalloc(ARRAY_SIZE(supply), + sizeof(res->regul_bulk[0]), GFP_KERNEL); if (!res->regul_bulk) { dev_err(dev, "failed to get memory for regulators\n"); goto fail; @@ -1016,28 +1016,4 @@ static struct platform_driver hdmi_driver __refdata = { } }; -/* D R I V E R I N I T I A L I Z A T I O N */ - -static int __init hdmi_init(void) -{ - int ret; - static const char banner[] __initdata = KERN_INFO \ - "Samsung HDMI output driver, " - "(c) 2010-2011 Samsung Electronics Co., Ltd.\n"; - printk(banner); - - ret = platform_driver_register(&hdmi_driver); - if (ret) - printk(KERN_ERR "HDMI platform driver register failed\n"); - - return ret; -} -module_init(hdmi_init); - -static void __exit hdmi_exit(void) -{ - platform_driver_unregister(&hdmi_driver); -} -module_exit(hdmi_exit); - - +module_platform_driver(hdmi_driver); diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h index 51ad59b30358..1597078c4a50 100644 --- a/drivers/media/video/s5p-tv/mixer.h +++ b/drivers/media/video/s5p-tv/mixer.h @@ -86,6 +86,17 @@ struct mxr_crop { unsigned int field; }; +/** stages of geometry operations */ +enum mxr_geometry_stage { + MXR_GEOMETRY_SINK, + MXR_GEOMETRY_COMPOSE, + MXR_GEOMETRY_CROP, + MXR_GEOMETRY_SOURCE, +}; + +/* flag indicating that offset should be 0 */ +#define MXR_NO_OFFSET 0x80000000 + /** description of transformation from source to destination image */ struct mxr_geometry { /** cropping for source image */ @@ -133,7 +144,8 @@ struct mxr_layer_ops { /** streaming stop/start */ void (*stream_set)(struct mxr_layer *, int); /** adjusting geometry */ - void (*fix_geometry)(struct mxr_layer *); + void (*fix_geometry)(struct mxr_layer *, + enum mxr_geometry_stage, unsigned long); }; /** layer instance, a single window and content displayed on output */ diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c index de8270c2b6e7..b93a21f5aa13 100644 --- a/drivers/media/video/s5p-tv/mixer_grp_layer.c +++ b/drivers/media/video/s5p-tv/mixer_grp_layer.c @@ -101,47 +101,132 @@ static void mxr_graph_format_set(struct mxr_layer *layer) layer->fmt, &layer->geo); } -static void mxr_graph_fix_geometry(struct mxr_layer *layer) +static inline unsigned int closest(unsigned int x, unsigned int a, + unsigned int b, unsigned long flags) +{ + unsigned int mid = (a + b) / 2; + + /* choosing closest value with constraints according to table: + * -------------+-----+-----+-----+-------+ + * flags | 0 | LE | GE | LE|GE | + * -------------+-----+-----+-----+-------+ + * x <= a | a | a | a | a | + * a < x <= mid | a | a | b | a | + * mid < x < b | b | a | b | b | + * b <= x | b | b | b | b | + * -------------+-----+-----+-----+-------+ + */ + + /* remove all non-constraint flags */ + flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE; + + if (x <= a) + return a; + if (x >= b) + return b; + if (flags == V4L2_SEL_FLAG_LE) + return a; + if (flags == V4L2_SEL_FLAG_GE) + return b; + if (x <= mid) + return a; + return b; +} + +static inline unsigned int do_center(unsigned int center, + unsigned int size, unsigned int upper, unsigned int flags) +{ + unsigned int lower; + + if (flags & MXR_NO_OFFSET) + return 0; + + lower = center - min(center, size / 2); + return min(lower, upper - size); +} + +static void mxr_graph_fix_geometry(struct mxr_layer *layer, + enum mxr_geometry_stage stage, unsigned long flags) { struct mxr_geometry *geo = &layer->geo; + struct mxr_crop *src = &geo->src; + struct mxr_crop *dst = &geo->dst; + unsigned int x_center, y_center; - /* limit to boundary size */ - geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767); - geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047); - geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width); - geo->src.width = min(geo->src.width, 2047U); - /* not possible to crop of Y axis */ - geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1); - geo->src.height = geo->src.full_height - geo->src.y_offset; - /* limitting offset */ - geo->src.x_offset = min(geo->src.x_offset, - geo->src.full_width - geo->src.width); - - /* setting position in output */ - geo->dst.width = min(geo->dst.width, geo->dst.full_width); - geo->dst.height = min(geo->dst.height, geo->dst.full_height); - - /* Mixer supports only 1x and 2x scaling */ - if (geo->dst.width >= 2 * geo->src.width) { - geo->x_ratio = 1; - geo->dst.width = 2 * geo->src.width; - } else { - geo->x_ratio = 0; - geo->dst.width = geo->src.width; - } + switch (stage) { - if (geo->dst.height >= 2 * geo->src.height) { - geo->y_ratio = 1; - geo->dst.height = 2 * geo->src.height; - } else { - geo->y_ratio = 0; - geo->dst.height = geo->src.height; - } + case MXR_GEOMETRY_SINK: /* nothing to be fixed here */ + flags = 0; + /* fall through */ + + case MXR_GEOMETRY_COMPOSE: + /* remember center of the area */ + x_center = dst->x_offset + dst->width / 2; + y_center = dst->y_offset + dst->height / 2; + /* round up/down to 2 multiple depending on flags */ + if (flags & V4L2_SEL_FLAG_LE) { + dst->width = round_down(dst->width, 2); + dst->height = round_down(dst->height, 2); + } else { + dst->width = round_up(dst->width, 2); + dst->height = round_up(dst->height, 2); + } + /* assure that compose rect is inside display area */ + dst->width = min(dst->width, dst->full_width); + dst->height = min(dst->height, dst->full_height); + + /* ensure that compose is reachable using 2x scaling */ + dst->width = min(dst->width, 2 * src->full_width); + dst->height = min(dst->height, 2 * src->full_height); + + /* setup offsets */ + dst->x_offset = do_center(x_center, dst->width, + dst->full_width, flags); + dst->y_offset = do_center(y_center, dst->height, + dst->full_height, flags); + flags = 0; + /* fall through */ - geo->dst.x_offset = min(geo->dst.x_offset, - geo->dst.full_width - geo->dst.width); - geo->dst.y_offset = min(geo->dst.y_offset, - geo->dst.full_height - geo->dst.height); + case MXR_GEOMETRY_CROP: + /* remember center of the area */ + x_center = src->x_offset + src->width / 2; + y_center = src->y_offset + src->height / 2; + /* ensure that cropping area lies inside the buffer */ + if (src->full_width < dst->width) + src->width = dst->width / 2; + else + src->width = closest(src->width, dst->width / 2, + dst->width, flags); + + if (src->width == dst->width) + geo->x_ratio = 0; + else + geo->x_ratio = 1; + + if (src->full_height < dst->height) + src->height = dst->height / 2; + else + src->height = closest(src->height, dst->height / 2, + dst->height, flags); + + if (src->height == dst->height) + geo->y_ratio = 0; + else + geo->y_ratio = 1; + + /* setup offsets */ + src->x_offset = do_center(x_center, src->width, + src->full_width, flags); + src->y_offset = do_center(y_center, src->height, + src->full_height, flags); + flags = 0; + /* fall through */ + case MXR_GEOMETRY_SOURCE: + src->full_width = clamp_val(src->full_width, + src->width + src->x_offset, 32767); + src->full_height = clamp_val(src->full_height, + src->height + src->y_offset, 2047); + }; } /* PUBLIC API */ diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index b47d0c06ecf5..7884baeff76a 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -170,18 +170,22 @@ static int mxr_querycap(struct file *file, void *priv, return 0; } -/* Geometry handling */ -static void mxr_layer_geo_fix(struct mxr_layer *layer) +static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo) { - struct mxr_device *mdev = layer->mdev; - struct v4l2_mbus_framefmt mbus_fmt; - - /* TODO: add some dirty flag to avoid unnecessary adjustments */ - mxr_get_mbus_fmt(mdev, &mbus_fmt); - layer->geo.dst.full_width = mbus_fmt.width; - layer->geo.dst.full_height = mbus_fmt.height; - layer->geo.dst.field = mbus_fmt.field; - layer->ops.fix_geometry(layer); + mxr_dbg(mdev, "src.full_size = (%u, %u)\n", + geo->src.full_width, geo->src.full_height); + mxr_dbg(mdev, "src.size = (%u, %u)\n", + geo->src.width, geo->src.height); + mxr_dbg(mdev, "src.offset = (%u, %u)\n", + geo->src.x_offset, geo->src.y_offset); + mxr_dbg(mdev, "dst.full_size = (%u, %u)\n", + geo->dst.full_width, geo->dst.full_height); + mxr_dbg(mdev, "dst.size = (%u, %u)\n", + geo->dst.width, geo->dst.height); + mxr_dbg(mdev, "dst.offset = (%u, %u)\n", + geo->dst.x_offset, geo->dst.y_offset); + mxr_dbg(mdev, "ratio = (%u, %u)\n", + geo->x_ratio, geo->y_ratio); } static void mxr_layer_default_geo(struct mxr_layer *layer) @@ -204,27 +208,29 @@ static void mxr_layer_default_geo(struct mxr_layer *layer) layer->geo.src.width = layer->geo.src.full_width; layer->geo.src.height = layer->geo.src.full_height; - layer->ops.fix_geometry(layer); + mxr_geometry_dump(mdev, &layer->geo); + layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0); + mxr_geometry_dump(mdev, &layer->geo); } -static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo) +static void mxr_layer_update_output(struct mxr_layer *layer) { - mxr_dbg(mdev, "src.full_size = (%u, %u)\n", - geo->src.full_width, geo->src.full_height); - mxr_dbg(mdev, "src.size = (%u, %u)\n", - geo->src.width, geo->src.height); - mxr_dbg(mdev, "src.offset = (%u, %u)\n", - geo->src.x_offset, geo->src.y_offset); - mxr_dbg(mdev, "dst.full_size = (%u, %u)\n", - geo->dst.full_width, geo->dst.full_height); - mxr_dbg(mdev, "dst.size = (%u, %u)\n", - geo->dst.width, geo->dst.height); - mxr_dbg(mdev, "dst.offset = (%u, %u)\n", - geo->dst.x_offset, geo->dst.y_offset); - mxr_dbg(mdev, "ratio = (%u, %u)\n", - geo->x_ratio, geo->y_ratio); -} + struct mxr_device *mdev = layer->mdev; + struct v4l2_mbus_framefmt mbus_fmt; + + mxr_get_mbus_fmt(mdev, &mbus_fmt); + /* checking if update is needed */ + if (layer->geo.dst.full_width == mbus_fmt.width && + layer->geo.dst.full_height == mbus_fmt.width) + return; + layer->geo.dst.full_width = mbus_fmt.width; + layer->geo.dst.full_height = mbus_fmt.height; + layer->geo.dst.field = mbus_fmt.field; + layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0); + + mxr_geometry_dump(mdev, &layer->geo); +} static const struct mxr_format *find_format_by_fourcc( struct mxr_layer *layer, unsigned long fourcc); @@ -249,37 +255,6 @@ static int mxr_enum_fmt(struct file *file, void *priv, return 0; } -static int mxr_s_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct mxr_layer *layer = video_drvdata(file); - const struct mxr_format *fmt; - struct v4l2_pix_format_mplane *pix; - struct mxr_device *mdev = layer->mdev; - struct mxr_geometry *geo = &layer->geo; - - mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__); - - pix = &f->fmt.pix_mp; - fmt = find_format_by_fourcc(layer, pix->pixelformat); - if (fmt == NULL) { - mxr_warn(mdev, "not recognized fourcc: %08x\n", - pix->pixelformat); - return -EINVAL; - } - layer->fmt = fmt; - geo->src.full_width = pix->width; - geo->src.width = pix->width; - geo->src.full_height = pix->height; - geo->src.height = pix->height; - /* assure consistency of geometry */ - mxr_layer_geo_fix(layer); - mxr_dbg(mdev, "width=%u height=%u span=%u\n", - geo->src.width, geo->src.height, geo->src.full_width); - - return 0; -} - static unsigned int divup(unsigned int divident, unsigned int divisor) { return (divident + divisor - 1) / divisor; @@ -299,6 +274,10 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes, { int i; + /* checking if nothing to fill */ + if (!planes) + return; + memset(planes, 0, sizeof(*planes) * fmt->num_subframes); for (i = 0; i < fmt->num_planes; ++i) { struct v4l2_plane_pix_format *plane = planes @@ -332,73 +311,194 @@ static int mxr_g_fmt(struct file *file, void *priv, return 0; } -static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return &geo->dst; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - return &geo->src; - default: - return NULL; - } -} - -static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a) +static int mxr_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) { struct mxr_layer *layer = video_drvdata(file); - struct mxr_crop *crop; + const struct mxr_format *fmt; + struct v4l2_pix_format_mplane *pix; + struct mxr_device *mdev = layer->mdev; + struct mxr_geometry *geo = &layer->geo; - mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); - crop = choose_crop_by_type(&layer->geo, a->type); - if (crop == NULL) + mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__); + + pix = &f->fmt.pix_mp; + fmt = find_format_by_fourcc(layer, pix->pixelformat); + if (fmt == NULL) { + mxr_warn(mdev, "not recognized fourcc: %08x\n", + pix->pixelformat); return -EINVAL; - mxr_layer_geo_fix(layer); - a->c.left = crop->x_offset; - a->c.top = crop->y_offset; - a->c.width = crop->width; - a->c.height = crop->height; + } + layer->fmt = fmt; + /* set source size to highest accepted value */ + geo->src.full_width = max(geo->dst.full_width, pix->width); + geo->src.full_height = max(geo->dst.full_height, pix->height); + layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); + mxr_geometry_dump(mdev, &layer->geo); + /* set cropping to total visible screen */ + geo->src.width = pix->width; + geo->src.height = pix->height; + geo->src.x_offset = 0; + geo->src.y_offset = 0; + /* assure consistency of geometry */ + layer->ops.fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET); + mxr_geometry_dump(mdev, &layer->geo); + /* set full size to lowest possible value */ + geo->src.full_width = 0; + geo->src.full_height = 0; + layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); + mxr_geometry_dump(mdev, &layer->geo); + + /* returning results */ + mxr_g_fmt(file, priv, f); + return 0; } -static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a) +static int mxr_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) { struct mxr_layer *layer = video_drvdata(file); - struct mxr_crop *crop; + struct mxr_geometry *geo = &layer->geo; mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); - crop = choose_crop_by_type(&layer->geo, a->type); - if (crop == NULL) + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP_ACTIVE: + s->r.left = geo->src.x_offset; + s->r.top = geo->src.y_offset; + s->r.width = geo->src.width; + s->r.height = geo->src.height; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = geo->src.full_width; + s->r.height = geo->src.full_height; + break; + case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE_PADDED: + s->r.left = geo->dst.x_offset; + s->r.top = geo->dst.y_offset; + s->r.width = geo->dst.width; + s->r.height = geo->dst.height; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = geo->dst.full_width; + s->r.height = geo->dst.full_height; + break; + default: return -EINVAL; - crop->x_offset = a->c.left; - crop->y_offset = a->c.top; - crop->width = a->c.width; - crop->height = a->c.height; - mxr_layer_geo_fix(layer); + } + return 0; } -static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a) +/* returns 1 if rectangle 'a' is inside 'b' */ +static int mxr_is_rect_inside(struct v4l2_rect *a, struct v4l2_rect *b) +{ + if (a->left < b->left) + return 0; + if (a->top < b->top) + return 0; + if (a->left + a->width > b->left + b->width) + return 0; + if (a->top + a->height > b->top + b->height) + return 0; + return 1; +} + +static int mxr_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) { struct mxr_layer *layer = video_drvdata(file); - struct mxr_crop *crop; + struct mxr_geometry *geo = &layer->geo; + struct mxr_crop *target = NULL; + enum mxr_geometry_stage stage; + struct mxr_geometry tmp; + struct v4l2_rect res; - mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); - crop = choose_crop_by_type(&layer->geo, a->type); - if (crop == NULL) + memset(&res, 0, sizeof res); + + mxr_dbg(layer->mdev, "%s: rect: %dx%d@%d,%d\n", __func__, + s->r.width, s->r.height, s->r.left, s->r.top); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; - mxr_layer_geo_fix(layer); - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = crop->full_width; - a->bounds.top = crop->full_height; - a->defrect = a->bounds; - /* setting pixel aspect to 1/1 */ - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; + + switch (s->target) { + /* ignore read-only targets */ + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + res.width = geo->src.full_width; + res.height = geo->src.full_height; + break; + + /* ignore read-only targets */ + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + res.width = geo->dst.full_width; + res.height = geo->dst.full_height; + break; + + case V4L2_SEL_TGT_CROP_ACTIVE: + target = &geo->src; + stage = MXR_GEOMETRY_CROP; + break; + case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE_PADDED: + target = &geo->dst; + stage = MXR_GEOMETRY_COMPOSE; + break; + default: + return -EINVAL; + } + /* apply change and update geometry if needed */ + if (target) { + /* backup current geometry if setup fails */ + memcpy(&tmp, geo, sizeof tmp); + + /* apply requested selection */ + target->x_offset = s->r.left; + target->y_offset = s->r.top; + target->width = s->r.width; + target->height = s->r.height; + + layer->ops.fix_geometry(layer, stage, s->flags); + + /* retrieve update selection rectangle */ + res.left = target->x_offset; + res.top = target->y_offset; + res.width = target->width; + res.height = target->height; + + mxr_geometry_dump(layer->mdev, &layer->geo); + } + + /* checking if the rectangle satisfies constraints */ + if ((s->flags & V4L2_SEL_FLAG_LE) && !mxr_is_rect_inside(&res, &s->r)) + goto fail; + if ((s->flags & V4L2_SEL_FLAG_GE) && !mxr_is_rect_inside(&s->r, &res)) + goto fail; + + /* return result rectangle */ + s->r = res; + return 0; +fail: + /* restore old geometry, which is not touched if target is NULL */ + if (target) + memcpy(geo, &tmp, sizeof tmp); + return -ERANGE; } static int mxr_enum_dv_presets(struct file *file, void *fh, @@ -438,6 +538,8 @@ static int mxr_s_dv_preset(struct file *file, void *fh, mutex_unlock(&mdev->mutex); + mxr_layer_update_output(layer); + /* any failure should return EINVAL according to V4L2 doc */ return ret ? -EINVAL : 0; } @@ -478,6 +580,8 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm) mutex_unlock(&mdev->mutex); + mxr_layer_update_output(layer); + return ret ? -EINVAL : 0; } @@ -526,25 +630,27 @@ static int mxr_s_output(struct file *file, void *fh, unsigned int i) struct video_device *vfd = video_devdata(file); struct mxr_layer *layer = video_drvdata(file); struct mxr_device *mdev = layer->mdev; - int ret = 0; if (i >= mdev->output_cnt || mdev->output[i] == NULL) return -EINVAL; mutex_lock(&mdev->mutex); if (mdev->n_output > 0) { - ret = -EBUSY; - goto done; + mutex_unlock(&mdev->mutex); + return -EBUSY; } mdev->current_output = i; vfd->tvnorms = 0; v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output, &vfd->tvnorms); + mutex_unlock(&mdev->mutex); + + /* update layers geometry */ + mxr_layer_update_output(layer); + mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms); -done: - mutex_unlock(&mdev->mutex); - return ret; + return 0; } static int mxr_g_output(struct file *file, void *fh, unsigned int *p) @@ -633,10 +739,9 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = { .vidioc_enum_output = mxr_enum_output, .vidioc_s_output = mxr_s_output, .vidioc_g_output = mxr_g_output, - /* Crop ioctls */ - .vidioc_g_crop = mxr_g_crop, - .vidioc_s_crop = mxr_s_crop, - .vidioc_cropcap = mxr_cropcap, + /* selection ioctls */ + .vidioc_g_selection = mxr_g_selection, + .vidioc_s_selection = mxr_s_selection, }; static int mxr_video_open(struct file *file) @@ -805,10 +910,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) /* block any changes in output configuration */ mxr_output_get(mdev); - /* update layers geometry */ - mxr_layer_geo_fix(layer); - mxr_geometry_dump(mdev, &layer->geo); - + mxr_layer_update_output(layer); layer->ops.format_set(layer); /* enabling layer in hardware */ spin_lock_irqsave(&layer->enq_slock, flags); diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c index f3bb2e34cb51..3d13a636877b 100644 --- a/drivers/media/video/s5p-tv/mixer_vp_layer.c +++ b/drivers/media/video/s5p-tv/mixer_vp_layer.c @@ -127,47 +127,77 @@ static void mxr_vp_format_set(struct mxr_layer *layer) mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo); } -static void mxr_vp_fix_geometry(struct mxr_layer *layer) +static inline unsigned int do_center(unsigned int center, + unsigned int size, unsigned int upper, unsigned int flags) { - struct mxr_geometry *geo = &layer->geo; + unsigned int lower; + + if (flags & MXR_NO_OFFSET) + return 0; + + lower = center - min(center, size / 2); + return min(lower, upper - size); +} - /* align horizontal size to 8 pixels */ - geo->src.full_width = ALIGN(geo->src.full_width, 8); - /* limit to boundary size */ - geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192); - geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192); - geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width); - geo->src.width = min(geo->src.width, 2047U); - geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height); - geo->src.height = min(geo->src.height, 2047U); - - /* setting size of output window */ - geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width); - geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height); - - /* ensure that scaling is in range 1/4x to 16x */ - if (geo->src.width >= 4 * geo->dst.width) - geo->src.width = 4 * geo->dst.width; - if (geo->dst.width >= 16 * geo->src.width) - geo->dst.width = 16 * geo->src.width; - if (geo->src.height >= 4 * geo->dst.height) - geo->src.height = 4 * geo->dst.height; - if (geo->dst.height >= 16 * geo->src.height) - geo->dst.height = 16 * geo->src.height; - - /* setting scaling ratio */ - geo->x_ratio = (geo->src.width << 16) / geo->dst.width; - geo->y_ratio = (geo->src.height << 16) / geo->dst.height; - - /* adjust offsets */ - geo->src.x_offset = min(geo->src.x_offset, - geo->src.full_width - geo->src.width); - geo->src.y_offset = min(geo->src.y_offset, - geo->src.full_height - geo->src.height); - geo->dst.x_offset = min(geo->dst.x_offset, - geo->dst.full_width - geo->dst.width); - geo->dst.y_offset = min(geo->dst.y_offset, - geo->dst.full_height - geo->dst.height); +static void mxr_vp_fix_geometry(struct mxr_layer *layer, + enum mxr_geometry_stage stage, unsigned long flags) +{ + struct mxr_geometry *geo = &layer->geo; + struct mxr_crop *src = &geo->src; + struct mxr_crop *dst = &geo->dst; + unsigned long x_center, y_center; + + switch (stage) { + + case MXR_GEOMETRY_SINK: /* nothing to be fixed here */ + case MXR_GEOMETRY_COMPOSE: + /* remember center of the area */ + x_center = dst->x_offset + dst->width / 2; + y_center = dst->y_offset + dst->height / 2; + + /* ensure that compose is reachable using 16x scaling */ + dst->width = clamp(dst->width, 8U, 16 * src->full_width); + dst->height = clamp(dst->height, 1U, 16 * src->full_height); + + /* setup offsets */ + dst->x_offset = do_center(x_center, dst->width, + dst->full_width, flags); + dst->y_offset = do_center(y_center, dst->height, + dst->full_height, flags); + flags = 0; /* remove possible MXR_NO_OFFSET flag */ + /* fall through */ + case MXR_GEOMETRY_CROP: + /* remember center of the area */ + x_center = src->x_offset + src->width / 2; + y_center = src->y_offset + src->height / 2; + + /* ensure scaling is between 0.25x .. 16x */ + src->width = clamp(src->width, round_up(dst->width / 16, 4), + dst->width * 4); + src->height = clamp(src->height, round_up(dst->height / 16, 4), + dst->height * 4); + + /* hardware limits */ + src->width = clamp(src->width, 32U, 2047U); + src->height = clamp(src->height, 4U, 2047U); + + /* setup offsets */ + src->x_offset = do_center(x_center, src->width, + src->full_width, flags); + src->y_offset = do_center(y_center, src->height, + src->full_height, flags); + + /* setting scaling ratio */ + geo->x_ratio = (src->width << 16) / dst->width; + geo->y_ratio = (src->height << 16) / dst->height; + /* fall through */ + + case MXR_GEOMETRY_SOURCE: + src->full_width = clamp(src->full_width, + ALIGN(src->width + src->x_offset, 8), 8192U); + src->full_height = clamp(src->full_height, + src->height + src->y_offset, 8192U); + }; } /* PUBLIC API */ diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c index 8cec67ef48c9..059e7749ce95 100644 --- a/drivers/media/video/s5p-tv/sdo_drv.c +++ b/drivers/media/video/s5p-tv/sdo_drv.c @@ -457,24 +457,4 @@ static struct platform_driver sdo_driver __refdata = { } }; -static int __init sdo_init(void) -{ - int ret; - static const char banner[] __initdata = KERN_INFO \ - "Samsung Standard Definition Output (SDO) driver, " - "(c) 2010-2011 Samsung Electronics Co., Ltd.\n"; - printk(banner); - - ret = platform_driver_register(&sdo_driver); - if (ret) - printk(KERN_ERR "SDO platform driver register failed\n"); - - return ret; -} -module_init(sdo_init); - -static void __exit sdo_exit(void) -{ - platform_driver_unregister(&sdo_driver); -} -module_exit(sdo_exit); +module_platform_driver(sdo_driver); diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 5cfdbc78b918..0ef5484696b6 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -57,7 +57,7 @@ MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " "Hans Verkuil, Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 0f9fb99adeb4..065d0f6be4a0 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -5691,6 +5691,27 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, }, }, + [SAA7134_BOARD_SENSORAY811_911] = { + .name = "Sensoray 811/911", + .audio_clock = 0x00200000, + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + }, { + .name = name_comp3, + .vmux = 2, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + }, }; @@ -6914,6 +6935,18 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0xd136, .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x6000, + .subdevice = 0x0811, + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x6000, + .subdevice = 0x0911, + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index ca65cda3e101..5fbb4e49495c 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1263,7 +1263,6 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_tvaudio_setmute(dev); saa7134_tvaudio_setvolume(dev, dev->ctl_volume); saa7134_tvaudio_init(dev); - saa7134_tvaudio_do_scan(dev); saa7134_enable_i2s(dev); saa7134_hw_enable2(dev); diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 1e4ef1669887..089fa0fb5c94 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -183,9 +183,9 @@ static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe) return 0; } -static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) +static int mt352_pinnacle_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u8 off[] = { 0x00, 0xf1}; u8 on[] = { 0x00, 0x71}; struct i2c_msg msg = {.addr=0x43, .flags=0, .buf=off, .len = sizeof(off)}; @@ -196,7 +196,7 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe, /* set frequency (mt2050) */ f.tuner = 0; f.type = V4L2_TUNER_DIGITAL_TV; - f.frequency = params->frequency / 1000 * 16 / 1000; + f.frequency = c->frequency / 1000 * 16 / 1000; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(&dev->i2c_adap, &msg, 1); @@ -287,8 +287,9 @@ static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, * these tuners are tu1216, td1316(a) */ -static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tda6651_pll_set(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct saa7134_dev *dev = fe->dvb->priv; struct tda1004x_state *state = fe->demodulator_priv; u8 addr = state->config->tuner_address; @@ -299,7 +300,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ u8 band, cp, filter; /* determine charge pump */ - tuner_frequency = params->frequency + 36166000; + tuner_frequency = c->frequency + 36166000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) @@ -324,28 +325,28 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ return -EINVAL; /* determine band */ - if (params->frequency < 49000000) + if (c->frequency < 49000000) return -EINVAL; - else if (params->frequency < 161000000) + else if (c->frequency < 161000000) band = 1; - else if (params->frequency < 444000000) + else if (c->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) + else if (c->frequency < 861000000) band = 4; else return -EINVAL; /* setup PLL filter */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: filter = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: filter = 0; break; - case BANDWIDTH_8_MHZ: + case 8000000: filter = 1; break; @@ -356,7 +357,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ /* calculate divisor * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) */ - tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; + tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000; /* setup tuner buffer */ tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; @@ -436,9 +437,9 @@ static int philips_td1316_tuner_init(struct dvb_frontend *fe) return 0; } -static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_td1316_tuner_set_params(struct dvb_frontend *fe) { - return philips_tda6651_pll_set(fe, params); + return philips_tda6651_pll_set(fe); } static int philips_td1316_tuner_sleep(struct dvb_frontend *fe) diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index d4ee24bf6928..22ecd7297d2d 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -235,22 +235,25 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { - unsigned char buf[5], cod4, code3, code4; + unsigned char buf[5]; /* poll IR chip */ if (5 != i2c_master_recv(ir->c, buf, 5)) return -EIO; - cod4 = buf[4]; - code4 = (cod4 >> 2); - code3 = buf[3]; - if (code3 == 0) - /* no key pressed */ + /* Check if some key were pressed */ + if (!(buf[0] & 0x80)) return 0; - /* return key */ - *ir_key = code4; - *ir_raw = code4; + /* + * buf[3] & 0x80 is always high. + * buf[3] & 0x40 is a parity bit. A repeat event is marked + * by preserving it into two separate readings + * buf[4] bits 0 and 1, and buf[1] and buf[2] are always + * zero. + */ + *ir_key = 0x1fff & ((buf[3] << 8) | (buf[4] >> 2)); + *ir_raw = *ir_key; return 1; } @@ -752,7 +755,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) polling = 50; /* ms */ break; case SAA7134_BOARD_VIDEOMATE_M1F: - ir_codes = RC_MAP_VIDEOMATE_M1F; + ir_codes = RC_MAP_VIDEOMATE_K100; mask_keycode = 0x0ff00; mask_keyup = 0x040000; break; diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 57e646bb48b3..b7a99bee2f98 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -332,6 +332,13 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) { __s32 left,right,value; + if (!(dev->tvnorm->id & scan->std)) { + value = 0; + dprintk("skipping %d.%03d MHz [%4s]\n", + scan->carr / 1000, scan->carr % 1000, scan->name); + return 0; + } + if (audio_debug > 1) { int i; dprintk("debug %d:",scan->carr); @@ -348,30 +355,25 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) } printk("\n"); } - if (dev->tvnorm->id & scan->std) { - tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); - saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) - return -1; - left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - - tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90); - saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) - return -1; - right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - - left >>= 16; - right >>= 16; - value = left > right ? left - right : right - left; - dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", - scan->carr / 1000, scan->carr % 1000, - scan->name, value, left, right); - } else { - value = 0; - dprintk("skipping %d.%03d MHz [%4s]\n", - scan->carr / 1000, scan->carr % 1000, scan->name); - } + + tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); + saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) + return -1; + left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + + tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90); + saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) + return -1; + right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + + left >>= 16; + right >>= 16; + value = left > right ? left - right : right - left; + dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", + scan->carr / 1000, scan->carr % 1000, + scan->name, value, left, right); return value; } @@ -546,6 +548,7 @@ static int tvaudio_thread(void *data) dev->tvnorm->name, carrier/1000, carrier%1000, max1, max2); dev->last_carrier = carrier; + dev->automute = 0; } else if (0 != dev->last_carrier) { /* no carrier -- try last detected one as fallback */ @@ -553,6 +556,7 @@ static int tvaudio_thread(void *data) dprintk("audio carrier scan failed, " "using %d.%03d MHz [last detected]\n", carrier/1000, carrier%1000); + dev->automute = 1; } else { /* no carrier + no fallback -- use default */ @@ -560,9 +564,9 @@ static int tvaudio_thread(void *data) dprintk("audio carrier scan failed, " "using %d.%03d MHz [default]\n", carrier/1000, carrier%1000); + dev->automute = 1; } tvaudio_setcarrier(dev,carrier,carrier); - dev->automute = 0; saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00); saa7134_tvaudio_setmute(dev); /* find the exact tv audio norm */ @@ -601,7 +605,7 @@ static int tvaudio_thread(void *data) if (kthread_should_stop()) break; if (UNSET == dev->thread.mode) { - rx = tvaudio_getstereo(dev,&tvaudio[i]); + rx = tvaudio_getstereo(dev, &tvaudio[audio]); mode = saa7134_tvaudio_rx2mode(rx); } else { mode = dev->thread.mode; @@ -1020,6 +1024,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) } dev->thread.thread = NULL; + dev->thread.scan1 = dev->thread.scan2 = 0; if (my_thread) { saa7134_tvaudio_init(dev); /* start tvaudio thread */ @@ -1029,13 +1034,19 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) dev->name); /* XXX: missing error handling here */ } - saa7134_tvaudio_do_scan(dev); } saa7134_enable_i2s(dev); return 0; } +int saa7134_tvaudio_close(struct saa7134_dev *dev) +{ + dev->automute = 1; + /* anything else to undo? */ + return 0; +} + int saa7134_tvaudio_fini(struct saa7134_dev *dev) { /* shutdown tvaudio thread */ diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9cf7914f6f90..417034eb6ad2 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1462,6 +1462,8 @@ static int video_release(struct file *file) struct saa6588_command cmd; unsigned long flags; + saa7134_tvaudio_close(dev); + /* turn off overlay */ if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 9b550687213a..42fba4f93c72 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -330,6 +330,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185 #define SAA7134_BOARD_BEHOLD_501 186 #define SAA7134_BOARD_BEHOLD_503FM 187 +#define SAA7134_BOARD_SENSORAY811_911 188 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 @@ -817,6 +818,7 @@ void saa7134_tvaudio_init(struct saa7134_dev *dev); int saa7134_tvaudio_init2(struct saa7134_dev *dev); int saa7134_tvaudio_fini(struct saa7134_dev *dev); int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); +int saa7134_tvaudio_close(struct saa7134_dev *dev); int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value); diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c index 466e1b02f91f..a7f58a998752 100644 --- a/drivers/media/video/saa7164/saa7164-bus.c +++ b/drivers/media/video/saa7164/saa7164-bus.c @@ -149,7 +149,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, saa7164_bus_verify(dev); msg->size = cpu_to_le16(msg->size); - msg->command = cpu_to_le16(msg->command); + msg->command = cpu_to_le32(msg->command); msg->controlselector = cpu_to_le16(msg->controlselector); if (msg->size > dev->bus.m_wMaxReqSize) { @@ -464,7 +464,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, peekout: msg->size = le16_to_cpu(msg->size); - msg->command = le16_to_cpu(msg->command); + msg->command = le32_to_cpu(msg->command); msg->controlselector = le16_to_cpu(msg->controlselector); ret = SAA_OK; out: diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c index 971591d6450f..5b72da5ce418 100644 --- a/drivers/media/video/saa7164/saa7164-cards.c +++ b/drivers/media/video/saa7164/saa7164-cards.c @@ -269,8 +269,6 @@ struct saa7164_board saa7164_boards[] = { .portb = SAA7164_MPEG_DVB, .portc = SAA7164_MPEG_ENCODER, .portd = SAA7164_MPEG_ENCODER, - .portc = SAA7164_MPEG_ENCODER, - .portd = SAA7164_MPEG_ENCODER, .porte = SAA7164_MPEG_VBI, .portf = SAA7164_MPEG_VBI, .chiprev = SAA7164_CHIP_REV3, @@ -333,8 +331,6 @@ struct saa7164_board saa7164_boards[] = { .portd = SAA7164_MPEG_ENCODER, .porte = SAA7164_MPEG_VBI, .portf = SAA7164_MPEG_VBI, - .porte = SAA7164_MPEG_VBI, - .portf = SAA7164_MPEG_VBI, .chiprev = SAA7164_CHIP_REV3, .unit = {{ .id = 0x28, diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index c51decfcae19..f854d85a387c 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -786,8 +786,7 @@ static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, V4L2_MBUS_DATA_ACTIVE_HIGH) /* Capture is not running, no interrupts, no locking needed */ -static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) +static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; @@ -925,11 +924,6 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, ceu_write(pcdev, CDOCR, value); ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ - dev_dbg(icd->parent, "S_FMT successful for %c%c%c%c %ux%u\n", - pixfmt & 0xff, (pixfmt >> 8) & 0xff, - (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff, - icd->user_width, icd->user_height); - capture_restore(pcdev, capsr); /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ @@ -1966,8 +1960,7 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, if (!ret) { icd->user_width = out_width & ~3; icd->user_height = out_height & ~3; - ret = sh_mobile_ceu_set_bus_param(icd, - icd->current_fmt->host_fmt->fourcc); + ret = sh_mobile_ceu_set_bus_param(icd); } } diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 8a652b53ff7e..05286500b4d4 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -390,18 +390,7 @@ static struct platform_driver __refdata sh_csi2_pdrv = { }, }; -static int __init sh_csi2_init(void) -{ - return platform_driver_register(&sh_csi2_pdrv); -} - -static void __exit sh_csi2_exit(void) -{ - platform_driver_unregister(&sh_csi2_pdrv); -} - -module_init(sh_csi2_init); -module_exit(sh_csi2_exit); +module_platform_driver(sh_csi2_pdrv); MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver"); MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 7025be129286..c2882fa5be85 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -75,8 +75,8 @@ MODULE_PARM_DESC(video_nr, "\none and for every other camera." "\n"); -static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = - SN9C102_FORCE_MUNMAP}; +static bool force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = + SN9C102_FORCE_MUNMAP}; module_param_array(force_munmap, bool, NULL, 0444); MODULE_PARM_DESC(force_munmap, " <0|1[,...]>" diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 62e4312515cb..b82710745ba8 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -487,7 +487,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, icd->user_width, icd->user_height); /* set physical bus parameters */ - return ici->ops->set_bus_param(icd, pix->pixelformat); + return ici->ops->set_bus_param(icd); } static int soc_camera_open(struct file *file) @@ -600,9 +600,9 @@ static int soc_camera_close(struct file *file) pm_runtime_suspend(&icd->vdev->dev); pm_runtime_disable(&icd->vdev->dev); - ici->ops->remove(icd); if (ici->ops->init_videobuf2) vb2_queue_release(&icd->vb2_vidq); + ici->ops->remove(icd); soc_camera_power_off(icd, icl); } diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 4402a8a74f7a..f59ccade07c8 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -189,18 +189,7 @@ static struct platform_driver soc_camera_platform_driver = { .remove = soc_camera_platform_remove, }; -static int __init soc_camera_platform_module_init(void) -{ - return platform_driver_register(&soc_camera_platform_driver); -} - -static void __exit soc_camera_platform_module_exit(void) -{ - platform_driver_unregister(&soc_camera_platform_driver); -} - -module_init(soc_camera_platform_module_init); -module_exit(soc_camera_platform_module_exit); +module_platform_driver(soc_camera_platform_driver); MODULE_DESCRIPTION("SoC Camera Platform driver"); MODULE_AUTHOR("Magnus Damm"); diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index b7fb5a5cad7e..d427f8436c70 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -38,11 +38,11 @@ #include "stk-webcam.h" -static int hflip = 1; +static bool hflip = 1; module_param(hflip, bool, 0444); MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1"); -static int vflip = 1; +static bool vflip = 1; module_param(vflip, bool, 0444); MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1"); @@ -377,8 +377,8 @@ static int stk_prepare_iso(struct stk_camera *dev) if (dev->isobufs) STK_ERROR("isobufs already allocated. Bad\n"); else - dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs), - GFP_KERNEL); + dev->isobufs = kcalloc(MAX_ISO_BUFS, sizeof(*dev->isobufs), + GFP_KERNEL); if (dev->isobufs == NULL) { STK_ERROR("Unable to allocate iso buffers\n"); return -ENOMEM; diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c index a0895bf07487..4ed1c7c28ae7 100644 --- a/drivers/media/video/timblogiw.c +++ b/drivers/media/video/timblogiw.c @@ -565,7 +565,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) spin_unlock_irq(&fh->queue_lock); desc = fh->chan->device->device_prep_slave_sg(fh->chan, - buf->sg, sg_elems, DMA_FROM_DEVICE, + buf->sg, sg_elems, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); if (!desc) { spin_lock_irq(&fh->queue_lock); @@ -872,20 +872,7 @@ static struct platform_driver timblogiw_platform_driver = { .remove = __devexit_p(timblogiw_remove), }; -/* Module functions */ - -static int __init timblogiw_init(void) -{ - return platform_driver_register(&timblogiw_platform_driver); -} - -static void __exit timblogiw_exit(void) -{ - platform_driver_unregister(&timblogiw_platform_driver); -} - -module_init(timblogiw_init); -module_exit(timblogiw_exit); +module_platform_driver(timblogiw_platform_driver); MODULE_DESCRIPTION(TIMBLOGIWIN_NAME); MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>"); diff --git a/drivers/media/video/tlg2300/pd-common.h b/drivers/media/video/tlg2300/pd-common.h index 56564e6aaac2..5dd73b7857d1 100644 --- a/drivers/media/video/tlg2300/pd-common.h +++ b/drivers/media/video/tlg2300/pd-common.h @@ -140,7 +140,7 @@ struct pd_dvb_adapter { u8 reserved[3]; /* data for power resume*/ - struct dvb_frontend_parameters fe_param; + struct dtv_frontend_properties fe_param; /* for channel scanning */ int prev_freq; diff --git a/drivers/media/video/tlg2300/pd-dvb.c b/drivers/media/video/tlg2300/pd-dvb.c index d0da11ae19df..30fcb117e898 100644 --- a/drivers/media/video/tlg2300/pd-dvb.c +++ b/drivers/media/video/tlg2300/pd-dvb.c @@ -12,9 +12,9 @@ static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb); static int dvb_bandwidth[][2] = { - { TLG_BW_8, BANDWIDTH_8_MHZ }, - { TLG_BW_7, BANDWIDTH_7_MHZ }, - { TLG_BW_6, BANDWIDTH_6_MHZ } + { TLG_BW_8, 8000000 }, + { TLG_BW_7, 7000000 }, + { TLG_BW_6, 6000000 } }; static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth); @@ -146,9 +146,9 @@ static int fw_delay_overflow(struct pd_dvb_adapter *adapter) return msec > 800 ? true : false; } -static int poseidon_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int poseidon_set_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; s32 ret = 0, cmd_status = 0; s32 i, bandwidth = -1; struct poseidon *pd = fe->demodulator_priv; @@ -159,7 +159,7 @@ static int poseidon_set_fe(struct dvb_frontend *fe, mutex_lock(&pd->lock); for (i = 0; i < dvb_bandwidth_length; i++) - if (fep->u.ofdm.bandwidth == dvb_bandwidth[i][1]) + if (fep->bandwidth_hz == dvb_bandwidth[i][1]) bandwidth = dvb_bandwidth[i][0]; if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) { @@ -210,7 +210,7 @@ static int pm_dvb_resume(struct poseidon *pd) poseidon_check_mode_dvbt(pd); msleep(300); - poseidon_set_fe(&pd_dvb->dvb_fe, &pd_dvb->fe_param); + poseidon_set_fe(&pd_dvb->dvb_fe); dvb_start_streaming(pd_dvb); return 0; @@ -227,13 +227,13 @@ static s32 poseidon_fe_init(struct dvb_frontend *fe) pd->pm_resume = pm_dvb_resume; #endif memset(&pd_dvb->fe_param, 0, - sizeof(struct dvb_frontend_parameters)); + sizeof(struct dtv_frontend_properties)); return 0; } -static int poseidon_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int poseidon_get_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct poseidon *pd = fe->demodulator_priv; struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; @@ -332,9 +332,9 @@ static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) } static struct dvb_frontend_ops poseidon_frontend_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Poseidon DVB-T", - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 62500,/* FIXME */ diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c index 129f135d5a5f..c096b3f74200 100644 --- a/drivers/media/video/tlg2300/pd-main.c +++ b/drivers/media/video/tlg2300/pd-main.c @@ -374,7 +374,7 @@ static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev) } #endif -static bool check_firmware(struct usb_device *udev, int *down_firmware) +static int check_firmware(struct usb_device *udev, int *down_firmware) { void *buf; int ret; @@ -398,7 +398,7 @@ static bool check_firmware(struct usb_device *udev, int *down_firmware) *down_firmware = 1; return firmware_download(udev); } - return ret; + return 0; } static int poseidon_probe(struct usb_interface *interface, diff --git a/drivers/media/video/tm6000/Kconfig b/drivers/media/video/tm6000/Kconfig index 114eec8a630a..a43b77abd931 100644 --- a/drivers/media/video/tm6000/Kconfig +++ b/drivers/media/video/tm6000/Kconfig @@ -1,6 +1,6 @@ config VIDEO_TM6000 tristate "TV Master TM5600/6000/6010 driver" - depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL + depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB select VIDEO_TUNER select MEDIA_TUNER_XC2028 select MEDIA_TUNER_XC5000 @@ -16,7 +16,7 @@ config VIDEO_TM6000 config VIDEO_TM6000_ALSA tristate "TV Master TM5600/6000/6010 audio support" - depends on VIDEO_TM6000 && SND && EXPERIMENTAL + depends on VIDEO_TM6000 && SND select SND_PCM ---help--- This is a video4linux driver for direct (DMA) audio for @@ -27,7 +27,7 @@ config VIDEO_TM6000_ALSA config VIDEO_TM6000_DVB tristate "DVB Support for tm6000 based TV cards" - depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL + depends on VIDEO_TM6000 && DVB_CORE && USB select DVB_ZL10353 ---help--- This adds support for DVB cards based on the tm5600/tm6000 chip. diff --git a/drivers/media/video/tm6000/tm6000-alsa.c b/drivers/media/video/tm6000/tm6000-alsa.c index 7d675c72fd47..bd07ec707956 100644 --- a/drivers/media/video/tm6000/tm6000-alsa.c +++ b/drivers/media/video/tm6000/tm6000-alsa.c @@ -42,7 +42,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; +static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled."); @@ -146,20 +146,21 @@ static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size) #define DEFAULT_FIFO_SIZE 4096 static struct snd_pcm_hardware snd_tm6000_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | + .info = SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, .rate_min = 48000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .period_bytes_min = 64, .period_bytes_max = 12544, - .periods_min = 1, + .periods_min = 2, .periods_max = 98, .buffer_bytes_max = 62720 * 8, }; @@ -181,6 +182,7 @@ static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream) chip->substream = substream; runtime->hw = snd_tm6000_digital_hw; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); return 0; _error: @@ -347,9 +349,13 @@ static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd) int err = 0; switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ + case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: atomic_set(&core->stream_started, 1); break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ + case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: atomic_set(&core->stream_started, 0); break; @@ -371,6 +377,14 @@ static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream) return chip->buf_pos; } +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + /* * operators */ @@ -383,6 +397,7 @@ static struct snd_pcm_ops snd_tm6000_pcm_ops = { .prepare = snd_tm6000_prepare, .trigger = snd_tm6000_card_trigger, .pointer = snd_tm6000_pointer, + .page = snd_pcm_get_vmalloc_page, }; /* diff --git a/drivers/media/video/tm6000/tm6000-cards.c b/drivers/media/video/tm6000/tm6000-cards.c index ff939bc0e0b9..034659b13174 100644 --- a/drivers/media/video/tm6000/tm6000-cards.c +++ b/drivers/media/video/tm6000/tm6000-cards.c @@ -351,6 +351,7 @@ static struct tm6000_board tm6000_boards[] = { .tuner_addr = 0xc2 >> 1, .demod_addr = 0x1e >> 1, .type = TM6010, + .ir_codes = RC_MAP_HAUPPAUGE, .caps = { .has_tuner = 1, .has_dvb = 1, @@ -639,6 +640,7 @@ static struct usb_device_id tm6000_id_table[] = { { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, { } }; +MODULE_DEVICE_TABLE(usb, tm6000_id_table); /* Control power led for show some activity */ void tm6000_flash_led(struct tm6000_core *dev, u8 state) @@ -941,6 +943,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev) case TM6010_BOARD_HAUPPAUGE_900H: case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: case TM6010_BOARD_TWINHAN_TU501: + ctl.max_len = 80; ctl.fname = "xc3028L-v36.fw"; break; default: @@ -1002,6 +1005,7 @@ static int fill_board_specific_data(struct tm6000_core *dev) /* setup per-model quirks */ switch (dev->model) { case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_HAUPPAUGE_900H: dev->quirks |= TM6000_QUIRK_NO_USB_DELAY; break; @@ -1050,6 +1054,33 @@ static void use_alternative_detection_method(struct tm6000_core *dev) tm6000_boards[model].name, model); } +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + struct tm6000_core *dev = container_of(work, struct tm6000_core, + request_module_wk); + + request_module("tm6000-alsa"); + + if (dev->caps.has_dvb) + request_module("tm6000-dvb"); +} + +static void request_modules(struct tm6000_core *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} + +static void flush_request_modules(struct tm6000_core *dev) +{ + flush_work_sync(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#define flush_request_modules(dev) +#endif /* CONFIG_MODULES */ + static int tm6000_init_dev(struct tm6000_core *dev) { struct v4l2_frequency f; @@ -1112,6 +1143,8 @@ static int tm6000_init_dev(struct tm6000_core *dev) tm6000_ir_init(dev); + request_modules(dev); + mutex_unlock(&dev->lock); return 0; @@ -1324,6 +1357,8 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name); + flush_request_modules(dev); + tm6000_ir_fini(dev); if (dev->gpio.power_led) { diff --git a/drivers/media/video/tm6000/tm6000-core.c b/drivers/media/video/tm6000/tm6000-core.c index 9783616a0da2..22cc0116deb6 100644 --- a/drivers/media/video/tm6000/tm6000-core.c +++ b/drivers/media/video/tm6000/tm6000-core.c @@ -38,6 +38,7 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, int ret, i; unsigned int pipe; u8 *data = NULL; + int delay = 5000; mutex_lock(&dev->usb_lock); @@ -88,7 +89,20 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, } kfree(data); - msleep(5); + + if (dev->quirks & TM6000_QUIRK_NO_USB_DELAY) + delay = 0; + + if (req == REQ_16_SET_GET_I2C_WR1_RDN && !(req_type & USB_DIR_IN)) { + unsigned int tsleep; + /* Calculate delay time, 14000us for 64 bytes */ + tsleep = (len * 200) + 200; + if (tsleep < delay) + tsleep = delay; + usleep_range(tsleep, tsleep + 1000); + } + else if (delay) + usleep_range(delay, delay + 1000); mutex_unlock(&dev->usb_lock); return ret; @@ -125,14 +139,14 @@ int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, u8 new_index; rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 1); + value, 0, buf, 1); if (rc < 0) return rc; new_index = (buf[0] & ~mask) | (index & mask); - if (new_index == index) + if (new_index == buf[0]) return 0; return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, @@ -536,16 +550,16 @@ static struct reg_init tm6010_init_tab[] = { { TM6010_REQ05_R18_IMASK7, 0x00 }, - { TM6010_REQ07_RD8_IR_LEADER1, 0xaa }, - { TM6010_REQ07_RD8_IR_LEADER0, 0x30 }, - { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 }, - { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 }, + { TM6010_REQ07_RDC_IR_LEADER1, 0xaa }, + { TM6010_REQ07_RDD_IR_LEADER0, 0x30 }, + { TM6010_REQ07_RDE_IR_PULSE_CNT1, 0x20 }, + { TM6010_REQ07_RDF_IR_PULSE_CNT0, 0xd0 }, { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 }, - { TM6010_REQ07_RD8_IR, 0x2f }, + { TM6010_REQ07_RD8_IR, 0x0f }, /* set remote wakeup key:any key wakeup */ { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe }, - { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff }, + { TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff }, }; int tm6000_init(struct tm6000_core *dev) @@ -599,55 +613,6 @@ int tm6000_init(struct tm6000_core *dev) return rc; } -int tm6000_reset(struct tm6000_core *dev) -{ - int pipe; - int err; - - msleep(500); - - err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0); - if (err < 0) { - tm6000_err("failed to select interface %d, alt. setting 0\n", - dev->isoc_in.bInterfaceNumber); - return err; - } - - err = usb_reset_configuration(dev->udev); - if (err < 0) { - tm6000_err("failed to reset configuration\n"); - return err; - } - - if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0) - msleep(5); - - /* - * Not all devices have int_in defined - */ - if (!dev->int_in.endp) - return 0; - - err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2); - if (err < 0) { - tm6000_err("failed to select interface %d, alt. setting 2\n", - dev->isoc_in.bInterfaceNumber); - return err; - } - - msleep(5); - - pipe = usb_rcvintpipe(dev->udev, - dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - - err = usb_clear_halt(dev->udev, pipe); - if (err < 0) { - tm6000_err("usb_clear_halt failed: %d\n", err); - return err; - } - - return 0; -} int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) { @@ -696,11 +661,13 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev) if (dev->dev_type == TM6010) { /* Audio crossbar setting, default SIF1 */ u8 areg_f0; + u8 areg_07 = 0x10; switch (dev->rinput.amux) { case TM6000_AMUX_SIF1: case TM6000_AMUX_SIF2: areg_f0 = 0x03; + areg_07 = 0x30; break; case TM6000_AMUX_ADC1: areg_f0 = 0x00; @@ -720,6 +687,9 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev) /* Set audio input crossbar */ tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, areg_f0, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + areg_07, 0xf0); } else { u8 areg_eb; /* Audio setting, default LINE1 */ diff --git a/drivers/media/video/tm6000/tm6000-dvb.c b/drivers/media/video/tm6000/tm6000-dvb.c index 5e6c129a4beb..e1f3f66e1e63 100644 --- a/drivers/media/video/tm6000/tm6000-dvb.c +++ b/drivers/media/video/tm6000/tm6000-dvb.c @@ -89,9 +89,19 @@ static void tm6000_urb_received(struct urb *urb) int ret; struct tm6000_core *dev = urb->context; - if (urb->status != 0) + switch (urb->status) { + case 0: + case -ETIMEDOUT: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + return; + default: print_err_status(dev, 0, urb->status); - else if (urb->actual_length > 0) + } + + if (urb->actual_length > 0) dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer, urb->actual_length); @@ -151,7 +161,7 @@ static int tm6000_start_stream(struct tm6000_core *dev) printk(KERN_ERR "tm6000: pipe resetted\n"); /* mutex_lock(&tm6000_driver.open_close_mutex); */ - ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL); + ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC); /* mutex_unlock(&tm6000_driver.open_close_mutex); */ if (ret) { @@ -396,6 +406,11 @@ static int dvb_init(struct tm6000_core *dev) if (!dev->caps.has_dvb) return 0; + if (dev->udev->speed == USB_SPEED_FULL) { + printk(KERN_INFO "This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)\n"); + return 0; + } + dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL); if (!dvb) { printk(KERN_INFO "Cannot allocate memory\n"); diff --git a/drivers/media/video/tm6000/tm6000-i2c.c b/drivers/media/video/tm6000/tm6000-i2c.c index 0290bbf00c3e..c7e23e3dd75e 100644 --- a/drivers/media/video/tm6000/tm6000-i2c.c +++ b/drivers/media/video/tm6000/tm6000-i2c.c @@ -46,11 +46,10 @@ static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, __u8 reg, char *buf, int len) { int rc; - unsigned int tsleep; unsigned int i2c_packet_limit = 16; if (dev->dev_type == TM6010) - i2c_packet_limit = 64; + i2c_packet_limit = 80; if (!buf) return -1; @@ -71,10 +70,6 @@ static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, return rc; } - /* Calculate delay time, 14000us for 64 bytes */ - tsleep = ((len * 200) + 200 + 1000) / 1000; - msleep(tsleep); - /* release mutex */ return rc; } @@ -145,7 +140,6 @@ static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr, return rc; } - msleep(1400 / 1000); rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ, reg, 0, buf, len); diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c index 405d12729d05..7844607dd45a 100644 --- a/drivers/media/video/tm6000/tm6000-input.c +++ b/drivers/media/video/tm6000/tm6000-input.c @@ -31,22 +31,25 @@ static unsigned int ir_debug; module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debug message [IR]"); +MODULE_PARM_DESC(ir_debug, "debug message level"); static unsigned int enable_ir = 1; module_param(enable_ir, int, 0644); MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)"); -/* number of 50ms for ON-OFF-ON power led */ -/* show IR activity */ -#define PWLED_OFF 2 +static unsigned int ir_clock_mhz = 12; +module_param(ir_clock_mhz, int, 0644); +MODULE_PARM_DESC(enable_ir, "ir clock, in MHz"); + +#define URB_SUBMIT_DELAY 100 /* ms - Delay to submit an URB request on retrial and init */ +#define URB_INT_LED_DELAY 100 /* ms - Delay to turn led on again on int mode */ #undef dprintk -#define dprintk(fmt, arg...) \ - if (ir_debug) { \ +#define dprintk(level, fmt, arg...) do {\ + if (ir_debug >= level) \ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ - } + } while (0) struct tm6000_ir_poll_result { u16 rc_data; @@ -62,20 +65,15 @@ struct tm6000_IR { int polling; struct delayed_work work; u8 wait:1; - u8 key:1; - u8 pwled:1; - u8 pwledcnt; + u8 pwled:2; + u8 submit_urb:1; u16 key_addr; struct urb *int_urb; - u8 *urb_data; - - int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *); /* IR device properties */ u64 rc_type; }; - void tm6000_ir_wait(struct tm6000_core *dev, u8 state) { struct tm6000_IR *ir = dev->ir; @@ -83,62 +81,84 @@ void tm6000_ir_wait(struct tm6000_core *dev, u8 state) if (!dev->ir) return; + dprintk(2, "%s: %i\n",__func__, ir->wait); + if (state) ir->wait = 1; else ir->wait = 0; } - static int tm6000_ir_config(struct tm6000_IR *ir) { struct tm6000_core *dev = ir->dev; - u8 buf[10]; - int rc; + u32 pulse = 0, leader = 0; + + dprintk(2, "%s\n",__func__); + + /* + * The IR decoder supports RC-5 or NEC, with a configurable timing. + * The timing configuration there is not that accurate, as it uses + * approximate values. The NEC spec mentions a 562.5 unit period, + * and RC-5 uses a 888.8 period. + * Currently, driver assumes a clock provided by a 12 MHz XTAL, but + * a modprobe parameter can adjust it. + * Adjustments are required for other timings. + * It seems that the 900ms timing for NEC is used to detect a RC-5 + * IR, in order to discard such decoding + */ switch (ir->rc_type) { case RC_TYPE_NEC: - /* Setup IR decoder for NEC standard 12MHz system clock */ - /* IR_LEADER_CNT = 0.9ms */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30); - /* IR_PULSE_CNT = 0.7ms */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0); - /* Remote WAKEUP = enable */ - tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); - /* IR_WKUP_SEL = Low byte in decoded IR data */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff); - /* IR_WKU_ADD code */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff); - tm6000_flash_led(dev, 0); - msleep(100); - tm6000_flash_led(dev, 1); + leader = 900; /* ms */ + pulse = 700; /* ms - the actual value would be 562 */ break; default: - /* hack */ - buf[0] = 0xff; - buf[1] = 0xff; - buf[2] = 0xf2; - buf[3] = 0x2b; - buf[4] = 0x20; - buf[5] = 0x35; - buf[6] = 0x60; - buf[7] = 0x04; - buf[8] = 0xc0; - buf[9] = 0x08; - - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a); - msleep(100); - - if (rc < 0) { - printk(KERN_INFO "IR configuration failed"); - return rc; - } + case RC_TYPE_RC5: + leader = 900; /* ms - from the NEC decoding */ + pulse = 1780; /* ms - The actual value would be 1776 */ break; } + pulse = ir_clock_mhz * pulse; + leader = ir_clock_mhz * leader; + if (ir->rc_type == RC_TYPE_NEC) + leader = leader | 0x8000; + + dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n", + __func__, + (ir->rc_type == RC_TYPE_NEC) ? "NEC" : "RC-5", + ir_clock_mhz, leader, pulse); + + /* Remote WAKEUP = enable, normal mode, from IR decoder output */ + tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); + + /* Enable IR reception on non-busrt mode */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR, 0x2f); + + /* IR_WKUP_SEL = Low byte in decoded IR data */ + tm6000_set_reg(dev, TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff); + /* IR_WKU_ADD code */ + tm6000_set_reg(dev, TM6010_REQ07_RDB_IR_WAKEUP_ADD, 0xff); + + tm6000_set_reg(dev, TM6010_REQ07_RDC_IR_LEADER1, leader >> 8); + tm6000_set_reg(dev, TM6010_REQ07_RDD_IR_LEADER0, leader); + + tm6000_set_reg(dev, TM6010_REQ07_RDE_IR_PULSE_CNT1, pulse >> 8); + tm6000_set_reg(dev, TM6010_REQ07_RDF_IR_PULSE_CNT0, pulse); + + if (!ir->polling) + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); + else + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); + msleep(10); + + /* Shows that IR is working via the LED */ + tm6000_flash_led(dev, 0); + msleep(100); + tm6000_flash_led(dev, 1); + ir->pwled = 1; + return 0; } @@ -146,132 +166,124 @@ static void tm6000_ir_urb_received(struct urb *urb) { struct tm6000_core *dev = urb->context; struct tm6000_IR *ir = dev->ir; + struct tm6000_ir_poll_result poll_result; + char *buf; int rc; - if (urb->status != 0) - printk(KERN_INFO "not ready\n"); - else if (urb->actual_length > 0) { - memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length); + dprintk(2, "%s\n",__func__); + if (urb->status < 0 || urb->actual_length <= 0) { + printk(KERN_INFO "tm6000: IR URB failure: status: %i, length %i\n", + urb->status, urb->actual_length); + ir->submit_urb = 1; + schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); + return; + } + buf = urb->transfer_buffer; - dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0], - ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]); + if (ir_debug) + print_hex_dump(KERN_DEBUG, "tm6000: IR data: ", + DUMP_PREFIX_OFFSET,16, 1, + buf, urb->actual_length, false); - ir->key = 1; - } + poll_result.rc_data = buf[0]; + if (urb->actual_length > 1) + poll_result.rc_data |= buf[1] << 8; + + dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data); + rc_keydown(ir->rc, poll_result.rc_data, 0); rc = usb_submit_urb(urb, GFP_ATOMIC); + /* + * Flash the led. We can't do it here, as it is running on IRQ context. + * So, use the scheduler to do it, in a few ms. + */ + ir->pwled = 2; + schedule_delayed_work(&ir->work, msecs_to_jiffies(10)); } -static int default_polling_getkey(struct tm6000_IR *ir, - struct tm6000_ir_poll_result *poll_result) +static void tm6000_ir_handle_key(struct work_struct *work) { + struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); struct tm6000_core *dev = ir->dev; + struct tm6000_ir_poll_result poll_result; int rc; u8 buf[2]; - if (ir->wait && !&dev->int_in) - return 0; - - if (&dev->int_in) { - switch (ir->rc_type) { - case RC_TYPE_RC5: - poll_result->rc_data = ir->urb_data[0]; - break; - case RC_TYPE_NEC: - if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) { - poll_result->rc_data = ir->urb_data[0] - | ir->urb_data[1] << 8; - } - break; - default: - poll_result->rc_data = ir->urb_data[0] - | ir->urb_data[1] << 8; - break; - } - } else { - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); - msleep(10); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); - msleep(10); - - if (ir->rc_type == RC_TYPE_RC5) { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 1); - - msleep(10); - - dprintk("read data=%02x\n", buf[0]); - if (rc < 0) - return rc; + if (ir->wait) + return; - poll_result->rc_data = buf[0]; - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 2); + dprintk(3, "%s\n",__func__); - msleep(10); + rc = tm6000_read_write_usb(dev, USB_DIR_IN | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + REQ_02_GET_IR_CODE, 0, 0, buf, 2); + if (rc < 0) + return; - dprintk("read data=%04x\n", buf[0] | buf[1] << 8); - if (rc < 0) - return rc; + if (rc > 1) + poll_result.rc_data = buf[0] | buf[1] << 8; + else + poll_result.rc_data = buf[0]; - poll_result->rc_data = buf[0] | buf[1] << 8; + /* Check if something was read */ + if ((poll_result.rc_data & 0xff) == 0xff) { + if (!ir->pwled) { + tm6000_flash_led(dev, 1); + ir->pwled = 1; } - if ((poll_result->rc_data & 0x00ff) != 0xff) - ir->key = 1; + return; } - return 0; + + dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data); + rc_keydown(ir->rc, poll_result.rc_data, 0); + tm6000_flash_led(dev, 0); + ir->pwled = 0; + + /* Re-schedule polling */ + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); } -static void tm6000_ir_handle_key(struct tm6000_IR *ir) +static void tm6000_ir_int_work(struct work_struct *work) { + struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); struct tm6000_core *dev = ir->dev; - int result; - struct tm6000_ir_poll_result poll_result; + int rc; - /* read the registers containing the IR status */ - result = ir->get_key(ir, &poll_result); - if (result < 0) { - printk(KERN_INFO "ir->get_key() failed %d\n", result); - return; - } + dprintk(3, "%s, submit_urb = %d, pwled = %d\n",__func__, ir->submit_urb, + ir->pwled); - dprintk("ir->get_key result data=%04x\n", poll_result.rc_data); + if (ir->submit_urb) { + dprintk(3, "Resubmit urb\n"); + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); - if (ir->pwled) { - if (ir->pwledcnt >= PWLED_OFF) { - ir->pwled = 0; - ir->pwledcnt = 0; - tm6000_flash_led(dev, 1); - } else - ir->pwledcnt += 1; + rc = usb_submit_urb(ir->int_urb, GFP_ATOMIC); + if (rc < 0) { + printk(KERN_ERR "tm6000: Can't submit an IR interrupt. Error %i\n", + rc); + /* Retry in 100 ms */ + schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); + return; + } + ir->submit_urb = 0; } - if (ir->key) { - rc_keydown(ir->rc, poll_result.rc_data, 0); - ir->key = 0; - ir->pwled = 1; - ir->pwledcnt = 0; + /* Led is enabled only if USB submit doesn't fail */ + if (ir->pwled == 2) { tm6000_flash_led(dev, 0); + ir->pwled = 0; + schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_INT_LED_DELAY)); + } else if (!ir->pwled) { + tm6000_flash_led(dev, 1); + ir->pwled = 1; } - return; -} - -static void tm6000_ir_work(struct work_struct *work) -{ - struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); - - tm6000_ir_handle_key(ir); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); } static int tm6000_ir_start(struct rc_dev *rc) { struct tm6000_IR *ir = rc->priv; - INIT_DELAYED_WORK(&ir->work, tm6000_ir_work); + dprintk(2, "%s\n",__func__); + schedule_delayed_work(&ir->work, 0); return 0; @@ -281,6 +293,8 @@ static void tm6000_ir_stop(struct rc_dev *rc) { struct tm6000_IR *ir = rc->priv; + dprintk(2, "%s\n",__func__); + cancel_delayed_work_sync(&ir->work); } @@ -291,10 +305,11 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) if (!ir) return 0; + dprintk(2, "%s\n",__func__); + if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC)) ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff); - ir->get_key = default_polling_getkey; ir->rc_type = rc_type; tm6000_ir_config(ir); @@ -302,17 +317,19 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) return 0; } -int tm6000_ir_int_start(struct tm6000_core *dev) +static int __tm6000_ir_int_start(struct rc_dev *rc) { - struct tm6000_IR *ir = dev->ir; + struct tm6000_IR *ir = rc->priv; + struct tm6000_core *dev = ir->dev; int pipe, size; int err = -ENOMEM; - if (!ir) return -ENODEV; - ir->int_urb = usb_alloc_urb(0, GFP_KERNEL); + dprintk(2, "%s\n",__func__); + + ir->int_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!ir->int_urb) return -ENOMEM; @@ -321,42 +338,59 @@ int tm6000_ir_int_start(struct tm6000_core *dev) & USB_ENDPOINT_NUMBER_MASK); size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - dprintk("IR max size: %d\n", size); + dprintk(1, "IR max size: %d\n", size); - ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); + ir->int_urb->transfer_buffer = kzalloc(size, GFP_ATOMIC); if (ir->int_urb->transfer_buffer == NULL) { usb_free_urb(ir->int_urb); return err; } - dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval); + dprintk(1, "int interval: %d\n", dev->int_in.endp->desc.bInterval); + usb_fill_int_urb(ir->int_urb, dev->udev, pipe, ir->int_urb->transfer_buffer, size, tm6000_ir_urb_received, dev, dev->int_in.endp->desc.bInterval); - err = usb_submit_urb(ir->int_urb, GFP_KERNEL); - if (err) { - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - return err; - } - ir->urb_data = kzalloc(size, GFP_KERNEL); + + ir->submit_urb = 1; + schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); return 0; } -void tm6000_ir_int_stop(struct tm6000_core *dev) +static void __tm6000_ir_int_stop(struct rc_dev *rc) { - struct tm6000_IR *ir = dev->ir; + struct tm6000_IR *ir = rc->priv; - if (!ir) + if (!ir || !ir->int_urb) return; + dprintk(2, "%s\n",__func__); + usb_kill_urb(ir->int_urb); kfree(ir->int_urb->transfer_buffer); usb_free_urb(ir->int_urb); ir->int_urb = NULL; - kfree(ir->urb_data); - ir->urb_data = NULL; +} + +int tm6000_ir_int_start(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + + if (!ir) + return 0; + + return __tm6000_ir_int_start(ir->rc); +} + +void tm6000_ir_int_stop(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + + if (!ir || !ir->rc) + return; + + __tm6000_ir_int_stop(ir->rc); } int tm6000_ir_init(struct tm6000_core *dev) @@ -374,29 +408,36 @@ int tm6000_ir_init(struct tm6000_core *dev) if (!dev->ir_codes) return 0; - ir = kzalloc(sizeof(*ir), GFP_KERNEL); + ir = kzalloc(sizeof(*ir), GFP_ATOMIC); rc = rc_allocate_device(); if (!ir || !rc) goto out; + dprintk(2, "%s\n", __func__); + /* record handles to ourself */ ir->dev = dev; dev->ir = ir; ir->rc = rc; - /* input einrichten */ + /* input setup */ rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; + /* Neded, in order to support NEC remotes with 24 or 32 bits */ + rc->scanmask = 0xffff; rc->priv = ir; rc->change_protocol = tm6000_ir_change_protocol; - rc->open = tm6000_ir_start; - rc->close = tm6000_ir_stop; + if (dev->int_in.endp) { + rc->open = __tm6000_ir_int_start; + rc->close = __tm6000_ir_int_stop; + INIT_DELAYED_WORK(&ir->work, tm6000_ir_int_work); + } else { + rc->open = tm6000_ir_start; + rc->close = tm6000_ir_stop; + ir->polling = 50; + INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key); + } rc->driver_type = RC_DRIVER_SCANCODE; - ir->polling = 50; - ir->pwled = 0; - ir->pwledcnt = 0; - - snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)", dev->name); @@ -415,15 +456,6 @@ int tm6000_ir_init(struct tm6000_core *dev) rc->driver_name = "tm6000"; rc->dev.parent = &dev->udev->dev; - if (&dev->int_in) { - dprintk("IR over int\n"); - - err = tm6000_ir_int_start(dev); - - if (err) - goto out; - } - /* ir register */ err = rc_register_device(rc); if (err) @@ -447,10 +479,19 @@ int tm6000_ir_fini(struct tm6000_core *dev) if (!ir) return 0; + dprintk(2, "%s\n",__func__); + rc_unregister_device(ir->rc); - if (ir->int_urb) - tm6000_ir_int_stop(dev); + if (!ir->polling) + __tm6000_ir_int_stop(ir->rc); + + tm6000_ir_stop(ir->rc); + + /* Turn off the led */ + tm6000_flash_led(dev, 0); + ir->pwled = 0; + kfree(ir); dev->ir = NULL; diff --git a/drivers/media/video/tm6000/tm6000-regs.h b/drivers/media/video/tm6000/tm6000-regs.h index 7f491b6de933..a38c251ed57b 100644 --- a/drivers/media/video/tm6000/tm6000-regs.h +++ b/drivers/media/video/tm6000/tm6000-regs.h @@ -284,19 +284,19 @@ enum { /* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR 0x07, 0xd8 /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_BSIZE 0x07, 0xd9 +#define TM6010_REQ07_RD9_IR_BSIZE 0x07, 0xd9 /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_WAKEUP_SEL 0x07, 0xda +#define TM6010_REQ07_RDA_IR_WAKEUP_SEL 0x07, 0xda /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_WAKEUP_ADD 0x07, 0xdb +#define TM6010_REQ07_RDB_IR_WAKEUP_ADD 0x07, 0xdb /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_LEADER1 0x07, 0xdc +#define TM6010_REQ07_RDC_IR_LEADER1 0x07, 0xdc /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_LEADER0 0x07, 0xdd +#define TM6010_REQ07_RDD_IR_LEADER0 0x07, 0xdd /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_PULSE_CNT1 0x07, 0xde +#define TM6010_REQ07_RDE_IR_PULSE_CNT1 0x07, 0xde /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_PULSE_CNT0 0x07, 0xdf +#define TM6010_REQ07_RDF_IR_PULSE_CNT0 0x07, 0xdf /* ONLY for TM6010 */ #define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0 /* ONLY for TM6010 */ diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/video/tm6000/tm6000-stds.c index 9a4145dc3d87..9dc0831d813f 100644 --- a/drivers/media/video/tm6000/tm6000-stds.c +++ b/drivers/media/video/tm6000/tm6000-stds.c @@ -361,82 +361,51 @@ static int tm6000_set_audio_std(struct tm6000_core *dev) return 0; } - switch (tm6010_a_mode) { + /* + * STD/MN shouldn't be affected by tm6010_a_mode, as there's just one + * audio standard for each V4L2_STD type. + */ + if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_KR) { + areg_05 |= 0x04; + } else if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_JP) { + areg_05 |= 0x43; + } else if (dev->norm & V4L2_STD_MN) { + areg_05 |= 0x22; + } else switch (tm6010_a_mode) { /* auto */ case 0: - switch (dev->norm) { - case V4L2_STD_NTSC_M_KR: + if ((dev->norm & V4L2_STD_SECAM) == V4L2_STD_SECAM_L) areg_05 |= 0x00; - break; - case V4L2_STD_NTSC_M_JP: - areg_05 |= 0x40; - break; - case V4L2_STD_NTSC_M: - case V4L2_STD_PAL_M: - case V4L2_STD_PAL_N: - areg_05 |= 0x20; - break; - case V4L2_STD_PAL_Nc: - areg_05 |= 0x60; - break; - case V4L2_STD_SECAM_L: - areg_05 |= 0x00; - break; - case V4L2_STD_DK: + else /* Other PAL/SECAM standards */ areg_05 |= 0x10; - break; - } break; /* A2 */ case 1: - switch (dev->norm) { - case V4L2_STD_B: - case V4L2_STD_GH: - areg_05 = 0x05; - break; - case V4L2_STD_DK: + if (dev->norm & V4L2_STD_DK) areg_05 = 0x09; - break; - } + else + areg_05 = 0x05; break; /* NICAM */ case 2: - switch (dev->norm) { - case V4L2_STD_B: - case V4L2_STD_GH: - areg_05 = 0x07; - break; - case V4L2_STD_DK: + if (dev->norm & V4L2_STD_DK) { areg_05 = 0x06; - break; - case V4L2_STD_PAL_I: + } else if (dev->norm & V4L2_STD_PAL_I) { areg_05 = 0x08; - break; - case V4L2_STD_SECAM_L: + } else if (dev->norm & V4L2_STD_SECAM_L) { areg_05 = 0x0a; areg_02 = 0x02; - break; + } else { + areg_05 = 0x07; } nicam_flag = 1; break; /* other */ case 3: - switch (dev->norm) { - /* DK3_A2 */ - case V4L2_STD_DK: + if (dev->norm & V4L2_STD_DK) { areg_05 = 0x0b; - break; - /* Korea */ - case V4L2_STD_NTSC_M_KR: - areg_05 = 0x04; - break; - /* EIAJ */ - case V4L2_STD_NTSC_M_JP: - areg_05 = 0x03; - break; - default: + } else { areg_05 = 0x02; - break; } break; } @@ -557,10 +526,16 @@ int tm6000_set_standard(struct tm6000_core *dev) case TM6000_AMUX_ADC1: tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x00, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + 0x10, 0xf0); break; case TM6000_AMUX_ADC2: tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x08, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + 0x10, 0xf0); break; case TM6000_AMUX_SIF1: reg_08_e2 |= 0x02; @@ -570,6 +545,9 @@ int tm6000_set_standard(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3); tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x02, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + 0x30, 0xf0); break; case TM6000_AMUX_SIF2: reg_08_e2 |= 0x02; @@ -579,6 +557,9 @@ int tm6000_set_standard(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7); tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x02, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + 0x30, 0xf0); break; default: break; diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c index 1e5ace0b5d10..bc13db736e24 100644 --- a/drivers/media/video/tm6000/tm6000-video.c +++ b/drivers/media/video/tm6000/tm6000-video.c @@ -1605,16 +1605,25 @@ static int tm6000_release(struct file *file) res_free(dev, fh); if (!dev->users) { - int err; - tm6000_uninit_isoc(dev); + /* Stop interrupt USB pipe */ + tm6000_ir_int_stop(dev); + + usb_reset_configuration(dev->udev); + + if (dev->int_in.endp) + usb_set_interface(dev->udev, + dev->isoc_in.bInterfaceNumber, 2); + else + usb_set_interface(dev->udev, + dev->isoc_in.bInterfaceNumber, 0); + + /* Start interrupt USB pipe */ + tm6000_ir_int_start(dev); + if (!fh->radio) videobuf_mmap_free(&fh->vb_vidq); - - err = tm6000_reset(dev); - if (err < 0) - dev_err(&vdev->dev, "reset failed: %d\n", err); } kfree(fh); diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/video/tm6000/tm6000.h index 2777e514eff2..27ba659cfa85 100644 --- a/drivers/media/video/tm6000/tm6000.h +++ b/drivers/media/video/tm6000/tm6000.h @@ -188,6 +188,9 @@ struct tm6000_core { /* Device Capabilities*/ struct tm6000_capabilities caps; + /* Used to load alsa/dvb */ + struct work_struct request_module_wk; + /* Tuner configuration */ int tuner_type; /* type of the tuner */ int tuner_addr; /* tuner address */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 11cc980b0cd5..4059ea178c2d 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -326,6 +326,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->mode_mask = T_RADIO; break; case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_PHILIPS_FMD1216MEX_MK3: buffer[0] = 0x0b; buffer[1] = 0xdc; buffer[2] = 0x9c; diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 926f03931156..dd26cacd0556 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -52,7 +52,7 @@ #define LOCK_RETRY_DELAY (200) /* Debug functions */ -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 6abaa16ae136..6be9910a6e24 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -703,21 +703,21 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) /* First tests should be against specific std */ if (std == V4L2_STD_ALL) { - fmt = 0; /* Autodetect mode */ + fmt = VIDEO_STD_AUTO_SWITCH_BIT; /* Autodetect mode */ } else if (std & V4L2_STD_NTSC_443) { - fmt = 0xa; + fmt = VIDEO_STD_NTSC_4_43_BIT; } else if (std & V4L2_STD_PAL_M) { - fmt = 0x6; + fmt = VIDEO_STD_PAL_M_BIT; } else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) { - fmt = 0x8; + fmt = VIDEO_STD_PAL_COMBINATION_N_BIT; } else { /* Then, test against generic ones */ if (std & V4L2_STD_NTSC) - fmt = 0x2; + fmt = VIDEO_STD_NTSC_MJ_BIT; else if (std & V4L2_STD_PAL) - fmt = 0x4; + fmt = VIDEO_STD_PAL_BDGHIN_BIT; else if (std & V4L2_STD_SECAM) - fmt = 0xc; + fmt = VIDEO_STD_SECAM_BIT; } v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt); @@ -779,6 +779,70 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) return -EINVAL; } +static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) +{ + int val = tvp5150_read(sd, TVP5150_STATUS_REG_5); + + switch (val & 0x0F) { + case 0x01: + return V4L2_STD_NTSC; + case 0x03: + return V4L2_STD_PAL; + case 0x05: + return V4L2_STD_PAL_M; + case 0x07: + return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc; + case 0x09: + return V4L2_STD_NTSC_443; + case 0xb: + return V4L2_STD_SECAM; + default: + return V4L2_STD_UNKNOWN; + } +} + +static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, + enum v4l2_mbus_pixelcode *code) +{ + if (index) + return -EINVAL; + + *code = V4L2_MBUS_FMT_YUYV8_2X8; + return 0; +} + +static int tvp5150_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *f) +{ + struct tvp5150 *decoder = to_tvp5150(sd); + v4l2_std_id std; + + if (f == NULL) + return -EINVAL; + + tvp5150_reset(sd, 0); + + /* Calculate height and width based on current standard */ + if (decoder->norm == V4L2_STD_ALL) + std = tvp5150_read_std(sd); + else + std = decoder->norm; + + f->width = 720; + if (std & V4L2_STD_525_60) + f->height = 480; + else + f->height = 576; + + f->code = V4L2_MBUS_FMT_YUYV8_2X8; + f->field = V4L2_FIELD_SEQ_TB; + f->colorspace = V4L2_COLORSPACE_SMPTE170M; + + v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width, + f->height); + return 0; +} + /**************************************************************************** I2C Command ****************************************************************************/ @@ -931,6 +995,9 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { static const struct v4l2_subdev_video_ops tvp5150_video_ops = { .s_routing = tvp5150_s_routing, + .enum_mbus_fmt = tvp5150_enum_mbus_fmt, + .s_mbus_fmt = tvp5150_mbus_fmt, + .try_mbus_fmt = tvp5150_mbus_fmt, }; static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index 7875e80cb2ff..236c559d5f51 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c @@ -63,7 +63,7 @@ MODULE_LICENSE("GPL"); #define TVP7002_CL_MASK 0x0f /* Debug functions */ -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-2)"); diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 9bbe61700fd5..65d065aa6091 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -34,7 +34,7 @@ MODULE_DESCRIPTION("uPD64083 driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index d7f97513b289..89fec029e924 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -110,42 +110,20 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, unsigned char addr; int ret; - if ((flags & I2C_M_TEN)) { - /* a ten bit address */ - addr = 0xf0 | ((msg->addr >> 7) & 0x03); - /* try extended address code... */ - ret = try_write_address(i2c_adap, addr, retries); - if (ret != 1) { - dev_err(&i2c_adap->dev, - "died at extended address code, while writing\n"); - return -EREMOTEIO; - } - add[0] = addr; - if (flags & I2C_M_RD) { - /* okay, now switch into reading mode */ - addr |= 0x01; - ret = try_read_address(i2c_adap, addr, retries); - if (ret != 1) { - dev_err(&i2c_adap->dev, - "died at extended address code, while reading\n"); - return -EREMOTEIO; - } - } - } else { /* normal 7bit address */ - addr = (msg->addr << 1); - if (flags & I2C_M_RD) - addr |= 1; + addr = (msg->addr << 1); + if (flags & I2C_M_RD) + addr |= 1; - add[0] = addr; - if (flags & I2C_M_RD) - ret = try_read_address(i2c_adap, addr, retries); - else - ret = try_write_address(i2c_adap, addr, retries); + add[0] = addr; + if (flags & I2C_M_RD) + ret = try_read_address(i2c_adap, addr, retries); + else + ret = try_write_address(i2c_adap, addr, retries); + + if (ret != 1) + return -EREMOTEIO; - if (ret != 1) - return -EREMOTEIO; - } return 0; } @@ -184,7 +162,7 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) static u32 functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } /* -----exported algorithm data: ------------------------------------- */ diff --git a/drivers/media/video/uvc/Kconfig b/drivers/media/video/uvc/Kconfig index 2956a7637219..6c197da531b2 100644 --- a/drivers/media/video/uvc/Kconfig +++ b/drivers/media/video/uvc/Kconfig @@ -1,5 +1,6 @@ config USB_VIDEO_CLASS tristate "USB Video Class (UVC)" + select VIDEOBUF2_VMALLOC ---help--- Support for the USB Video Class (UVC). Currently only video input devices, such as webcams, are supported. diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile index 2071ca8a2f03..c26d12fdb8f4 100644 --- a/drivers/media/video/uvc/Makefile +++ b/drivers/media/video/uvc/Makefile @@ -1,5 +1,5 @@ uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ - uvc_status.o uvc_isight.o + uvc_status.o uvc_isight.o uvc_debugfs.o ifeq ($(CONFIG_MEDIA_CONTROLLER),y) uvcvideo-objs += uvc_entity.o endif diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 254d32688843..0efd3b10b353 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -878,8 +878,21 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, chain->dev->intfnum, ctrl->info.selector, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), ctrl->info.size); - if (ret < 0) - return ret; + if (ret < 0) { + if (UVC_ENTITY_TYPE(ctrl->entity) != + UVC_VC_EXTENSION_UNIT) + return ret; + + /* GET_RES is mandatory for XU controls, but some + * cameras still choke on it. Ignore errors and set the + * resolution value to zero. + */ + uvc_warn_once(chain->dev, UVC_WARN_XU_GET_RES, + "UVC non compliance - GET_RES failed on " + "an XU control. Enabling workaround.\n"); + memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0, + ctrl->info.size); + } } ctrl->cached = 1; @@ -1861,7 +1874,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) if (ncontrols == 0) continue; - entity->controls = kzalloc(ncontrols * sizeof(*ctrl), + entity->controls = kcalloc(ncontrols, sizeof(*ctrl), GFP_KERNEL); if (entity->controls == NULL) return -ENOMEM; diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c new file mode 100644 index 000000000000..14561a5abb79 --- /dev/null +++ b/drivers/media/video/uvc/uvc_debugfs.c @@ -0,0 +1,136 @@ +/* + * uvc_debugfs.c -- USB Video Class driver - Debugging support + * + * Copyright (C) 2011 + * Laurent Pinchart (laurent.pinchart@ideasonboard.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/debugfs.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include "uvcvideo.h" + +/* ----------------------------------------------------------------------------- + * Statistics + */ + +#define UVC_DEBUGFS_BUF_SIZE 1024 + +struct uvc_debugfs_buffer { + size_t count; + char data[UVC_DEBUGFS_BUF_SIZE]; +}; + +static int uvc_debugfs_stats_open(struct inode *inode, struct file *file) +{ + struct uvc_streaming *stream = inode->i_private; + struct uvc_debugfs_buffer *buf; + + buf = kmalloc(sizeof(*buf), GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data)); + + file->private_data = buf; + return 0; +} + +static ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf, + size_t nbytes, loff_t *ppos) +{ + struct uvc_debugfs_buffer *buf = file->private_data; + + return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data, + buf->count); +} + +static int uvc_debugfs_stats_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + file->private_data = NULL; + + return 0; +} + +static const struct file_operations uvc_debugfs_stats_fops = { + .owner = THIS_MODULE, + .open = uvc_debugfs_stats_open, + .llseek = no_llseek, + .read = uvc_debugfs_stats_read, + .release = uvc_debugfs_stats_release, +}; + +/* ----------------------------------------------------------------------------- + * Global and stream initialization/cleanup + */ + +static struct dentry *uvc_debugfs_root_dir; + +int uvc_debugfs_init_stream(struct uvc_streaming *stream) +{ + struct usb_device *udev = stream->dev->udev; + struct dentry *dent; + char dir_name[32]; + + if (uvc_debugfs_root_dir == NULL) + return -ENODEV; + + sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum); + + dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir); + if (IS_ERR_OR_NULL(dent)) { + uvc_printk(KERN_INFO, "Unable to create debugfs %s " + "directory.\n", dir_name); + return -ENODEV; + } + + stream->debugfs_dir = dent; + + dent = debugfs_create_file("stats", 0444, stream->debugfs_dir, + stream, &uvc_debugfs_stats_fops); + if (IS_ERR_OR_NULL(dent)) { + uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n"); + uvc_debugfs_cleanup_stream(stream); + return -ENODEV; + } + + return 0; +} + +void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream) +{ + if (stream->debugfs_dir == NULL) + return; + + debugfs_remove_recursive(stream->debugfs_dir); + stream->debugfs_dir = NULL; +} + +int uvc_debugfs_init(void) +{ + struct dentry *dir; + + dir = debugfs_create_dir("uvcvideo", usb_debug_root); + if (IS_ERR_OR_NULL(dir)) { + uvc_printk(KERN_INFO, "Unable to create debugfs directory\n"); + return -ENODATA; + } + + uvc_debugfs_root_dir = dir; + return 0; +} + +void uvc_debugfs_cleanup(void) +{ + if (uvc_debugfs_root_dir != NULL) + debugfs_remove_recursive(uvc_debugfs_root_dir); +} diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 656d4c9e3b9f..a240d43d15d1 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1675,6 +1675,8 @@ static void uvc_unregister_video(struct uvc_device *dev) video_unregister_device(stream->vdev); stream->vdev = NULL; + + uvc_debugfs_cleanup_stream(stream); } /* Decrement the stream count and call uvc_delete explicitly if there @@ -1700,6 +1702,8 @@ static int uvc_register_video(struct uvc_device *dev, return ret; } + uvc_debugfs_init_stream(stream); + /* Register the device with V4L. */ vdev = video_device_alloc(); if (vdev == NULL) { @@ -2033,6 +2037,15 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); * though they are compliant. */ static struct usb_device_id uvc_ids[] = { + /* LogiLink Wireless Webcam */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0416, + .idProduct = 0xa91a, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Genius eFace 2025 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2396,17 +2409,24 @@ struct uvc_driver uvc_driver = { static int __init uvc_init(void) { - int result; + int ret; + + uvc_debugfs_init(); - result = usb_register(&uvc_driver.driver); - if (result == 0) - printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n"); - return result; + ret = usb_register(&uvc_driver.driver); + if (ret < 0) { + uvc_debugfs_cleanup(); + return ret; + } + + printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n"); + return 0; } static void __exit uvc_cleanup(void) { usb_deregister(&uvc_driver.driver); + uvc_debugfs_cleanup(); } module_init(uvc_init); diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c index 74bbe8f18f3e..8510e7259e76 100644 --- a/drivers/media/video/uvc/uvc_isight.c +++ b/drivers/media/video/uvc/uvc_isight.c @@ -74,7 +74,7 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, * Empty buffers (bytesused == 0) don't trigger end of frame detection * as it doesn't make sense to return an empty buffer. */ - if (is_header && buf->buf.bytesused != 0) { + if (is_header && buf->bytesused != 0) { buf->state = UVC_BUF_STATE_DONE; return -EAGAIN; } @@ -83,13 +83,13 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, * contain no data. */ if (!is_header) { - maxlen = buf->buf.length - buf->buf.bytesused; - mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused; + maxlen = buf->length - buf->bytesused; + mem = buf->mem + buf->bytesused; nbytes = min(len, maxlen); memcpy(mem, data, nbytes); - buf->buf.bytesused += nbytes; + buf->bytesused += nbytes; - if (len > maxlen || buf->buf.bytesused == buf->buf.length) { + if (len > maxlen || buf->bytesused == buf->length) { uvc_trace(UVC_TRACE_FRAME, "Frame complete " "(overflow).\n"); buf->state = UVC_BUF_STATE_DONE; diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 677691c44500..518f77d3a4d8 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -11,6 +11,7 @@ * */ +#include <linux/atomic.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/list.h> @@ -19,7 +20,7 @@ #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> -#include <linux/atomic.h> +#include <media/videobuf2-vmalloc.h> #include "uvcvideo.h" @@ -29,467 +30,211 @@ * Video queues is initialized by uvc_queue_init(). The function performs * basic initialization of the uvc_video_queue struct and never fails. * - * Video buffer allocation and freeing are performed by uvc_alloc_buffers and - * uvc_free_buffers respectively. The former acquires the video queue lock, - * while the later must be called with the lock held (so that allocation can - * free previously allocated buffers). Trying to free buffers that are mapped - * to user space will return -EBUSY. - * - * Video buffers are managed using two queues. However, unlike most USB video - * drivers that use an in queue and an out queue, we use a main queue to hold - * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to - * hold empty buffers. This design (copied from video-buf) minimizes locking - * in interrupt, as only one queue is shared between interrupt and user - * contexts. - * - * Use cases - * --------- - * - * Unless stated otherwise, all operations that modify the irq buffers queue - * are protected by the irq spinlock. - * - * 1. The user queues the buffers, starts streaming and dequeues a buffer. - * - * The buffers are added to the main and irq queues. Both operations are - * protected by the queue lock, and the later is protected by the irq - * spinlock as well. - * - * The completion handler fetches a buffer from the irq queue and fills it - * with video data. If no buffer is available (irq queue empty), the handler - * returns immediately. - * - * When the buffer is full, the completion handler removes it from the irq - * queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue. - * At that point, any process waiting on the buffer will be woken up. If a - * process tries to dequeue a buffer after it has been marked done, the - * dequeing will succeed immediately. - * - * 2. Buffers are queued, user is waiting on a buffer and the device gets - * disconnected. - * - * When the device is disconnected, the kernel calls the completion handler - * with an appropriate status code. The handler marks all buffers in the - * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so - * that any process waiting on a buffer gets woken up. - * - * Waking up up the first buffer on the irq list is not enough, as the - * process waiting on the buffer might restart the dequeue operation - * immediately. - * + * Video buffers are managed by videobuf2. The driver uses a mutex to protect + * the videobuf2 queue operations by serializing calls to videobuf2 and a + * spinlock to protect the IRQ queue that holds the buffers to be processed by + * the driver. */ -void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, - int drop_corrupted) -{ - mutex_init(&queue->mutex); - spin_lock_init(&queue->irqlock); - INIT_LIST_HEAD(&queue->mainqueue); - INIT_LIST_HEAD(&queue->irqqueue); - queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; - queue->type = type; -} - -/* - * Free the video buffers. - * - * This function must be called with the queue lock held. +/* ----------------------------------------------------------------------------- + * videobuf2 queue operations */ -static int __uvc_free_buffers(struct uvc_video_queue *queue) + +static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - unsigned int i; + struct uvc_video_queue *queue = vb2_get_drv_priv(vq); + struct uvc_streaming *stream = + container_of(queue, struct uvc_streaming, queue); - for (i = 0; i < queue->count; ++i) { - if (queue->buffer[i].vma_use_count != 0) - return -EBUSY; - } + if (*nbuffers > UVC_MAX_VIDEO_BUFFERS) + *nbuffers = UVC_MAX_VIDEO_BUFFERS; - if (queue->count) { - uvc_queue_cancel(queue, 0); - INIT_LIST_HEAD(&queue->mainqueue); - vfree(queue->mem); - queue->count = 0; - } + *nplanes = 1; + + sizes[0] = stream->ctrl.dwMaxVideoFrameSize; return 0; } -int uvc_free_buffers(struct uvc_video_queue *queue) +static int uvc_buffer_prepare(struct vb2_buffer *vb) { - int ret; + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); - mutex_lock(&queue->mutex); - ret = __uvc_free_buffers(queue); - mutex_unlock(&queue->mutex); + if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { + uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); + return -EINVAL; + } - return ret; -} + if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED)) + return -ENODEV; -/* - * Allocate the video buffers. - * - * Pages are reserved to make sure they will not be swapped, as they will be - * filled in the URB completion handler. - * - * Buffers will be individually mapped, so they must all be page aligned. - */ -int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, - unsigned int buflength) -{ - unsigned int bufsize = PAGE_ALIGN(buflength); - unsigned int i; - void *mem = NULL; - int ret; + buf->state = UVC_BUF_STATE_QUEUED; + buf->error = 0; + buf->mem = vb2_plane_vaddr(vb, 0); + buf->length = vb2_plane_size(vb, 0); + if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + buf->bytesused = 0; + else + buf->bytesused = vb2_get_plane_payload(vb, 0); - if (nbuffers > UVC_MAX_VIDEO_BUFFERS) - nbuffers = UVC_MAX_VIDEO_BUFFERS; + return 0; +} - mutex_lock(&queue->mutex); +static void uvc_buffer_queue(struct vb2_buffer *vb) +{ + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); + unsigned long flags; - if ((ret = __uvc_free_buffers(queue)) < 0) - goto done; + spin_lock_irqsave(&queue->irqlock, flags); + if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) { + list_add_tail(&buf->queue, &queue->irqqueue); + } else { + /* If the device is disconnected return the buffer to userspace + * directly. The next QBUF call will fail with -ENODEV. + */ + buf->state = UVC_BUF_STATE_ERROR; + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); + } - /* Bail out if no buffers should be allocated. */ - if (nbuffers == 0) - goto done; + spin_unlock_irqrestore(&queue->irqlock, flags); +} - /* Decrement the number of buffers until allocation succeeds. */ - for (; nbuffers > 0; --nbuffers) { - mem = vmalloc_32(nbuffers * bufsize); - if (mem != NULL) - break; - } +static int uvc_buffer_finish(struct vb2_buffer *vb) +{ + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_streaming *stream = + container_of(queue, struct uvc_streaming, queue); + struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); - if (mem == NULL) { - ret = -ENOMEM; - goto done; - } + uvc_video_clock_update(stream, &vb->v4l2_buf, buf); + return 0; +} - for (i = 0; i < nbuffers; ++i) { - memset(&queue->buffer[i], 0, sizeof queue->buffer[i]); - queue->buffer[i].buf.index = i; - queue->buffer[i].buf.m.offset = i * bufsize; - queue->buffer[i].buf.length = buflength; - queue->buffer[i].buf.type = queue->type; - queue->buffer[i].buf.field = V4L2_FIELD_NONE; - queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; - queue->buffer[i].buf.flags = 0; - init_waitqueue_head(&queue->buffer[i].wait); - } +static struct vb2_ops uvc_queue_qops = { + .queue_setup = uvc_queue_setup, + .buf_prepare = uvc_buffer_prepare, + .buf_queue = uvc_buffer_queue, + .buf_finish = uvc_buffer_finish, +}; - queue->mem = mem; - queue->count = nbuffers; - queue->buf_size = bufsize; - ret = nbuffers; +void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, + int drop_corrupted) +{ + queue->queue.type = type; + queue->queue.io_modes = VB2_MMAP; + 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); -done: - mutex_unlock(&queue->mutex); - 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; } -/* - * Check if buffers have been allocated. +/* ----------------------------------------------------------------------------- + * V4L2 queue operations */ -int uvc_queue_allocated(struct uvc_video_queue *queue) + +int uvc_alloc_buffers(struct uvc_video_queue *queue, + struct v4l2_requestbuffers *rb) { - int allocated; + int ret; mutex_lock(&queue->mutex); - allocated = queue->count != 0; + ret = vb2_reqbufs(&queue->queue, rb); mutex_unlock(&queue->mutex); - return allocated; + return ret ? ret : rb->count; } -static void __uvc_query_buffer(struct uvc_buffer *buf, - struct v4l2_buffer *v4l2_buf) +void uvc_free_buffers(struct uvc_video_queue *queue) { - memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf); - - if (buf->vma_use_count) - v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - case UVC_BUF_STATE_DONE: - v4l2_buf->flags |= V4L2_BUF_FLAG_DONE; - break; - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - case UVC_BUF_STATE_READY: - v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case UVC_BUF_STATE_IDLE: - default: - break; - } + mutex_lock(&queue->mutex); + vb2_queue_release(&queue->queue); + mutex_unlock(&queue->mutex); } -int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf) +int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) { - int ret = 0; + int ret; mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - ret = -EINVAL; - goto done; - } - - __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf); - -done: + ret = vb2_querybuf(&queue->queue, buf); mutex_unlock(&queue->mutex); + return ret; } -/* - * Queue a video buffer. Attempting to queue a buffer that has already been - * queued will return -EINVAL. - */ -int uvc_queue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf) +int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) { - struct uvc_buffer *buf; - unsigned long flags; - int ret = 0; - - uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index); - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } + int ret; mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n"); - ret = -EINVAL; - goto done; - } - - buf = &queue->buffer[v4l2_buf->index]; - if (buf->state != UVC_BUF_STATE_IDLE) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state " - "(%u).\n", buf->state); - ret = -EINVAL; - goto done; - } - - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - v4l2_buf->bytesused > buf->buf.length) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); - ret = -EINVAL; - goto done; - } - - spin_lock_irqsave(&queue->irqlock, flags); - if (queue->flags & UVC_QUEUE_DISCONNECTED) { - spin_unlock_irqrestore(&queue->irqlock, flags); - ret = -ENODEV; - goto done; - } - buf->state = UVC_BUF_STATE_QUEUED; - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - buf->buf.bytesused = 0; - else - buf->buf.bytesused = v4l2_buf->bytesused; - - list_add_tail(&buf->stream, &queue->mainqueue); - list_add_tail(&buf->queue, &queue->irqqueue); - spin_unlock_irqrestore(&queue->irqlock, flags); - -done: + ret = vb2_qbuf(&queue->queue, buf); mutex_unlock(&queue->mutex); - return ret; -} -static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking) -{ - if (nonblocking) { - return (buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE && - buf->state != UVC_BUF_STATE_READY) - ? 0 : -EAGAIN; - } - - return wait_event_interruptible(buf->wait, - buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE && - buf->state != UVC_BUF_STATE_READY); + return ret; } -/* - * Dequeue a video buffer. If nonblocking is false, block until a buffer is - * available. - */ -int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking) +int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, + int nonblocking) { - struct uvc_buffer *buf; - int ret = 0; - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } + int ret; mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n"); - ret = -EINVAL; - goto done; - } - - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0) - goto done; - - uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n", - buf->buf.index, buf->state, buf->buf.bytesused); - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data " - "(transmission error).\n"); - ret = -EIO; - case UVC_BUF_STATE_DONE: - buf->state = UVC_BUF_STATE_IDLE; - break; - - case UVC_BUF_STATE_IDLE: - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - case UVC_BUF_STATE_READY: - default: - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u " - "(driver bug?).\n", buf->state); - ret = -EINVAL; - goto done; - } - - list_del(&buf->stream); - __uvc_query_buffer(buf, v4l2_buf); - -done: + ret = vb2_dqbuf(&queue->queue, buf, nonblocking); mutex_unlock(&queue->mutex); - return ret; -} -/* - * VMA operations. - */ -static void uvc_vm_open(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count++; -} - -static void uvc_vm_close(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count--; + return ret; } -static const struct vm_operations_struct uvc_vm_ops = { - .open = uvc_vm_open, - .close = uvc_vm_close, -}; - -/* - * Memory-map a video buffer. - * - * This function implements video buffers memory mapping and is intended to be - * used by the device mmap handler. - */ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) { - struct uvc_buffer *uninitialized_var(buffer); - struct page *page; - unsigned long addr, start, size; - unsigned int i; - int ret = 0; - - start = vma->vm_start; - size = vma->vm_end - vma->vm_start; + int ret; mutex_lock(&queue->mutex); + ret = vb2_mmap(&queue->queue, vma); + mutex_unlock(&queue->mutex); - for (i = 0; i < queue->count; ++i) { - buffer = &queue->buffer[i]; - if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) { - ret = -EINVAL; - goto done; - } - - /* - * VM_IO marks the area as being an mmaped region for I/O to a - * device. It also prevents the region from being core dumped. - */ - vma->vm_flags |= VM_IO; - - addr = (unsigned long)queue->mem + buffer->buf.m.offset; -#ifdef CONFIG_MMU - while (size > 0) { - page = vmalloc_to_page((void *)addr); - if ((ret = vm_insert_page(vma, start, page)) < 0) - goto done; - - start += PAGE_SIZE; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } -#endif + return ret; +} - vma->vm_ops = &uvc_vm_ops; - vma->vm_private_data = buffer; - uvc_vm_open(vma); +unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, + poll_table *wait) +{ + unsigned int ret; -done: + mutex_lock(&queue->mutex); + ret = vb2_poll(&queue->queue, file, wait); mutex_unlock(&queue->mutex); + return ret; } -/* - * Poll the video queue. +/* ----------------------------------------------------------------------------- * - * This function implements video queue polling and is intended to be used by - * the device poll handler. */ -unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait) + +/* + * Check if buffers have been allocated. + */ +int uvc_queue_allocated(struct uvc_video_queue *queue) { - struct uvc_buffer *buf; - unsigned int mask = 0; + int allocated; mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) { - mask |= POLLERR; - goto done; - } - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - - poll_wait(file, &buf->wait, wait); - if (buf->state == UVC_BUF_STATE_DONE || - buf->state == UVC_BUF_STATE_ERROR) { - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - mask |= POLLIN | POLLRDNORM; - else - mask |= POLLOUT | POLLWRNORM; - } - -done: + allocated = vb2_is_busy(&queue->queue); mutex_unlock(&queue->mutex); - return mask; + + return allocated; } #ifndef CONFIG_MMU @@ -515,7 +260,7 @@ unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, ret = -EINVAL; goto done; } - ret = (unsigned long)queue->mem + buffer->buf.m.offset; + ret = (unsigned long)buf->mem; done: mutex_unlock(&queue->mutex); return ret; @@ -540,27 +285,24 @@ done: */ int uvc_queue_enable(struct uvc_video_queue *queue, int enable) { - unsigned int i; - int ret = 0; + unsigned long flags; + int ret; mutex_lock(&queue->mutex); if (enable) { - if (uvc_queue_streaming(queue)) { - ret = -EBUSY; + ret = vb2_streamon(&queue->queue, queue->queue.type); + if (ret < 0) goto done; - } - queue->flags |= UVC_QUEUE_STREAMING; + queue->buf_used = 0; } else { - uvc_queue_cancel(queue, 0); - INIT_LIST_HEAD(&queue->mainqueue); - - for (i = 0; i < queue->count; ++i) { - queue->buffer[i].error = 0; - queue->buffer[i].state = UVC_BUF_STATE_IDLE; - } + ret = vb2_streamoff(&queue->queue, queue->queue.type); + if (ret < 0) + goto done; - queue->flags &= ~UVC_QUEUE_STREAMING; + spin_lock_irqsave(&queue->irqlock, flags); + INIT_LIST_HEAD(&queue->irqqueue); + spin_unlock_irqrestore(&queue->irqlock, flags); } done: @@ -591,12 +333,12 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) queue); list_del(&buf->queue); buf->state = UVC_BUF_STATE_ERROR; - wake_up(&buf->wait); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); } /* This must be protected by the irqlock spinlock to avoid race - * conditions between uvc_queue_buffer and the disconnection event that + * conditions between uvc_buffer_queue and the disconnection event that * could result in an interruptible wait in uvc_dequeue_buffer. Do not - * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED + * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED * state outside the queue code. */ if (disconnect) @@ -613,14 +355,12 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) { buf->error = 0; buf->state = UVC_BUF_STATE_QUEUED; - buf->buf.bytesused = 0; + vb2_set_plane_payload(&buf->buf, 0, 0); return buf; } spin_lock_irqsave(&queue->irqlock, flags); list_del(&buf->queue); - buf->error = 0; - buf->state = UVC_BUF_STATE_DONE; if (!list_empty(&queue->irqqueue)) nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, queue); @@ -628,7 +368,9 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, nextbuf = NULL; spin_unlock_irqrestore(&queue->irqlock, flags); - wake_up(&buf->wait); + buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; + vb2_set_plane_payload(&buf->buf, 0, buf->bytesused); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); + return nextbuf; } - diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index dadf11f704dc..2ae4f880ea05 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -58,6 +58,15 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, break; case V4L2_CTRL_TYPE_MENU: + /* Prevent excessive memory consumption, as well as integer + * overflows. + */ + if (xmap->menu_count == 0 || + xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) { + ret = -EINVAL; + goto done; + } + size = xmap->menu_count * sizeof(*map->menu_info); map->menu_info = kmalloc(size, GFP_KERNEL); if (map->menu_info == NULL) { @@ -513,10 +522,7 @@ static int uvc_v4l2_release(struct file *file) /* Only free resources if this is a privileged handle. */ if (uvc_has_privileges(handle)) { uvc_video_enable(stream, 0); - - if (uvc_free_buffers(&stream->queue) < 0) - uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " - "free buffers.\n"); + uvc_free_buffers(&stream->queue); } /* Release the file handle. */ @@ -914,19 +920,11 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) /* Buffers & streaming */ case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - - if (rb->type != stream->type || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; mutex_lock(&stream->mutex); - ret = uvc_alloc_buffers(&stream->queue, rb->count, - stream->ctrl.dwMaxVideoFrameSize); + ret = uvc_alloc_buffers(&stream->queue, arg); mutex_unlock(&stream->mutex); if (ret < 0) return ret; @@ -934,18 +932,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (ret == 0) uvc_dismiss_privileges(handle); - rb->count = ret; ret = 0; break; - } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; - if (buf->type != stream->type) - return -EINVAL; - if (!uvc_has_privileges(handle)) return -EBUSY; diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index b015e8e5e8b0..c7e69b8f81c9 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -351,25 +351,553 @@ done: return ret; } -int uvc_commit_video(struct uvc_streaming *stream, - struct uvc_streaming_control *probe) +static int uvc_commit_video(struct uvc_streaming *stream, + struct uvc_streaming_control *probe) { return uvc_set_video_ctrl(stream, probe, 0); } +/* ----------------------------------------------------------------------------- + * Clocks and timestamps + */ + +static void +uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, + const __u8 *data, int len) +{ + struct uvc_clock_sample *sample; + unsigned int header_size; + bool has_pts = false; + bool has_scr = false; + unsigned long flags; + struct timespec ts; + u16 host_sof; + u16 dev_sof; + + switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) { + case UVC_STREAM_PTS | UVC_STREAM_SCR: + header_size = 12; + has_pts = true; + has_scr = true; + break; + case UVC_STREAM_PTS: + header_size = 6; + has_pts = true; + break; + case UVC_STREAM_SCR: + header_size = 8; + has_scr = true; + break; + default: + header_size = 2; + break; + } + + /* Check for invalid headers. */ + if (len < header_size) + return; + + /* Extract the timestamps: + * + * - store the frame PTS in the buffer structure + * - if the SCR field is present, retrieve the host SOF counter and + * kernel timestamps and store them with the SCR STC and SOF fields + * in the ring buffer + */ + if (has_pts && buf != NULL) + buf->pts = get_unaligned_le32(&data[2]); + + if (!has_scr) + return; + + /* To limit the amount of data, drop SCRs with an SOF identical to the + * previous one. + */ + dev_sof = get_unaligned_le16(&data[header_size - 2]); + if (dev_sof == stream->clock.last_sof) + return; + + stream->clock.last_sof = dev_sof; + + host_sof = usb_get_current_frame_number(stream->dev->udev); + ktime_get_ts(&ts); + + /* The UVC specification allows device implementations that can't obtain + * the USB frame number to keep their own frame counters as long as they + * match the size and frequency of the frame number associated with USB + * SOF tokens. The SOF values sent by such devices differ from the USB + * SOF tokens by a fixed offset that needs to be estimated and accounted + * for to make timestamp recovery as accurate as possible. + * + * The offset is estimated the first time a device SOF value is received + * as the difference between the host and device SOF values. As the two + * SOF values can differ slightly due to transmission delays, consider + * that the offset is null if the difference is not higher than 10 ms + * (negative differences can not happen and are thus considered as an + * offset). The video commit control wDelay field should be used to + * compute a dynamic threshold instead of using a fixed 10 ms value, but + * devices don't report reliable wDelay values. + * + * See uvc_video_clock_host_sof() for an explanation regarding why only + * the 8 LSBs of the delta are kept. + */ + if (stream->clock.sof_offset == (u16)-1) { + u16 delta_sof = (host_sof - dev_sof) & 255; + if (delta_sof >= 10) + stream->clock.sof_offset = delta_sof; + else + stream->clock.sof_offset = 0; + } + + dev_sof = (dev_sof + stream->clock.sof_offset) & 2047; + + spin_lock_irqsave(&stream->clock.lock, flags); + + sample = &stream->clock.samples[stream->clock.head]; + sample->dev_stc = get_unaligned_le32(&data[header_size - 6]); + sample->dev_sof = dev_sof; + sample->host_sof = host_sof; + sample->host_ts = ts; + + /* Update the sliding window head and count. */ + stream->clock.head = (stream->clock.head + 1) % stream->clock.size; + + if (stream->clock.count < stream->clock.size) + stream->clock.count++; + + spin_unlock_irqrestore(&stream->clock.lock, flags); +} + +static int uvc_video_clock_init(struct uvc_streaming *stream) +{ + struct uvc_clock *clock = &stream->clock; + + spin_lock_init(&clock->lock); + clock->head = 0; + clock->count = 0; + clock->size = 32; + clock->last_sof = -1; + clock->sof_offset = -1; + + clock->samples = kmalloc(clock->size * sizeof(*clock->samples), + GFP_KERNEL); + if (clock->samples == NULL) + return -ENOMEM; + + return 0; +} + +static void uvc_video_clock_cleanup(struct uvc_streaming *stream) +{ + kfree(stream->clock.samples); + stream->clock.samples = NULL; +} + +/* + * uvc_video_clock_host_sof - Return the host SOF value for a clock sample + * + * Host SOF counters reported by usb_get_current_frame_number() usually don't + * cover the whole 11-bits SOF range (0-2047) but are limited to the HCI frame + * schedule window. They can be limited to 8, 9 or 10 bits depending on the host + * controller and its configuration. + * + * We thus need to recover the SOF value corresponding to the host frame number. + * As the device and host frame numbers are sampled in a short interval, the + * difference between their values should be equal to a small delta plus an + * integer multiple of 256 caused by the host frame number limited precision. + * + * To obtain the recovered host SOF value, compute the small delta by masking + * the high bits of the host frame counter and device SOF difference and add it + * to the device SOF value. + */ +static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample) +{ + /* The delta value can be negative. */ + s8 delta_sof; + + delta_sof = (sample->host_sof - sample->dev_sof) & 255; + + return (sample->dev_sof + delta_sof) & 2047; +} + +/* + * uvc_video_clock_update - Update the buffer timestamp + * + * This function converts the buffer PTS timestamp to the host clock domain by + * going through the USB SOF clock domain and stores the result in the V4L2 + * buffer timestamp field. + * + * The relationship between the device clock and the host clock isn't known. + * However, the device and the host share the common USB SOF clock which can be + * used to recover that relationship. + * + * The relationship between the device clock and the USB SOF clock is considered + * to be linear over the clock samples sliding window and is given by + * + * SOF = m * PTS + p + * + * Several methods to compute the slope (m) and intercept (p) can be used. As + * the clock drift should be small compared to the sliding window size, we + * assume that the line that goes through the points at both ends of the window + * is a good approximation. Naming those points P1 and P2, we get + * + * SOF = (SOF2 - SOF1) / (STC2 - STC1) * PTS + * + (SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1) + * + * or + * + * SOF = ((SOF2 - SOF1) * PTS + SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1) (1) + * + * to avoid loosing precision in the division. Similarly, the host timestamp is + * computed with + * + * TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1) (2) + * + * SOF values are coded on 11 bits by USB. We extend their precision with 16 + * decimal bits, leading to a 11.16 coding. + * + * TODO: To avoid surprises with device clock values, PTS/STC timestamps should + * be normalized using the nominal device clock frequency reported through the + * UVC descriptors. + * + * Both the PTS/STC and SOF counters roll over, after a fixed but device + * specific amount of time for PTS/STC and after 2048ms for SOF. As long as the + * sliding window size is smaller than the rollover period, differences computed + * on unsigned integers will produce the correct result. However, the p term in + * the linear relations will be miscomputed. + * + * To fix the issue, we subtract a constant from the PTS and STC values to bring + * PTS to half the 32 bit STC range. The sliding window STC values then fit into + * the 32 bit range without any rollover. + * + * Similarly, we add 2048 to the device SOF values to make sure that the SOF + * computed by (1) will never be smaller than 0. This offset is then compensated + * by adding 2048 to the SOF values used in (2). However, this doesn't prevent + * rollovers between (1) and (2): the SOF value computed by (1) can be slightly + * lower than 4096, and the host SOF counters can have rolled over to 2048. This + * case is handled by subtracting 2048 from the SOF value if it exceeds the host + * SOF value at the end of the sliding window. + * + * Finally we subtract a constant from the host timestamps to bring the first + * timestamp of the sliding window to 1s. + */ +void uvc_video_clock_update(struct uvc_streaming *stream, + struct v4l2_buffer *v4l2_buf, + struct uvc_buffer *buf) +{ + struct uvc_clock *clock = &stream->clock; + struct uvc_clock_sample *first; + struct uvc_clock_sample *last; + unsigned long flags; + struct timespec ts; + u32 delta_stc; + u32 y1, y2; + u32 x1, x2; + u32 mean; + u32 sof; + u32 div; + u32 rem; + u64 y; + + spin_lock_irqsave(&clock->lock, flags); + + if (clock->count < clock->size) + goto done; + + first = &clock->samples[clock->head]; + last = &clock->samples[(clock->head - 1) % clock->size]; + + /* First step, PTS to SOF conversion. */ + delta_stc = buf->pts - (1UL << 31); + x1 = first->dev_stc - delta_stc; + x2 = last->dev_stc - delta_stc; + y1 = (first->dev_sof + 2048) << 16; + y2 = (last->dev_sof + 2048) << 16; + + if (y2 < y1) + y2 += 2048 << 16; + + y = (u64)(y2 - y1) * (1ULL << 31) + (u64)y1 * (u64)x2 + - (u64)y2 * (u64)x1; + y = div_u64(y, x2 - x1); + + sof = y; + + uvc_trace(UVC_TRACE_CLOCK, "%s: PTS %u y %llu.%06llu SOF %u.%06llu " + "(x1 %u x2 %u y1 %u y2 %u SOF offset %u)\n", + stream->dev->name, buf->pts, + y >> 16, div_u64((y & 0xffff) * 1000000, 65536), + sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536), + x1, x2, y1, y2, clock->sof_offset); + + /* Second step, SOF to host clock conversion. */ + ts = timespec_sub(last->host_ts, first->host_ts); + x1 = (uvc_video_clock_host_sof(first) + 2048) << 16; + x2 = (uvc_video_clock_host_sof(last) + 2048) << 16; + y1 = NSEC_PER_SEC; + y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec; + + if (x2 < x1) + x2 += 2048 << 16; + + /* Interpolated and host SOF timestamps can wrap around at slightly + * different times. Handle this by adding or removing 2048 to or from + * the computed SOF value to keep it close to the SOF samples mean + * value. + */ + mean = (x1 + x2) / 2; + if (mean - (1024 << 16) > sof) + sof += 2048 << 16; + else if (sof > mean + (1024 << 16)) + sof -= 2048 << 16; + + y = (u64)(y2 - y1) * (u64)sof + (u64)y1 * (u64)x2 + - (u64)y2 * (u64)x1; + y = div_u64(y, x2 - x1); + + div = div_u64_rem(y, NSEC_PER_SEC, &rem); + ts.tv_sec = first->host_ts.tv_sec - 1 + div; + ts.tv_nsec = first->host_ts.tv_nsec + rem; + if (ts.tv_nsec >= NSEC_PER_SEC) { + ts.tv_sec++; + ts.tv_nsec -= NSEC_PER_SEC; + } + + uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %lu.%06lu " + "buf ts %lu.%06lu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n", + stream->dev->name, + sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536), + y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC, + v4l2_buf->timestamp.tv_sec, v4l2_buf->timestamp.tv_usec, + x1, first->host_sof, first->dev_sof, + x2, last->host_sof, last->dev_sof, y1, y2); + + /* Update the V4L2 buffer. */ + v4l2_buf->timestamp.tv_sec = ts.tv_sec; + v4l2_buf->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; + +done: + spin_unlock_irqrestore(&stream->clock.lock, flags); +} + /* ------------------------------------------------------------------------ - * Video codecs + * Stream statistics */ -/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ -#define UVC_STREAM_EOH (1 << 7) -#define UVC_STREAM_ERR (1 << 6) -#define UVC_STREAM_STI (1 << 5) -#define UVC_STREAM_RES (1 << 4) -#define UVC_STREAM_SCR (1 << 3) -#define UVC_STREAM_PTS (1 << 2) -#define UVC_STREAM_EOF (1 << 1) -#define UVC_STREAM_FID (1 << 0) +static void uvc_video_stats_decode(struct uvc_streaming *stream, + const __u8 *data, int len) +{ + unsigned int header_size; + bool has_pts = false; + bool has_scr = false; + u16 uninitialized_var(scr_sof); + u32 uninitialized_var(scr_stc); + u32 uninitialized_var(pts); + + if (stream->stats.stream.nb_frames == 0 && + stream->stats.frame.nb_packets == 0) + ktime_get_ts(&stream->stats.stream.start_ts); + + switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) { + case UVC_STREAM_PTS | UVC_STREAM_SCR: + header_size = 12; + has_pts = true; + has_scr = true; + break; + case UVC_STREAM_PTS: + header_size = 6; + has_pts = true; + break; + case UVC_STREAM_SCR: + header_size = 8; + has_scr = true; + break; + default: + header_size = 2; + break; + } + + /* Check for invalid headers. */ + if (len < header_size || data[0] < header_size) { + stream->stats.frame.nb_invalid++; + return; + } + + /* Extract the timestamps. */ + if (has_pts) + pts = get_unaligned_le32(&data[2]); + + if (has_scr) { + scr_stc = get_unaligned_le32(&data[header_size - 6]); + scr_sof = get_unaligned_le16(&data[header_size - 2]); + } + + /* Is PTS constant through the whole frame ? */ + if (has_pts && stream->stats.frame.nb_pts) { + if (stream->stats.frame.pts != pts) { + stream->stats.frame.nb_pts_diffs++; + stream->stats.frame.last_pts_diff = + stream->stats.frame.nb_packets; + } + } + + if (has_pts) { + stream->stats.frame.nb_pts++; + stream->stats.frame.pts = pts; + } + + /* Do all frames have a PTS in their first non-empty packet, or before + * their first empty packet ? + */ + if (stream->stats.frame.size == 0) { + if (len > header_size) + stream->stats.frame.has_initial_pts = has_pts; + if (len == header_size && has_pts) + stream->stats.frame.has_early_pts = true; + } + + /* Do the SCR.STC and SCR.SOF fields vary through the frame ? */ + if (has_scr && stream->stats.frame.nb_scr) { + if (stream->stats.frame.scr_stc != scr_stc) + stream->stats.frame.nb_scr_diffs++; + } + + if (has_scr) { + /* Expand the SOF counter to 32 bits and store its value. */ + if (stream->stats.stream.nb_frames > 0 || + stream->stats.frame.nb_scr > 0) + stream->stats.stream.scr_sof_count += + (scr_sof - stream->stats.stream.scr_sof) % 2048; + stream->stats.stream.scr_sof = scr_sof; + + stream->stats.frame.nb_scr++; + stream->stats.frame.scr_stc = scr_stc; + stream->stats.frame.scr_sof = scr_sof; + + if (scr_sof < stream->stats.stream.min_sof) + stream->stats.stream.min_sof = scr_sof; + if (scr_sof > stream->stats.stream.max_sof) + stream->stats.stream.max_sof = scr_sof; + } + + /* Record the first non-empty packet number. */ + if (stream->stats.frame.size == 0 && len > header_size) + stream->stats.frame.first_data = stream->stats.frame.nb_packets; + + /* Update the frame size. */ + stream->stats.frame.size += len - header_size; + + /* Update the packets counters. */ + stream->stats.frame.nb_packets++; + if (len > header_size) + stream->stats.frame.nb_empty++; + + if (data[1] & UVC_STREAM_ERR) + stream->stats.frame.nb_errors++; +} + +static void uvc_video_stats_update(struct uvc_streaming *stream) +{ + struct uvc_stats_frame *frame = &stream->stats.frame; + + uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets, " + "%u/%u/%u pts (%searly %sinitial), %u/%u scr, " + "last pts/stc/sof %u/%u/%u\n", + stream->sequence, frame->first_data, + frame->nb_packets - frame->nb_empty, frame->nb_packets, + frame->nb_pts_diffs, frame->last_pts_diff, frame->nb_pts, + frame->has_early_pts ? "" : "!", + frame->has_initial_pts ? "" : "!", + frame->nb_scr_diffs, frame->nb_scr, + frame->pts, frame->scr_stc, frame->scr_sof); + + stream->stats.stream.nb_frames++; + stream->stats.stream.nb_packets += stream->stats.frame.nb_packets; + stream->stats.stream.nb_empty += stream->stats.frame.nb_empty; + stream->stats.stream.nb_errors += stream->stats.frame.nb_errors; + stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid; + + if (frame->has_early_pts) + stream->stats.stream.nb_pts_early++; + if (frame->has_initial_pts) + stream->stats.stream.nb_pts_initial++; + if (frame->last_pts_diff <= frame->first_data) + stream->stats.stream.nb_pts_constant++; + if (frame->nb_scr >= frame->nb_packets - frame->nb_empty) + stream->stats.stream.nb_scr_count_ok++; + if (frame->nb_scr_diffs + 1 == frame->nb_scr) + stream->stats.stream.nb_scr_diffs_ok++; + + memset(&stream->stats.frame, 0, sizeof(stream->stats.frame)); +} + +size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, + size_t size) +{ + unsigned int scr_sof_freq; + unsigned int duration; + struct timespec ts; + size_t count = 0; + + ts.tv_sec = stream->stats.stream.stop_ts.tv_sec + - stream->stats.stream.start_ts.tv_sec; + ts.tv_nsec = stream->stats.stream.stop_ts.tv_nsec + - stream->stats.stream.start_ts.tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000; + } + + /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF + * frequency this will not overflow before more than 1h. + */ + duration = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + if (duration != 0) + scr_sof_freq = stream->stats.stream.scr_sof_count * 1000 + / duration; + else + scr_sof_freq = 0; + + count += scnprintf(buf + count, size - count, + "frames: %u\npackets: %u\nempty: %u\n" + "errors: %u\ninvalid: %u\n", + stream->stats.stream.nb_frames, + stream->stats.stream.nb_packets, + stream->stats.stream.nb_empty, + stream->stats.stream.nb_errors, + stream->stats.stream.nb_invalid); + count += scnprintf(buf + count, size - count, + "pts: %u early, %u initial, %u ok\n", + stream->stats.stream.nb_pts_early, + stream->stats.stream.nb_pts_initial, + stream->stats.stream.nb_pts_constant); + count += scnprintf(buf + count, size - count, + "scr: %u count ok, %u diff ok\n", + stream->stats.stream.nb_scr_count_ok, + stream->stats.stream.nb_scr_diffs_ok); + count += scnprintf(buf + count, size - count, + "sof: %u <= sof <= %u, freq %u.%03u kHz\n", + stream->stats.stream.min_sof, + stream->stats.stream.max_sof, + scr_sof_freq / 1000, scr_sof_freq % 1000); + + return count; +} + +static void uvc_video_stats_start(struct uvc_streaming *stream) +{ + memset(&stream->stats, 0, sizeof(stream->stats)); + stream->stats.stream.min_sof = 2048; +} + +static void uvc_video_stats_stop(struct uvc_streaming *stream) +{ + ktime_get_ts(&stream->stats.stream.stop_ts); +} + +/* ------------------------------------------------------------------------ + * Video codecs + */ /* Video payload decoding is handled by uvc_video_decode_start(), * uvc_video_decode_data() and uvc_video_decode_end(). @@ -416,14 +944,9 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, * - bHeaderLength value must be at least 2 bytes (see above) * - bHeaderLength value can't be larger than the packet size. */ - if (len < 2 || data[0] < 2 || data[0] > len) + if (len < 2 || data[0] < 2 || data[0] > len) { + stream->stats.frame.nb_invalid++; return -EINVAL; - - /* Skip payloads marked with the error bit ("error frames"). */ - if (data[1] & UVC_STREAM_ERR) { - uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit " - "set).\n"); - return -ENODATA; } fid = data[1] & UVC_STREAM_FID; @@ -431,8 +954,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, /* Increase the sequence number regardless of any buffer states, so * that discontinuous sequence numbers always indicate lost frames. */ - if (stream->last_fid != fid) + if (stream->last_fid != fid) { stream->sequence++; + if (stream->sequence) + uvc_video_stats_update(stream); + } + + uvc_video_clock_decode(stream, buf, data, len); + uvc_video_stats_decode(stream, data, len); /* Store the payload FID bit and return immediately when the buffer is * NULL. @@ -442,6 +971,13 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return -ENODATA; } + /* Mark the buffer as bad if the error bit is set. */ + if (data[1] & UVC_STREAM_ERR) { + uvc_trace(UVC_TRACE_FRAME, "Marking buffer as bad (error bit " + "set).\n"); + buf->error = 1; + } + /* Synchronize to the input stream by waiting for the FID bit to be * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE. * stream->last_fid is initialized to -1, so the first isochronous @@ -467,9 +1003,10 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, else ktime_get_real_ts(&ts); - buf->buf.sequence = stream->sequence; - buf->buf.timestamp.tv_sec = ts.tv_sec; - buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; + buf->buf.v4l2_buf.sequence = stream->sequence; + buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec; + buf->buf.v4l2_buf.timestamp.tv_usec = + ts.tv_nsec / NSEC_PER_USEC; /* TODO: Handle PTS and SCR. */ buf->state = UVC_BUF_STATE_ACTIVE; @@ -490,7 +1027,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, * avoids detecting end of frame conditions at FID toggling if the * previous payload had the EOF bit set. */ - if (fid != stream->last_fid && buf->buf.bytesused != 0) { + if (fid != stream->last_fid && buf->bytesused != 0) { uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit " "toggled).\n"); buf->state = UVC_BUF_STATE_READY; @@ -505,7 +1042,6 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, static void uvc_video_decode_data(struct uvc_streaming *stream, struct uvc_buffer *buf, const __u8 *data, int len) { - struct uvc_video_queue *queue = &stream->queue; unsigned int maxlen, nbytes; void *mem; @@ -513,11 +1049,11 @@ static void uvc_video_decode_data(struct uvc_streaming *stream, return; /* Copy the video data to the buffer. */ - maxlen = buf->buf.length - buf->buf.bytesused; - mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused; + maxlen = buf->length - buf->bytesused; + mem = buf->mem + buf->bytesused; nbytes = min((unsigned int)len, maxlen); memcpy(mem, data, nbytes); - buf->buf.bytesused += nbytes; + buf->bytesused += nbytes; /* Complete the current frame if the buffer size was exceeded. */ if (len > maxlen) { @@ -530,7 +1066,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream, struct uvc_buffer *buf, const __u8 *data, int len) { /* Mark the buffer as done if the EOF marker is set. */ - if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) { + if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) { uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n"); if (data[0] == len) uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n"); @@ -568,8 +1104,8 @@ static int uvc_video_encode_data(struct uvc_streaming *stream, void *mem; /* Copy video data to the URB buffer. */ - mem = queue->mem + buf->buf.m.offset + queue->buf_used; - nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); + mem = buf->mem + queue->buf_used; + nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used); nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size, nbytes); memcpy(data, mem, nbytes); @@ -624,7 +1160,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, urb->iso_frame_desc[i].actual_length); if (buf->state == UVC_BUF_STATE_READY) { - if (buf->buf.length != buf->buf.bytesused && + if (buf->length != buf->bytesused && !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)) buf->error = 1; @@ -724,12 +1260,12 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream, stream->bulk.payload_size += ret; len -= ret; - if (buf->buf.bytesused == stream->queue.buf_used || + if (buf->bytesused == stream->queue.buf_used || stream->bulk.payload_size == stream->bulk.max_payload_size) { - if (buf->buf.bytesused == stream->queue.buf_used) { + if (buf->bytesused == stream->queue.buf_used) { stream->queue.buf_used = 0; buf->state = UVC_BUF_STATE_READY; - buf->buf.sequence = ++stream->sequence; + buf->buf.v4l2_buf.sequence = ++stream->sequence; uvc_queue_next_buffer(&stream->queue, buf); stream->last_fid ^= UVC_STREAM_FID; } @@ -870,6 +1406,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) struct urb *urb; unsigned int i; + uvc_video_stats_stop(stream); + for (i = 0; i < UVC_URBS; ++i) { urb = stream->urb[i]; if (urb == NULL) @@ -882,6 +1420,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) if (free_buffers) uvc_free_urb_buffers(stream); + + uvc_video_clock_cleanup(stream); } /* @@ -1009,6 +1549,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) stream->bulk.skip_payload = 0; stream->bulk.payload_size = 0; + uvc_video_stats_start(stream); + + ret = uvc_video_clock_init(stream); + if (ret < 0) + return ret; + if (intf->num_altsetting > 1) { struct usb_host_endpoint *best_ep = NULL; unsigned int best_psize = 3 * 1024; @@ -1283,6 +1829,11 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) return ret; } - return uvc_init_video(stream, GFP_KERNEL); -} + ret = uvc_init_video(stream, GFP_KERNEL); + if (ret < 0) { + usb_set_interface(stream->dev->udev, stream->intfnum, 0); + uvc_queue_enable(&stream->queue, 0); + } + return ret; +} diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 4c1392ebcd4b..67f88d85bb16 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -13,6 +13,7 @@ #include <linux/videodev2.h> #include <media/media-device.h> #include <media/v4l2-device.h> +#include <media/videobuf2-core.h> /* -------------------------------------------------------------------------- * UVC constants @@ -113,6 +114,7 @@ /* Maximum allowed number of control mappings per device */ #define UVC_MAX_CONTROL_MAPPINGS 1024 +#define UVC_MAX_CONTROL_MENU_ENTRIES 32 /* Devices quirks */ #define UVC_QUIRK_STATUS_INTERVAL 0x00000001 @@ -319,35 +321,30 @@ enum uvc_buffer_state { }; struct uvc_buffer { - unsigned long vma_use_count; - struct list_head stream; - - /* Touched by interrupt handler. */ - struct v4l2_buffer buf; + struct vb2_buffer buf; struct list_head queue; - wait_queue_head_t wait; + enum uvc_buffer_state state; unsigned int error; + + void *mem; + unsigned int length; + unsigned int bytesused; + + u32 pts; }; -#define UVC_QUEUE_STREAMING (1 << 0) -#define UVC_QUEUE_DISCONNECTED (1 << 1) -#define UVC_QUEUE_DROP_CORRUPTED (1 << 2) +#define UVC_QUEUE_DISCONNECTED (1 << 0) +#define UVC_QUEUE_DROP_CORRUPTED (1 << 1) struct uvc_video_queue { - enum v4l2_buf_type type; + struct vb2_queue queue; + struct mutex mutex; /* Protects queue */ - void *mem; unsigned int flags; - - unsigned int count; - unsigned int buf_size; unsigned int buf_used; - struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; - struct mutex mutex; /* protects buffers and mainqueue */ - spinlock_t irqlock; /* protects irqqueue */ - struct list_head mainqueue; + spinlock_t irqlock; /* Protects irqqueue */ struct list_head irqqueue; }; @@ -362,6 +359,51 @@ struct uvc_video_chain { struct mutex ctrl_mutex; /* Protects ctrl.info */ }; +struct uvc_stats_frame { + unsigned int size; /* Number of bytes captured */ + unsigned int first_data; /* Index of the first non-empty packet */ + + unsigned int nb_packets; /* Number of packets */ + unsigned int nb_empty; /* Number of empty packets */ + unsigned int nb_invalid; /* Number of packets with an invalid header */ + unsigned int nb_errors; /* Number of packets with the error bit set */ + + unsigned int nb_pts; /* Number of packets with a PTS timestamp */ + unsigned int nb_pts_diffs; /* Number of PTS differences inside a frame */ + unsigned int last_pts_diff; /* Index of the last PTS difference */ + bool has_initial_pts; /* Whether the first non-empty packet has a PTS */ + bool has_early_pts; /* Whether a PTS is present before the first non-empty packet */ + u32 pts; /* PTS of the last packet */ + + unsigned int nb_scr; /* Number of packets with a SCR timestamp */ + unsigned int nb_scr_diffs; /* Number of SCR.STC differences inside a frame */ + u16 scr_sof; /* SCR.SOF of the last packet */ + u32 scr_stc; /* SCR.STC of the last packet */ +}; + +struct uvc_stats_stream { + struct timespec start_ts; /* Stream start timestamp */ + struct timespec stop_ts; /* Stream stop timestamp */ + + unsigned int nb_frames; /* Number of frames */ + + unsigned int nb_packets; /* Number of packets */ + unsigned int nb_empty; /* Number of empty packets */ + unsigned int nb_invalid; /* Number of packets with an invalid header */ + unsigned int nb_errors; /* Number of packets with the error bit set */ + + unsigned int nb_pts_constant; /* Number of frames with constant PTS */ + unsigned int nb_pts_early; /* Number of frames with early PTS */ + unsigned int nb_pts_initial; /* Number of frames with initial PTS */ + + unsigned int nb_scr_count_ok; /* Number of frames with at least one SCR per non empty packet */ + unsigned int nb_scr_diffs_ok; /* Number of frames with varying SCR.STC */ + unsigned int scr_sof_count; /* STC.SOF counter accumulated since stream start */ + unsigned int scr_sof; /* STC.SOF of the last packet */ + unsigned int min_sof; /* Minimum STC.SOF value */ + unsigned int max_sof; /* Maximum STC.SOF value */ +}; + struct uvc_streaming { struct list_head list; struct uvc_device *dev; @@ -387,6 +429,7 @@ struct uvc_streaming { */ struct mutex mutex; + /* Buffers queue. */ unsigned int frozen : 1; struct uvc_video_queue queue; void (*decode) (struct urb *urb, struct uvc_streaming *video, @@ -408,6 +451,32 @@ struct uvc_streaming { __u32 sequence; __u8 last_fid; + + /* debugfs */ + struct dentry *debugfs_dir; + struct { + struct uvc_stats_frame frame; + struct uvc_stats_stream stream; + } stats; + + /* Timestamps support. */ + struct uvc_clock { + struct uvc_clock_sample { + u32 dev_stc; + u16 dev_sof; + struct timespec host_ts; + u16 host_sof; + } *samples; + + unsigned int head; + unsigned int count; + unsigned int size; + + u16 last_sof; + u16 sof_offset; + + spinlock_t lock; + } clock; }; enum uvc_device_state { @@ -479,9 +548,12 @@ struct uvc_driver { #define UVC_TRACE_SUSPEND (1 << 8) #define UVC_TRACE_STATUS (1 << 9) #define UVC_TRACE_VIDEO (1 << 10) +#define UVC_TRACE_STATS (1 << 11) +#define UVC_TRACE_CLOCK (1 << 12) #define UVC_WARN_MINMAX 0 #define UVC_WARN_PROBE_DEF 1 +#define UVC_WARN_XU_GET_RES 2 extern unsigned int uvc_clock_param; extern unsigned int uvc_no_drop_param; @@ -516,8 +588,8 @@ extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); extern void 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, - unsigned int nbuffers, unsigned int buflength); -extern int uvc_free_buffers(struct uvc_video_queue *queue); + struct v4l2_requestbuffers *rb); +extern void uvc_free_buffers(struct uvc_video_queue *queue); extern int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf); extern int uvc_queue_buffer(struct uvc_video_queue *queue, @@ -539,7 +611,7 @@ extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, extern int uvc_queue_allocated(struct uvc_video_queue *queue); static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { - return queue->flags & UVC_QUEUE_STREAMING; + return vb2_is_streaming(&queue->queue); } /* V4L2 interface */ @@ -556,10 +628,11 @@ extern int uvc_video_resume(struct uvc_streaming *stream, int reset); extern int uvc_video_enable(struct uvc_streaming *stream, int enable); extern int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); -extern int uvc_commit_video(struct uvc_streaming *stream, - struct uvc_streaming_control *ctrl); extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, __u8 intfnum, __u8 cs, void *data, __u16 size); +void uvc_video_clock_update(struct uvc_streaming *stream, + struct v4l2_buffer *v4l2_buf, + struct uvc_buffer *buf); /* Status */ extern int uvc_status_init(struct uvc_device *dev); @@ -612,4 +685,13 @@ extern struct usb_host_endpoint *uvc_find_endpoint( void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, struct uvc_buffer *buf); +/* debugfs and statistics */ +int uvc_debugfs_init(void); +void uvc_debugfs_cleanup(void); +int uvc_debugfs_init_stream(struct uvc_streaming *stream); +void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream); + +size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, + size_t size); + #endif diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index c68531b88279..af4419e6c658 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -985,6 +985,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_CROPCAP: case VIDIOC_G_CROP: case VIDIOC_S_CROP: + case VIDIOC_G_SELECTION: + case VIDIOC_S_SELECTION: case VIDIOC_G_JPEGCOMP: case VIDIOC_S_JPEGCOMP: case VIDIOC_QUERYSTD: diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 0f415dade05a..cccd42be718a 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -465,8 +465,9 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_CHROMA_GAIN: return "Chroma Gain"; case V4L2_CID_ILLUMINATORS_1: return "Illuminator 1"; case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2"; - case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Minimum Number of Capture Buffers"; - case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Minimum Number of Output Buffers"; + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Min Number of Capture Buffers"; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Min Number of Output Buffers"; + case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component"; /* MPEG controls */ /* Keep the order of the 'case's the same as in videodev2.h! */ @@ -505,25 +506,25 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV"; case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface"; case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable"; - case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "The Number of Intra Refresh MBs"; + case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs"; case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable"; case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control"; case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode"; - case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "The Max Number of Reference Picture"; + case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "Max Number of Reference Pics"; case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: return "H263 I-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: return "H263 Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: return "H263 Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: return "H264 I-Frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "H264 P frame QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "H264 B frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "H264 P-Frame QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "H264 B-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: return "H264 Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: return "H264 Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: return "H264 8x8 Transform Enable"; case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: return "H264 CPB Buffer Size"; - case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "H264 Entorpy Mode"; - case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: return "H264 I Period"; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "H264 Entropy Mode"; + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: return "H264 I-Frame Period"; case V4L2_CID_MPEG_VIDEO_H264_LEVEL: return "H264 Level"; case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: return "H264 Loop Filter Alpha Offset"; case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: return "H264 Loop Filter Beta Offset"; @@ -534,16 +535,16 @@ const char *v4l2_ctrl_get_name(u32 id) 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_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"; + 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"; case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: return "MPEG4 Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: return "MPEG4 Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return "MPEG4 Level"; case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: return "MPEG4 Profile"; case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: return "Quarter Pixel Search Enable"; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "The Maximum Bytes Per Slice"; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "The Number of MB in a Slice"; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "The Slice Partitioning Method"; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: return "Maximum Bytes in a Slice"; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Number of MBs in a Slice"; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Partitioning Method"; case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; /* CAMERA controls */ @@ -579,7 +580,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled"; case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time"; case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation"; - case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled"; + case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Enabled"; case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain"; case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold"; case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time"; @@ -587,24 +588,24 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled"; case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation"; case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency"; - case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings"; + case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-Emphasis"; case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level"; case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor"; /* Flash controls */ - case V4L2_CID_FLASH_CLASS: return "Flash controls"; - case V4L2_CID_FLASH_LED_MODE: return "LED mode"; - case V4L2_CID_FLASH_STROBE_SOURCE: return "Strobe source"; + case V4L2_CID_FLASH_CLASS: return "Flash Controls"; + case V4L2_CID_FLASH_LED_MODE: return "LED Mode"; + case V4L2_CID_FLASH_STROBE_SOURCE: return "Strobe Source"; case V4L2_CID_FLASH_STROBE: return "Strobe"; - case V4L2_CID_FLASH_STROBE_STOP: return "Stop strobe"; - case V4L2_CID_FLASH_STROBE_STATUS: return "Strobe status"; - case V4L2_CID_FLASH_TIMEOUT: return "Strobe timeout"; - case V4L2_CID_FLASH_INTENSITY: return "Intensity, flash mode"; - case V4L2_CID_FLASH_TORCH_INTENSITY: return "Intensity, torch mode"; - case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, indicator"; + case V4L2_CID_FLASH_STROBE_STOP: return "Stop Strobe"; + case V4L2_CID_FLASH_STROBE_STATUS: return "Strobe Status"; + case V4L2_CID_FLASH_TIMEOUT: return "Strobe Timeout"; + case V4L2_CID_FLASH_INTENSITY: return "Intensity, Flash Mode"; + case V4L2_CID_FLASH_TORCH_INTENSITY: return "Intensity, Torch Mode"; + case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, Indicator"; case V4L2_CID_FLASH_FAULT: return "Faults"; case V4L2_CID_FLASH_CHARGE: return "Charge"; - case V4L2_CID_FLASH_READY: return "Ready to strobe"; + case V4L2_CID_FLASH_READY: return "Ready to Strobe"; default: return NULL; @@ -1108,8 +1109,8 @@ int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, INIT_LIST_HEAD(&hdl->ctrls); INIT_LIST_HEAD(&hdl->ctrl_refs); hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; - hdl->buckets = kzalloc(sizeof(hdl->buckets[0]) * hdl->nr_of_buckets, - GFP_KERNEL); + hdl->buckets = kcalloc(hdl->nr_of_buckets, sizeof(hdl->buckets[0]), + GFP_KERNEL); hdl->error = hdl->buckets ? 0 : -ENOMEM; return hdl->error; } diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index a5c9ed128b97..96e9615663e9 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -146,10 +146,9 @@ static void v4l2_device_release(struct device *cd) struct v4l2_device *v4l2_dev = vdev->v4l2_dev; mutex_lock(&videodev_lock); - if (video_device[vdev->minor] != vdev) { - mutex_unlock(&videodev_lock); + if (WARN_ON(video_device[vdev->minor] != vdev)) { /* should not happen */ - WARN_ON(1); + mutex_unlock(&videodev_lock); return; } @@ -168,7 +167,7 @@ static void v4l2_device_release(struct device *cd) mutex_unlock(&videodev_lock); #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + if (v4l2_dev && v4l2_dev->mdev && vdev->vfl_type != VFL_TYPE_SUBDEV) media_device_unregister_entity(&vdev->entity); #endif @@ -556,8 +555,7 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->minor = -1; /* the release callback MUST be present */ - WARN_ON(!vdev->release); - if (!vdev->release) + if (WARN_ON(!vdev->release)) return -EINVAL; /* v4l2_fh support */ @@ -703,8 +701,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; - vdev->entity.v4l.major = VIDEO_MAJOR; - vdev->entity.v4l.minor = vdev->minor; + vdev->entity.info.v4l.major = VIDEO_MAJOR; + vdev->entity.info.v4l.minor = vdev->minor; ret = media_device_register_entity(vdev->v4l2_dev->mdev, &vdev->entity); if (ret < 0) diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 0edd618b9ddf..1f203b85a637 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -234,8 +234,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) goto clean_up; } #if defined(CONFIG_MEDIA_CONTROLLER) - sd->entity.v4l.major = VIDEO_MAJOR; - sd->entity.v4l.minor = vdev->minor; + sd->entity.info.v4l.major = VIDEO_MAJOR; + sd->entity.info.v4l.minor = vdev->minor; #endif sd->devnode = vdev; } diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index e1da8fc9dd2f..3f623859a337 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -238,6 +238,8 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", + [_IOC_NR(VIDIOC_G_SELECTION)] = "VIDIOC_G_SELECTION", + [_IOC_NR(VIDIOC_S_SELECTION)] = "VIDIOC_S_SELECTION", [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", @@ -1547,11 +1549,32 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_crop *p = arg; - if (!ops->vidioc_g_crop) + if (!ops->vidioc_g_crop && !ops->vidioc_g_selection) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = ops->vidioc_g_crop(file, fh, p); + + if (ops->vidioc_g_crop) { + ret = ops->vidioc_g_crop(file, fh, p); + } else { + /* simulate capture crop using selection api */ + struct v4l2_selection s = { + .type = p->type, + }; + + /* crop means compose for output devices */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + else + s.target = V4L2_SEL_TGT_CROP_ACTIVE; + + ret = ops->vidioc_g_selection(file, fh, &s); + + /* copying results to old structure on success */ + if (!ret) + p->c = s.r; + } + if (!ret) dbgrect(vfd, "", &p->c); break; @@ -1560,15 +1583,65 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_crop *p = arg; - if (!ops->vidioc_s_crop) + if (!ops->vidioc_s_crop && !ops->vidioc_s_selection) break; + if (ret_prio) { ret = ret_prio; break; } dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); dbgrect(vfd, "", &p->c); - ret = ops->vidioc_s_crop(file, fh, p); + + if (ops->vidioc_s_crop) { + ret = ops->vidioc_s_crop(file, fh, p); + } else { + /* simulate capture crop using selection api */ + struct v4l2_selection s = { + .type = p->type, + .r = p->c, + }; + + /* crop means compose for output devices */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + else + s.target = V4L2_SEL_TGT_CROP_ACTIVE; + + ret = ops->vidioc_s_selection(file, fh, &s); + } + break; + } + case VIDIOC_G_SELECTION: + { + struct v4l2_selection *p = arg; + + if (!ops->vidioc_g_selection) + break; + + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + + ret = ops->vidioc_g_selection(file, fh, p); + if (!ret) + dbgrect(vfd, "", &p->r); + break; + } + case VIDIOC_S_SELECTION: + { + struct v4l2_selection *p = arg; + + if (!ops->vidioc_s_selection) + break; + + if (ret_prio) { + ret = ret_prio; + break; + } + + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + dbgrect(vfd, "", &p->r); + + ret = ops->vidioc_s_selection(file, fh, p); break; } case VIDIOC_CROPCAP: @@ -1576,11 +1649,42 @@ static long __video_do_ioctl(struct file *file, struct v4l2_cropcap *p = arg; /*FIXME: Should also show v4l2_fract pixelaspect */ - if (!ops->vidioc_cropcap) + if (!ops->vidioc_cropcap && !ops->vidioc_g_selection) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = ops->vidioc_cropcap(file, fh, p); + if (ops->vidioc_cropcap) { + ret = ops->vidioc_cropcap(file, fh, p); + } else { + struct v4l2_selection s = { .type = p->type }; + + /* obtaining bounds */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS; + else + s.target = V4L2_SEL_TGT_CROP_BOUNDS; + + ret = ops->vidioc_g_selection(file, fh, &s); + if (ret) + break; + p->bounds = s.r; + + /* obtaining defrect */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; + else + s.target = V4L2_SEL_TGT_CROP_DEFAULT; + + ret = ops->vidioc_g_selection(file, fh, &s); + if (ret) + break; + p->defrect = s.r; + + /* setting trivial pixelaspect */ + p->pixelaspect.numerator = 1; + p->pixelaspect.denominator = 1; + } + if (!ret) { dbgrect(vfd, "bounds ", &p->bounds); dbgrect(vfd, "defrect ", &p->defrect); @@ -1767,6 +1871,7 @@ static long __video_do_ioctl(struct file *file, case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *p = arg; + enum v4l2_tuner_type type; if (!ops->vidioc_s_frequency) break; @@ -1774,9 +1879,14 @@ static long __video_do_ioctl(struct file *file, ret = ret_prio; break; } + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", p->tuner, p->type, p->frequency); - ret = ops->vidioc_s_frequency(file, fh, p); + if (p->type != type) + ret = -EINVAL; + else + ret = ops->vidioc_s_frequency(file, fh, p); break; } case VIDIOC_G_SLICED_VBI_CAP: @@ -2226,6 +2336,10 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, struct v4l2_ext_controls *ctrls = parg; if (ctrls->count != 0) { + if (ctrls->count > V4L2_CID_MAX_CTRLS) { + ret = -EINVAL; + break; + } *user_ptr = (void __user *)ctrls->controls; *kernel_ptr = (void *)&ctrls->controls; *array_size = sizeof(struct v4l2_ext_control) diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 65ade5f03c2e..41d118ee2de6 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -193,6 +193,10 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return v4l2_subdev_call(sd, core, s_register, p); } #endif + + case VIDIOC_LOG_STATUS: + return v4l2_subdev_call(sd, core, log_status); + #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index cbf13d09b4ac..20f7237b8242 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -34,13 +34,13 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver"); MODULE_LICENSE("GPL"); -static int flip_image; +static bool flip_image; module_param(flip_image, bool, 0444); MODULE_PARM_DESC(flip_image, "If set, the sensor will be instructed to flip the image " "vertically."); -static int override_serial; +static bool override_serial; module_param(override_serial, bool, 0444); MODULE_PARM_DESC(override_serial, "The camera driver will normally refuse to load if " @@ -156,14 +156,10 @@ static struct via_format { .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, .bpp = 2, }, - { - .desc = "RGB 565", - .pixelformat = V4L2_PIX_FMT_RGB565, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, - .bpp = 2, - }, /* RGB444 and Bayer should be doable, but have never been - tested with this driver. */ + tested with this driver. RGB565 seems to work at the default + resolution, but results in color corruption when being scaled by + viacam_set_scaled(), and is disabled as a result. */ }; #define N_VIA_FMTS ARRAY_SIZE(via_formats) @@ -1504,14 +1500,4 @@ static struct platform_driver viacam_driver = { .remove = viacam_remove, }; -static int viacam_init(void) -{ - return platform_driver_register(&viacam_driver); -} -module_init(viacam_init); - -static void viacam_exit(void) -{ - platform_driver_unregister(&viacam_driver); -} -module_exit(viacam_exit); +module_platform_driver(viacam_driver); diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index 3de7c7e4402d..59cb54aa2946 100644 --- a/drivers/media/video/videobuf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -226,9 +226,10 @@ static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, } /* register network adapter */ - dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); - if (dvb->net.dvbdev == NULL) { - result = -ENOMEM; + result = dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_net_init failed (errno = %d)\n", + dvb->name, result); goto fail_fe_conn; } return 0; diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 95a3f5e82aef..2e8f1df775b6 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -30,7 +30,7 @@ module_param(debug, int, 0644); printk(KERN_DEBUG "vb2: " fmt, ## arg); \ } while (0) -#define call_memop(q, plane, op, args...) \ +#define call_memop(q, op, args...) \ (((q)->mem_ops->op) ? \ ((q)->mem_ops->op(args)) : 0) @@ -52,7 +52,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) /* Allocate memory for all planes in this buffer */ for (plane = 0; plane < vb->num_planes; ++plane) { - mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], + mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], q->plane_sizes[plane]); if (IS_ERR_OR_NULL(mem_priv)) goto free; @@ -65,8 +65,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) return 0; free: /* Free already allocated memory if one of the allocations failed */ - for (; plane > 0; --plane) - call_memop(q, plane, put, vb->planes[plane - 1].mem_priv); + for (; plane > 0; --plane) { + call_memop(q, put, vb->planes[plane - 1].mem_priv); + vb->planes[plane - 1].mem_priv = NULL; + } return -ENOMEM; } @@ -80,10 +82,10 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb) unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { - call_memop(q, plane, put, vb->planes[plane].mem_priv); + call_memop(q, put, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; - dprintk(3, "Freed plane %d of buffer %d\n", - plane, vb->v4l2_buf.index); + dprintk(3, "Freed plane %d of buffer %d\n", plane, + vb->v4l2_buf.index); } } @@ -97,12 +99,9 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { - void *mem_priv = vb->planes[plane].mem_priv; - - if (mem_priv) { - call_memop(q, plane, put_userptr, mem_priv); - vb->planes[plane].mem_priv = NULL; - } + if (vb->planes[plane].mem_priv) + call_memop(q, put_userptr, vb->planes[plane].mem_priv); + vb->planes[plane].mem_priv = NULL; } } @@ -305,7 +304,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) * case anyway. If num_users() returns more than 1, * we are not the only user of the plane's memory. */ - if (mem_priv && call_memop(q, plane, num_users, mem_priv) > 1) + if (mem_priv && call_memop(q, num_users, mem_priv) > 1) return true; } return false; @@ -731,10 +730,10 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) { struct vb2_queue *q = vb->vb2_queue; - if (plane_no > vb->num_planes) + if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_memop(q, plane_no, vaddr, vb->planes[plane_no].mem_priv); + return call_memop(q, vaddr, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_vaddr); @@ -754,10 +753,10 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) { struct vb2_queue *q = vb->vb2_queue; - if (plane_no > vb->num_planes) + if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_memop(q, plane_no, cookie, vb->planes[plane_no].mem_priv); + return call_memop(q, cookie, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_cookie); @@ -883,7 +882,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) for (plane = 0; plane < vb->num_planes; ++plane) { /* Skip the plane if already verified */ - if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr + if (vb->v4l2_planes[plane].m.userptr && + vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr && vb->v4l2_planes[plane].length == planes[plane].length) continue; @@ -898,27 +898,23 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) /* Release previously acquired memory if present */ if (vb->planes[plane].mem_priv) - call_memop(q, plane, put_userptr, - vb->planes[plane].mem_priv); + call_memop(q, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].length = 0; /* Acquire each plane's memory */ - if (q->mem_ops->get_userptr) { - mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane], - planes[plane].m.userptr, - planes[plane].length, - write); - if (IS_ERR(mem_priv)) { - dprintk(1, "qbuf: failed acquiring userspace " + mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane], + planes[plane].m.userptr, + planes[plane].length, write); + if (IS_ERR_OR_NULL(mem_priv)) { + dprintk(1, "qbuf: failed acquiring userspace " "memory for plane %d\n", plane); - ret = PTR_ERR(mem_priv); - goto err; - } - vb->planes[plane].mem_priv = mem_priv; + ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL; + goto err; } + vb->planes[plane].mem_priv = mem_priv; } /* @@ -943,8 +939,7 @@ err: /* In case of errors, release planes that were already acquired */ for (plane = 0; plane < vb->num_planes; ++plane) { if (vb->planes[plane].mem_priv) - call_memop(q, plane, put_userptr, - vb->planes[plane].mem_priv); + call_memop(q, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].length = 0; @@ -1081,46 +1076,76 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf); */ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) { + struct rw_semaphore *mmap_sem = NULL; struct vb2_buffer *vb; - int ret; + int ret = 0; + + /* + * In case of user pointer buffers vb2 allocator needs to get direct + * access to userspace pages. This requires getting read access on + * mmap semaphore in the current process structure. The same + * semaphore is taken before calling mmap operation, while both mmap + * and qbuf are called by the driver or v4l2 core with driver's lock + * held. To avoid a AB-BA deadlock (mmap_sem then driver's lock in + * mmap and driver's lock then mmap_sem in qbuf) the videobuf2 core + * release driver's lock, takes mmap_sem and then takes again driver's + * lock. + * + * To avoid race with other vb2 calls, which might be called after + * releasing driver's lock, this operation is performed at the + * beggining of qbuf processing. This way the queue status is + * consistent after getting driver's lock back. + */ + if (q->memory == V4L2_MEMORY_USERPTR) { + mmap_sem = ¤t->mm->mmap_sem; + call_qop(q, wait_prepare, q); + down_read(mmap_sem); + call_qop(q, wait_finish, q); + } if (q->fileio) { dprintk(1, "qbuf: file io in progress\n"); - return -EBUSY; + ret = -EBUSY; + goto unlock; } if (b->type != q->type) { dprintk(1, "qbuf: invalid buffer type\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } if (b->index >= q->num_buffers) { dprintk(1, "qbuf: buffer index out of range\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } vb = q->bufs[b->index]; if (NULL == vb) { /* Should never happen */ dprintk(1, "qbuf: buffer is NULL\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } if (b->memory != q->memory) { dprintk(1, "qbuf: invalid memory type\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } switch (vb->state) { case VB2_BUF_STATE_DEQUEUED: ret = __buf_prepare(vb, b); if (ret) - return ret; + goto unlock; case VB2_BUF_STATE_PREPARED: break; default: dprintk(1, "qbuf: buffer already in use\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } /* @@ -1141,7 +1166,10 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) __fill_v4l2_buffer(vb, b); dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); - return 0; +unlock: + if (mmap_sem) + up_read(mmap_sem); + return ret; } EXPORT_SYMBOL_GPL(vb2_qbuf); @@ -1521,7 +1549,6 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) { unsigned long off = vma->vm_pgoff << PAGE_SHIFT; - struct vb2_plane *vb_plane; struct vb2_buffer *vb; unsigned int buffer, plane; int ret; @@ -1558,9 +1585,8 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) return ret; vb = q->bufs[buffer]; - vb_plane = &vb->planes[plane]; - ret = q->mem_ops->mmap(vb_plane->mem_priv, vma); + ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma); if (ret) return ret; diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c index 3bad8b105fea..25c3b360e1ad 100644 --- a/drivers/media/video/videobuf2-dma-sg.c +++ b/drivers/media/video/videobuf2-dma-sg.c @@ -140,7 +140,6 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, if (!buf->pages) goto userptr_fail_pages_array_alloc; - down_read(¤t->mm->mmap_sem); num_pages_from_user = get_user_pages(current, current->mm, vaddr & PAGE_MASK, buf->sg_desc.num_pages, @@ -148,7 +147,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, 1, /* force */ buf->pages, NULL); - up_read(¤t->mm->mmap_sem); + if (num_pages_from_user != buf->sg_desc.num_pages) goto userptr_fail_get_user_pages; diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c index 71a7a78c3fc0..c41cb60245d6 100644 --- a/drivers/media/video/videobuf2-memops.c +++ b/drivers/media/video/videobuf2-memops.c @@ -100,29 +100,26 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, unsigned long offset, start, end; unsigned long this_pfn, prev_pfn; dma_addr_t pa = 0; - int ret = -EFAULT; start = vaddr; offset = start & ~PAGE_MASK; end = start + size; - down_read(&mm->mmap_sem); vma = find_vma(mm, start); if (vma == NULL || vma->vm_end < end) - goto done; + return -EFAULT; for (prev_pfn = 0; start < end; start += PAGE_SIZE) { - ret = follow_pfn(vma, start, &this_pfn); + int ret = follow_pfn(vma, start, &this_pfn); if (ret) - goto done; + return ret; if (prev_pfn == 0) pa = this_pfn << PAGE_SHIFT; - else if (this_pfn != prev_pfn + 1) { - ret = -EFAULT; - goto done; - } + else if (this_pfn != prev_pfn + 1) + return -EFAULT; + prev_pfn = this_pfn; } @@ -130,16 +127,11 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, * Memory is contigous, lock vma and return to the caller */ *res_vma = vb2_get_vma(vma); - if (*res_vma == NULL) { - ret = -ENOMEM; - goto done; - } - *res_pa = pa + offset; - ret = 0; + if (*res_vma == NULL) + return -ENOMEM; -done: - up_read(&mm->mmap_sem); - return ret; + *res_pa = pa + offset; + return 0; } EXPORT_SYMBOL_GPL(vb2_get_contig_userptr); diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c index a3a884234059..4e789a178f8a 100644 --- a/drivers/media/video/videobuf2-vmalloc.c +++ b/drivers/media/video/videobuf2-vmalloc.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/mm.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/vmalloc.h> @@ -20,7 +21,10 @@ struct vb2_vmalloc_buf { void *vaddr; + struct page **pages; + int write; unsigned long size; + unsigned int n_pages; atomic_t refcount; struct vb2_vmarea_handler handler; }; @@ -31,7 +35,7 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size) { struct vb2_vmalloc_buf *buf; - buf = kzalloc(sizeof *buf, GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return NULL; @@ -42,15 +46,12 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size) buf->handler.arg = buf; if (!buf->vaddr) { - printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size); + pr_debug("vmalloc of size %ld failed\n", buf->size); kfree(buf); return NULL; } atomic_inc(&buf->refcount); - printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n", - buf->size, buf->vaddr); - return buf; } @@ -59,21 +60,84 @@ static void vb2_vmalloc_put(void *buf_priv) struct vb2_vmalloc_buf *buf = buf_priv; if (atomic_dec_and_test(&buf->refcount)) { - printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n", - __func__, buf->vaddr); vfree(buf->vaddr); kfree(buf); } } -static void *vb2_vmalloc_vaddr(void *buf_priv) +static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, + unsigned long size, int write) +{ + struct vb2_vmalloc_buf *buf; + unsigned long first, last; + int n_pages, offset; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return NULL; + + buf->write = write; + offset = vaddr & ~PAGE_MASK; + buf->size = size; + + first = vaddr >> PAGE_SHIFT; + last = (vaddr + size - 1) >> PAGE_SHIFT; + buf->n_pages = last - first + 1; + buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL); + if (!buf->pages) + goto fail_pages_array_alloc; + + /* current->mm->mmap_sem is taken by videobuf2 core */ + n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK, + buf->n_pages, write, 1, /* force */ + buf->pages, NULL); + if (n_pages != buf->n_pages) + goto fail_get_user_pages; + + buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL); + if (!buf->vaddr) + goto fail_get_user_pages; + + buf->vaddr += offset; + return buf; + +fail_get_user_pages: + pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages, + buf->n_pages); + while (--n_pages >= 0) + put_page(buf->pages[n_pages]); + kfree(buf->pages); + +fail_pages_array_alloc: + kfree(buf); + + return NULL; +} + +static void vb2_vmalloc_put_userptr(void *buf_priv) { struct vb2_vmalloc_buf *buf = buf_priv; + unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; + unsigned int i; + + if (vaddr) + vm_unmap_ram((void *)vaddr, buf->n_pages); + for (i = 0; i < buf->n_pages; ++i) { + if (buf->write) + set_page_dirty_lock(buf->pages[i]); + put_page(buf->pages[i]); + } + kfree(buf->pages); + kfree(buf); +} - BUG_ON(!buf); +static void *vb2_vmalloc_vaddr(void *buf_priv) +{ + struct vb2_vmalloc_buf *buf = buf_priv; if (!buf->vaddr) { - printk(KERN_ERR "Address of an unallocated plane requested\n"); + pr_err("Address of an unallocated plane requested " + "or cannot map user pointer\n"); return NULL; } @@ -92,13 +156,13 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) int ret; if (!buf) { - printk(KERN_ERR "No memory to map\n"); + pr_err("No memory to map\n"); return -EINVAL; } ret = remap_vmalloc_range(vma, buf->vaddr, 0); if (ret) { - printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret); + pr_err("Remapping vmalloc memory, error: %d\n", ret); return ret; } @@ -121,6 +185,8 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) const struct vb2_mem_ops vb2_vmalloc_memops = { .alloc = vb2_vmalloc_alloc, .put = vb2_vmalloc_put, + .get_userptr = vb2_vmalloc_get_userptr, + .put_userptr = vb2_vmalloc_put_userptr, .vaddr = vb2_vmalloc_vaddr, .mmap = vb2_vmalloc_mmap, .num_users = vb2_vmalloc_num_users, diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 52a0a3736c82..4d7391ec8001 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -708,7 +708,7 @@ static int vino_allocate_buffer(struct vino_framebuffer *fb, size, count); /* allocate memory for table with virtual (page) addresses */ - fb->desc_table.virtual = (unsigned long *) + fb->desc_table.virtual = kmalloc(count * sizeof(unsigned long), GFP_KERNEL); if (!fb->desc_table.virtual) return -ENOMEM; diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c index e8a27844bf39..e86173bd1327 100644 --- a/drivers/media/video/zoran/zoran_device.c +++ b/drivers/media/video/zoran/zoran_device.c @@ -57,7 +57,7 @@ ZR36057_ISR_GIRQ1 | \ ZR36057_ISR_JPEGRepIRQ ) -static int lml33dpath; /* default = 0 +static bool lml33dpath; /* default = 0 * 1 will use digital path in capture * mode instead of analog. It can be * used for picture adjustments using diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index f6d26419445e..4c09ab781ec3 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -1958,7 +1958,6 @@ static int zoran_g_fbuf(struct file *file, void *__fh, mutex_unlock(&zr->resource_lock); fb->fmt.colorspace = V4L2_COLORSPACE_SRGB; fb->fmt.field = V4L2_FIELD_INTERLACED; - fb->flags = V4L2_FBUF_FLAG_OVERLAY; fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; return 0; diff --git a/drivers/media/video/zoran/zr36060.c b/drivers/media/video/zoran/zr36060.c index 5e4f57cbf314..f08546fe2234 100644 --- a/drivers/media/video/zoran/zr36060.c +++ b/drivers/media/video/zoran/zr36060.c @@ -50,7 +50,7 @@ /* amount of chips attached via this driver */ static int zr36060_codecs; -static int low_bitrate; +static bool low_bitrate; module_param(low_bitrate, bool, 0); MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate"); diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 6ce70e9615d3..5319e9b65847 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -21,7 +21,7 @@ #define DRIVER_NAME "jmb38x_ms" -static int no_dma; +static bool no_dma; module_param(no_dma, bool, 0644); enum { diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 668f5c6a0399..29b2172ae18f 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -23,7 +23,7 @@ #include <linux/swab.h> #include "r592.h" -static int r592_enable_dma = 1; +static bool r592_enable_dma = 1; static int debug; static const char *tpc_names[] = { diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index b7aacf47703a..6902b83eb1b4 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -22,7 +22,7 @@ #define DRIVER_NAME "tifm_ms" -static int no_dma; +static bool no_dma; module_param(no_dma, bool, 0644); /* diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index e017dc88622a..f93dd9571c3c 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -12,51 +12,20 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/err.h> +#include <linux/regmap.h> #include <linux/mfd/88pm860x.h> #include <linux/slab.h> -static inline int pm860x_read_device(struct i2c_client *i2c, - int reg, int bytes, void *dest) -{ - unsigned char data; - int ret; - - data = (unsigned char)reg; - ret = i2c_master_send(i2c, &data, 1); - if (ret < 0) - return ret; - - ret = i2c_master_recv(i2c, dest, bytes); - if (ret < 0) - return ret; - return 0; -} - -static inline int pm860x_write_device(struct i2c_client *i2c, - int reg, int bytes, void *src) -{ - unsigned char buf[bytes + 1]; - int ret; - - buf[0] = (unsigned char)reg; - memcpy(&buf[1], src, bytes); - - ret = i2c_master_send(i2c, buf, bytes + 1); - if (ret < 0) - return ret; - return 0; -} - int pm860x_reg_read(struct i2c_client *i2c, int reg) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); - unsigned char data; + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; + unsigned int data; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_read_device(i2c, reg, 1, &data); - mutex_unlock(&chip->io_lock); - + ret = regmap_read(map, reg, &data); if (ret < 0) return ret; else @@ -68,12 +37,11 @@ int pm860x_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_write_device(i2c, reg, 1, &data); - mutex_unlock(&chip->io_lock); - + ret = regmap_write(map, reg, data); return ret; } EXPORT_SYMBOL(pm860x_reg_write); @@ -82,12 +50,11 @@ int pm860x_bulk_read(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_read_device(i2c, reg, count, buf); - mutex_unlock(&chip->io_lock); - + ret = regmap_raw_read(map, reg, buf, count); return ret; } EXPORT_SYMBOL(pm860x_bulk_read); @@ -96,12 +63,11 @@ int pm860x_bulk_write(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_write_device(i2c, reg, count, buf); - mutex_unlock(&chip->io_lock); - + ret = regmap_raw_write(map, reg, buf, count); return ret; } EXPORT_SYMBOL(pm860x_bulk_write); @@ -110,39 +76,78 @@ int pm860x_set_bits(struct i2c_client *i2c, int reg, unsigned char mask, unsigned char data) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); - unsigned char value; + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_read_device(i2c, reg, 1, &value); - if (ret < 0) - goto out; - value &= ~mask; - value |= data; - ret = pm860x_write_device(i2c, reg, 1, &value); -out: - mutex_unlock(&chip->io_lock); + ret = regmap_update_bits(map, reg, mask, data); return ret; } EXPORT_SYMBOL(pm860x_set_bits); +static int read_device(struct i2c_client *i2c, int reg, + int bytes, void *dest) +{ + unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3]; + unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2]; + struct i2c_adapter *adap = i2c->adapter; + struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0}, + {i2c->addr, I2C_M_RD, 0, msgbuf1}, + }; + int num = 1, ret = 0; + + if (dest == NULL) + return -EINVAL; + msgbuf0[0] = (unsigned char)reg; /* command */ + msg[1].len = bytes; + + /* if data needs to read back, num should be 2 */ + if (bytes > 0) + num = 2; + ret = adap->algo->master_xfer(adap, msg, num); + memcpy(dest, msgbuf1, bytes); + if (ret < 0) + return ret; + return 0; +} + +static int write_device(struct i2c_client *i2c, int reg, + int bytes, void *src) +{ + unsigned char buf[bytes + 1]; + struct i2c_adapter *adap = i2c->adapter; + struct i2c_msg msg; + int ret; + + buf[0] = (unsigned char)reg; + memcpy(&buf[1], src, bytes); + msg.addr = i2c->addr; + msg.flags = 0; + msg.len = bytes + 1; + msg.buf = buf; + + ret = adap->algo->master_xfer(adap, &msg, 1); + if (ret < 0) + return ret; + return 0; +} + int pm860x_page_reg_read(struct i2c_client *i2c, int reg) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero = 0; unsigned char data; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_read_device(i2c, reg, 1, &data); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xFA, 0, &zero); + read_device(i2c, 0xFB, 0, &zero); + read_device(i2c, 0xFF, 0, &zero); + ret = read_device(i2c, reg, 1, &data); if (ret >= 0) ret = (int)data; - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_reg_read); @@ -150,18 +155,17 @@ EXPORT_SYMBOL(pm860x_page_reg_read); int pm860x_page_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_write_device(i2c, reg, 1, &data); - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xFA, 0, &zero); + read_device(i2c, 0xFB, 0, &zero); + read_device(i2c, 0xFF, 0, &zero); + ret = write_device(i2c, reg, 1, &data); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_reg_write); @@ -169,18 +173,17 @@ EXPORT_SYMBOL(pm860x_page_reg_write); int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero = 0; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_read_device(i2c, reg, count, buf); - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xfa, 0, &zero); + read_device(i2c, 0xfb, 0, &zero); + read_device(i2c, 0xff, 0, &zero); + ret = read_device(i2c, reg, count, buf); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_bulk_read); @@ -188,18 +191,18 @@ EXPORT_SYMBOL(pm860x_page_bulk_read); int pm860x_page_bulk_write(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero = 0; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_write_device(i2c, reg, count, buf); - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xFA, 0, &zero); + read_device(i2c, 0xFB, 0, &zero); + read_device(i2c, 0xFF, 0, &zero); + ret = write_device(i2c, reg, count, buf); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_bulk_write); @@ -207,25 +210,24 @@ EXPORT_SYMBOL(pm860x_page_bulk_write); int pm860x_page_set_bits(struct i2c_client *i2c, int reg, unsigned char mask, unsigned char data) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero; unsigned char value; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_read_device(i2c, reg, 1, &value); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xFA, 0, &zero); + read_device(i2c, 0xFB, 0, &zero); + read_device(i2c, 0xFF, 0, &zero); + ret = read_device(i2c, reg, 1, &value); if (ret < 0) goto out; value &= ~mask; value |= data; - ret = pm860x_write_device(i2c, reg, 1, &value); + ret = write_device(i2c, reg, 1, &value); out: - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_set_bits); @@ -257,11 +259,17 @@ static int verify_addr(struct i2c_client *i2c) return 0; } +static struct regmap_config pm860x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + static int __devinit pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pm860x_platform_data *pdata = client->dev.platform_data; struct pm860x_chip *chip; + int ret; if (!pdata) { pr_info("No platform data in %s!\n", __func__); @@ -273,10 +281,17 @@ static int __devinit pm860x_probe(struct i2c_client *client, return -ENOMEM; chip->id = verify_addr(client); + chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + kfree(chip); + return ret; + } chip->client = client; i2c_set_clientdata(client, chip); chip->dev = &client->dev; - mutex_init(&chip->io_lock); dev_set_drvdata(chip->dev, chip); /* @@ -290,6 +305,14 @@ static int __devinit pm860x_probe(struct i2c_client *client, chip->companion_addr = pdata->companion_addr; chip->companion = i2c_new_dummy(chip->client->adapter, chip->companion_addr); + chip->regmap_companion = regmap_init_i2c(chip->companion, + &pm860x_regmap_config); + if (IS_ERR(chip->regmap_companion)) { + ret = PTR_ERR(chip->regmap_companion); + dev_err(&chip->companion->dev, + "Failed to allocate register map: %d\n", ret); + return ret; + } i2c_set_clientdata(chip->companion, chip); } @@ -302,7 +325,11 @@ static int __devexit pm860x_remove(struct i2c_client *client) struct pm860x_chip *chip = i2c_get_clientdata(client); pm860x_device_exit(chip); - i2c_unregister_device(chip->companion); + if (chip->companion) { + regmap_exit(chip->regmap_companion); + i2c_unregister_device(chip->companion); + } + regmap_exit(chip->regmap); kfree(chip); return 0; } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 053208d31fb9..cd13e9f2f5e6 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -12,6 +12,7 @@ config MFD_CORE config MFD_88PM860X bool "Support Marvell 88PM8606/88PM8607" depends on I2C=y && GENERIC_HARDIRQS + select REGMAP_I2C select MFD_CORE help This supports for Marvell 88PM8606/88PM8607 Power Management IC. @@ -199,7 +200,7 @@ config MENELAUS config TWL4030_CORE bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN help Say yes here if you have TWL4030 / TWL6030 family chip on your board. This core driver provides register access and IRQ handling @@ -257,7 +258,7 @@ config TWL6040_CORE config MFD_STMPE bool "Support STMicroelectronics STMPE" - depends on I2C=y && GENERIC_HARDIRQS + depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS select MFD_CORE help Support for the STMPE family of I/O Expanders from @@ -278,6 +279,23 @@ config MFD_STMPE Keypad: stmpe-keypad Touchscreen: stmpe-ts +menu "STMPE Interface Drivers" +depends on MFD_STMPE + +config STMPE_I2C + bool "STMPE I2C Inteface" + depends on I2C=y + default y + help + This is used to enable I2C interface of STMPE + +config STMPE_SPI + bool "STMPE SPI Inteface" + depends on SPI_MASTER + help + This is used to enable SPI interface of STMPE +endmenu + config MFD_TC3589X bool "Support Toshiba TC35892 and variants" depends on I2C=y && GENERIC_HARDIRQS @@ -311,7 +329,7 @@ config MFD_TC6387XB config MFD_TC6393XB bool "Support Toshiba TC6393XB" - depends on GPIOLIB && ARM + depends on GPIOLIB && ARM && HAVE_CLK select MFD_CORE select MFD_TMIO help @@ -399,6 +417,17 @@ config MFD_MAX8998 additional drivers must be enabled in order to use the functionality of the device. +config MFD_S5M_CORE + bool "SAMSUNG S5M Series Support" + depends on I2C=y && GENERIC_HARDIRQS + select MFD_CORE + select REGMAP_I2C + help + Support for the Samsung Electronics S5M MFD series. + This driver provies common support for accessing the device, + additional drivers must be enabled in order to use the functionality + of the device + config MFD_WM8400 tristate "Support Wolfson Microelectronics WM8400" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 47591fc7d0d2..b953bab934f7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o obj-$(CONFIG_MFD_STMPE) += stmpe.o +obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o +obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o obj-$(CONFIG_MFD_TC3589X) += tc3589x.o obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o @@ -109,3 +111,4 @@ obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o +obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 02c42015ba51..3aa36eb5c79b 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -407,13 +407,13 @@ static int aat2870_i2c_probe(struct i2c_client *client, aat2870->init(aat2870); if (aat2870->en_pin >= 0) { - ret = gpio_request(aat2870->en_pin, "aat2870-en"); + ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH, + "aat2870-en"); if (ret < 0) { dev_err(&client->dev, "Failed to request GPIO %d\n", aat2870->en_pin); goto out_kfree; } - gpio_direction_output(aat2870->en_pin, 1); } aat2870_enable(aat2870); @@ -468,9 +468,10 @@ static int aat2870_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int aat2870_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct aat2870_data *aat2870 = i2c_get_clientdata(client); aat2870_disable(aat2870); @@ -478,8 +479,9 @@ static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state) return 0; } -static int aat2870_i2c_resume(struct i2c_client *client) +static int aat2870_i2c_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct aat2870_data *aat2870 = i2c_get_clientdata(client); struct aat2870_register *reg = NULL; int i; @@ -495,12 +497,12 @@ static int aat2870_i2c_resume(struct i2c_client *client) return 0; } -#else -#define aat2870_i2c_suspend NULL -#define aat2870_i2c_resume NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend, + aat2870_i2c_resume); -static struct i2c_device_id aat2870_i2c_id_table[] = { +static const struct i2c_device_id aat2870_i2c_id_table[] = { { "aat2870", 0 }, { } }; @@ -510,11 +512,10 @@ static struct i2c_driver aat2870_i2c_driver = { .driver = { .name = "aat2870", .owner = THIS_MODULE, + .pm = &aat2870_pm_ops, }, .probe = aat2870_i2c_probe, .remove = aat2870_i2c_remove, - .suspend = aat2870_i2c_suspend, - .resume = aat2870_i2c_resume, .id_table = aat2870_i2c_id_table, }; diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c index ec10629a0b0b..bd56a764dea1 100644 --- a/drivers/mfd/ab5500-core.c +++ b/drivers/mfd/ab5500-core.c @@ -22,8 +22,8 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/random.h> -#include <linux/mfd/ab5500/ab5500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab5500.h> #include <linux/list.h> #include <linux/bitops.h> #include <linux/spinlock.h> diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c index b7b2d3483fd4..72006940937a 100644 --- a/drivers/mfd/ab5500-debugfs.c +++ b/drivers/mfd/ab5500-debugfs.c @@ -7,8 +7,8 @@ #include <linux/module.h> #include <linux/debugfs.h> #include <linux/seq_file.h> -#include <linux/mfd/ab5500/ab5500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab5500.h> #include <linux/uaccess.h> #include "ab5500-core.h" diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index d3d572b2317b..53e2a80f42fa 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -17,7 +17,7 @@ #include <linux/platform_device.h> #include <linux/mfd/core.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/regulator/ab8500.h> /* diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index dedb7f65cea6..9a0211aa8897 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -13,7 +13,7 @@ #include <linux/platform_device.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> static u32 debug_bank; static u32 debug_address; diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index e985d1701a83..c39fc716e1dc 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -18,9 +18,9 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/list.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500/gpadc.h> +#include <linux/mfd/abx500/ab8500.h> +#include <linux/mfd/abx500/ab8500-gpadc.h> /* * GPADC register offsets diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c index 9be541c6b004..087fecd71ce0 100644 --- a/drivers/mfd/ab8500-i2c.c +++ b/drivers/mfd/ab8500-i2c.c @@ -10,7 +10,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/db8500-prcmu.h> static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index f20feefac190..c28d4eb1eff0 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -7,9 +7,9 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500/sysctrl.h> +#include <linux/mfd/abx500/ab8500.h> +#include <linux/mfd/abx500/ab8500-sysctrl.h> static struct device *sysctrl_dev; diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 155fa0407882..315fef5d466a 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -172,14 +172,14 @@ static void __devexit cs5535_mfd_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id cs5535_mfd_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(cs5535_mfd_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, { 0, } }; MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl); -static struct pci_driver cs5535_mfd_drv = { +static struct pci_driver cs5535_mfd_driver = { .name = DRV_NAME, .id_table = cs5535_mfd_pci_tbl, .probe = cs5535_mfd_probe, @@ -188,12 +188,12 @@ static struct pci_driver cs5535_mfd_drv = { static int __init cs5535_mfd_init(void) { - return pci_register_driver(&cs5535_mfd_drv); + return pci_register_driver(&cs5535_mfd_driver); } static void __exit cs5535_mfd_exit(void) { - pci_unregister_driver(&cs5535_mfd_drv); + pci_unregister_driver(&cs5535_mfd_driver); } module_init(cs5535_mfd_init); diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 8ad88da647b9..7710227d284e 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -308,8 +308,7 @@ static int add_children(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(config_inputs); i++) { int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset; - gpio_request(gpio, config_inputs[i].label); - gpio_direction_input(gpio); + gpio_request_one(gpio, GPIOF_IN, config_inputs[i].label); /* make it easy for userspace to see these */ gpio_export(gpio, false); diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 97c27762174f..b76657eb0c51 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c @@ -485,17 +485,7 @@ static struct platform_driver intel_msic_driver = { }, }; -static int __init intel_msic_init(void) -{ - return platform_driver_register(&intel_msic_driver); -} -module_init(intel_msic_init); - -static void __exit intel_msic_exit(void) -{ - platform_driver_unregister(&intel_msic_driver); -} -module_exit(intel_msic_exit); +module_platform_driver(intel_msic_driver); MODULE_DESCRIPTION("Driver for Intel MSIC"); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 5c2a06acb77f..a9223ed1b7c5 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -33,7 +33,7 @@ /* Module Parameters */ static unsigned int num_modules = CMODIO_MAX_MODULES; -static unsigned char *modules[CMODIO_MAX_MODULES] = { +static char *modules[CMODIO_MAX_MODULES] = { "empty", "empty", "empty", "empty", }; diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index ef39528088f2..87662a17dec6 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -181,7 +181,7 @@ static struct resource jz4740_battery_resources[] = { }, }; -const struct mfd_cell jz4740_adc_cells[] = { +static struct mfd_cell jz4740_adc_cells[] = { { .id = 0, .name = "jz4740-hwmon", @@ -338,17 +338,7 @@ static struct platform_driver jz4740_adc_driver = { }, }; -static int __init jz4740_adc_init(void) -{ - return platform_driver_register(&jz4740_adc_driver); -} -module_init(jz4740_adc_init); - -static void __exit jz4740_adc_exit(void) -{ - platform_driver_unregister(&jz4740_adc_driver); -} -module_exit(jz4740_adc_exit); +module_platform_driver(jz4740_adc_driver); MODULE_DESCRIPTION("JZ4740 SoC ADC driver"); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index ea1169b04779..abc421364a45 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -74,7 +74,7 @@ static struct mfd_cell tunnelcreek_cells[] = { }, }; -static struct pci_device_id lpc_sch_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) }, { 0, } diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 0219115e00c7..d9e4b36edee9 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -161,6 +161,8 @@ static int __devinit max8925_probe(struct i2c_client *client, chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR); i2c_set_clientdata(chip->adc, chip); + device_init_wakeup(&client->dev, 1); + max8925_device_init(chip, pdata); return 0; @@ -177,10 +179,35 @@ static int __devexit max8925_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_SLEEP +static int max8925_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct max8925_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev) && chip->wakeup_flag) + enable_irq_wake(chip->core_irq); + return 0; +} + +static int max8925_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct max8925_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev) && chip->wakeup_flag) + disable_irq_wake(chip->core_irq); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume); + static struct i2c_driver max8925_driver = { .driver = { .name = "max8925", .owner = THIS_MODULE, + .pm = &max8925_pm_ops, }, .probe = max8925_probe, .remove = __devexit_p(max8925_remove), diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 5be53ae9b61c..cb83a7ab53e7 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -43,7 +43,8 @@ static struct mfd_cell max8997_devs[] = { { .name = "max8997-battery", }, { .name = "max8997-haptic", }, { .name = "max8997-muic", }, - { .name = "max8997-flash", }, + { .name = "max8997-led", .id = 1 }, + { .name = "max8997-led", .id = 2 }, }; int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index de4096aee248..6ef56d28c056 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -176,6 +176,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, if (ret < 0) goto err; + device_init_wakeup(max8998->dev, max8998->wakeup); + return ret; err: @@ -210,7 +212,7 @@ static int max8998_suspend(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max8998_dev *max8998 = i2c_get_clientdata(i2c); - if (max8998->wakeup) + if (device_may_wakeup(dev)) irq_set_irq_wake(max8998->irq, 1); return 0; } @@ -220,7 +222,7 @@ static int max8998_resume(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max8998_dev *max8998 = i2c_get_clientdata(i2c); - if (max8998->wakeup) + if (device_may_wakeup(dev)) irq_set_irq_wake(max8998->irq, 0); /* * In LP3974, if IRQ registers are not "read & clear" diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index e9619acc0237..7122386b4e3c 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -18,11 +18,15 @@ #include <linux/spi/spi.h> #include <linux/mfd/core.h> #include <linux/mfd/mc13xxx.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> struct mc13xxx { struct spi_device *spidev; struct mutex lock; int irq; + int flags; irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; void *irqdata[MC13XXX_NUM_IRQ]; @@ -550,10 +554,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) int mc13xxx_get_flags(struct mc13xxx *mc13xxx) { - struct mc13xxx_platform_data *pdata = - dev_get_platdata(&mc13xxx->spidev->dev); - - return pdata->flags; + return mc13xxx->flags; } EXPORT_SYMBOL(mc13xxx_get_flags); @@ -615,13 +616,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, break; case MC13XXX_ADC_MODE_SINGLE_CHAN: - adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK; + adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK; adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT; adc1 |= MC13XXX_ADC1_RAND; break; case MC13XXX_ADC_MODE_MULT_CHAN: - adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK; + adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK; adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT; break; @@ -696,17 +697,67 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); } +#ifdef CONFIG_OF +static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx) +{ + struct device_node *np = mc13xxx->spidev->dev.of_node; + + if (!np) + return -ENODEV; + + if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL)) + mc13xxx->flags |= MC13XXX_USE_ADC; + + if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL)) + mc13xxx->flags |= MC13XXX_USE_CODEC; + + if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL)) + mc13xxx->flags |= MC13XXX_USE_RTC; + + if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL)) + mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN; + + return 0; +} +#else +static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx) +{ + return -ENODEV; +} +#endif + +static const struct spi_device_id mc13xxx_device_id[] = { + { + .name = "mc13783", + .driver_data = MC13XXX_ID_MC13783, + }, { + .name = "mc13892", + .driver_data = MC13XXX_ID_MC13892, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); + +static const struct of_device_id mc13xxx_dt_ids[] = { + { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, }, + { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids); + static int mc13xxx_probe(struct spi_device *spi) { + const struct of_device_id *of_id; + struct spi_driver *sdrv = to_spi_driver(spi->dev.driver); struct mc13xxx *mc13xxx; struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); enum mc13xxx_id id; int ret; - if (!pdata) { - dev_err(&spi->dev, "invalid platform data\n"); - return -EINVAL; - } + of_id = of_match_device(mc13xxx_dt_ids, &spi->dev); + if (of_id) + sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data]; mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); if (!mc13xxx) @@ -749,28 +800,33 @@ err_revision: mc13xxx_unlock(mc13xxx); - if (pdata->flags & MC13XXX_USE_ADC) + if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata) + mc13xxx->flags = pdata->flags; + + if (mc13xxx->flags & MC13XXX_USE_ADC) mc13xxx_add_subdevice(mc13xxx, "%s-adc"); - if (pdata->flags & MC13XXX_USE_CODEC) + if (mc13xxx->flags & MC13XXX_USE_CODEC) mc13xxx_add_subdevice(mc13xxx, "%s-codec"); - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", - &pdata->regulators, sizeof(pdata->regulators)); - - if (pdata->flags & MC13XXX_USE_RTC) + if (mc13xxx->flags & MC13XXX_USE_RTC) mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); - if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) + if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) mc13xxx_add_subdevice(mc13xxx, "%s-ts"); - if (pdata->leds) + if (pdata) { + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", + &pdata->regulators, sizeof(pdata->regulators)); mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds, sizeof(*pdata->leds)); - - if (pdata->buttons) mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton", pdata->buttons, sizeof(*pdata->buttons)); + } else { + mc13xxx_add_subdevice(mc13xxx, "%s-regulator"); + mc13xxx_add_subdevice(mc13xxx, "%s-led"); + mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton"); + } return 0; } @@ -788,25 +844,12 @@ static int __devexit mc13xxx_remove(struct spi_device *spi) return 0; } -static const struct spi_device_id mc13xxx_device_id[] = { - { - .name = "mc13783", - .driver_data = MC13XXX_ID_MC13783, - }, { - .name = "mc13892", - .driver_data = MC13XXX_ID_MC13892, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); - static struct spi_driver mc13xxx_driver = { .id_table = mc13xxx_device_id, .driver = { .name = "mc13xxx", - .bus = &spi_bus_type, .owner = THIS_MODULE, + .of_match_table = mc13xxx_dt_ids, }, .probe = mc13xxx_probe, .remove = __devexit_p(mc13xxx_remove), diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 84815f9ef636..63be60bc3455 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -26,9 +26,35 @@ #define to_mcp(d) container_of(d, struct mcp, attached_device) #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) +static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id, + const char *codec) +{ + while (id->name[0]) { + if (strcmp(codec, id->name) == 0) + return id; + id++; + } + return NULL; +} + +const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp) +{ + const struct mcp_driver *driver = + to_mcp_driver(mcp->attached_device.driver); + + return mcp_match_id(driver->id_table, mcp->codec); +} +EXPORT_SYMBOL(mcp_get_device_id); + static int mcp_bus_match(struct device *dev, struct device_driver *drv) { - return 1; + const struct mcp *mcp = to_mcp(dev); + const struct mcp_driver *driver = to_mcp_driver(drv); + + if (driver->id_table) + return !!mcp_match_id(driver->id_table, mcp->codec); + + return 0; } static int mcp_bus_probe(struct device *dev) @@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev) return ret; } +static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct mcp *mcp = to_mcp(dev); + + add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec); + return 0; +} + static struct bus_type mcp_bus_type = { .name = "mcp", .match = mcp_bus_match, + .uevent = mcp_bus_uevent, .probe = mcp_bus_probe, .remove = mcp_bus_remove, .suspend = mcp_bus_suspend, @@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) } EXPORT_SYMBOL(mcp_host_alloc); -int mcp_host_register(struct mcp *mcp) +int mcp_host_register(struct mcp *mcp, void *pdata) { + if (!mcp->codec) + return -EINVAL; + + mcp->attached_device.platform_data = pdata; dev_set_name(&mcp->attached_device, "mcp0"); + request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec); return device_register(&mcp->attached_device); } EXPORT_SYMBOL(mcp_host_register); diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 2dab02d9ac8b..9adc2eb69492 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -19,6 +19,7 @@ #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/mfd/mcp.h> +#include <linux/io.h> #include <mach/dma.h> #include <mach/hardware.h> @@ -26,12 +27,19 @@ #include <asm/system.h> #include <mach/mcp.h> -#include <mach/assabet.h> - +/* Register offsets */ +#define MCCR0 0x00 +#define MCDR0 0x08 +#define MCDR1 0x0C +#define MCDR2 0x10 +#define MCSR 0x18 +#define MCCR1 0x00 struct mcp_sa11x0 { - u32 mccr0; - u32 mccr1; + u32 mccr0; + u32 mccr1; + unsigned char *mccr0_base; + unsigned char *mccr1_base; }; #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) @@ -39,25 +47,25 @@ struct mcp_sa11x0 { static void mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) { - unsigned int mccr0; + struct mcp_sa11x0 *priv = priv(mcp); divisor /= 32; - mccr0 = Ser4MCCR0 & ~0x00007f00; - mccr0 |= divisor << 8; - Ser4MCCR0 = mccr0; + priv->mccr0 &= ~0x00007f00; + priv->mccr0 |= divisor << 8; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); } static void mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) { - unsigned int mccr0; + struct mcp_sa11x0 *priv = priv(mcp); divisor /= 32; - mccr0 = Ser4MCCR0 & ~0x0000007f; - mccr0 |= divisor; - Ser4MCCR0 = mccr0; + priv->mccr0 &= ~0x0000007f; + priv->mccr0 |= divisor; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); } /* @@ -71,12 +79,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) { int ret = -ETIME; int i; + u32 mcpreg; + struct mcp_sa11x0 *priv = priv(mcp); - Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); + mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff); + __raw_writel(mcpreg, priv->mccr0_base + MCDR2); for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); - if (Ser4MCSR & MCSR_CWC) { + mcpreg = __raw_readl(priv->mccr0_base + MCSR); + if (mcpreg & MCSR_CWC) { ret = 0; break; } @@ -97,13 +109,18 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) { int ret = -ETIME; int i; + u32 mcpreg; + struct mcp_sa11x0 *priv = priv(mcp); - Ser4MCDR2 = reg << 17 | MCDR2_Rd; + mcpreg = reg << 17 | MCDR2_Rd; + __raw_writel(mcpreg, priv->mccr0_base + MCDR2); for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); - if (Ser4MCSR & MCSR_CRC) { - ret = Ser4MCDR2 & 0xffff; + mcpreg = __raw_readl(priv->mccr0_base + MCSR); + if (mcpreg & MCSR_CRC) { + ret = __raw_readl(priv->mccr0_base + MCDR2) + & 0xffff; break; } } @@ -116,13 +133,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) static void mcp_sa11x0_enable(struct mcp *mcp) { - Ser4MCSR = -1; - Ser4MCCR0 |= MCCR0_MCE; + struct mcp_sa11x0 *priv = priv(mcp); + + __raw_writel(-1, priv->mccr0_base + MCSR); + priv->mccr0 |= MCCR0_MCE; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); } static void mcp_sa11x0_disable(struct mcp *mcp) { - Ser4MCCR0 &= ~MCCR0_MCE; + struct mcp_sa11x0 *priv = priv(mcp); + + priv->mccr0 &= ~MCCR0_MCE; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); } /* @@ -142,50 +165,69 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) struct mcp_plat_data *data = pdev->dev.platform_data; struct mcp *mcp; int ret; + struct mcp_sa11x0 *priv; + struct resource *res_mem0, *res_mem1; + u32 size0, size1; if (!data) return -ENODEV; - if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) + if (!data->codec) + return -ENODEV; + + res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem0) + return -ENODEV; + size0 = res_mem0->end - res_mem0->start + 1; + + res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res_mem1) + return -ENODEV; + size1 = res_mem1->end - res_mem1->start + 1; + + if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp")) return -EBUSY; + if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) { + ret = -EBUSY; + goto release; + } + mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); if (!mcp) { ret = -ENOMEM; - goto release; + goto release2; } + priv = priv(mcp); + mcp->owner = THIS_MODULE; mcp->ops = &mcp_sa11x0; mcp->sclk_rate = data->sclk_rate; - mcp->dma_audio_rd = DMA_Ser4MCP0Rd; - mcp->dma_audio_wr = DMA_Ser4MCP0Wr; - mcp->dma_telco_rd = DMA_Ser4MCP1Rd; - mcp->dma_telco_wr = DMA_Ser4MCP1Wr; - mcp->gpio_base = data->gpio_base; + mcp->dma_audio_rd = DDAR_DevAdd(res_mem0->start + MCDR0) + + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev; + mcp->dma_audio_wr = DDAR_DevAdd(res_mem0->start + MCDR0) + + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev; + mcp->dma_telco_rd = DDAR_DevAdd(res_mem0->start + MCDR1) + + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev; + mcp->dma_telco_wr = DDAR_DevAdd(res_mem0->start + MCDR1) + + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev; + mcp->codec = data->codec; platform_set_drvdata(pdev, mcp); - if (machine_is_assabet()) { - ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); - } - - /* - * Setup the PPC unit correctly. - */ - PPDR &= ~PPC_RXD4; - PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; - PSDR |= PPC_RXD4; - PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); - PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); - /* * Initialise device. Note that we initially * set the sampling rate to minimum. */ - Ser4MCSR = -1; - Ser4MCCR1 = data->mccr1; - Ser4MCCR0 = data->mccr0 | 0x7f7f; + priv->mccr0_base = ioremap(res_mem0->start, size0); + priv->mccr1_base = ioremap(res_mem1->start, size1); + + __raw_writel(-1, priv->mccr0_base + MCSR); + priv->mccr1 = data->mccr1; + priv->mccr0 = data->mccr0 | 0x7f7f; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); + __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1); /* * Calculate the read/write timeout (us) from the bit clock @@ -195,36 +237,53 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / mcp->sclk_rate; - ret = mcp_host_register(mcp); + ret = mcp_host_register(mcp, data->codec_pdata); if (ret == 0) goto out; + release2: + release_mem_region(res_mem1->start, size1); release: - release_mem_region(0x80060000, 0x60); + release_mem_region(res_mem0->start, size0); platform_set_drvdata(pdev, NULL); out: return ret; } -static int mcp_sa11x0_remove(struct platform_device *dev) +static int mcp_sa11x0_remove(struct platform_device *pdev) { - struct mcp *mcp = platform_get_drvdata(dev); + struct mcp *mcp = platform_get_drvdata(pdev); + struct mcp_sa11x0 *priv = priv(mcp); + struct resource *res_mem; + u32 size; - platform_set_drvdata(dev, NULL); + platform_set_drvdata(pdev, NULL); mcp_host_unregister(mcp); - release_mem_region(0x80060000, 0x60); + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem) { + size = res_mem->end - res_mem->start + 1; + release_mem_region(res_mem->start, size); + } + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res_mem) { + size = res_mem->end - res_mem->start + 1; + release_mem_region(res_mem->start, size); + } + iounmap(priv->mccr0_base); + iounmap(priv->mccr1_base); return 0; } static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) { struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *priv = priv(mcp); + u32 mccr0; - priv(mcp)->mccr0 = Ser4MCCR0; - priv(mcp)->mccr1 = Ser4MCCR1; - Ser4MCCR0 &= ~MCCR0_MCE; + mccr0 = priv->mccr0 & ~MCCR0_MCE; + __raw_writel(mccr0, priv->mccr0_base + MCCR0); return 0; } @@ -232,9 +291,10 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) static int mcp_sa11x0_resume(struct platform_device *dev) { struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *priv = priv(mcp); - Ser4MCCR1 = priv(mcp)->mccr1; - Ser4MCCR0 = priv(mcp)->mccr0; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); + __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1); return 0; } @@ -251,24 +311,14 @@ static struct platform_driver mcp_sa11x0_driver = { .resume = mcp_sa11x0_resume, .driver = { .name = "sa11x0-mcp", + .owner = THIS_MODULE, }, }; /* * This needs re-working */ -static int __init mcp_sa11x0_init(void) -{ - return platform_driver_register(&mcp_sa11x0_driver); -} - -static void __exit mcp_sa11x0_exit(void) -{ - platform_driver_unregister(&mcp_sa11x0_driver); -} - -module_init(mcp_sa11x0_init); -module_exit(mcp_sa11x0_exit); +module_platform_driver(mcp_sa11x0_driver); MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 3f565ef3e149..68ac2c55d5ae 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -503,19 +503,13 @@ static void omap_usbhs_init(struct device *dev) spin_lock_irqsave(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { - gpio_request(pdata->ehci_data->reset_gpio_port[0], - "USB1 PHY reset"); - gpio_direction_output - (pdata->ehci_data->reset_gpio_port[0], 0); - } + if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) + gpio_request_one(pdata->ehci_data->reset_gpio_port[0], + GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { - gpio_request(pdata->ehci_data->reset_gpio_port[1], - "USB2 PHY reset"); - gpio_direction_output - (pdata->ehci_data->reset_gpio_port[1], 0); - } + if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) + gpio_request_one(pdata->ehci_data->reset_gpio_port[1], + GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index aed0d2a9b032..3927c17e4175 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -249,17 +249,7 @@ static struct platform_driver pcf50633_adc_driver = { .remove = __devexit_p(pcf50633_adc_remove), }; -static int __init pcf50633_adc_init(void) -{ - return platform_driver_register(&pcf50633_adc_driver); -} -module_init(pcf50633_adc_init); - -static void __exit pcf50633_adc_exit(void) -{ - platform_driver_unregister(&pcf50633_adc_driver); -} -module_exit(pcf50633_adc_exit); +module_platform_driver(pcf50633_adc_driver); MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); MODULE_DESCRIPTION("PCF50633 adc driver"); diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c new file mode 100644 index 000000000000..e075c113eec6 --- /dev/null +++ b/drivers/mfd/s5m-core.c @@ -0,0 +1,176 @@ +/* + * s5m87xx.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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/pm_runtime.h> +#include <linux/mutex.h> +#include <linux/mfd/core.h> +#include <linux/mfd/s5m87xx/s5m-core.h> +#include <linux/mfd/s5m87xx/s5m-pmic.h> +#include <linux/mfd/s5m87xx/s5m-rtc.h> +#include <linux/regmap.h> + +static struct mfd_cell s5m87xx_devs[] = { + { + .name = "s5m8767-pmic", + }, { + .name = "s5m-rtc", + }, +}; + +int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest) +{ + return regmap_read(s5m87xx->regmap, reg, dest); +} +EXPORT_SYMBOL_GPL(s5m_reg_read); + +int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf) +{ + return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);; +} +EXPORT_SYMBOL_GPL(s5m_bulk_read); + +int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value) +{ + return regmap_write(s5m87xx->regmap, reg, value); +} +EXPORT_SYMBOL_GPL(s5m_reg_write); + +int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf) +{ + return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16)); +} +EXPORT_SYMBOL_GPL(s5m_bulk_write); + +int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask) +{ + return regmap_update_bits(s5m87xx->regmap, reg, mask, val); +} +EXPORT_SYMBOL_GPL(s5m_reg_update); + +static struct regmap_config s5m_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int s5m87xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct s5m_platform_data *pdata = i2c->dev.platform_data; + struct s5m87xx_dev *s5m87xx; + int ret = 0; + int error; + + s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL); + if (s5m87xx == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, s5m87xx); + s5m87xx->dev = &i2c->dev; + s5m87xx->i2c = i2c; + s5m87xx->irq = i2c->irq; + s5m87xx->type = id->driver_data; + + if (pdata) { + s5m87xx->device_type = pdata->device_type; + s5m87xx->ono = pdata->ono; + s5m87xx->irq_base = pdata->irq_base; + s5m87xx->wakeup = pdata->wakeup; + } + + s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config); + if (IS_ERR(s5m87xx->regmap)) { + error = PTR_ERR(s5m87xx->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + error); + goto err; + } + + s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); + i2c_set_clientdata(s5m87xx->rtc, s5m87xx); + + if (pdata->cfg_pmic_irq) + pdata->cfg_pmic_irq(); + + s5m_irq_init(s5m87xx); + + pm_runtime_set_active(s5m87xx->dev); + + ret = mfd_add_devices(s5m87xx->dev, -1, + s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs), + NULL, 0); + + if (ret < 0) + goto err; + + return ret; + +err: + mfd_remove_devices(s5m87xx->dev); + s5m_irq_exit(s5m87xx); + i2c_unregister_device(s5m87xx->rtc); + regmap_exit(s5m87xx->regmap); + kfree(s5m87xx); + return ret; +} + +static int s5m87xx_i2c_remove(struct i2c_client *i2c) +{ + struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c); + + mfd_remove_devices(s5m87xx->dev); + s5m_irq_exit(s5m87xx); + i2c_unregister_device(s5m87xx->rtc); + regmap_exit(s5m87xx->regmap); + kfree(s5m87xx); + return 0; +} + +static const struct i2c_device_id s5m87xx_i2c_id[] = { + { "s5m87xx", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id); + +static struct i2c_driver s5m87xx_i2c_driver = { + .driver = { + .name = "s5m87xx", + .owner = THIS_MODULE, + }, + .probe = s5m87xx_i2c_probe, + .remove = s5m87xx_i2c_remove, + .id_table = s5m87xx_i2c_id, +}; + +static int __init s5m87xx_i2c_init(void) +{ + return i2c_add_driver(&s5m87xx_i2c_driver); +} + +subsys_initcall(s5m87xx_i2c_init); + +static void __exit s5m87xx_i2c_exit(void) +{ + i2c_del_driver(&s5m87xx_i2c_driver); +} +module_exit(s5m87xx_i2c_exit); + +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_DESCRIPTION("Core support for the S5M MFD"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c new file mode 100644 index 000000000000..de76dfb6f0ad --- /dev/null +++ b/drivers/mfd/s5m-irq.c @@ -0,0 +1,487 @@ +/* + * s5m-irq.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 <linux/device.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mfd/s5m87xx/s5m-core.h> + +struct s5m_irq_data { + int reg; + int mask; +}; + +static struct s5m_irq_data s5m8767_irqs[] = { + [S5M8767_IRQ_PWRR] = { + .reg = 1, + .mask = S5M8767_IRQ_PWRR_MASK, + }, + [S5M8767_IRQ_PWRF] = { + .reg = 1, + .mask = S5M8767_IRQ_PWRF_MASK, + }, + [S5M8767_IRQ_PWR1S] = { + .reg = 1, + .mask = S5M8767_IRQ_PWR1S_MASK, + }, + [S5M8767_IRQ_JIGR] = { + .reg = 1, + .mask = S5M8767_IRQ_JIGR_MASK, + }, + [S5M8767_IRQ_JIGF] = { + .reg = 1, + .mask = S5M8767_IRQ_JIGF_MASK, + }, + [S5M8767_IRQ_LOWBAT2] = { + .reg = 1, + .mask = S5M8767_IRQ_LOWBAT2_MASK, + }, + [S5M8767_IRQ_LOWBAT1] = { + .reg = 1, + .mask = S5M8767_IRQ_LOWBAT1_MASK, + }, + [S5M8767_IRQ_MRB] = { + .reg = 2, + .mask = S5M8767_IRQ_MRB_MASK, + }, + [S5M8767_IRQ_DVSOK2] = { + .reg = 2, + .mask = S5M8767_IRQ_DVSOK2_MASK, + }, + [S5M8767_IRQ_DVSOK3] = { + .reg = 2, + .mask = S5M8767_IRQ_DVSOK3_MASK, + }, + [S5M8767_IRQ_DVSOK4] = { + .reg = 2, + .mask = S5M8767_IRQ_DVSOK4_MASK, + }, + [S5M8767_IRQ_RTC60S] = { + .reg = 3, + .mask = S5M8767_IRQ_RTC60S_MASK, + }, + [S5M8767_IRQ_RTCA1] = { + .reg = 3, + .mask = S5M8767_IRQ_RTCA1_MASK, + }, + [S5M8767_IRQ_RTCA2] = { + .reg = 3, + .mask = S5M8767_IRQ_RTCA2_MASK, + }, + [S5M8767_IRQ_SMPL] = { + .reg = 3, + .mask = S5M8767_IRQ_SMPL_MASK, + }, + [S5M8767_IRQ_RTC1S] = { + .reg = 3, + .mask = S5M8767_IRQ_RTC1S_MASK, + }, + [S5M8767_IRQ_WTSR] = { + .reg = 3, + .mask = S5M8767_IRQ_WTSR_MASK, + }, +}; + +static struct s5m_irq_data s5m8763_irqs[] = { + [S5M8763_IRQ_DCINF] = { + .reg = 1, + .mask = S5M8763_IRQ_DCINF_MASK, + }, + [S5M8763_IRQ_DCINR] = { + .reg = 1, + .mask = S5M8763_IRQ_DCINR_MASK, + }, + [S5M8763_IRQ_JIGF] = { + .reg = 1, + .mask = S5M8763_IRQ_JIGF_MASK, + }, + [S5M8763_IRQ_JIGR] = { + .reg = 1, + .mask = S5M8763_IRQ_JIGR_MASK, + }, + [S5M8763_IRQ_PWRONF] = { + .reg = 1, + .mask = S5M8763_IRQ_PWRONF_MASK, + }, + [S5M8763_IRQ_PWRONR] = { + .reg = 1, + .mask = S5M8763_IRQ_PWRONR_MASK, + }, + [S5M8763_IRQ_WTSREVNT] = { + .reg = 2, + .mask = S5M8763_IRQ_WTSREVNT_MASK, + }, + [S5M8763_IRQ_SMPLEVNT] = { + .reg = 2, + .mask = S5M8763_IRQ_SMPLEVNT_MASK, + }, + [S5M8763_IRQ_ALARM1] = { + .reg = 2, + .mask = S5M8763_IRQ_ALARM1_MASK, + }, + [S5M8763_IRQ_ALARM0] = { + .reg = 2, + .mask = S5M8763_IRQ_ALARM0_MASK, + }, + [S5M8763_IRQ_ONKEY1S] = { + .reg = 3, + .mask = S5M8763_IRQ_ONKEY1S_MASK, + }, + [S5M8763_IRQ_TOPOFFR] = { + .reg = 3, + .mask = S5M8763_IRQ_TOPOFFR_MASK, + }, + [S5M8763_IRQ_DCINOVPR] = { + .reg = 3, + .mask = S5M8763_IRQ_DCINOVPR_MASK, + }, + [S5M8763_IRQ_CHGRSTF] = { + .reg = 3, + .mask = S5M8763_IRQ_CHGRSTF_MASK, + }, + [S5M8763_IRQ_DONER] = { + .reg = 3, + .mask = S5M8763_IRQ_DONER_MASK, + }, + [S5M8763_IRQ_CHGFAULT] = { + .reg = 3, + .mask = S5M8763_IRQ_CHGFAULT_MASK, + }, + [S5M8763_IRQ_LOBAT1] = { + .reg = 4, + .mask = S5M8763_IRQ_LOBAT1_MASK, + }, + [S5M8763_IRQ_LOBAT2] = { + .reg = 4, + .mask = S5M8763_IRQ_LOBAT2_MASK, + }, +}; + +static inline struct s5m_irq_data * +irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq) +{ + return &s5m8767_irqs[irq - s5m87xx->irq_base]; +} + +static void s5m8767_irq_lock(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + + mutex_lock(&s5m87xx->irqlock); +} + +static void s5m8767_irq_sync_unlock(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + int i; + + for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) { + if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) { + s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i]; + s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i, + s5m87xx->irq_masks_cur[i]); + } + } + + mutex_unlock(&s5m87xx->irqlock); +} + +static void s5m8767_irq_unmask(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx, + data->irq); + + s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; +} + +static void s5m8767_irq_mask(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx, + data->irq); + + s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; +} + +static struct irq_chip s5m8767_irq_chip = { + .name = "s5m8767", + .irq_bus_lock = s5m8767_irq_lock, + .irq_bus_sync_unlock = s5m8767_irq_sync_unlock, + .irq_mask = s5m8767_irq_mask, + .irq_unmask = s5m8767_irq_unmask, +}; + +static inline struct s5m_irq_data * +irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq) +{ + return &s5m8763_irqs[irq - s5m87xx->irq_base]; +} + +static void s5m8763_irq_lock(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + + mutex_lock(&s5m87xx->irqlock); +} + +static void s5m8763_irq_sync_unlock(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + int i; + + for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) { + if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) { + s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i]; + s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i, + s5m87xx->irq_masks_cur[i]); + } + } + + mutex_unlock(&s5m87xx->irqlock); +} + +static void s5m8763_irq_unmask(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx, + data->irq); + + s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; +} + +static void s5m8763_irq_mask(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx, + data->irq); + + s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; +} + +static struct irq_chip s5m8763_irq_chip = { + .name = "s5m8763", + .irq_bus_lock = s5m8763_irq_lock, + .irq_bus_sync_unlock = s5m8763_irq_sync_unlock, + .irq_mask = s5m8763_irq_mask, + .irq_unmask = s5m8763_irq_unmask, +}; + + +static irqreturn_t s5m8767_irq_thread(int irq, void *data) +{ + struct s5m87xx_dev *s5m87xx = data; + u8 irq_reg[NUM_IRQ_REGS-1]; + int ret; + int i; + + + ret = s5m_bulk_read(s5m87xx, S5M8767_REG_INT1, + NUM_IRQ_REGS - 1, irq_reg); + if (ret < 0) { + dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n", + ret); + return IRQ_NONE; + } + + for (i = 0; i < NUM_IRQ_REGS - 1; i++) + irq_reg[i] &= ~s5m87xx->irq_masks_cur[i]; + + for (i = 0; i < S5M8767_IRQ_NR; i++) { + if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask) + handle_nested_irq(s5m87xx->irq_base + i); + } + + return IRQ_HANDLED; +} + +static irqreturn_t s5m8763_irq_thread(int irq, void *data) +{ + struct s5m87xx_dev *s5m87xx = data; + u8 irq_reg[NUM_IRQ_REGS]; + int ret; + int i; + + ret = s5m_bulk_read(s5m87xx, S5M8763_REG_IRQ1, + NUM_IRQ_REGS, irq_reg); + if (ret < 0) { + dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n", + ret); + return IRQ_NONE; + } + + for (i = 0; i < NUM_IRQ_REGS; i++) + irq_reg[i] &= ~s5m87xx->irq_masks_cur[i]; + + for (i = 0; i < S5M8763_IRQ_NR; i++) { + if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask) + handle_nested_irq(s5m87xx->irq_base + i); + } + + return IRQ_HANDLED; +} + +int s5m_irq_resume(struct s5m87xx_dev *s5m87xx) +{ + if (s5m87xx->irq && s5m87xx->irq_base){ + switch (s5m87xx->device_type) { + case S5M8763X: + s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx); + break; + case S5M8767X: + s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx); + break; + default: + break; + + } + } + return 0; +} + +int s5m_irq_init(struct s5m87xx_dev *s5m87xx) +{ + int i; + int cur_irq; + int ret = 0; + int type = s5m87xx->device_type; + + if (!s5m87xx->irq) { + dev_warn(s5m87xx->dev, + "No interrupt specified, no interrupts\n"); + s5m87xx->irq_base = 0; + return 0; + } + + if (!s5m87xx->irq_base) { + dev_err(s5m87xx->dev, + "No interrupt base specified, no interrupts\n"); + return 0; + } + + mutex_init(&s5m87xx->irqlock); + + switch (type) { + case S5M8763X: + for (i = 0; i < NUM_IRQ_REGS; i++) { + s5m87xx->irq_masks_cur[i] = 0xff; + s5m87xx->irq_masks_cache[i] = 0xff; + s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i, + 0xff); + } + + s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM1, 0xff); + s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM2, 0xff); + + for (i = 0; i < S5M8763_IRQ_NR; i++) { + cur_irq = i + s5m87xx->irq_base; + irq_set_chip_data(cur_irq, s5m87xx); + irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip, + handle_edge_irq); + irq_set_nested_thread(cur_irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(cur_irq, IRQF_VALID); +#else + irq_set_noprobe(cur_irq); +#endif + } + + ret = request_threaded_irq(s5m87xx->irq, NULL, + s5m8763_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "s5m87xx-irq", s5m87xx); + if (ret) { + dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n", + s5m87xx->irq, ret); + return ret; + } + break; + case S5M8767X: + for (i = 0; i < NUM_IRQ_REGS - 1; i++) { + s5m87xx->irq_masks_cur[i] = 0xff; + s5m87xx->irq_masks_cache[i] = 0xff; + s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i, + 0xff); + } + for (i = 0; i < S5M8767_IRQ_NR; i++) { + cur_irq = i + s5m87xx->irq_base; + irq_set_chip_data(cur_irq, s5m87xx); + if (ret) { + dev_err(s5m87xx->dev, + "Failed to irq_set_chip_data %d: %d\n", + s5m87xx->irq, ret); + return ret; + } + + irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip, + handle_edge_irq); + irq_set_nested_thread(cur_irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(cur_irq, IRQF_VALID); +#else + irq_set_noprobe(cur_irq); +#endif + } + + ret = request_threaded_irq(s5m87xx->irq, NULL, + s5m8767_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "s5m87xx-irq", s5m87xx); + if (ret) { + dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n", + s5m87xx->irq, ret); + return ret; + } + break; + default: + break; + } + + if (!s5m87xx->ono) + return 0; + + switch (type) { + case S5M8763X: + ret = request_threaded_irq(s5m87xx->ono, NULL, + s5m8763_irq_thread, + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "s5m87xx-ono", + s5m87xx); + break; + case S5M8767X: + ret = request_threaded_irq(s5m87xx->ono, NULL, + s5m8767_irq_thread, + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "s5m87xx-ono", s5m87xx); + break; + default: + break; + } + + if (ret) + dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n", + s5m87xx->ono, ret); + + return 0; +} + +void s5m_irq_exit(struct s5m87xx_dev *s5m87xx) +{ + if (s5m87xx->ono) + free_irq(s5m87xx->ono, s5m87xx); + + if (s5m87xx->irq) + free_irq(s5m87xx->irq, s5m87xx); +} diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index df3702c1756d..f4d86117f44a 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1720,7 +1720,7 @@ static int sm501_plat_remove(struct platform_device *dev) return 0; } -static struct pci_device_id sm501_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(sm501_pci_tbl) = { { 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, }, }; diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c new file mode 100644 index 000000000000..373f423b1181 --- /dev/null +++ b/drivers/mfd/stmpe-i2c.c @@ -0,0 +1,109 @@ +/* + * ST Microelectronics MFD: stmpe's i2c client specific driver + * + * Copyright (C) ST-Ericsson SA 2010 + * Copyright (C) ST Microelectronics SA 2011 + * + * License Terms: GNU General Public License, version 2 + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include "stmpe.h" + +static int i2c_reg_read(struct stmpe *stmpe, u8 reg) +{ + struct i2c_client *i2c = stmpe->client; + + return i2c_smbus_read_byte_data(i2c, reg); +} + +static int i2c_reg_write(struct stmpe *stmpe, u8 reg, u8 val) +{ + struct i2c_client *i2c = stmpe->client; + + return i2c_smbus_write_byte_data(i2c, reg, val); +} + +static int i2c_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values) +{ + struct i2c_client *i2c = stmpe->client; + + return i2c_smbus_read_i2c_block_data(i2c, reg, length, values); +} + +static int i2c_block_write(struct stmpe *stmpe, u8 reg, u8 length, + const u8 *values) +{ + struct i2c_client *i2c = stmpe->client; + + return i2c_smbus_write_i2c_block_data(i2c, reg, length, values); +} + +static struct stmpe_client_info i2c_ci = { + .read_byte = i2c_reg_read, + .write_byte = i2c_reg_write, + .read_block = i2c_block_read, + .write_block = i2c_block_write, +}; + +static int __devinit +stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + i2c_ci.data = (void *)id; + i2c_ci.irq = i2c->irq; + i2c_ci.client = i2c; + i2c_ci.dev = &i2c->dev; + + return stmpe_probe(&i2c_ci, id->driver_data); +} + +static int __devexit stmpe_i2c_remove(struct i2c_client *i2c) +{ + struct stmpe *stmpe = dev_get_drvdata(&i2c->dev); + + return stmpe_remove(stmpe); +} + +static const struct i2c_device_id stmpe_i2c_id[] = { + { "stmpe610", STMPE610 }, + { "stmpe801", STMPE801 }, + { "stmpe811", STMPE811 }, + { "stmpe1601", STMPE1601 }, + { "stmpe2401", STMPE2401 }, + { "stmpe2403", STMPE2403 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, stmpe_id); + +static struct i2c_driver stmpe_i2c_driver = { + .driver.name = "stmpe-i2c", + .driver.owner = THIS_MODULE, +#ifdef CONFIG_PM + .driver.pm = &stmpe_dev_pm_ops, +#endif + .probe = stmpe_i2c_probe, + .remove = __devexit_p(stmpe_i2c_remove), + .id_table = stmpe_i2c_id, +}; + +static int __init stmpe_init(void) +{ + return i2c_add_driver(&stmpe_i2c_driver); +} +subsys_initcall(stmpe_init); + +static void __exit stmpe_exit(void) +{ + i2c_del_driver(&stmpe_i2c_driver); +} +module_exit(stmpe_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver"); +MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>"); diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c new file mode 100644 index 000000000000..b58c43c7ea93 --- /dev/null +++ b/drivers/mfd/stmpe-spi.c @@ -0,0 +1,150 @@ +/* + * ST Microelectronics MFD: stmpe's spi client specific driver + * + * Copyright (C) ST Microelectronics SA 2011 + * + * License Terms: GNU General Public License, version 2 + * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics + */ + +#include <linux/spi/spi.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include "stmpe.h" + +#define READ_CMD (1 << 7) + +static int spi_reg_read(struct stmpe *stmpe, u8 reg) +{ + struct spi_device *spi = stmpe->client; + int status = spi_w8r16(spi, reg | READ_CMD); + + return (status < 0) ? status : status >> 8; +} + +static int spi_reg_write(struct stmpe *stmpe, u8 reg, u8 val) +{ + struct spi_device *spi = stmpe->client; + u16 cmd = (val << 8) | reg; + + return spi_write(spi, (const u8 *)&cmd, 2); +} + +static int spi_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values) +{ + int ret, i; + + for (i = 0; i < length; i++) { + ret = spi_reg_read(stmpe, reg + i); + if (ret < 0) + return ret; + *(values + i) = ret; + } + + return 0; +} + +static int spi_block_write(struct stmpe *stmpe, u8 reg, u8 length, + const u8 *values) +{ + int ret = 0, i; + + for (i = length; i > 0; i--, reg++) { + ret = spi_reg_write(stmpe, reg, *(values + i - 1)); + if (ret < 0) + return ret; + } + + return ret; +} + +static void spi_init(struct stmpe *stmpe) +{ + struct spi_device *spi = stmpe->client; + + spi->bits_per_word = 8; + + /* This register is only present for stmpe811 */ + if (stmpe->variant->id_val == 0x0811) + spi_reg_write(stmpe, STMPE811_REG_SPI_CFG, spi->mode); + + if (spi_setup(spi) < 0) + dev_dbg(&spi->dev, "spi_setup failed\n"); +} + +static struct stmpe_client_info spi_ci = { + .read_byte = spi_reg_read, + .write_byte = spi_reg_write, + .read_block = spi_block_read, + .write_block = spi_block_write, + .init = spi_init, +}; + +static int __devinit +stmpe_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + + /* don't exceed max specified rate - 1MHz - Limitation of STMPE */ + if (spi->max_speed_hz > 1000000) { + dev_dbg(&spi->dev, "f(sample) %d KHz?\n", + (spi->max_speed_hz/1000)); + return -EINVAL; + } + + spi_ci.irq = spi->irq; + spi_ci.client = spi; + spi_ci.dev = &spi->dev; + + return stmpe_probe(&spi_ci, id->driver_data); +} + +static int __devexit stmpe_spi_remove(struct spi_device *spi) +{ + struct stmpe *stmpe = dev_get_drvdata(&spi->dev); + + return stmpe_remove(stmpe); +} + +static const struct spi_device_id stmpe_spi_id[] = { + { "stmpe610", STMPE610 }, + { "stmpe801", STMPE801 }, + { "stmpe811", STMPE811 }, + { "stmpe1601", STMPE1601 }, + { "stmpe2401", STMPE2401 }, + { "stmpe2403", STMPE2403 }, + { } +}; +MODULE_DEVICE_TABLE(spi, stmpe_id); + +static struct spi_driver stmpe_spi_driver = { + .driver = { + .name = "stmpe-spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &stmpe_dev_pm_ops, +#endif + }, + .probe = stmpe_spi_probe, + .remove = __devexit_p(stmpe_spi_remove), + .id_table = stmpe_spi_id, +}; + +static int __init stmpe_init(void) +{ + return spi_register_driver(&stmpe_spi_driver); +} +subsys_initcall(stmpe_init); + +static void __exit stmpe_exit(void) +{ + spi_unregister_driver(&stmpe_spi_driver); +} +module_exit(stmpe_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver"); +MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 2963689cf45c..e07947e56b2a 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1,18 +1,20 @@ /* + * ST Microelectronics MFD: stmpe's driver + * * Copyright (C) ST-Ericsson SA 2010 * * License Terms: GNU General Public License, version 2 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ +#include <linux/gpio.h> +#include <linux/export.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/pm.h> #include <linux/slab.h> -#include <linux/i2c.h> #include <linux/mfd/core.h> -#include <linux/mfd/stmpe.h> #include "stmpe.h" static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) @@ -29,10 +31,9 @@ static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg) { int ret; - ret = i2c_smbus_read_byte_data(stmpe->i2c, reg); + ret = stmpe->ci->read_byte(stmpe, reg); if (ret < 0) - dev_err(stmpe->dev, "failed to read reg %#x: %d\n", - reg, ret); + dev_err(stmpe->dev, "failed to read reg %#x: %d\n", reg, ret); dev_vdbg(stmpe->dev, "rd: reg %#x => data %#x\n", reg, ret); @@ -45,10 +46,9 @@ static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val) dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val); - ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val); + ret = stmpe->ci->write_byte(stmpe, reg, val); if (ret < 0) - dev_err(stmpe->dev, "failed to write reg %#x: %d\n", - reg, ret); + dev_err(stmpe->dev, "failed to write reg %#x: %d\n", reg, ret); return ret; } @@ -72,10 +72,9 @@ static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length, { int ret; - ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values); + ret = stmpe->ci->read_block(stmpe, reg, length, values); if (ret < 0) - dev_err(stmpe->dev, "failed to read regs %#x: %d\n", - reg, ret); + dev_err(stmpe->dev, "failed to read regs %#x: %d\n", reg, ret); dev_vdbg(stmpe->dev, "rd: reg %#x (%d) => ret %#x\n", reg, length, ret); stmpe_dump_bytes("stmpe rd: ", values, length); @@ -91,11 +90,9 @@ static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length, dev_vdbg(stmpe->dev, "wr: regs %#x (%d)\n", reg, length); stmpe_dump_bytes("stmpe wr: ", values, length); - ret = i2c_smbus_write_i2c_block_data(stmpe->i2c, reg, length, - values); + ret = stmpe->ci->write_block(stmpe, reg, length, values); if (ret < 0) - dev_err(stmpe->dev, "failed to write regs %#x: %d\n", - reg, ret); + dev_err(stmpe->dev, "failed to write regs %#x: %d\n", reg, ret); return ret; } @@ -245,12 +242,14 @@ int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block) u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB]; int af_bits = variant->af_bits; int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8); - int afperreg = 8 / af_bits; int mask = (1 << af_bits) - 1; u8 regs[numregs]; - int af; - int ret; + int af, afperreg, ret; + + if (!variant->get_altfunc) + return 0; + afperreg = 8 / af_bits; mutex_lock(&stmpe->lock); ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO); @@ -325,7 +324,51 @@ static struct mfd_cell stmpe_keypad_cell = { }; /* - * Touchscreen (STMPE811) + * STMPE801 + */ +static const u8 stmpe801_regs[] = { + [STMPE_IDX_CHIP_ID] = STMPE801_REG_CHIP_ID, + [STMPE_IDX_ICR_LSB] = STMPE801_REG_SYS_CTRL, + [STMPE_IDX_GPMR_LSB] = STMPE801_REG_GPIO_MP_STA, + [STMPE_IDX_GPSR_LSB] = STMPE801_REG_GPIO_SET_PIN, + [STMPE_IDX_GPCR_LSB] = STMPE801_REG_GPIO_SET_PIN, + [STMPE_IDX_GPDR_LSB] = STMPE801_REG_GPIO_DIR, + [STMPE_IDX_IEGPIOR_LSB] = STMPE801_REG_GPIO_INT_EN, + [STMPE_IDX_ISGPIOR_MSB] = STMPE801_REG_GPIO_INT_STA, + +}; + +static struct stmpe_variant_block stmpe801_blocks[] = { + { + .cell = &stmpe_gpio_cell, + .irq = 0, + .block = STMPE_BLOCK_GPIO, + }, +}; + +static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks, + bool enable) +{ + if (blocks & STMPE_BLOCK_GPIO) + return 0; + else + return -EINVAL; +} + +static struct stmpe_variant_info stmpe801 = { + .name = "stmpe801", + .id_val = STMPE801_ID, + .id_mask = 0xffff, + .num_gpios = 8, + .regs = stmpe801_regs, + .blocks = stmpe801_blocks, + .num_blocks = ARRAY_SIZE(stmpe801_blocks), + .num_irqs = STMPE801_NR_INTERNAL_IRQS, + .enable = stmpe801_enable, +}; + +/* + * Touchscreen (STMPE811 or STMPE610) */ static struct resource stmpe_ts_resources[] = { @@ -350,7 +393,7 @@ static struct mfd_cell stmpe_ts_cell = { }; /* - * STMPE811 + * STMPE811 or STMPE610 */ static const u8 stmpe811_regs[] = { @@ -421,6 +464,21 @@ static struct stmpe_variant_info stmpe811 = { .get_altfunc = stmpe811_get_altfunc, }; +/* Similar to 811, except number of gpios */ +static struct stmpe_variant_info stmpe610 = { + .name = "stmpe610", + .id_val = 0x0811, + .id_mask = 0xffff, + .num_gpios = 6, + .af_bits = 1, + .regs = stmpe811_regs, + .blocks = stmpe811_blocks, + .num_blocks = ARRAY_SIZE(stmpe811_blocks), + .num_irqs = STMPE811_NR_INTERNAL_IRQS, + .enable = stmpe811_enable, + .get_altfunc = stmpe811_get_altfunc, +}; + /* * STMPE1601 */ @@ -655,6 +713,8 @@ static struct stmpe_variant_info stmpe2403 = { }; static struct stmpe_variant_info *stmpe_variant_info[] = { + [STMPE610] = &stmpe610, + [STMPE801] = &stmpe801, [STMPE811] = &stmpe811, [STMPE1601] = &stmpe1601, [STMPE2401] = &stmpe2401, @@ -671,6 +731,11 @@ static irqreturn_t stmpe_irq(int irq, void *data) int ret; int i; + if (variant->id_val == STMPE801_ID) { + handle_nested_irq(stmpe->irq_base); + return IRQ_HANDLED; + } + ret = stmpe_block_read(stmpe, israddr, num, isr); if (ret < 0) return IRQ_NONE; @@ -757,14 +822,17 @@ static struct irq_chip stmpe_irq_chip = { static int __devinit stmpe_irq_init(struct stmpe *stmpe) { + struct irq_chip *chip = NULL; int num_irqs = stmpe->variant->num_irqs; int base = stmpe->irq_base; int irq; + if (stmpe->variant->id_val != STMPE801_ID) + chip = &stmpe_irq_chip; + for (irq = base; irq < base + num_irqs; irq++) { irq_set_chip_data(irq, stmpe); - irq_set_chip_and_handler(irq, &stmpe_irq_chip, - handle_edge_irq); + irq_set_chip_and_handler(irq, chip, handle_edge_irq); irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); @@ -796,7 +864,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe) unsigned int irq_trigger = stmpe->pdata->irq_trigger; int autosleep_timeout = stmpe->pdata->autosleep_timeout; struct stmpe_variant_info *variant = stmpe->variant; - u8 icr = STMPE_ICR_LSB_GIM; + u8 icr; unsigned int id; u8 data[2]; int ret; @@ -819,16 +887,32 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe) if (ret) return ret; - if (irq_trigger == IRQF_TRIGGER_FALLING || - irq_trigger == IRQF_TRIGGER_RISING) - icr |= STMPE_ICR_LSB_EDGE; + if (id == STMPE801_ID) + icr = STMPE801_REG_SYS_CTRL_INT_EN; + else + icr = STMPE_ICR_LSB_GIM; + + /* STMPE801 doesn't support Edge interrupts */ + if (id != STMPE801_ID) { + if (irq_trigger == IRQF_TRIGGER_FALLING || + irq_trigger == IRQF_TRIGGER_RISING) + icr |= STMPE_ICR_LSB_EDGE; + } if (irq_trigger == IRQF_TRIGGER_RISING || - irq_trigger == IRQF_TRIGGER_HIGH) - icr |= STMPE_ICR_LSB_HIGH; + irq_trigger == IRQF_TRIGGER_HIGH) { + if (id == STMPE801_ID) + icr |= STMPE801_REG_SYS_CTRL_INT_HI; + else + icr |= STMPE_ICR_LSB_HIGH; + } - if (stmpe->pdata->irq_invert_polarity) - icr ^= STMPE_ICR_LSB_HIGH; + if (stmpe->pdata->irq_invert_polarity) { + if (id == STMPE801_ID) + icr ^= STMPE801_REG_SYS_CTRL_INT_HI; + else + icr ^= STMPE_ICR_LSB_HIGH; + } if (stmpe->pdata->autosleep) { ret = stmpe_autosleep(stmpe, autosleep_timeout); @@ -873,32 +957,10 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe) return ret; } -#ifdef CONFIG_PM -static int stmpe_suspend(struct device *dev) -{ - struct i2c_client *i2c = to_i2c_client(dev); - - if (device_may_wakeup(&i2c->dev)) - enable_irq_wake(i2c->irq); - - return 0; -} - -static int stmpe_resume(struct device *dev) -{ - struct i2c_client *i2c = to_i2c_client(dev); - - if (device_may_wakeup(&i2c->dev)) - disable_irq_wake(i2c->irq); - - return 0; -} -#endif - -static int __devinit stmpe_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +/* Called from client specific probe routines */ +int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) { - struct stmpe_platform_data *pdata = i2c->dev.platform_data; + struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev); struct stmpe *stmpe; int ret; @@ -912,30 +974,43 @@ static int __devinit stmpe_probe(struct i2c_client *i2c, mutex_init(&stmpe->irq_lock); mutex_init(&stmpe->lock); - stmpe->dev = &i2c->dev; - stmpe->i2c = i2c; - + stmpe->dev = ci->dev; + stmpe->client = ci->client; stmpe->pdata = pdata; stmpe->irq_base = pdata->irq_base; - - stmpe->partnum = id->driver_data; - stmpe->variant = stmpe_variant_info[stmpe->partnum]; + stmpe->ci = ci; + stmpe->partnum = partnum; + stmpe->variant = stmpe_variant_info[partnum]; stmpe->regs = stmpe->variant->regs; stmpe->num_gpios = stmpe->variant->num_gpios; + dev_set_drvdata(stmpe->dev, stmpe); - i2c_set_clientdata(i2c, stmpe); + if (ci->init) + ci->init(stmpe); + + if (pdata->irq_over_gpio) { + ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "stmpe"); + if (ret) { + dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n", + ret); + goto out_free; + } + + stmpe->irq = gpio_to_irq(pdata->irq_gpio); + } else { + stmpe->irq = ci->irq; + } ret = stmpe_chip_init(stmpe); if (ret) - goto out_free; + goto free_gpio; ret = stmpe_irq_init(stmpe); if (ret) - goto out_free; + goto free_gpio; - ret = request_threaded_irq(stmpe->i2c->irq, NULL, stmpe_irq, - pdata->irq_trigger | IRQF_ONESHOT, - "stmpe", stmpe); + ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq, + pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe); if (ret) { dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret); goto out_removeirq; @@ -951,67 +1026,55 @@ static int __devinit stmpe_probe(struct i2c_client *i2c, out_removedevs: mfd_remove_devices(stmpe->dev); - free_irq(stmpe->i2c->irq, stmpe); + free_irq(stmpe->irq, stmpe); out_removeirq: stmpe_irq_remove(stmpe); +free_gpio: + if (pdata->irq_over_gpio) + gpio_free(pdata->irq_gpio); out_free: kfree(stmpe); return ret; } -static int __devexit stmpe_remove(struct i2c_client *client) +int stmpe_remove(struct stmpe *stmpe) { - struct stmpe *stmpe = i2c_get_clientdata(client); - mfd_remove_devices(stmpe->dev); - free_irq(stmpe->i2c->irq, stmpe); + free_irq(stmpe->irq, stmpe); stmpe_irq_remove(stmpe); + if (stmpe->pdata->irq_over_gpio) + gpio_free(stmpe->pdata->irq_gpio); + kfree(stmpe); return 0; } -static const struct i2c_device_id stmpe_id[] = { - { "stmpe811", STMPE811 }, - { "stmpe1601", STMPE1601 }, - { "stmpe2401", STMPE2401 }, - { "stmpe2403", STMPE2403 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, stmpe_id); - #ifdef CONFIG_PM -static const struct dev_pm_ops stmpe_dev_pm_ops = { - .suspend = stmpe_suspend, - .resume = stmpe_resume, -}; -#endif +static int stmpe_suspend(struct device *dev) +{ + struct stmpe *stmpe = dev_get_drvdata(dev); -static struct i2c_driver stmpe_driver = { - .driver.name = "stmpe", - .driver.owner = THIS_MODULE, -#ifdef CONFIG_PM - .driver.pm = &stmpe_dev_pm_ops, -#endif - .probe = stmpe_probe, - .remove = __devexit_p(stmpe_remove), - .id_table = stmpe_id, -}; + if (device_may_wakeup(dev)) + enable_irq_wake(stmpe->irq); -static int __init stmpe_init(void) -{ - return i2c_add_driver(&stmpe_driver); + return 0; } -subsys_initcall(stmpe_init); -static void __exit stmpe_exit(void) +static int stmpe_resume(struct device *dev) { - i2c_del_driver(&stmpe_driver); + struct stmpe *stmpe = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(stmpe->irq); + + return 0; } -module_exit(stmpe_exit); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("STMPE MFD core driver"); -MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>"); +const struct dev_pm_ops stmpe_dev_pm_ops = { + .suspend = stmpe_suspend, + .resume = stmpe_resume, +}; +#endif diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index e4ee38956583..7b8e13f5b764 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h @@ -8,6 +8,14 @@ #ifndef __STMPE_H #define __STMPE_H +#include <linux/device.h> +#include <linux/mfd/core.h> +#include <linux/mfd/stmpe.h> +#include <linux/printk.h> +#include <linux/types.h> + +extern const struct dev_pm_ops stmpe_dev_pm_ops; + #ifdef STMPE_DUMP_BYTES static inline void stmpe_dump_bytes(const char *str, const void *buf, size_t len) @@ -67,11 +75,55 @@ struct stmpe_variant_info { int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout); }; +/** + * struct stmpe_client_info - i2c or spi specific routines/info + * @data: client specific data + * @read_byte: read single byte + * @write_byte: write single byte + * @read_block: read block or multiple bytes + * @write_block: write block or multiple bytes + * @init: client init routine, called during probe + */ +struct stmpe_client_info { + void *data; + int irq; + void *client; + struct device *dev; + int (*read_byte)(struct stmpe *stmpe, u8 reg); + int (*write_byte)(struct stmpe *stmpe, u8 reg, u8 val); + int (*read_block)(struct stmpe *stmpe, u8 reg, u8 len, u8 *values); + int (*write_block)(struct stmpe *stmpe, u8 reg, u8 len, + const u8 *values); + void (*init)(struct stmpe *stmpe); +}; + +int stmpe_probe(struct stmpe_client_info *ci, int partnum); +int stmpe_remove(struct stmpe *stmpe); + #define STMPE_ICR_LSB_HIGH (1 << 2) #define STMPE_ICR_LSB_EDGE (1 << 1) #define STMPE_ICR_LSB_GIM (1 << 0) /* + * STMPE801 + */ +#define STMPE801_ID 0x0108 +#define STMPE801_NR_INTERNAL_IRQS 1 + +#define STMPE801_REG_CHIP_ID 0x00 +#define STMPE801_REG_VERSION_ID 0x02 +#define STMPE801_REG_SYS_CTRL 0x04 +#define STMPE801_REG_GPIO_INT_EN 0x08 +#define STMPE801_REG_GPIO_INT_STA 0x09 +#define STMPE801_REG_GPIO_MP_STA 0x10 +#define STMPE801_REG_GPIO_SET_PIN 0x11 +#define STMPE801_REG_GPIO_DIR 0x12 + +#define STMPE801_REG_SYS_CTRL_RESET (1 << 7) +#define STMPE801_REG_SYS_CTRL_INT_EN (1 << 2) +#define STMPE801_REG_SYS_CTRL_INT_HI (1 << 0) + +/* * STMPE811 */ @@ -87,6 +139,7 @@ struct stmpe_variant_info { #define STMPE811_REG_CHIP_ID 0x00 #define STMPE811_REG_SYS_CTRL2 0x04 +#define STMPE811_REG_SPI_CFG 0x08 #define STMPE811_REG_INT_CTRL 0x09 #define STMPE811_REG_INT_EN 0x0A #define STMPE811_REG_INT_STA 0x0B diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 91ad21ef7721..2d9e8799e733 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -442,21 +442,7 @@ static struct platform_driver t7l66xb_platform_driver = { /*--------------------------------------------------------------------------*/ -static int __init t7l66xb_init(void) -{ - int retval = 0; - - retval = platform_driver_register(&t7l66xb_platform_driver); - return retval; -} - -static void __exit t7l66xb_exit(void) -{ - platform_driver_unregister(&t7l66xb_platform_driver); -} - -module_init(t7l66xb_init); -module_exit(t7l66xb_exit); +module_platform_driver(t7l66xb_platform_driver); MODULE_DESCRIPTION("Toshiba T7L66XB core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 71bc835324d8..d20a284ad4ba 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -234,19 +234,7 @@ static struct platform_driver tc6387xb_platform_driver = { .resume = tc6387xb_resume, }; - -static int __init tc6387xb_init(void) -{ - return platform_driver_register(&tc6387xb_platform_driver); -} - -static void __exit tc6387xb_exit(void) -{ - platform_driver_unregister(&tc6387xb_platform_driver); -} - -module_init(tc6387xb_init); -module_exit(tc6387xb_exit); +module_platform_driver(tc6387xb_platform_driver); MODULE_DESCRIPTION("Toshiba TC6387XB core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c index af9ab0e5ca64..4fb0e6c8e8fe 100644 --- a/drivers/mfd/ti-ssp.c +++ b/drivers/mfd/ti-ssp.c @@ -458,17 +458,7 @@ static struct platform_driver ti_ssp_driver = { } }; -static int __init ti_ssp_init(void) -{ - return platform_driver_register(&ti_ssp_driver); -} -module_init(ti_ssp_init); - -static void __exit ti_ssp_exit(void) -{ - platform_driver_unregister(&ti_ssp_driver); -} -module_exit(ti_ssp_exit); +module_platform_driver(ti_ssp_driver); MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver"); MODULE_AUTHOR("Cyril Chemparathy"); diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 02d65692ceb4..0ba26fb12cf5 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -857,7 +857,7 @@ static void __devexit timb_remove(struct pci_dev *dev) kfree(priv); } -static struct pci_device_id timberdale_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(timberdale_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) }, { 0 } }; diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index a56be931551c..95c0d7978bec 100644 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -215,6 +215,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, int tps65910_irq_exit(struct tps65910 *tps65910) { - free_irq(tps65910->chip_irq, tps65910); + if (tps65910->chip_irq) + free_irq(tps65910->chip_irq, tps65910); return 0; } diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index c1da84bc1573..01cf5012a08f 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -172,15 +172,12 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); - ret = tps65910_irq_init(tps65910, init_data->irq, init_data); - if (ret < 0) - goto err; + tps65910_irq_init(tps65910, init_data->irq, init_data); kfree(init_data); return ret; err: - mfd_remove_devices(tps65910->dev); kfree(tps65910); kfree(init_data); return ret; @@ -190,8 +187,8 @@ static int tps65910_i2c_remove(struct i2c_client *i2c) { struct tps65910 *tps65910 = i2c_get_clientdata(i2c); - mfd_remove_devices(tps65910->dev); tps65910_irq_exit(tps65910); + mfd_remove_devices(tps65910->dev); kfree(tps65910); return 0; diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index 6d71e0d25744..27d3302d56b8 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -111,7 +111,6 @@ static int __devexit tps65912_spi_remove(struct spi_device *spi) static struct spi_driver tps65912_spi_driver = { .driver = { .name = "tps65912", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = tps65912_spi_probe, diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 61e70cfaa774..e04e04ddc15e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -34,6 +34,11 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/device.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/irqdomain.h> #include <linux/regulator/machine.h> @@ -144,6 +149,9 @@ #define TWL_MODULE_LAST TWL4030_MODULE_LAST +#define TWL4030_NR_IRQS 8 +#define TWL6030_NR_IRQS 20 + /* Base Address defns for twl4030_map[] */ /* subchip/slave 0 - USB ID */ @@ -255,6 +263,7 @@ struct twl_client { static struct twl_client twl_modules[TWL_NUM_SLAVES]; +static struct irq_domain domain; /* mapping the module id to slave id and base address */ struct twl_mapping { @@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) int status; unsigned i; struct twl4030_platform_data *pdata = client->dev.platform_data; + struct device_node *node = client->dev.of_node; u8 temp; int ret = 0; + int nr_irqs = TWL4030_NR_IRQS; + + if ((id->driver_data) & TWL6030_CLASS) + nr_irqs = TWL6030_NR_IRQS; + + if (node && !pdata) { + /* + * XXX: Temporary pdata until the information is correctly + * retrieved by every TWL modules from DT. + */ + pdata = devm_kzalloc(&client->dev, + sizeof(struct twl4030_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + } if (!pdata) { dev_dbg(&client->dev, "no platform data?\n"); return -EINVAL; } + status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0); + if (IS_ERR_VALUE(status)) { + dev_err(&client->dev, "Fail to allocate IRQ descs\n"); + return status; + } + + pdata->irq_base = status; + pdata->irq_end = pdata->irq_base + nr_irqs; + + domain.irq_base = pdata->irq_base; + domain.nr_irq = nr_irqs; +#ifdef CONFIG_OF_IRQ + domain.of_node = of_node_get(node); + domain.ops = &irq_domain_simple_ops; +#endif + irq_domain_add(&domain); + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { dev_dbg(&client->dev, "can't talk I2C?\n"); return -EIO; @@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); } - status = add_children(pdata, id->driver_data); +#ifdef CONFIG_OF_DEVICE + if (node) + status = of_platform_populate(node, NULL, NULL, &client->dev); + else +#endif + status = add_children(pdata, id->driver_data); + fail: if (status < 0) twl_remove(client); diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index ae51ab5d0e5d..838ce4eb444e 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -261,17 +261,7 @@ static struct platform_driver twl4030_audio_driver = { }, }; -static int __devinit twl4030_audio_init(void) -{ - return platform_driver_register(&twl4030_audio_driver); -} -module_init(twl4030_audio_init); - -static void __devexit twl4030_audio_exit(void) -{ - platform_driver_unregister(&twl4030_audio_driver); -} -module_exit(twl4030_audio_exit); +module_platform_driver(twl4030_audio_driver); MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 29f11e0765fe..b69bb517b102 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -492,7 +492,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) u8 bytes[4]; } imr; - /* byte[0] gets overwriten as we write ... */ + /* byte[0] gets overwritten as we write ... */ imr.word = cpu_to_le32(agent->imr << 8); agent->imr_change_pending = false; @@ -667,6 +667,7 @@ int twl4030_sih_setup(int module) irq_set_chip_data(irq, agent); irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip, handle_edge_irq); + irq_set_nested_thread(irq, 1); activate_irq(irq); } diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 834f824d3c11..456ecb5ac4fe 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -807,19 +807,7 @@ static struct platform_driver twl4030_madc_driver = { }, }; -static int __init twl4030_madc_init(void) -{ - return platform_driver_register(&twl4030_madc_driver); -} - -module_init(twl4030_madc_init); - -static void __exit twl4030_madc_exit(void) -{ - platform_driver_unregister(&twl4030_madc_driver); -} - -module_exit(twl4030_madc_exit); +module_platform_driver(twl4030_madc_driver); MODULE_DESCRIPTION("TWL4030 ADC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index a764676f0922..d905f5171153 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -34,7 +34,8 @@ static u8 twl4030_start_script_address = 0x2b; #define PWR_P1_SW_EVENTS 0x10 -#define PWR_DEVOFF (1<<0) +#define PWR_DEVOFF (1 << 0) +#define SEQ_OFFSYNC (1 << 0) #define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) #define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b) @@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags) return err; } +/* + * In master mode, start the power off sequence. + * After a successful execution, TWL shuts down the power to the SoC + * and all peripherals connected to it. + */ +void twl4030_power_off(void) +{ + int err; + + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF, + TWL4030_PM_MASTER_P1_SW_EVENTS); + if (err) + pr_err("TWL4030 Unable to power off\n"); +} + void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) { int err = 0; int i; struct twl4030_resconfig *resconfig; - u8 address = twl4030_start_script_address; + u8 val, address = twl4030_start_script_address; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, @@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) } } + /* Board has to be wired properly to use this feature */ + if (twl4030_scripts->use_poweroff && !pm_power_off) { + /* Default for SEQ_OFFSYNC is set, lets ensure this */ + err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, + TWL4030_PM_MASTER_CFG_P123_TRANSITION); + if (err) { + pr_warning("TWL4030 Unable to read registers\n"); + + } else if (!(val & SEQ_OFFSYNC)) { + val |= SEQ_OFFSYNC; + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, + TWL4030_PM_MASTER_CFG_P123_TRANSITION); + if (err) { + pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n"); + goto relock; + } + } + + pm_power_off = twl4030_power_off; + } + +relock: err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, TWL4030_PM_MASTER_PROTECT_KEY); if (err) diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index 268f80fd0439..dda86293dc9f 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -509,13 +509,10 @@ static int __devinit twl6040_probe(struct platform_device *pdev) twl6040->audpwron = -EINVAL; if (gpio_is_valid(twl6040->audpwron)) { - ret = gpio_request(twl6040->audpwron, "audpwron"); + ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW, + "audpwron"); if (ret) goto gpio1_err; - - ret = gpio_direction_output(twl6040->audpwron, 0); - if (ret) - goto gpio2_err; } /* codec interrupt */ @@ -619,18 +616,7 @@ static struct platform_driver twl6040_driver = { }, }; -static int __devinit twl6040_init(void) -{ - return platform_driver_register(&twl6040_driver); -} -module_init(twl6040_init); - -static void __devexit twl6040_exit(void) -{ - platform_driver_unregister(&twl6040_driver); -} - -module_exit(twl6040_exit); +module_platform_driver(twl6040_driver); MODULE_DESCRIPTION("TWL6040 MFD"); MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index b281217334eb..91c4f25e0e55 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -36,6 +36,15 @@ static DEFINE_MUTEX(ucb1x00_mutex); static LIST_HEAD(ucb1x00_drivers); static LIST_HEAD(ucb1x00_devices); +static struct mcp_device_id ucb1x00_id[] = { + { "ucb1x00", 0 }, /* auto-detection */ + { "ucb1200", UCB_ID_1200 }, + { "ucb1300", UCB_ID_1300 }, + { "tc35143", UCB_ID_TC35143 }, + { } +}; +MODULE_DEVICE_TABLE(mcp, ucb1x00_id); + /** * ucb1x00_io_set_dir - set IO direction * @ucb: UCB1x00 structure describing chip @@ -527,17 +536,33 @@ static struct class ucb1x00_class = { static int ucb1x00_probe(struct mcp *mcp) { + const struct mcp_device_id *mid; struct ucb1x00 *ucb; struct ucb1x00_driver *drv; + struct ucb1x00_plat_data *pdata; unsigned int id; int ret = -ENODEV; int temp; mcp_enable(mcp); id = mcp_reg_read(mcp, UCB_ID); + mid = mcp_get_device_id(mcp); - if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) { - printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); + if (mid && mid->driver_data) { + if (id != mid->driver_data) { + printk(KERN_WARNING "%s wrong ID %04x found: %04x\n", + mid->name, (unsigned int) mid->driver_data, id); + goto err_disable; + } + } else { + mid = &ucb1x00_id[1]; + while (mid->driver_data) { + if (id == mid->driver_data) + break; + mid++; + } + printk(KERN_WARNING "%s ID not found: %04x\n", + ucb1x00_id[0].name, id); goto err_disable; } @@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp) if (!ucb) goto err_disable; - + pdata = mcp->attached_device.platform_data; ucb->dev.class = &ucb1x00_class; ucb->dev.parent = &mcp->attached_device; - dev_set_name(&ucb->dev, "ucb1x00"); + dev_set_name(&ucb->dev, mid->name); spin_lock_init(&ucb->lock); spin_lock_init(&ucb->io_lock); sema_init(&ucb->adc_sem, 1); - ucb->id = id; + ucb->id = mid; ucb->mcp = mcp; ucb->irq = ucb1x00_detect_irq(ucb); if (ucb->irq == NO_IRQ) { - printk(KERN_ERR "UCB1x00: IRQ probe failed\n"); + printk(KERN_ERR "%s: IRQ probe failed\n", mid->name); ret = -ENODEV; goto err_free; } ucb->gpio.base = -1; - if (mcp->gpio_base != 0) { + if (pdata && (pdata->gpio_base >= 0)) { ucb->gpio.label = dev_name(&ucb->dev); - ucb->gpio.base = mcp->gpio_base; + ucb->gpio.base = pdata->gpio_base; ucb->gpio.ngpio = 10; ucb->gpio.set = ucb1x00_gpio_set; ucb->gpio.get = ucb1x00_gpio_get; @@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp) dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, - "UCB1x00", ucb); + mid->name, ucb); if (ret) { - printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", - ucb->irq, ret); + printk(KERN_ERR "%s: unable to grab irq%d: %d\n", + mid->name, ucb->irq, ret); goto err_gpio; } @@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = { .remove = ucb1x00_remove, .suspend = ucb1x00_suspend, .resume = ucb1x00_resume, + .id_table = ucb1x00_id, }; static int __init ucb1x00_init(void) diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 38ffbd50a0d2..40ec3c118868 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; idev->name = "Touchscreen panel"; - idev->id.product = ts->ucb->id; + idev->id.product = ts->ucb->id->driver_data; idev->open = ucb1x00_ts_open; idev->close = ucb1x00_ts_close; diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index d698703dbd46..b73cc15e0081 100644 --- a/drivers/mfd/vx855.c +++ b/drivers/mfd/vx855.c @@ -118,7 +118,7 @@ static void __devexit vx855_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id vx855_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(vx855_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, { 0, } }; diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 0a2b8d41a702..f5e54fae8ada 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -559,6 +559,8 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg, dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n", buf[i], reg + i, reg + i); ret = regmap_write(wm831x->regmap, reg + i, buf[i]); + if (ret != 0) + return ret; } return 0; @@ -1875,7 +1877,6 @@ err_irq: err_regmap: mfd_remove_devices(wm831x->dev); regmap_exit(wm831x->regmap); - kfree(wm831x); return ret; } @@ -1887,7 +1888,6 @@ void wm831x_device_exit(struct wm831x *wm831x) free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x); wm831x_irq_exit(wm831x); regmap_exit(wm831x->regmap); - kfree(wm831x); } int wm831x_device_suspend(struct wm831x *wm831x) diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index ac8da1d439da..cb15609b0a48 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -30,7 +30,7 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, struct wm831x *wm831x; int ret; - wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); + wm831x = devm_kzalloc(&i2c->dev, sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) return -ENOMEM; @@ -42,7 +42,6 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(wm831x->regmap); dev_err(wm831x->dev, "Failed to allocate register map: %d\n", ret); - kfree(wm831x); return ret; } diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index f4747a4a9a93..bec4d0539160 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -325,11 +325,6 @@ static inline int irq_data_to_status_reg(struct wm831x_irq_data *irq_data) return WM831X_INTERRUPT_STATUS_1 - 1 + irq_data->reg; } -static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data) -{ - return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg; -} - static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, int irq) { @@ -477,8 +472,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); if (primary & WM831X_TCHDATA_INT) handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); - if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT)) - goto out; + primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { int offset = wm831x_irqs[i].reg - 1; diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index 8d6a9a969dbc..62ef3254105f 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -30,7 +30,7 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) type = (enum wm831x_parent)id->driver_data; - wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); + wm831x = devm_kzalloc(&spi->dev, sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) return -ENOMEM; @@ -45,7 +45,6 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) ret = PTR_ERR(wm831x->regmap); dev_err(wm831x->dev, "Failed to allocate register map: %d\n", ret); - kfree(wm831x); return ret; } @@ -95,7 +94,6 @@ MODULE_DEVICE_TABLE(spi, wm831x_spi_id); static struct spi_driver wm831x_spi_driver = { .driver = { .name = "wm831x", - .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index e81cc31e4202..dd1caaac55e4 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -573,6 +573,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, u16 id1, id2, mask_rev; u16 cust_id, mode, chip_rev; + dev_set_drvdata(wm8350->dev, wm8350); + /* get WM8350 revision and config mode */ ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1); if (ret != 0) { diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 5fe5de166adb..d955faaf27c4 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -63,7 +63,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, struct wm8350 *wm8350; int ret = 0; - wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL); + wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL); if (wm8350 == NULL) return -ENOMEM; @@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, return ret; err: - kfree(wm8350); return ret; } @@ -89,7 +88,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c) struct wm8350 *wm8350 = i2c_get_clientdata(i2c); wm8350_device_exit(wm8350); - kfree(wm8350); return 0; } diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 62b4626f4561..2204893444a6 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -344,7 +344,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, struct wm8400 *wm8400; int ret; - wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL); + wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL); if (wm8400 == NULL) { ret = -ENOMEM; goto err; @@ -353,7 +353,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config); if (IS_ERR(wm8400->regmap)) { ret = PTR_ERR(wm8400->regmap); - goto struct_err; + goto err; } wm8400->dev = &i2c->dev; @@ -367,8 +367,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, map_err: regmap_exit(wm8400->regmap); -struct_err: - kfree(wm8400); err: return ret; } @@ -379,7 +377,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c) wm8400_release(wm8400); regmap_exit(wm8400->regmap); - kfree(wm8400); return 0; } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 5664696f2d3a..6a1a092db146 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -500,6 +500,14 @@ config USB_SWITCH_FSA9480 stereo and mono audio, video, microphone and UART data to use a common connector port. +config MAX8997_MUIC + tristate "MAX8997 MUIC Support" + depends on MFD_MAX8997 + help + If you say yes here you get support for the MUIC device of + Maxim MAX8997 PMIC. + The MAX8997 MUIC is a USB port accessory detector and switch. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b26495a02554..3e1d80106f04 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -48,3 +48,4 @@ obj-y += lis3lv02d/ obj-y += carma/ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ +obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c index 2208a9d52622..d7a9aa14e5d5 100644 --- a/drivers/misc/ab8500-pwm.c +++ b/drivers/misc/ab8500-pwm.c @@ -8,8 +8,8 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/pwm.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/module.h> /* diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c index eb5cd28bc6d8..a2d25e4857e3 100644 --- a/drivers/misc/carma/carma-fpga-program.c +++ b/drivers/misc/carma/carma-fpga-program.c @@ -513,7 +513,7 @@ static noinline int fpga_program_dma(struct fpga_dev *priv) * transaction, and then put it under external control */ memset(&config, 0, sizeof(config)); - config.direction = DMA_TO_DEVICE; + config.direction = DMA_MEM_TO_DEV; config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; config.dst_maxburst = fpga_fifo_size(priv->regs) / 2 / 4; ret = chan->device->device_control(chan, DMA_SLAVE_CONFIG, diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c index b1f4563be9ae..701eb600b127 100644 --- a/drivers/misc/iwmc3200top/main.c +++ b/drivers/misc/iwmc3200top/main.c @@ -376,20 +376,20 @@ static int blocks; module_param(blocks, int, 0604); MODULE_PARM_DESC(blocks, "max_blocks_to_send"); -static int dump; +static bool dump; module_param(dump, bool, 0604); MODULE_PARM_DESC(dump, "dump_hex_content"); -static int jump = 1; +static bool jump = 1; module_param(jump, bool, 0604); -static int direct = 1; +static bool direct = 1; module_param(direct, bool, 0604); -static int checksum = 1; +static bool checksum = 1; module_param(checksum, bool, 0604); -static int fw_download = 1; +static bool fw_download = 1; module_param(fw_download, bool, 0604); static int block_size = IWMC_SDIO_BLK_SIZE; @@ -398,7 +398,7 @@ module_param(block_size, int, 0404); static int download_trans_blks = IWMC_DEFAULT_TR_BLK; module_param(download_trans_blks, int, 0604); -static int rubbish_barker; +static bool rubbish_barker; module_param(rubbish_barker, bool, 0604); #ifdef CONFIG_IWMC3200TOP_DEBUG diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index 29d12a70eb1b..a981e2a42f92 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -111,6 +111,8 @@ static struct kernel_param_ops param_ops_axis = { .get = param_get_int, }; +#define param_check_axis(name, p) param_check_int(name, p) + module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644); MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions"); diff --git a/drivers/misc/max8997-muic.c b/drivers/misc/max8997-muic.c new file mode 100644 index 000000000000..d74ef41aabd5 --- /dev/null +++ b/drivers/misc/max8997-muic.c @@ -0,0 +1,505 @@ +/* + * max8997-muic.c - MAX8997 muic driver for the Maxim 8997 + * + * Copyright (C) 2011 Samsung Electrnoics + * Donggeun Kim <dg77.kim@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. + * + * 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/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/kobject.h> +#include <linux/mfd/max8997.h> +#include <linux/mfd/max8997-private.h> + +/* MAX8997-MUIC STATUS1 register */ +#define STATUS1_ADC_SHIFT 0 +#define STATUS1_ADCLOW_SHIFT 5 +#define STATUS1_ADCERR_SHIFT 6 +#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) +#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT) +#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT) + +/* MAX8997-MUIC STATUS2 register */ +#define STATUS2_CHGTYP_SHIFT 0 +#define STATUS2_CHGDETRUN_SHIFT 3 +#define STATUS2_DCDTMR_SHIFT 4 +#define STATUS2_DBCHG_SHIFT 5 +#define STATUS2_VBVOLT_SHIFT 6 +#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) +#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT) +#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT) +#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT) +#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT) + +/* MAX8997-MUIC STATUS3 register */ +#define STATUS3_OVP_SHIFT 2 +#define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT) + +/* MAX8997-MUIC CONTROL1 register */ +#define COMN1SW_SHIFT 0 +#define COMP2SW_SHIFT 3 +#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT) +#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT) +#define SW_MASK (COMP2SW_MASK | COMN1SW_MASK) + +#define MAX8997_SW_USB ((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT)) +#define MAX8997_SW_AUDIO ((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT)) +#define MAX8997_SW_UART ((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT)) +#define MAX8997_SW_OPEN ((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT)) + +#define MAX8997_ADC_GROUND 0x00 +#define MAX8997_ADC_MHL 0x01 +#define MAX8997_ADC_JIG_USB_1 0x18 +#define MAX8997_ADC_JIG_USB_2 0x19 +#define MAX8997_ADC_DESKDOCK 0x1a +#define MAX8997_ADC_JIG_UART 0x1c +#define MAX8997_ADC_CARDOCK 0x1d +#define MAX8997_ADC_OPEN 0x1f + +struct max8997_muic_irq { + unsigned int irq; + const char *name; +}; + +static struct max8997_muic_irq muic_irqs[] = { + { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" }, + { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" }, + { MAX8997_MUICIRQ_ADC, "muic-ADC" }, + { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" }, + { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" }, + { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" }, + { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" }, + { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" }, + { MAX8997_MUICIRQ_OVP, "muic-over_voltage" }, +}; + +struct max8997_muic_info { + struct device *dev; + struct max8997_dev *iodev; + struct i2c_client *muic; + struct max8997_muic_platform_data *muic_pdata; + + int irq; + struct work_struct irq_work; + + enum max8997_muic_charger_type pre_charger_type; + int pre_adc; + + struct mutex mutex; +}; + +static int max8997_muic_handle_usb(struct max8997_muic_info *info, + enum max8997_muic_usb_type usb_type, bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + if (usb_type == MAX8997_USB_HOST) { + /* switch to USB */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_USB : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + } + + if (mdata->usb_callback) + mdata->usb_callback(usb_type, attached); +out: + return ret; +} + +static void max8997_muic_handle_mhl(struct max8997_muic_info *info, + bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + + if (mdata->mhl_callback) + mdata->mhl_callback(attached); +} + +static int max8997_muic_handle_dock(struct max8997_muic_info *info, + int adc, bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + /* switch to AUDIO */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + + switch (adc) { + case MAX8997_ADC_DESKDOCK: + if (mdata->deskdock_callback) + mdata->deskdock_callback(attached); + break; + case MAX8997_ADC_CARDOCK: + if (mdata->cardock_callback) + mdata->cardock_callback(attached); + break; + default: + break; + } +out: + return ret; +} + +static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, + bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + /* switch to UART */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_UART : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + + if (mdata->uart_callback) + mdata->uart_callback(attached); +out: + return ret; +} + +static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info) +{ + int ret = 0; + + switch (info->pre_adc) { + case MAX8997_ADC_GROUND: + ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false); + break; + case MAX8997_ADC_MHL: + max8997_muic_handle_mhl(info, false); + break; + case MAX8997_ADC_JIG_USB_1: + case MAX8997_ADC_JIG_USB_2: + ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false); + break; + case MAX8997_ADC_DESKDOCK: + case MAX8997_ADC_CARDOCK: + ret = max8997_muic_handle_dock(info, info->pre_adc, false); + break; + case MAX8997_ADC_JIG_UART: + ret = max8997_muic_handle_jig_uart(info, false); + break; + default: + break; + } + + return ret; +} + +static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc) +{ + int ret = 0; + + switch (adc) { + case MAX8997_ADC_GROUND: + ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true); + break; + case MAX8997_ADC_MHL: + max8997_muic_handle_mhl(info, true); + break; + case MAX8997_ADC_JIG_USB_1: + case MAX8997_ADC_JIG_USB_2: + ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true); + break; + case MAX8997_ADC_DESKDOCK: + case MAX8997_ADC_CARDOCK: + ret = max8997_muic_handle_dock(info, adc, true); + break; + case MAX8997_ADC_JIG_UART: + ret = max8997_muic_handle_jig_uart(info, true); + break; + case MAX8997_ADC_OPEN: + ret = max8997_muic_handle_adc_detach(info); + break; + default: + break; + } + + info->pre_adc = adc; + + return ret; +} + +static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, + enum max8997_muic_charger_type charger_type) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + u8 adc; + int ret; + + ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + goto out; + } + + switch (charger_type) { + case MAX8997_CHARGER_TYPE_NONE: + if (mdata->charger_callback) + mdata->charger_callback(false, charger_type); + if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) { + max8997_muic_handle_usb(info, + MAX8997_USB_DEVICE, false); + } + break; + case MAX8997_CHARGER_TYPE_USB: + if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) { + max8997_muic_handle_usb(info, + MAX8997_USB_DEVICE, true); + } + if (mdata->charger_callback) + mdata->charger_callback(true, charger_type); + break; + case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: + case MAX8997_CHARGER_TYPE_DEDICATED_CHG: + case MAX8997_CHARGER_TYPE_500MA: + case MAX8997_CHARGER_TYPE_1A: + if (mdata->charger_callback) + mdata->charger_callback(true, charger_type); + break; + default: + break; + } + + info->pre_charger_type = charger_type; +out: + return ret; +} + +static void max8997_muic_irq_work(struct work_struct *work) +{ + struct max8997_muic_info *info = container_of(work, + struct max8997_muic_info, irq_work); + struct max8997_platform_data *pdata = + dev_get_platdata(info->iodev->dev); + u8 status[3]; + u8 adc, chg_type; + + int irq_type = info->irq - pdata->irq_base; + int ret; + + mutex_lock(&info->mutex); + + ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, + 3, status); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + mutex_unlock(&info->mutex); + return; + } + + dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__, + status[0], status[1]); + + switch (irq_type) { + case MAX8997_MUICIRQ_ADC: + adc = status[0] & STATUS1_ADC_MASK; + adc >>= STATUS1_ADC_SHIFT; + + max8997_muic_handle_adc(info, adc); + break; + case MAX8997_MUICIRQ_ChgTyp: + chg_type = status[1] & STATUS2_CHGTYP_MASK; + chg_type >>= STATUS2_CHGTYP_SHIFT; + + max8997_muic_handle_charger_type(info, chg_type); + break; + default: + dev_info(info->dev, "misc interrupt: %s occurred\n", + muic_irqs[irq_type].name); + break; + } + + mutex_unlock(&info->mutex); + + return; +} + +static irqreturn_t max8997_muic_irq_handler(int irq, void *data) +{ + struct max8997_muic_info *info = data; + + dev_dbg(info->dev, "irq:%d\n", irq); + info->irq = irq; + + schedule_work(&info->irq_work); + + return IRQ_HANDLED; +} + +static void max8997_muic_detect_dev(struct max8997_muic_info *info) +{ + int ret; + u8 status[2], adc, chg_type; + + ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, + 2, status); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + return; + } + + dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n", + status[0], status[1]); + + adc = status[0] & STATUS1_ADC_MASK; + adc >>= STATUS1_ADC_SHIFT; + + chg_type = status[1] & STATUS2_CHGTYP_MASK; + chg_type >>= STATUS2_CHGTYP_SHIFT; + + max8997_muic_handle_adc(info, adc); + max8997_muic_handle_charger_type(info, chg_type); +} + +static void max8997_initialize_device(struct max8997_muic_info *info) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int i; + + for (i = 0; i < mdata->num_init_data; i++) { + max8997_write_reg(info->muic, mdata->init_data[i].addr, + mdata->init_data[i].data); + } +} + +static int __devinit max8997_muic_probe(struct platform_device *pdev) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); + struct max8997_muic_info *info; + int ret, i; + + info = kzalloc(sizeof(struct max8997_muic_info), GFP_KERNEL); + if (!info) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + ret = -ENOMEM; + goto err_kfree; + } + + if (!pdata->muic_pdata) { + dev_err(&pdev->dev, "failed to get platform_data\n"); + ret = -EINVAL; + goto err_pdata; + } + info->muic_pdata = pdata->muic_pdata; + + info->dev = &pdev->dev; + info->iodev = iodev; + info->muic = iodev->muic; + + platform_set_drvdata(pdev, info); + mutex_init(&info->mutex); + + INIT_WORK(&info->irq_work, max8997_muic_irq_work); + + for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) { + struct max8997_muic_irq *muic_irq = &muic_irqs[i]; + + ret = request_threaded_irq(pdata->irq_base + muic_irq->irq, + NULL, max8997_muic_irq_handler, + 0, muic_irq->name, + info); + if (ret) { + dev_err(&pdev->dev, + "failed: irq request (IRQ: %d," + " error :%d)\n", + muic_irq->irq, ret); + + for (i = i - 1; i >= 0; i--) + free_irq(muic_irq->irq, info); + + goto err_irq; + } + } + + /* Initialize registers according to platform data */ + max8997_initialize_device(info); + + /* Initial device detection */ + max8997_muic_detect_dev(info); + + return ret; + +err_irq: +err_pdata: + kfree(info); +err_kfree: + return ret; +} + +static int __devexit max8997_muic_remove(struct platform_device *pdev) +{ + struct max8997_muic_info *info = platform_get_drvdata(pdev); + struct max8997_platform_data *pdata = + dev_get_platdata(info->iodev->dev); + int i; + + for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) + free_irq(pdata->irq_base + muic_irqs[i].irq, info); + cancel_work_sync(&info->irq_work); + + kfree(info); + + return 0; +} + +static struct platform_driver max8997_muic_driver = { + .driver = { + .name = "max8997-muic", + .owner = THIS_MODULE, + }, + .probe = max8997_muic_probe, + .remove = __devexit_p(max8997_muic_remove), +}; + +static int __init max8997_muic_init(void) +{ + return platform_driver_register(&max8997_muic_driver); +} +module_init(max8997_muic_init); + +static void __exit max8997_muic_exit(void) +{ + platform_driver_unregister(&max8997_muic_driver); +} +module_exit(max8997_muic_exit); + +MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver"); +MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 12eef393e216..400756ec7c49 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -6,5 +6,4 @@ subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG obj-$(CONFIG_MMC) += core/ obj-$(CONFIG_MMC) += card/ -obj-$(CONFIG_MMC) += host/ - +obj-$(subst m,y,$(CONFIG_MMC)) += host/ diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 1e0e27cbe987..0cad48a284a8 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -107,6 +107,8 @@ struct mmc_blk_data { */ unsigned int part_curr; struct device_attribute force_ro; + struct device_attribute power_ro_lock; + int area_type; }; static DEFINE_MUTEX(open_lock); @@ -119,6 +121,7 @@ enum mmc_blk_status { MMC_BLK_ABORT, MMC_BLK_DATA_ERR, MMC_BLK_ECC_ERR, + MMC_BLK_NOMEDIUM, }; module_param(perdev_minors, int, 0444); @@ -165,6 +168,70 @@ static void mmc_blk_put(struct mmc_blk_data *md) mutex_unlock(&open_lock); } +static ssize_t power_ro_lock_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); + struct mmc_card *card = md->queue.card; + int locked = 0; + + if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN) + locked = 2; + else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) + locked = 1; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); + + return ret; +} + +static ssize_t power_ro_lock_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct mmc_blk_data *md, *part_md; + struct mmc_card *card; + unsigned long set; + + if (kstrtoul(buf, 0, &set)) + return -EINVAL; + + if (set != 1) + return count; + + md = mmc_blk_get(dev_to_disk(dev)); + card = md->queue.card; + + mmc_claim_host(card->host); + + ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, + card->ext_csd.boot_ro_lock | + EXT_CSD_BOOT_WP_B_PWR_WP_EN, + card->ext_csd.part_time); + if (ret) + pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret); + else + card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; + + mmc_release_host(card->host); + + if (!ret) { + pr_info("%s: Locking boot partition ro until next power on\n", + md->disk->disk_name); + set_disk_ro(md->disk, 1); + + list_for_each_entry(part_md, &md->part, part) + if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) { + pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name); + set_disk_ro(part_md->disk, 1); + } + } + + mmc_blk_put(md); + return count; +} + static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -266,6 +333,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( goto idata_err; } + if (!idata->buf_bytes) + return idata; + idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); if (!idata->buf) { err = -ENOMEM; @@ -312,25 +382,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (IS_ERR(idata)) return PTR_ERR(idata); - cmd.opcode = idata->ic.opcode; - cmd.arg = idata->ic.arg; - cmd.flags = idata->ic.flags; - - data.sg = &sg; - data.sg_len = 1; - data.blksz = idata->ic.blksz; - data.blocks = idata->ic.blocks; - - sg_init_one(data.sg, idata->buf, idata->buf_bytes); - - if (idata->ic.write_flag) - data.flags = MMC_DATA_WRITE; - else - data.flags = MMC_DATA_READ; - - mrq.cmd = &cmd; - mrq.data = &data; - md = mmc_blk_get(bdev->bd_disk); if (!md) { err = -EINVAL; @@ -343,6 +394,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_done; } + cmd.opcode = idata->ic.opcode; + cmd.arg = idata->ic.arg; + cmd.flags = idata->ic.flags; + + if (idata->buf_bytes) { + data.sg = &sg; + data.sg_len = 1; + data.blksz = idata->ic.blksz; + data.blocks = idata->ic.blocks; + + sg_init_one(data.sg, idata->buf, idata->buf_bytes); + + if (idata->ic.write_flag) + data.flags = MMC_DATA_WRITE; + else + data.flags = MMC_DATA_READ; + + /* data.flags must already be set before doing this. */ + mmc_set_data_timeout(&data, card); + + /* Allow overriding the timeout_ns for empirical tuning. */ + if (idata->ic.data_timeout_ns) + data.timeout_ns = idata->ic.data_timeout_ns; + + if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { + /* + * Pretend this is a data transfer and rely on the + * host driver to compute timeout. When all host + * drivers support cmd.cmd_timeout for R1B, this + * can be changed to: + * + * mrq.data = NULL; + * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; + */ + data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; + } + + mrq.data = &data; + } + + mrq.cmd = &cmd; + mmc_claim_host(card->host); if (idata->ic.is_acmd) { @@ -351,24 +444,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_rel_host; } - /* data.flags must already be set before doing this. */ - mmc_set_data_timeout(&data, card); - /* Allow overriding the timeout_ns for empirical tuning. */ - if (idata->ic.data_timeout_ns) - data.timeout_ns = idata->ic.data_timeout_ns; - - if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { - /* - * Pretend this is a data transfer and rely on the host driver - * to compute timeout. When all host drivers support - * cmd.cmd_timeout for R1B, this can be changed to: - * - * mrq.data = NULL; - * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; - */ - data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; - } - mmc_wait_for_req(card->host, &mrq); if (cmd.error) { @@ -565,6 +640,7 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries) return err; } +#define ERR_NOMEDIUM 3 #define ERR_RETRY 2 #define ERR_ABORT 1 #define ERR_CONTINUE 0 @@ -632,6 +708,9 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, u32 status, stop_status = 0; int err, retry; + if (mmc_card_removed(card)) + return ERR_NOMEDIUM; + /* * Try to get card status which indicates both the card state * and why there was no response. If the first attempt fails, @@ -648,8 +727,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, } /* We couldn't get a response from the card. Give up. */ - if (err) + if (err) { + /* Check if the card is removed */ + if (mmc_detect_card_removed(card->host)) + return ERR_NOMEDIUM; return ERR_ABORT; + } /* Flag ECC errors */ if ((status & R1_CARD_ECC_FAILED) || @@ -922,6 +1005,8 @@ static int mmc_blk_err_check(struct mmc_card *card, return MMC_BLK_RETRY; case ERR_ABORT: return MMC_BLK_ABORT; + case ERR_NOMEDIUM: + return MMC_BLK_NOMEDIUM; case ERR_CONTINUE: break; } @@ -1255,6 +1340,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) if (!ret) goto start_new_req; break; + case MMC_BLK_NOMEDIUM: + goto cmd_abort; } if (ret) { @@ -1271,6 +1358,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) cmd_abort: spin_lock_irq(&md->lock); + if (mmc_card_removed(card)) + req->cmd_flags |= REQ_QUIET; while (ret) ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); spin_unlock_irq(&md->lock); @@ -1339,7 +1428,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct device *parent, sector_t size, bool default_ro, - const char *subname) + const char *subname, + int area_type) { struct mmc_blk_data *md; int devidx, ret; @@ -1364,11 +1454,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, if (!subname) { md->name_idx = find_first_zero_bit(name_use, max_devices); __set_bit(md->name_idx, name_use); - } - else + } else md->name_idx = ((struct mmc_blk_data *) dev_to_disk(parent)->private_data)->name_idx; + md->area_type = area_type; + /* * Set the read-only status based on the supported commands * and the write protect switch. @@ -1462,7 +1553,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) size = card->csd.capacity << (card->csd.read_blkbits - 9); } - md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL); + md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL, + MMC_BLK_DATA_AREA_MAIN); return md; } @@ -1471,13 +1563,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card, unsigned int part_type, sector_t size, bool default_ro, - const char *subname) + const char *subname, + int area_type) { char cap_str[10]; struct mmc_blk_data *part_md; part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro, - subname); + subname, area_type); if (IS_ERR(part_md)) return PTR_ERR(part_md); part_md->part_type = part_type; @@ -1510,7 +1603,8 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) card->part[idx].part_cfg, card->part[idx].size >> 9, card->part[idx].force_ro, - card->part[idx].name); + card->part[idx].name, + card->part[idx].area_type); if (ret) return ret; } @@ -1539,9 +1633,16 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) static void mmc_blk_remove_req(struct mmc_blk_data *md) { + struct mmc_card *card; + if (md) { + card = md->queue.card; if (md->disk->flags & GENHD_FL_UP) { device_remove_file(disk_to_dev(md->disk), &md->force_ro); + if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && + card->ext_csd.boot_ro_lockable) + device_remove_file(disk_to_dev(md->disk), + &md->power_ro_lock); /* Stop new requests from getting into the queue */ del_gendisk(md->disk); @@ -1570,6 +1671,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card, static int mmc_add_disk(struct mmc_blk_data *md) { int ret; + struct mmc_card *card = md->queue.card; add_disk(md->disk); md->force_ro.show = force_ro_show; @@ -1579,18 +1681,53 @@ static int mmc_add_disk(struct mmc_blk_data *md) md->force_ro.attr.mode = S_IRUGO | S_IWUSR; ret = device_create_file(disk_to_dev(md->disk), &md->force_ro); if (ret) - del_gendisk(md->disk); + goto force_ro_fail; + + if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && + card->ext_csd.boot_ro_lockable) { + mode_t mode; + + if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) + mode = S_IRUGO; + else + mode = S_IRUGO | S_IWUSR; + + md->power_ro_lock.show = power_ro_lock_show; + md->power_ro_lock.store = power_ro_lock_store; + md->power_ro_lock.attr.mode = mode; + md->power_ro_lock.attr.name = + "ro_lock_until_next_power_on"; + ret = device_create_file(disk_to_dev(md->disk), + &md->power_ro_lock); + if (ret) + goto power_ro_lock_fail; + } + return ret; + +power_ro_lock_fail: + device_remove_file(disk_to_dev(md->disk), &md->force_ro); +force_ro_fail: + del_gendisk(md->disk); return ret; } +#define CID_MANFID_SANDISK 0x2 +#define CID_MANFID_TOSHIBA 0x11 +#define CID_MANFID_MICRON 0x13 + static const struct mmc_fixup blk_fixups[] = { - MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), /* * Some MMC cards experience performance degradation with CMD23 @@ -1600,18 +1737,18 @@ static const struct mmc_fixup blk_fixups[] = * * N.B. This doesn't affect SD cards. */ - MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), /* * Some Micron MMC cards needs longer data read timeout than * indicated in CSD. */ - MMC_FIXUP(CID_NAME_ANY, 0x13, 0x200, add_quirk_mmc, + MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, MMC_QUIRK_LONG_READ_TIME), END_FIXUP diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index e99bdc18002d..759714ed6bee 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -1581,6 +1581,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) t->max_segs = test->card->host->max_segs; t->max_seg_sz = test->card->host->max_seg_size; + t->max_seg_sz -= t->max_seg_sz % 512; t->max_tfr = t->max_sz; if (t->max_tfr >> 9 > test->card->host->max_blk_count) diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index dcad59cbfef1..2517547b4366 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -29,6 +29,8 @@ */ static int mmc_prep_request(struct request_queue *q, struct request *req) { + struct mmc_queue *mq = q->queuedata; + /* * We only like normal block requests and discards. */ @@ -37,6 +39,9 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) return BLKPREP_KILL; } + if (mq && mmc_card_removed(mq->card)) + return BLKPREP_KILL; + req->cmd_flags |= REQ_DONTPREP; return BLKPREP_OK; diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 639501970b41..dca4428380f1 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,6 +7,6 @@ mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ - quirks.o + quirks.o cd-gpio.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 6be49249895a..5d011a39dfff 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card) mmc_card_ddr_mode(card) ? "DDR " : "", type); } else { - printk(KERN_INFO "%s: new %s%s%s card at address %04x\n", + pr_info("%s: new %s%s%s%s card at address %04x\n", mmc_hostname(card->host), - mmc_sd_card_uhs(card) ? "ultra high speed " : + mmc_card_uhs(card) ? "ultra high speed " : (mmc_card_highspeed(card) ? "high speed " : ""), + (mmc_card_hs200(card) ? "HS200 " : ""), mmc_card_ddr_mode(card) ? "DDR " : "", type, card->rca); } diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c new file mode 100644 index 000000000000..082202ae4a03 --- /dev/null +++ b/drivers/mmc/core/cd-gpio.c @@ -0,0 +1,74 @@ +/* + * Generic GPIO card-detect helper + * + * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> + * + * 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 <linux/err.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/mmc/host.h> +#include <linux/module.h> +#include <linux/slab.h> + +struct mmc_cd_gpio { + unsigned int gpio; + char label[0]; +}; + +static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id) +{ + /* Schedule a card detection after a debounce timeout */ + mmc_detect_change(dev_id, msecs_to_jiffies(100)); + return IRQ_HANDLED; +} + +int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio, + unsigned int irq, unsigned long flags) +{ + size_t len = strlen(dev_name(host->parent)) + 4; + struct mmc_cd_gpio *cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL); + int ret; + + if (!cd) + return -ENOMEM; + + snprintf(cd->label, len, "%s cd", dev_name(host->parent)); + + ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label); + if (ret < 0) + goto egpioreq; + + ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt, + flags, cd->label, host); + if (ret < 0) + goto eirqreq; + + cd->gpio = gpio; + host->hotplug.irq = irq; + host->hotplug.handler_priv = cd; + + return 0; + +eirqreq: + gpio_free(gpio); +egpioreq: + kfree(cd); + return ret; +} +EXPORT_SYMBOL(mmc_cd_gpio_request); + +void mmc_cd_gpio_free(struct mmc_host *host) +{ + struct mmc_cd_gpio *cd = host->hotplug.handler_priv; + + free_irq(host->hotplug.irq, host); + gpio_free(cd->gpio); + kfree(cd); +} +EXPORT_SYMBOL(mmc_cd_gpio_free); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 950b97d7412a..f545a3e6eb80 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -48,7 +48,7 @@ static struct workqueue_struct *workqueue; * performance cost, and for other reasons may not always be desired. * So we allow it it to be disabled. */ -int use_spi_crc = 1; +bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); /* @@ -58,9 +58,9 @@ module_param(use_spi_crc, bool, 0); * overridden if necessary. */ #ifdef CONFIG_MMC_UNSAFE_RESUME -int mmc_assume_removable; +bool mmc_assume_removable; #else -int mmc_assume_removable = 1; +bool mmc_assume_removable = 1; #endif EXPORT_SYMBOL(mmc_assume_removable); module_param_named(removable, mmc_assume_removable, bool, 0644); @@ -140,7 +140,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) cmd->retries = 0; } - if (err && cmd->retries) { + if (err && cmd->retries && !mmc_card_removed(host->card)) { /* * Request starter must handle retries - see * mmc_wait_for_req_done(). @@ -247,6 +247,11 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) { init_completion(&mrq->completion); mrq->done = mmc_wait_done; + if (mmc_card_removed(host->card)) { + mrq->cmd->error = -ENOMEDIUM; + complete(&mrq->completion); + return; + } mmc_start_request(host, mrq); } @@ -259,7 +264,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host, wait_for_completion(&mrq->completion); cmd = mrq->cmd; - if (!cmd->error || !cmd->retries) + if (!cmd->error || !cmd->retries || + mmc_card_removed(host->card)) break; pr_debug("%s: req failed (CMD%u): %d, retrying...\n", @@ -1456,7 +1462,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) WARN_ON(host->removed); spin_unlock_irqrestore(&host->lock, flags); #endif - + host->detect_change = 1; mmc_schedule_delayed_work(&host->detect, delay); } @@ -2049,6 +2055,43 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) return -EIO; } +int _mmc_detect_card_removed(struct mmc_host *host) +{ + int ret; + + if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) + return 0; + + if (!host->card || mmc_card_removed(host->card)) + return 1; + + ret = host->bus_ops->alive(host); + if (ret) { + mmc_card_set_removed(host->card); + pr_debug("%s: card remove detected\n", mmc_hostname(host)); + } + + return ret; +} + +int mmc_detect_card_removed(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + + WARN_ON(!host->claimed); + /* + * The card will be considered unchanged unless we have been asked to + * detect a change or host requires polling to provide card detection. + */ + if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL)) + return mmc_card_removed(card); + + host->detect_change = 0; + + return _mmc_detect_card_removed(host); +} +EXPORT_SYMBOL(mmc_detect_card_removed); + void mmc_rescan(struct work_struct *work) { static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; @@ -2069,6 +2112,8 @@ void mmc_rescan(struct work_struct *work) && !(host->caps & MMC_CAP_NONREMOVABLE)) host->bus_ops->detect(host); + host->detect_change = 0; + /* * Let mmc_bus_put() free the bus/bus_ops if we've found that * the card is no longer present. @@ -2130,6 +2175,7 @@ void mmc_stop_host(struct mmc_host *host) mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { + /* Calling bus_ops->remove() with a claimed host can deadlock */ if (host->bus_ops->remove) host->bus_ops->remove(host); @@ -2201,6 +2247,9 @@ int mmc_card_awake(struct mmc_host *host) { int err = -ENOSYS; + if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) + return 0; + mmc_bus_get(host); if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) @@ -2216,6 +2265,9 @@ int mmc_card_sleep(struct mmc_host *host) { int err = -ENOSYS; + if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) + return 0; + mmc_bus_get(host); if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep) @@ -2270,6 +2322,7 @@ EXPORT_SYMBOL(mmc_flush_cache); int mmc_cache_ctrl(struct mmc_host *host, u8 enable) { struct mmc_card *card = host->card; + unsigned int timeout; int err = 0; if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) || @@ -2280,16 +2333,18 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable) (card->ext_csd.cache_size > 0)) { enable = !!enable; - if (card->ext_csd.cache_ctrl ^ enable) + if (card->ext_csd.cache_ctrl ^ enable) { + timeout = enable ? card->ext_csd.generic_cmd6_time : 0; err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, enable, 0); - if (err) - pr_err("%s: cache %s error %d\n", - mmc_hostname(card->host), - enable ? "on" : "off", - err); - else - card->ext_csd.cache_ctrl = enable; + EXT_CSD_CACHE_CTRL, enable, timeout); + if (err) + pr_err("%s: cache %s error %d\n", + mmc_hostname(card->host), + enable ? "on" : "off", + err); + else + card->ext_csd.cache_ctrl = enable; + } } return err; @@ -2310,7 +2365,13 @@ int mmc_suspend_host(struct mmc_host *host) cancel_delayed_work(&host->disable); cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); - err = mmc_cache_ctrl(host, 0); + if (mmc_try_claim_host(host)) { + err = mmc_cache_ctrl(host, 0); + mmc_do_release_host(host); + } else { + err = -EBUSY; + } + if (err) goto out; @@ -2338,7 +2399,9 @@ int mmc_suspend_host(struct mmc_host *host) if (err == -ENOSYS || !host->bus_ops->resume) { /* * We simply "remove" the card in this case. - * It will be redetected on resume. + * It will be redetected on resume. (Calling + * bus_ops->remove() with a claimed host can + * deadlock.) */ if (host->bus_ops->remove) host->bus_ops->remove(host); @@ -2431,11 +2494,11 @@ int mmc_pm_notify(struct notifier_block *notify_block, if (!host->bus_ops || host->bus_ops->suspend) break; - mmc_claim_host(host); - + /* Calling bus_ops->remove() with a claimed host can deadlock */ if (host->bus_ops->remove) host->bus_ops->remove(host); + mmc_claim_host(host); mmc_detach_bus(host); mmc_power_off(host); mmc_release_host(host); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 14664f1fb16f..3bdafbca354f 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -24,6 +24,7 @@ struct mmc_bus_ops { int (*resume)(struct mmc_host *); int (*power_save)(struct mmc_host *); int (*power_restore)(struct mmc_host *); + int (*alive)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); @@ -59,12 +60,14 @@ void mmc_rescan(struct work_struct *work); void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); +int _mmc_detect_card_removed(struct mmc_host *host); + int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); int mmc_attach_sdio(struct mmc_host *host); /* Module parameters */ -extern int use_spi_crc; +extern bool use_spi_crc; /* Debugfs information for hosts and cards */ void mmc_add_host_debugfs(struct mmc_host *host); diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 3923880118b6..9ab5b17d488a 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -57,6 +57,8 @@ static int mmc_ios_show(struct seq_file *s, void *data) const char *str; seq_printf(s, "clock:\t\t%u Hz\n", ios->clock); + if (host->actual_clock) + seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock); seq_printf(s, "vdd:\t\t%u ", ios->vdd); if ((1 << ios->vdd) & MMC_VDD_165_195) seq_printf(s, "(1.65 - 1.95 V)\n"); @@ -133,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data) case MMC_TIMING_UHS_DDR50: str = "sd uhs DDR50"; break; + case MMC_TIMING_MMC_HS200: + str = "mmc high-speed SDR200"; + break; default: str = "invalid"; break; diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index d31c78b72b0f..30055f2b0d44 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -54,6 +54,27 @@ static DEFINE_IDR(mmc_host_idr); static DEFINE_SPINLOCK(mmc_host_lock); #ifdef CONFIG_MMC_CLKGATE +static ssize_t clkgate_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay); +} + +static ssize_t clkgate_delay_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + unsigned long flags, value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + spin_lock_irqsave(&host->clk_lock, flags); + host->clkgate_delay = value; + spin_unlock_irqrestore(&host->clk_lock, flags); + return count; +} /* * Enabling clock gating will make the core call out to the host @@ -114,7 +135,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) static void mmc_host_clk_gate_work(struct work_struct *work) { struct mmc_host *host = container_of(work, struct mmc_host, - clk_gate_work); + clk_gate_work.work); mmc_host_clk_gate_delayed(host); } @@ -131,6 +152,8 @@ void mmc_host_clk_hold(struct mmc_host *host) { unsigned long flags; + /* cancel any clock gating work scheduled by mmc_host_clk_release() */ + cancel_delayed_work_sync(&host->clk_gate_work); mutex_lock(&host->clk_gate_mutex); spin_lock_irqsave(&host->clk_lock, flags); if (host->clk_gated) { @@ -180,7 +203,8 @@ void mmc_host_clk_release(struct mmc_host *host) host->clk_requests--; if (mmc_host_may_gate_card(host->card) && !host->clk_requests) - queue_work(system_nrt_wq, &host->clk_gate_work); + queue_delayed_work(system_nrt_wq, &host->clk_gate_work, + msecs_to_jiffies(host->clkgate_delay)); spin_unlock_irqrestore(&host->clk_lock, flags); } @@ -213,8 +237,13 @@ static inline void mmc_host_clk_init(struct mmc_host *host) host->clk_requests = 0; /* Hold MCI clock for 8 cycles by default */ host->clk_delay = 8; + /* + * Default clock gating delay is 200ms. + * This value can be tuned by writing into sysfs entry. + */ + host->clkgate_delay = 200; host->clk_gated = false; - INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); + INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); spin_lock_init(&host->clk_lock); mutex_init(&host->clk_gate_mutex); } @@ -229,7 +258,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) * Wait for any outstanding gate and then make sure we're * ungated before exiting. */ - if (cancel_work_sync(&host->clk_gate_work)) + if (cancel_delayed_work_sync(&host->clk_gate_work)) mmc_host_clk_gate_delayed(host); if (host->clk_gated) mmc_host_clk_hold(host); @@ -237,6 +266,17 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) WARN_ON(host->clk_requests > 1); } +static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) +{ + host->clkgate_delay_attr.show = clkgate_delay_show; + host->clkgate_delay_attr.store = clkgate_delay_store; + sysfs_attr_init(&host->clkgate_delay_attr.attr); + host->clkgate_delay_attr.attr.name = "clkgate_delay"; + host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR; + if (device_create_file(&host->class_dev, &host->clkgate_delay_attr)) + pr_err("%s: Failed to create clkgate_delay sysfs entry\n", + mmc_hostname(host)); +} #else static inline void mmc_host_clk_init(struct mmc_host *host) @@ -247,6 +287,10 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) { } +static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) +{ +} + #endif /** @@ -335,6 +379,7 @@ int mmc_add_host(struct mmc_host *host) #ifdef CONFIG_DEBUG_FS mmc_add_host_debugfs(host); #endif + mmc_host_clk_sysfs_init(host); mmc_start_host(host); register_pm_notifier(&host->pm_notify); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index d240427c1246..59b9ba52e66a 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { + case EXT_CSD_CARD_TYPE_SDR_ALL: + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V: + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V: + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52: + card->ext_csd.hs_max_dtr = 200000000; + card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200; + break; + case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL: + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V: + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V: + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52: + card->ext_csd.hs_max_dtr = 200000000; + card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V; + break; + case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL: + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V: + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V: + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52: + card->ext_csd.hs_max_dtr = 200000000; + card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V; + break; case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 52000000; @@ -348,7 +369,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; mmc_part_add(card, part_size, EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, - "boot%d", idx, true); + "boot%d", idx, true, + MMC_BLK_DATA_AREA_BOOT); } } } @@ -435,7 +457,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) hc_wp_grp_sz); mmc_part_add(card, part_size << 19, EXT_CSD_PART_CONFIG_ACC_GP0 + idx, - "gp%d", idx, false); + "gp%d", idx, false, + MMC_BLK_DATA_AREA_GP); } } card->ext_csd.sec_trim_mult = @@ -446,6 +469,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.trim_timeout = 300 * ext_csd[EXT_CSD_TRIM_MULT]; + + /* + * Note that the call to mmc_part_add above defaults to read + * only. If this default assumption is changed, the call must + * take into account the value of boot_locked below. + */ + card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; + card->ext_csd.boot_ro_lockable = true; } if (card->ext_csd.rev >= 5) { @@ -690,6 +721,79 @@ static int mmc_select_powerclass(struct mmc_card *card, } /* + * Selects the desired buswidth and switch to the HS200 mode + * if bus width set without error + */ +static int mmc_select_hs200(struct mmc_card *card) +{ + int idx, err = 0; + struct mmc_host *host; + static unsigned ext_csd_bits[] = { + EXT_CSD_BUS_WIDTH_4, + EXT_CSD_BUS_WIDTH_8, + }; + static unsigned bus_widths[] = { + MMC_BUS_WIDTH_4, + MMC_BUS_WIDTH_8, + }; + + BUG_ON(!card); + + host = card->host; + + if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V && + host->caps2 & MMC_CAP2_HS200_1_2V_SDR) + if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0)) + err = mmc_set_signal_voltage(host, + MMC_SIGNAL_VOLTAGE_180, 0); + + /* If fails try again during next card power cycle */ + if (err) + goto err; + + idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0; + + /* + * Unlike SD, MMC cards dont have a configuration register to notify + * supported bus width. So bus test command should be run to identify + * the supported bus width or compare the ext csd values of current + * bus width and ext csd values of 1 bit mode read earlier. + */ + for (; idx >= 0; idx--) { + + /* + * Host is capable of 8bit transfer, then switch + * the device to work in 8bit transfer mode. If the + * mmc switch command returns error then switch to + * 4bit transfer mode. On success set the corresponding + * bus width on the host. + */ + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, + ext_csd_bits[idx], + card->ext_csd.generic_cmd6_time); + if (err) + continue; + + mmc_set_bus_width(card->host, bus_widths[idx]); + + if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) + err = mmc_compare_ext_csds(card, bus_widths[idx]); + else + err = mmc_bus_test(card, bus_widths[idx]); + if (!err) + break; + } + + /* switch to HS200 mode if bus width set successfully */ + if (!err) + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, 2, 0); +err: + return err; +} + +/* * Handle the detection and initialisation of a card. * * In the case of a resume, "oldcard" will contain the card @@ -895,11 +999,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* * Activate high speed (if supported) */ - if ((card->ext_csd.hs_max_dtr != 0) && - (host->caps & MMC_CAP_MMC_HIGHSPEED)) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 1, - card->ext_csd.generic_cmd6_time); + if (card->ext_csd.hs_max_dtr != 0) { + err = 0; + if (card->ext_csd.hs_max_dtr > 52000000 && + host->caps2 & MMC_CAP2_HS200) + err = mmc_select_hs200(card); + else if (host->caps & MMC_CAP_MMC_HIGHSPEED) + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, 1, 0); + if (err && err != -EBADMSG) goto free_card; @@ -908,8 +1016,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_hostname(card->host)); err = 0; } else { - mmc_card_set_highspeed(card); - mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + if (card->ext_csd.hs_max_dtr > 52000000 && + host->caps2 & MMC_CAP2_HS200) { + mmc_card_set_hs200(card); + mmc_set_timing(card->host, + MMC_TIMING_MMC_HS200); + } else { + mmc_card_set_highspeed(card); + mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + } } } @@ -934,7 +1049,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ max_dtr = (unsigned int)-1; - if (mmc_card_highspeed(card)) { + if (mmc_card_highspeed(card) || mmc_card_hs200(card)) { if (max_dtr > card->ext_csd.hs_max_dtr) max_dtr = card->ext_csd.hs_max_dtr; } else if (max_dtr > card->csd.max_dtr) { @@ -960,9 +1075,48 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } /* + * Indicate HS200 SDR mode (if supported). + */ + if (mmc_card_hs200(card)) { + u32 ext_csd_bits; + u32 bus_width = card->host->ios.bus_width; + + /* + * For devices supporting HS200 mode, the bus width has + * to be set before executing the tuning function. If + * set before tuning, then device will respond with CRC + * errors for responses on CMD line. So for HS200 the + * sequence will be + * 1. set bus width 4bit / 8 bit (1 bit not supported) + * 2. switch to HS200 mode + * 3. set the clock to > 52Mhz <=200MHz and + * 4. execute tuning for HS200 + */ + if ((host->caps2 & MMC_CAP2_HS200) && + card->host->ops->execute_tuning) + err = card->host->ops->execute_tuning(card->host, + MMC_SEND_TUNING_BLOCK_HS200); + if (err) { + pr_warning("%s: tuning execution failed\n", + mmc_hostname(card->host)); + goto err; + } + + ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? + EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4; + err = mmc_select_powerclass(card, ext_csd_bits, ext_csd); + if (err) { + pr_err("%s: power class selection to bus width %d failed\n", + mmc_hostname(card->host), 1 << bus_width); + goto err; + } + } + + /* * Activate wide bus and DDR (if supported). */ - if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) && + if (!mmc_card_hs200(card) && + (card->csd.mmca_vsn >= CSD_SPEC_VER_3) && (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { static unsigned ext_csd_bits[][2] = { { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 }, @@ -1048,7 +1202,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * * WARNING: eMMC rules are NOT the same as SD DDR */ - if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) { + if (ddr == MMC_1_2V_DDR_MODE) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0); if (err) @@ -1067,14 +1221,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if ((host->caps2 & MMC_CAP2_CACHE_CTRL) && card->ext_csd.cache_size > 0) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, 1, 0); + EXT_CSD_CACHE_CTRL, 1, + card->ext_csd.generic_cmd6_time); if (err && err != -EBADMSG) goto free_card; /* * Only if no error, cache is turned on successfully. */ - card->ext_csd.cache_ctrl = err ? 0 : 1; + if (err) { + pr_warning("%s: Cache is supported, " + "but failed to turn on (%d)\n", + mmc_hostname(card->host), err); + card->ext_csd.cache_ctrl = 0; + err = 0; + } else { + card->ext_csd.cache_ctrl = 1; + } } if (!oldcard) @@ -1105,6 +1268,14 @@ static void mmc_remove(struct mmc_host *host) } /* + * Card detection - card is alive. + */ +static int mmc_alive(struct mmc_host *host) +{ + return mmc_send_status(host->card, NULL); +} + +/* * Card detection callback from host. */ static void mmc_detect(struct mmc_host *host) @@ -1119,7 +1290,7 @@ static void mmc_detect(struct mmc_host *host) /* * Just check if our card has been removed. */ - err = mmc_send_status(host->card, NULL); + err = _mmc_detect_card_removed(host); mmc_release_host(host); @@ -1224,6 +1395,7 @@ static const struct mmc_bus_ops mmc_ops = { .suspend = NULL, .resume = NULL, .power_restore = mmc_power_restore, + .alive = mmc_alive, }; static const struct mmc_bus_ops mmc_ops_unsafe = { @@ -1234,6 +1406,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = { .suspend = mmc_suspend, .resume = mmc_resume, .power_restore = mmc_power_restore, + .alive = mmc_alive, }; static void mmc_attach_bus_ops(struct mmc_host *host) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index f2a05ea40f2a..c63ad03c29c7 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -307,8 +307,8 @@ static int mmc_read_switch(struct mmc_card *card) goto out; } - if (status[13] & UHS_SDR50_BUS_SPEED) - card->sw_caps.hs_max_dtr = 50000000; + if (status[13] & SD_MODE_HIGH_SPEED) + card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR; if (card->scr.sda_spec3) { card->sw_caps.sd3_bus_mode = status[13]; @@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) /* SPI mode doesn't define CMD19 */ if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) - err = card->host->ops->execute_tuning(card->host); + err = card->host->ops->execute_tuning(card->host, + MMC_SEND_TUNING_BLOCK); out: kfree(status); @@ -960,7 +961,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto free_card; /* Card is an ultra-high-speed card */ - mmc_sd_card_set_uhs(card); + mmc_card_set_uhs(card); /* * Since initialization is now complete, enable preset @@ -1019,6 +1020,14 @@ static void mmc_sd_remove(struct mmc_host *host) } /* + * Card detection - card is alive. + */ +static int mmc_sd_alive(struct mmc_host *host) +{ + return mmc_send_status(host->card, NULL); +} + +/* * Card detection callback from host. */ static void mmc_sd_detect(struct mmc_host *host) @@ -1033,7 +1042,7 @@ static void mmc_sd_detect(struct mmc_host *host) /* * Just check if our card has been removed. */ - err = mmc_send_status(host->card, NULL); + err = _mmc_detect_card_removed(host); mmc_release_host(host); @@ -1102,6 +1111,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { .suspend = NULL, .resume = NULL, .power_restore = mmc_sd_power_restore, + .alive = mmc_sd_alive, }; static const struct mmc_bus_ops mmc_sd_ops_unsafe = { @@ -1110,6 +1120,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = { .suspend = mmc_sd_suspend, .resume = mmc_sd_resume, .power_restore = mmc_sd_power_restore, + .alive = mmc_sd_alive, }; static void mmc_sd_attach_bus_ops(struct mmc_host *host) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 3ab565e32a6a..bd7bacc950dc 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -14,6 +14,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/mmc.h> #include <linux/mmc/sdio.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> @@ -102,6 +103,7 @@ static int sdio_read_cccr(struct mmc_card *card) int ret; int cccr_vsn; unsigned char data; + unsigned char speed; memset(&card->cccr, 0, sizeof(struct sdio_cccr)); @@ -140,12 +142,60 @@ static int sdio_read_cccr(struct mmc_card *card) } if (cccr_vsn >= SDIO_CCCR_REV_1_20) { - ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); if (ret) goto out; - if (data & SDIO_SPEED_SHS) - card->cccr.high_speed = 1; + card->scr.sda_spec3 = 0; + card->sw_caps.sd3_bus_mode = 0; + card->sw_caps.sd3_drv_type = 0; + if (cccr_vsn >= SDIO_CCCR_REV_3_00) { + card->scr.sda_spec3 = 1; + ret = mmc_io_rw_direct(card, 0, 0, + SDIO_CCCR_UHS, 0, &data); + if (ret) + goto out; + + if (card->host->caps & + (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_DDR50)) { + if (data & SDIO_UHS_DDR50) + card->sw_caps.sd3_bus_mode + |= SD_MODE_UHS_DDR50; + + if (data & SDIO_UHS_SDR50) + card->sw_caps.sd3_bus_mode + |= SD_MODE_UHS_SDR50; + + if (data & SDIO_UHS_SDR104) + card->sw_caps.sd3_bus_mode + |= SD_MODE_UHS_SDR104; + } + + ret = mmc_io_rw_direct(card, 0, 0, + SDIO_CCCR_DRIVE_STRENGTH, 0, &data); + if (ret) + goto out; + + if (data & SDIO_DRIVE_SDTA) + card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_A; + if (data & SDIO_DRIVE_SDTC) + card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C; + if (data & SDIO_DRIVE_SDTD) + card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D; + } + + /* if no uhs mode ensure we check for high speed */ + if (!card->sw_caps.sd3_bus_mode) { + if (speed & SDIO_SPEED_SHS) { + card->cccr.high_speed = 1; + card->sw_caps.hs_max_dtr = 50000000; + } else { + card->cccr.high_speed = 0; + card->sw_caps.hs_max_dtr = 25000000; + } + } } out: @@ -327,6 +377,194 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) return max_dtr; } +static unsigned char host_drive_to_sdio_drive(int host_strength) +{ + switch (host_strength) { + case MMC_SET_DRIVER_TYPE_A: + return SDIO_DTSx_SET_TYPE_A; + case MMC_SET_DRIVER_TYPE_B: + return SDIO_DTSx_SET_TYPE_B; + case MMC_SET_DRIVER_TYPE_C: + return SDIO_DTSx_SET_TYPE_C; + case MMC_SET_DRIVER_TYPE_D: + return SDIO_DTSx_SET_TYPE_D; + default: + return SDIO_DTSx_SET_TYPE_B; + } +} + +static void sdio_select_driver_type(struct mmc_card *card) +{ + int host_drv_type = SD_DRIVER_TYPE_B; + int card_drv_type = SD_DRIVER_TYPE_B; + int drive_strength; + unsigned char card_strength; + int err; + + /* + * If the host doesn't support any of the Driver Types A,C or D, + * or there is no board specific handler then default Driver + * Type B is used. + */ + if (!(card->host->caps & + (MMC_CAP_DRIVER_TYPE_A | + MMC_CAP_DRIVER_TYPE_C | + MMC_CAP_DRIVER_TYPE_D))) + return; + + if (!card->host->ops->select_drive_strength) + return; + + if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) + host_drv_type |= SD_DRIVER_TYPE_A; + + if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) + host_drv_type |= SD_DRIVER_TYPE_C; + + if (card->host->caps & MMC_CAP_DRIVER_TYPE_D) + host_drv_type |= SD_DRIVER_TYPE_D; + + if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A) + card_drv_type |= SD_DRIVER_TYPE_A; + + if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) + card_drv_type |= SD_DRIVER_TYPE_C; + + if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D) + card_drv_type |= SD_DRIVER_TYPE_D; + + /* + * The drive strength that the hardware can support + * depends on the board design. Pass the appropriate + * information and let the hardware specific code + * return what is possible given the options + */ + drive_strength = card->host->ops->select_drive_strength( + card->sw_caps.uhs_max_dtr, + host_drv_type, card_drv_type); + + /* if error just use default for drive strength B */ + err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0, + &card_strength); + if (err) + return; + + card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT); + card_strength |= host_drive_to_sdio_drive(drive_strength); + + err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH, + card_strength, NULL); + + /* if error default to drive strength B */ + if (!err) + mmc_set_driver_type(card->host, drive_strength); +} + + +static int sdio_set_bus_speed_mode(struct mmc_card *card) +{ + unsigned int bus_speed, timing; + int err; + unsigned char speed; + + /* + * If the host doesn't support any of the UHS-I modes, fallback on + * default speed. + */ + if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) + return 0; + + bus_speed = SDIO_SPEED_SDR12; + timing = MMC_TIMING_UHS_SDR12; + if ((card->host->caps & MMC_CAP_UHS_SDR104) && + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) { + bus_speed = SDIO_SPEED_SDR104; + timing = MMC_TIMING_UHS_SDR104; + card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; + } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) { + bus_speed = SDIO_SPEED_DDR50; + timing = MMC_TIMING_UHS_DDR50; + card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; + } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & + SD_MODE_UHS_SDR50)) { + bus_speed = SDIO_SPEED_SDR50; + timing = MMC_TIMING_UHS_SDR50; + card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; + } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) { + bus_speed = SDIO_SPEED_SDR25; + timing = MMC_TIMING_UHS_SDR25; + card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; + } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & + SD_MODE_UHS_SDR12)) { + bus_speed = SDIO_SPEED_SDR12; + timing = MMC_TIMING_UHS_SDR12; + card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; + } + + err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); + if (err) + return err; + + speed &= ~SDIO_SPEED_BSS_MASK; + speed |= bus_speed; + err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); + if (err) + return err; + + if (bus_speed) { + mmc_set_timing(card->host, timing); + mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); + } + + return 0; +} + +/* + * UHS-I specific initialization procedure + */ +static int mmc_sdio_init_uhs_card(struct mmc_card *card) +{ + int err; + + if (!card->scr.sda_spec3) + return 0; + + /* + * Switch to wider bus (if supported). + */ + if (card->host->caps & MMC_CAP_4_BIT_DATA) { + err = sdio_enable_4bit_bus(card); + if (err > 0) { + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); + err = 0; + } + } + + /* Set the driver strength for the card */ + sdio_select_driver_type(card); + + /* Set bus speed mode of the card */ + err = sdio_set_bus_speed_mode(card); + if (err) + goto out; + + /* Initialize and start re-tuning timer */ + if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) + err = card->host->ops->execute_tuning(card->host, + MMC_SEND_TUNING_BLOCK); + +out: + + return err; +} + /* * Handle the detection and initialisation of a card. * @@ -394,6 +632,30 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, host->ops->init_card(host, card); /* + * If the host and card support UHS-I mode request the card + * to switch to 1.8V signaling level. No 1.8v signalling if + * UHS mode is not enabled to maintain compatibilty and some + * systems that claim 1.8v signalling in fact do not support + * it. + */ + if ((ocr & R4_18V_PRESENT) && + (host->caps & + (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_DDR50))) { + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, + true); + if (err) { + ocr &= ~R4_18V_PRESENT; + host->ocr &= ~R4_18V_PRESENT; + } + err = 0; + } else { + ocr &= ~R4_18V_PRESENT; + host->ocr &= ~R4_18V_PRESENT; + } + + /* * For native busses: set card RCA and quit open drain mode. */ if (!powered_resume && !mmc_host_is_spi(host)) { @@ -492,29 +754,39 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (err) goto remove; - /* - * Switch to high-speed (if supported). - */ - err = sdio_enable_hs(card); - if (err > 0) - mmc_sd_go_highspeed(card); - else if (err) - goto remove; + /* Initialization sequence for UHS-I cards */ + /* Only if card supports 1.8v and UHS signaling */ + if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) { + err = mmc_sdio_init_uhs_card(card); + if (err) + goto remove; - /* - * Change to the card's maximum speed. - */ - mmc_set_clock(host, mmc_sdio_get_max_clock(card)); + /* Card is an ultra-high-speed card */ + mmc_card_set_uhs(card); + } else { + /* + * Switch to high-speed (if supported). + */ + err = sdio_enable_hs(card); + if (err > 0) + mmc_sd_go_highspeed(card); + else if (err) + goto remove; - /* - * Switch to wider bus (if supported). - */ - err = sdio_enable_4bit_bus(card); - if (err > 0) - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - else if (err) - goto remove; + /* + * Change to the card's maximum speed. + */ + mmc_set_clock(host, mmc_sdio_get_max_clock(card)); + /* + * Switch to wider bus (if supported). + */ + err = sdio_enable_4bit_bus(card); + if (err > 0) + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); + else if (err) + goto remove; + } finish: if (!oldcard) host->card = card; @@ -550,6 +822,14 @@ static void mmc_sdio_remove(struct mmc_host *host) } /* + * Card detection - card is alive. + */ +static int mmc_sdio_alive(struct mmc_host *host) +{ + return mmc_select_card(host->card); +} + +/* * Card detection callback from host. */ static void mmc_sdio_detect(struct mmc_host *host) @@ -571,7 +851,7 @@ static void mmc_sdio_detect(struct mmc_host *host) /* * Just check if our card has been removed. */ - err = mmc_select_card(host->card); + err = _mmc_detect_card_removed(host); mmc_release_host(host); @@ -749,6 +1029,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { .suspend = mmc_sdio_suspend, .resume = mmc_sdio_resume, .power_restore = mmc_sdio_power_restore, + .alive = mmc_sdio_alive, }; @@ -797,8 +1078,17 @@ int mmc_attach_sdio(struct mmc_host *host) * Detect and init the card. */ err = mmc_sdio_init_card(host, host->ocr, NULL, 0); - if (err) - goto err; + if (err) { + if (err == -EAGAIN) { + /* + * Retry initialization with S18R set to 0. + */ + host->ocr &= ~R4_18V_PRESENT; + err = mmc_sdio_init_card(host, host->ocr, NULL, 0); + } + if (err) + goto err; + } card = host->card; /* diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index b1f3168f791b..8f6f5ac131fc 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -196,6 +196,9 @@ static inline unsigned int sdio_max_byte_size(struct sdio_func *func) else mval = min(mval, func->max_blksize); + if (mmc_card_broken_byte_mode_512(func->card)) + return min(mval, 511u); + return min(mval, 512u); /* maximum size for byte mode */ } @@ -314,7 +317,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, func->card->host->max_seg_size / func->cur_blksize); max_blocks = min(max_blocks, 511u); - while (remainder > func->cur_blksize) { + while (remainder >= func->cur_blksize) { unsigned blocks; blocks = remainder / func->cur_blksize; @@ -339,8 +342,9 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, while (remainder > 0) { size = min(remainder, sdio_max_byte_size(func)); + /* Indicate byte mode by setting "blocks" = 0 */ ret = mmc_io_rw_extended(func->card, write, func->num, addr, - incr_addr, buf, 1, size); + incr_addr, buf, 0, size); if (ret) return ret; diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index b0517cc06200..d29e20630eed 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -128,8 +128,6 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, BUG_ON(!card); BUG_ON(fn > 7); - BUG_ON(blocks == 1 && blksz > 512); - WARN_ON(blocks == 0); WARN_ON(blksz == 0); /* sanity check */ @@ -144,22 +142,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.arg |= fn << 28; cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; cmd.arg |= addr << 9; - if (blocks == 1 && blksz < 512) - cmd.arg |= blksz; /* byte mode */ - else if (blocks == 1 && blksz == 512 && - !(mmc_card_broken_byte_mode_512(card))) - cmd.arg |= 0; /* byte mode, 0==512 */ + if (blocks == 0) + cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ else cmd.arg |= 0x08000000 | blocks; /* block mode */ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; data.blksz = blksz; - data.blocks = blocks; + /* Code in host drivers/fwk assumes that "blocks" always is >=1 */ + data.blocks = blocks ? blocks : 1; data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, buf, blksz * blocks); + sg_init_one(&sg, buf, data.blksz * data.blocks); mmc_set_data_timeout(&data, card); diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index b4b83f302e32..745f8fce2519 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o +obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index f437c3e6f3aa..947faa5d2ce4 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -236,7 +236,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data sg = &data->sg[i]; - sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; amount = min(size, sg->length); size -= amount; @@ -252,7 +252,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data dmabuf = (unsigned *)tmpv; } - kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); + kunmap_atomic(sgbuffer); if (size == 0) break; @@ -302,7 +302,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host) sg = &data->sg[i]; - sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; amount = min(size, sg->length); size -= amount; @@ -318,7 +318,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host) } flush_kernel_dcache_page(sg_page(sg)); - kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); + kunmap_atomic(sgbuffer); data->bytes_xfered += amount; if (size == 0) break; diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index a7ee50271465..fcfe1eb5acc8 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -823,6 +823,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) struct scatterlist *sg; unsigned int i; enum dma_data_direction direction; + enum dma_transfer_direction slave_dirn; unsigned int sglen; u32 iflags; @@ -860,16 +861,19 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) if (host->caps.has_dma) atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN); - if (data->flags & MMC_DATA_READ) + if (data->flags & MMC_DATA_READ) { direction = DMA_FROM_DEVICE; - else + slave_dirn = DMA_DEV_TO_MEM; + } else { direction = DMA_TO_DEVICE; + slave_dirn = DMA_MEM_TO_DEV; + } sglen = dma_map_sg(chan->device->dev, data->sg, data->sg_len, direction); desc = chan->device->device_prep_slave_sg(chan, - data->sg, sglen, direction, + data->sg, sglen, slave_dirn, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) goto unmap_exit; diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 5d3b9ae64523..dbd0c8a4e98a 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -153,6 +153,7 @@ static inline int has_dbdma(void) { switch (alchemy_get_cputype()) { case ALCHEMY_CPU_AU1200: + case ALCHEMY_CPU_AU1300: return 1; default: return 0; @@ -768,11 +769,15 @@ static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) config2 = au_readl(HOST_CONFIG2(host)); switch (ios->bus_width) { + case MMC_BUS_WIDTH_8: + config2 |= SD_CONFIG2_BB; + break; case MMC_BUS_WIDTH_4: + config2 &= ~SD_CONFIG2_BB; config2 |= SD_CONFIG2_WB; break; case MMC_BUS_WIDTH_1: - config2 &= ~SD_CONFIG2_WB; + config2 &= ~(SD_CONFIG2_WB | SD_CONFIG2_BB); break; } au_writel(config2, HOST_CONFIG2(host)); @@ -943,7 +948,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) struct mmc_host *mmc; struct au1xmmc_host *host; struct resource *r; - int ret; + int ret, iflag; mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev); if (!mmc) { @@ -982,37 +987,43 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no IRQ defined\n"); goto out3; } - host->irq = r->start; - /* IRQ is shared among both SD controllers */ - ret = request_irq(host->irq, au1xmmc_irq, IRQF_SHARED, - DRIVER_NAME, host); - if (ret) { - dev_err(&pdev->dev, "cannot grab IRQ\n"); - goto out3; - } mmc->ops = &au1xmmc_ops; mmc->f_min = 450000; mmc->f_max = 24000000; + mmc->max_blk_size = 2048; + mmc->max_blk_count = 512; + + mmc->ocr_avail = AU1XMMC_OCR; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; + + iflag = IRQF_SHARED; /* Au1100/Au1200: one int for both ctrls */ + switch (alchemy_get_cputype()) { case ALCHEMY_CPU_AU1100: mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE; - mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; break; case ALCHEMY_CPU_AU1200: mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; - mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; + break; + case ALCHEMY_CPU_AU1300: + iflag = 0; /* nothing is shared */ + mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; + mmc->f_max = 52000000; + if (host->ioarea->start == AU1100_SD0_PHYS_ADDR) + mmc->caps |= MMC_CAP_8_BIT_DATA; break; } - mmc->max_blk_size = 2048; - mmc->max_blk_count = 512; - - mmc->ocr_avail = AU1XMMC_OCR; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + ret = request_irq(host->irq, au1xmmc_irq, iflag, DRIVER_NAME, host); + if (ret) { + dev_err(&pdev->dev, "cannot grab IRQ\n"); + goto out3; + } host->status = HOST_S_IDLE; diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index 0371bf502249..03666174ca48 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c @@ -627,17 +627,7 @@ static struct platform_driver sdh_driver = { }, }; -static int __init sdh_init(void) -{ - return platform_driver_register(&sdh_driver); -} -module_init(sdh_init); - -static void __exit sdh_exit(void) -{ - platform_driver_unregister(&sdh_driver); -} -module_exit(sdh_exit); +module_platform_driver(sdh_driver); MODULE_DESCRIPTION("Blackfin Secure Digital Host Driver"); MODULE_AUTHOR("Cliff Cai, Roy Huang"); diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index ce2a47b71dd6..83693fd7c6b3 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -780,18 +780,7 @@ static struct platform_driver cb710_mmc_driver = { #endif }; -static int __init cb710_mmc_init_module(void) -{ - return platform_driver_register(&cb710_mmc_driver); -} - -static void __exit cb710_mmc_cleanup_module(void) -{ - platform_driver_unregister(&cb710_mmc_driver); -} - -module_init(cb710_mmc_init_module); -module_exit(cb710_mmc_cleanup_module); +module_platform_driver(cb710_mmc_driver); MODULE_AUTHOR("MichaĹ‚ MirosĹ‚aw <mirq-linux@rere.qmqm.pl>"); MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part"); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 3aaeb0841914..0e342793ff14 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -588,11 +588,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot) mci_writel(host, CTYPE, (slot->ctype << slot->id)); } -static void dw_mci_start_request(struct dw_mci *host, - struct dw_mci_slot *slot) +static void __dw_mci_start_request(struct dw_mci *host, + struct dw_mci_slot *slot, + struct mmc_command *cmd) { struct mmc_request *mrq; - struct mmc_command *cmd; struct mmc_data *data; u32 cmdflags; @@ -610,14 +610,13 @@ static void dw_mci_start_request(struct dw_mci *host, host->completed_events = 0; host->data_status = 0; - data = mrq->data; + data = cmd->data; if (data) { dw_mci_set_timeout(host); mci_writel(host, BYTCNT, data->blksz*data->blocks); mci_writel(host, BLKSIZ, data->blksz); } - cmd = mrq->cmd; cmdflags = dw_mci_prepare_command(slot->mmc, cmd); /* this is the first command, send the initialization clock */ @@ -635,6 +634,16 @@ static void dw_mci_start_request(struct dw_mci *host, host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); } +static void dw_mci_start_request(struct dw_mci *host, + struct dw_mci_slot *slot) +{ + struct mmc_request *mrq = slot->mrq; + struct mmc_command *cmd; + + cmd = mrq->sbc ? mrq->sbc : mrq->cmd; + __dw_mci_start_request(host, slot, cmd); +} + /* must be called with host->lock held */ static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, struct mmc_request *mrq) @@ -698,12 +707,15 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) break; } + regs = mci_readl(slot->host, UHS_REG); + /* DDR mode set */ - if (ios->timing == MMC_TIMING_UHS_DDR50) { - regs = mci_readl(slot->host, UHS_REG); + if (ios->timing == MMC_TIMING_UHS_DDR50) regs |= (0x1 << slot->id) << 16; - mci_writel(slot->host, UHS_REG, regs); - } + else + regs &= ~(0x1 << slot->id) << 16; + + mci_writel(slot->host, UHS_REG, regs); if (ios->clock) { /* @@ -889,7 +901,14 @@ static void dw_mci_tasklet_func(unsigned long priv) cmd = host->cmd; host->cmd = NULL; set_bit(EVENT_CMD_COMPLETE, &host->completed_events); - dw_mci_command_complete(host, host->mrq->cmd); + dw_mci_command_complete(host, cmd); + if (cmd == host->mrq->sbc && !cmd->error) { + prev_state = state = STATE_SENDING_CMD; + __dw_mci_start_request(host, host->cur_slot, + host->mrq->cmd); + goto unlock; + } + if (!host->mrq->data || cmd->error) { dw_mci_request_end(host, host->mrq); goto unlock; @@ -967,6 +986,12 @@ static void dw_mci_tasklet_func(unsigned long priv) goto unlock; } + if (host->mrq->sbc && !data->error) { + data->stop->error = 0; + dw_mci_request_end(host, host->mrq); + goto unlock; + } + prev_state = state = STATE_SENDING_STOP; if (!data->error) send_stop_cmd(host, data); @@ -1678,8 +1703,9 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (host->pdata->caps) mmc->caps = host->pdata->caps; - else - mmc->caps = 0; + + if (host->pdata->caps2) + mmc->caps2 = host->pdata->caps2; if (host->pdata->get_bus_wd) if (host->pdata->get_bus_wd(slot->id) >= 4) @@ -1923,7 +1949,7 @@ static int dw_mci_probe(struct platform_device *pdev) * should put it in the platform data. */ fifo_size = mci_readl(host, FIFOTH); - fifo_size = 1 + ((fifo_size >> 16) & 0x7ff); + fifo_size = 1 + ((fifo_size >> 16) & 0xfff); } else { fifo_size = host->pdata->fifo_depth; } @@ -2062,14 +2088,14 @@ static int __exit dw_mci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP /* * TODO: we should probably disable the clock to the card in the suspend path. */ -static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg) +static int dw_mci_suspend(struct device *dev) { int i, ret; - struct dw_mci *host = platform_get_drvdata(pdev); + struct dw_mci *host = dev_get_drvdata(dev); for (i = 0; i < host->num_slots; i++) { struct dw_mci_slot *slot = host->slot[i]; @@ -2092,10 +2118,10 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg) return 0; } -static int dw_mci_resume(struct platform_device *pdev) +static int dw_mci_resume(struct device *dev) { int i, ret; - struct dw_mci *host = platform_get_drvdata(pdev); + struct dw_mci *host = dev_get_drvdata(dev); if (host->vmmc) regulator_enable(host->vmmc); @@ -2103,7 +2129,7 @@ static int dw_mci_resume(struct platform_device *pdev) if (host->dma_ops->init) host->dma_ops->init(host); - if (!mci_wait_reset(&pdev->dev, host)) { + if (!mci_wait_reset(dev, host)) { ret = -ENODEV; return ret; } @@ -2131,14 +2157,15 @@ static int dw_mci_resume(struct platform_device *pdev) #else #define dw_mci_suspend NULL #define dw_mci_resume NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(dw_mci_pmops, dw_mci_suspend, dw_mci_resume); static struct platform_driver dw_mci_driver = { .remove = __exit_p(dw_mci_remove), - .suspend = dw_mci_suspend, - .resume = dw_mci_resume, .driver = { .name = "dw_mmc", + .pm = &dw_mci_pmops, }, }; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 72c071f6e001..df392a1143f2 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -126,7 +126,7 @@ #define SDMMC_CMD_RESP_EXP BIT(6) #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ -#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FF) +#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) /* Internal DMAC interrupt defines */ #define SDMMC_IDMAC_INT_AI BIT(9) #define SDMMC_IDMAC_INT_NI BIT(8) diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 74218ad677e4..c8852a8128a9 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1012,17 +1012,7 @@ static struct platform_driver jz4740_mmc_driver = { }, }; -static int __init jz4740_mmc_init(void) -{ - return platform_driver_register(&jz4740_mmc_driver); -} -module_init(jz4740_mmc_init); - -static void __exit jz4740_mmc_exit(void) -{ - platform_driver_unregister(&jz4740_mmc_driver); -} -module_exit(jz4740_mmc_exit); +module_platform_driver(jz4740_mmc_driver); MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 92946b84e9fa..273306c68d58 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1525,7 +1525,6 @@ static struct of_device_id mmc_spi_of_match_table[] __devinitdata = { static struct spi_driver mmc_spi_driver = { .driver = { .name = "mmc_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, .of_match_table = mmc_spi_of_match_table, }, diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index fa8dd2fda4b2..0d955ffaf44e 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -374,6 +374,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, struct dma_chan *chan; struct dma_device *device; struct dma_async_tx_descriptor *desc; + enum dma_data_direction buffer_dirn; int nr_sg; /* Check if next job is already prepared */ @@ -387,10 +388,12 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, } if (data->flags & MMC_DATA_READ) { - conf.direction = DMA_FROM_DEVICE; + conf.direction = DMA_DEV_TO_MEM; + buffer_dirn = DMA_FROM_DEVICE; chan = host->dma_rx_channel; } else { - conf.direction = DMA_TO_DEVICE; + conf.direction = DMA_MEM_TO_DEV; + buffer_dirn = DMA_TO_DEVICE; chan = host->dma_tx_channel; } @@ -403,7 +406,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, return -EINVAL; device = chan->device; - nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, conf.direction); + nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, buffer_dirn); if (nr_sg == 0) return -EINVAL; @@ -426,7 +429,7 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, unmap_exit: if (!next) dmaengine_terminate_all(chan); - dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction); + dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn); return -ENOMEM; } @@ -1245,6 +1248,7 @@ static int __devinit mmci_probe(struct amba_device *dev, if (host->vcc == NULL) mmc->ocr_avail = plat->ocr_mask; mmc->caps = plat->capabilities; + mmc->caps2 = plat->capabilities2; /* * We can do SGIO diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 80d8eb143b48..1d14cda95e56 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -689,8 +689,8 @@ msmsdcc_pio_irq(int irq, void *dev_id) /* Map the current scatter buffer */ local_irq_save(flags); - buffer = kmap_atomic(sg_page(host->pio.sg), - KM_BIO_SRC_IRQ) + host->pio.sg->offset; + buffer = kmap_atomic(sg_page(host->pio.sg)) + + host->pio.sg->offset; buffer += host->pio.sg_off; remain = host->pio.sg->length - host->pio.sg_off; len = 0; @@ -700,7 +700,7 @@ msmsdcc_pio_irq(int irq, void *dev_id) len = msmsdcc_pio_write(host, buffer, remain, status); /* Unmap the buffer */ - kunmap_atomic(buffer, KM_BIO_SRC_IRQ); + kunmap_atomic(buffer); local_irq_restore(flags); host->pio.sg_off += len; @@ -1480,18 +1480,7 @@ static struct platform_driver msmsdcc_driver = { }, }; -static int __init msmsdcc_init(void) -{ - return platform_driver_register(&msmsdcc_driver); -} - -static void __exit msmsdcc_exit(void) -{ - platform_driver_unregister(&msmsdcc_driver); -} - -module_init(msmsdcc_init); -module_exit(msmsdcc_exit); +module_platform_driver(msmsdcc_driver); MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 8e0fbe994047..4184b7946bbf 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -218,6 +218,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) unsigned int blksz = data->blksz; unsigned int datasize = nob * blksz; struct scatterlist *sg; + enum dma_transfer_direction slave_dirn; int i, nents; if (data->flags & MMC_DATA_STREAM) @@ -240,10 +241,13 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) } } - if (data->flags & MMC_DATA_READ) + if (data->flags & MMC_DATA_READ) { host->dma_dir = DMA_FROM_DEVICE; - else + slave_dirn = DMA_DEV_TO_MEM; + } else { host->dma_dir = DMA_TO_DEVICE; + slave_dirn = DMA_MEM_TO_DEV; + } nents = dma_map_sg(host->dma->device->dev, data->sg, data->sg_len, host->dma_dir); @@ -251,7 +255,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) return -EINVAL; host->desc = host->dma->device->device_prep_slave_sg(host->dma, - data->sg, data->sg_len, host->dma_dir, + data->sg, data->sg_len, slave_dirn, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!host->desc) { @@ -1047,18 +1051,7 @@ static struct platform_driver mxcmci_driver = { } }; -static int __init mxcmci_init(void) -{ - return platform_driver_register(&mxcmci_driver); -} - -static void __exit mxcmci_exit(void) -{ - platform_driver_unregister(&mxcmci_driver); -} - -module_init(mxcmci_init); -module_exit(mxcmci_exit); +module_platform_driver(mxcmci_driver); MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 973011f9a298..382c835d217c 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -154,6 +154,7 @@ struct mxs_mmc_host { struct dma_chan *dmach; struct mxs_dma_data dma_data; unsigned int dma_dir; + enum dma_transfer_direction slave_dirn; u32 ssp_pio_words[SSP_PIO_NUM]; unsigned int version; @@ -324,7 +325,7 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma( } desc = host->dmach->device->device_prep_slave_sg(host->dmach, - sgl, sg_len, host->dma_dir, append); + sgl, sg_len, host->slave_dirn, append); if (desc) { desc->callback = mxs_mmc_dma_irq_callback; desc->callback_param = host; @@ -356,6 +357,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) host->ssp_pio_words[1] = cmd0; host->ssp_pio_words[2] = cmd1; host->dma_dir = DMA_NONE; + host->slave_dirn = DMA_TRANS_NONE; desc = mxs_mmc_prep_dma(host, 0); if (!desc) goto out; @@ -395,6 +397,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) host->ssp_pio_words[1] = cmd0; host->ssp_pio_words[2] = cmd1; host->dma_dir = DMA_NONE; + host->slave_dirn = DMA_TRANS_NONE; desc = mxs_mmc_prep_dma(host, 0); if (!desc) goto out; @@ -433,6 +436,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) int i; unsigned short dma_data_dir, timeout; + enum dma_transfer_direction slave_dirn; unsigned int data_size = 0, log2_blksz; unsigned int blocks = data->blocks; @@ -448,9 +452,11 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) if (data->flags & MMC_DATA_WRITE) { dma_data_dir = DMA_TO_DEVICE; + slave_dirn = DMA_MEM_TO_DEV; read = 0; } else { dma_data_dir = DMA_FROM_DEVICE; + slave_dirn = DMA_DEV_TO_MEM; read = BM_SSP_CTRL0_READ; } @@ -510,6 +516,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) host->ssp_pio_words[1] = cmd0; host->ssp_pio_words[2] = cmd1; host->dma_dir = DMA_NONE; + host->slave_dirn = DMA_TRANS_NONE; desc = mxs_mmc_prep_dma(host, 0); if (!desc) goto out; @@ -518,6 +525,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) WARN_ON(host->data != NULL); host->data = data; host->dma_dir = dma_data_dir; + host->slave_dirn = slave_dirn; desc = mxs_mmc_prep_dma(host, 1); if (!desc) goto out; @@ -855,18 +863,7 @@ static struct platform_driver mxs_mmc_driver = { }, }; -static int __init mxs_mmc_init(void) -{ - return platform_driver_register(&mxs_mmc_driver); -} - -static void __exit mxs_mmc_exit(void) -{ - platform_driver_unregister(&mxs_mmc_driver); -} - -module_init(mxs_mmc_init); -module_exit(mxs_mmc_exit); +module_platform_driver(mxs_mmc_driver); MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral"); MODULE_AUTHOR("Freescale Semiconductor"); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index d1fb561e089d..fd0c661bbad3 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -24,7 +24,6 @@ #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> -#include <linux/workqueue.h> #include <linux/timer.h> #include <linux/clk.h> #include <linux/mmc/host.h> @@ -120,7 +119,6 @@ #define MMC_AUTOSUSPEND_DELAY 100 #define MMC_TIMEOUT_MS 20 -#define OMAP_MMC_MASTER_CLOCK 96000000 #define OMAP_MMC_MIN_CLOCK 400000 #define OMAP_MMC_MAX_CLOCK 52000000 #define DRIVER_NAME "omap_hsmmc" @@ -163,7 +161,6 @@ struct omap_hsmmc_host { */ struct regulator *vcc; struct regulator *vcc_aux; - struct work_struct mmc_carddetect_work; void __iomem *base; resource_size_t mapbase; spinlock_t irq_lock; /* Prevent races with irq handler */ @@ -598,12 +595,12 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) } /* Calculate divisor for the given clock frequency */ -static u16 calc_divisor(struct mmc_ios *ios) +static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios) { u16 dsor = 0; if (ios->clock) { - dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, ios->clock); + dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock); if (dsor > 250) dsor = 250; } @@ -623,7 +620,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) regval = OMAP_HSMMC_READ(host->base, SYSCTL); regval = regval & ~(CLKD_MASK | DTO_MASK); - regval = regval | (calc_divisor(ios) << 6) | (DTO << 16); + regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16); OMAP_HSMMC_WRITE(host->base, SYSCTL, regval); OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_READ(host->base, SYSCTL) | ICE); @@ -1280,17 +1277,16 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) } /* - * Work Item to notify the core about card insertion/removal + * irq handler to notify the core about card insertion/removal */ -static void omap_hsmmc_detect(struct work_struct *work) +static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) { - struct omap_hsmmc_host *host = - container_of(work, struct omap_hsmmc_host, mmc_carddetect_work); + struct omap_hsmmc_host *host = dev_id; struct omap_mmc_slot_data *slot = &mmc_slot(host); int carddetect; if (host->suspended) - return; + return IRQ_HANDLED; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); @@ -1305,19 +1301,6 @@ static void omap_hsmmc_detect(struct work_struct *work) mmc_detect_change(host->mmc, (HZ * 200) / 1000); else mmc_detect_change(host->mmc, (HZ * 50) / 1000); -} - -/* - * ISR for handling card insertion and removal - */ -static irqreturn_t omap_hsmmc_cd_handler(int irq, void *dev_id) -{ - struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)dev_id; - - if (host->suspended) - return IRQ_HANDLED; - schedule_work(&host->mmc_carddetect_work); - return IRQ_HANDLED; } @@ -1919,7 +1902,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) host->next_data.cookie = 1; platform_set_drvdata(pdev, host); - INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect); mmc->ops = &omap_hsmmc_ops; @@ -2049,10 +2031,11 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) /* Request IRQ for card detect */ if ((mmc_slot(host).card_detect_irq)) { - ret = request_irq(mmc_slot(host).card_detect_irq, - omap_hsmmc_cd_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - mmc_hostname(mmc), host); + ret = request_threaded_irq(mmc_slot(host).card_detect_irq, + NULL, + omap_hsmmc_detect, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab MMC CD IRQ\n"); @@ -2131,7 +2114,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev) free_irq(host->irq, host); if (mmc_slot(host).card_detect_irq) free_irq(mmc_slot(host).card_detect_irq, host); - flush_work_sync(&host->mmc_carddetect_work); pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); @@ -2178,7 +2160,6 @@ static int omap_hsmmc_suspend(struct device *dev) return ret; } } - cancel_work_sync(&host->mmc_carddetect_work); ret = mmc_suspend_host(host->mmc); if (ret) { diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index fc4356e00d46..cb2dc0e75ba7 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -872,18 +872,7 @@ static struct platform_driver pxamci_driver = { }, }; -static int __init pxamci_init(void) -{ - return platform_driver_register(&pxamci_driver); -} - -static void __exit pxamci_exit(void) -{ - platform_driver_unregister(&pxamci_driver); -} - -module_init(pxamci_init); -module_exit(pxamci_exit); +module_platform_driver(pxamci_driver); MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 720f99334a7f..1bcfd6dbb5cc 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1914,18 +1914,7 @@ static struct platform_driver s3cmci_driver = { .shutdown = s3cmci_shutdown, }; -static int __init s3cmci_init(void) -{ - return platform_driver_register(&s3cmci_driver); -} - -static void __exit s3cmci_exit(void) -{ - platform_driver_unregister(&s3cmci_driver); -} - -module_init(s3cmci_init); -module_exit(s3cmci_exit); +module_platform_driver(s3cmci_driver); MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index b4257e700617..28a870804f60 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -115,17 +115,7 @@ static struct platform_driver sdhci_cns3xxx_driver = { .remove = __devexit_p(sdhci_cns3xxx_remove), }; -static int __init sdhci_cns3xxx_init(void) -{ - return platform_driver_register(&sdhci_cns3xxx_driver); -} -module_init(sdhci_cns3xxx_init); - -static void __exit sdhci_cns3xxx_exit(void) -{ - platform_driver_unregister(&sdhci_cns3xxx_driver); -} -module_exit(sdhci_cns3xxx_exit); +module_platform_driver(sdhci_cns3xxx_driver); MODULE_DESCRIPTION("SDHCI driver for CNS3xxx"); MODULE_AUTHOR("Scott Shu, " diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index a81312c91f70..46fd1fd1b605 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -88,17 +88,7 @@ static struct platform_driver sdhci_dove_driver = { .remove = __devexit_p(sdhci_dove_remove), }; -static int __init sdhci_dove_init(void) -{ - return platform_driver_register(&sdhci_dove_driver); -} -module_init(sdhci_dove_init); - -static void __exit sdhci_dove_exit(void) -{ - platform_driver_unregister(&sdhci_dove_driver); -} -module_exit(sdhci_dove_exit); +module_platform_driver(sdhci_dove_driver); MODULE_DESCRIPTION("SDHCI driver for Dove"); MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, " diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 38ebc4ea259f..d601e41af282 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -606,17 +606,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = { .remove = __devexit_p(sdhci_esdhc_imx_remove), }; -static int __init sdhci_esdhc_imx_init(void) -{ - return platform_driver_register(&sdhci_esdhc_imx_driver); -} -module_init(sdhci_esdhc_imx_init); - -static void __exit sdhci_esdhc_imx_exit(void) -{ - platform_driver_unregister(&sdhci_esdhc_imx_driver); -} -module_exit(sdhci_esdhc_imx_exit); +module_platform_driver(sdhci_esdhc_imx_driver); MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index c3b08f111942..b97b2f5dafdb 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -73,7 +73,7 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) | (div << ESDHC_DIVIDER_SHIFT) | (pre_div << ESDHC_PREDIV_SHIFT)); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - mdelay(100); + mdelay(1); out: host->clock = clock; } diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 01e5f627e0f0..ff4adc018041 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -131,17 +131,7 @@ static struct platform_driver sdhci_esdhc_driver = { .remove = __devexit_p(sdhci_esdhc_remove), }; -static int __init sdhci_esdhc_init(void) -{ - return platform_driver_register(&sdhci_esdhc_driver); -} -module_init(sdhci_esdhc_init); - -static void __exit sdhci_esdhc_exit(void) -{ - platform_driver_unregister(&sdhci_esdhc_driver); -} -module_exit(sdhci_esdhc_exit); +module_platform_driver(sdhci_esdhc_driver); MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC"); MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, " diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 3619adc7d9fc..0ce088ae0228 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -93,17 +93,7 @@ static struct platform_driver sdhci_hlwd_driver = { .remove = __devexit_p(sdhci_hlwd_remove), }; -static int __init sdhci_hlwd_init(void) -{ - return platform_driver_register(&sdhci_hlwd_driver); -} -module_init(sdhci_hlwd_init); - -static void __exit sdhci_hlwd_exit(void) -{ - platform_driver_unregister(&sdhci_hlwd_driver); -} -module_exit(sdhci_hlwd_exit); +module_platform_driver(sdhci_hlwd_driver); MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver"); MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz"); diff --git a/drivers/mmc/host/sdhci-pci-data.c b/drivers/mmc/host/sdhci-pci-data.c new file mode 100644 index 000000000000..a611217769f5 --- /dev/null +++ b/drivers/mmc/host/sdhci-pci-data.c @@ -0,0 +1,5 @@ +#include <linux/module.h> +#include <linux/mmc/sdhci-pci-data.h> + +struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno); +EXPORT_SYMBOL_GPL(sdhci_pci_get_data); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 6878a94626bc..7165e6a09274 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -23,8 +23,8 @@ #include <linux/scatterlist.h> #include <linux/io.h> #include <linux/gpio.h> -#include <linux/sfi.h> #include <linux/pm_runtime.h> +#include <linux/mmc/sdhci-pci-data.h> #include "sdhci.h" @@ -61,6 +61,7 @@ struct sdhci_pci_fixes { struct sdhci_pci_slot { struct sdhci_pci_chip *chip; struct sdhci_host *host; + struct sdhci_pci_data *data; int pci_bar; int rst_n_gpio; @@ -171,32 +172,9 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip) return 0; } -/* Medfield eMMC hardware reset GPIOs */ -static int mfd_emmc0_rst_gpio = -EINVAL; -static int mfd_emmc1_rst_gpio = -EINVAL; - -static int mfd_emmc_gpio_parse(struct sfi_table_header *table) -{ - struct sfi_table_simple *sb = (struct sfi_table_simple *)table; - struct sfi_gpio_table_entry *entry; - int i, num; - - num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); - entry = (struct sfi_gpio_table_entry *)sb->pentry; - - for (i = 0; i < num; i++, entry++) { - if (!strncmp(entry->pin_name, "emmc0_rst", SFI_NAME_LEN)) - mfd_emmc0_rst_gpio = entry->pin_no; - else if (!strncmp(entry->pin_name, "emmc1_rst", SFI_NAME_LEN)) - mfd_emmc1_rst_gpio = entry->pin_no; - } - - return 0; -} - #ifdef CONFIG_PM_RUNTIME -static irqreturn_t mfd_sd_cd(int irq, void *dev_id) +static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) { struct sdhci_pci_slot *slot = dev_id; struct sdhci_host *host = slot->host; @@ -205,15 +183,16 @@ static irqreturn_t mfd_sd_cd(int irq, void *dev_id) return IRQ_HANDLED; } -#define MFLD_SD_CD_PIN 69 - -static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot) +static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) { - int err, irq, gpio = MFLD_SD_CD_PIN; + int err, irq, gpio = slot->cd_gpio; slot->cd_gpio = -EINVAL; slot->cd_irq = -EINVAL; + if (!gpio_is_valid(gpio)) + return; + err = gpio_request(gpio, "sd_cd"); if (err < 0) goto out; @@ -226,72 +205,53 @@ static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot) if (irq < 0) goto out_free; - err = request_irq(irq, mfd_sd_cd, IRQF_TRIGGER_RISING | + err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "sd_cd", slot); if (err) goto out_free; slot->cd_gpio = gpio; slot->cd_irq = irq; - slot->host->quirks2 |= SDHCI_QUIRK2_OWN_CARD_DETECTION; - return 0; + return; out_free: gpio_free(gpio); out: dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); - return 0; } -static void mfd_sd_remove_slot(struct sdhci_pci_slot *slot, int dead) +static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) { if (slot->cd_irq >= 0) free_irq(slot->cd_irq, slot); - gpio_free(slot->cd_gpio); + if (gpio_is_valid(slot->cd_gpio)) + gpio_free(slot->cd_gpio); } #else -#define mfd_sd_probe_slot NULL -#define mfd_sd_remove_slot NULL +static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) +{ +} + +static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) +{ +} #endif static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) { - const char *name = NULL; - int gpio = -EINVAL; - - sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, mfd_emmc_gpio_parse); - - switch (slot->chip->pdev->device) { - case PCI_DEVICE_ID_INTEL_MFD_EMMC0: - gpio = mfd_emmc0_rst_gpio; - name = "eMMC0_reset"; - break; - case PCI_DEVICE_ID_INTEL_MFD_EMMC1: - gpio = mfd_emmc1_rst_gpio; - name = "eMMC1_reset"; - break; - } - - if (!gpio_request(gpio, name)) { - gpio_direction_output(gpio, 1); - slot->rst_n_gpio = gpio; - slot->host->mmc->caps |= MMC_CAP_HW_RESET; - } - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; - slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC; - return 0; } -static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead) +static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) { - gpio_free(slot->rst_n_gpio); + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD; + return 0; } static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { @@ -307,20 +267,18 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, - .probe_slot = mfd_sd_probe_slot, - .remove_slot = mfd_sd_remove_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, + .probe_slot = mfd_sdio_probe_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, .probe_slot = mfd_emmc_probe_slot, - .remove_slot = mfd_emmc_remove_slot, }; /* O2Micro extra registers */ @@ -1012,11 +970,8 @@ static int sdhci_pci_suspend(struct device *dev) ret = sdhci_suspend_host(slot->host); - if (ret) { - for (i--; i >= 0; i--) - sdhci_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_suspend; slot_pm_flags = slot->host->mmc->pm_flags; if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ) @@ -1027,11 +982,8 @@ static int sdhci_pci_suspend(struct device *dev) if (chip->fixes && chip->fixes->suspend) { ret = chip->fixes->suspend(chip); - if (ret) { - for (i = chip->num_slots - 1; i >= 0; i--) - sdhci_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_suspend; } pci_save_state(pdev); @@ -1048,6 +1000,11 @@ static int sdhci_pci_suspend(struct device *dev) } return 0; + +err_pci_suspend: + while (--i >= 0) + sdhci_resume_host(chip->slots[i]->host); + return ret; } static int sdhci_pci_resume(struct device *dev) @@ -1113,23 +1070,22 @@ static int sdhci_pci_runtime_suspend(struct device *dev) ret = sdhci_runtime_suspend_host(slot->host); - if (ret) { - for (i--; i >= 0; i--) - sdhci_runtime_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_runtime_suspend; } if (chip->fixes && chip->fixes->suspend) { ret = chip->fixes->suspend(chip); - if (ret) { - for (i = chip->num_slots - 1; i >= 0; i--) - sdhci_runtime_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_runtime_suspend; } return 0; + +err_pci_runtime_suspend: + while (--i >= 0) + sdhci_runtime_resume_host(chip->slots[i]->host); + return ret; } static int sdhci_pci_runtime_resume(struct device *dev) @@ -1190,11 +1146,12 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = { \*****************************************************************************/ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( - struct pci_dev *pdev, struct sdhci_pci_chip *chip, int bar) + struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, + int slotno) { struct sdhci_pci_slot *slot; struct sdhci_host *host; - int ret; + int ret, bar = first_bar + slotno; if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); @@ -1228,6 +1185,23 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( slot->host = host; slot->pci_bar = bar; slot->rst_n_gpio = -EINVAL; + slot->cd_gpio = -EINVAL; + + /* Retrieve platform data if there is any */ + if (*sdhci_pci_get_data) + slot->data = sdhci_pci_get_data(pdev, slotno); + + if (slot->data) { + if (slot->data->setup) { + ret = slot->data->setup(slot->data); + if (ret) { + dev_err(&pdev->dev, "platform setup failed\n"); + goto free; + } + } + slot->rst_n_gpio = slot->data->rst_n_gpio; + slot->cd_gpio = slot->data->cd_gpio; + } host->hw_name = "PCI"; host->ops = &sdhci_pci_ops; @@ -1238,7 +1212,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc)); if (ret) { dev_err(&pdev->dev, "cannot request region\n"); - goto free; + goto cleanup; } host->ioaddr = pci_ioremap_bar(pdev, bar); @@ -1254,15 +1228,30 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( goto unmap; } + if (gpio_is_valid(slot->rst_n_gpio)) { + if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) { + gpio_direction_output(slot->rst_n_gpio, 1); + slot->host->mmc->caps |= MMC_CAP_HW_RESET; + } else { + dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); + slot->rst_n_gpio = -EINVAL; + } + } + host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; ret = sdhci_add_host(host); if (ret) goto remove; + sdhci_pci_add_own_cd(slot); + return slot; remove: + if (gpio_is_valid(slot->rst_n_gpio)) + gpio_free(slot->rst_n_gpio); + if (chip->fixes && chip->fixes->remove_slot) chip->fixes->remove_slot(slot, 0); @@ -1272,6 +1261,10 @@ unmap: release: pci_release_region(pdev, bar); +cleanup: + if (slot->data && slot->data->cleanup) + slot->data->cleanup(slot->data); + free: sdhci_free_host(host); @@ -1283,6 +1276,8 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) int dead; u32 scratch; + sdhci_pci_remove_own_cd(slot); + dead = 0; scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) @@ -1290,9 +1285,15 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) sdhci_remove_host(slot->host, dead); + if (gpio_is_valid(slot->rst_n_gpio)) + gpio_free(slot->rst_n_gpio); + if (slot->chip->fixes && slot->chip->fixes->remove_slot) slot->chip->fixes->remove_slot(slot, dead); + if (slot->data && slot->data->cleanup) + slot->data->cleanup(slot->data); + pci_release_region(slot->chip->pdev, slot->pci_bar); sdhci_free_host(slot->host); @@ -1379,7 +1380,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, slots = chip->num_slots; /* Quirk may have changed this */ for (i = 0; i < slots; i++) { - slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i); + slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); if (IS_ERR(slot)) { for (i--; i >= 0; i--) sdhci_pci_remove_slot(chip->slots[i]); diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 7a039c3cb1f1..dbb75bfbcffb 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -223,18 +223,8 @@ static struct platform_driver sdhci_pxav2_driver = { .probe = sdhci_pxav2_probe, .remove = __devexit_p(sdhci_pxav2_remove), }; -static int __init sdhci_pxav2_init(void) -{ - return platform_driver_register(&sdhci_pxav2_driver); -} - -static void __exit sdhci_pxav2_exit(void) -{ - platform_driver_unregister(&sdhci_pxav2_driver); -} -module_init(sdhci_pxav2_init); -module_exit(sdhci_pxav2_exit); +module_platform_driver(sdhci_pxav2_driver); MODULE_DESCRIPTION("SDHCI driver for pxav2"); MODULE_AUTHOR("Marvell International Ltd."); diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 15673a7ee6a5..f29695683556 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -269,18 +269,8 @@ static struct platform_driver sdhci_pxav3_driver = { .probe = sdhci_pxav3_probe, .remove = __devexit_p(sdhci_pxav3_remove), }; -static int __init sdhci_pxav3_init(void) -{ - return platform_driver_register(&sdhci_pxav3_driver); -} - -static void __exit sdhci_pxav3_exit(void) -{ - platform_driver_unregister(&sdhci_pxav3_driver); -} -module_init(sdhci_pxav3_init); -module_exit(sdhci_pxav3_exit); +module_platform_driver(sdhci_pxav3_driver); MODULE_DESCRIPTION("SDHCI driver for pxav3"); MODULE_AUTHOR("Marvell International Ltd."); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 9a20d1f55bb7..1af756ee0f9a 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -80,7 +80,7 @@ static void sdhci_s3c_check_sclk(struct sdhci_host *host) tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - writel(tmp, host->ioaddr + 0x80); + writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2); } } @@ -521,6 +521,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; + if (pdata->pm_caps) + host->mmc->pm_caps |= pdata->pm_caps; + host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE); @@ -654,18 +657,7 @@ static struct platform_driver sdhci_s3c_driver = { }, }; -static int __init sdhci_s3c_init(void) -{ - return platform_driver_register(&sdhci_s3c_driver); -} - -static void __exit sdhci_s3c_exit(void) -{ - platform_driver_unregister(&sdhci_s3c_driver); -} - -module_init(sdhci_s3c_init); -module_exit(sdhci_s3c_exit); +module_platform_driver(sdhci_s3c_driver); MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue"); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 63cc8b6a1c9e..b7f8b33c5f19 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -21,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/slab.h> #include <linux/mmc/host.h> #include <linux/mmc/sdhci-spear.h> @@ -271,26 +272,54 @@ static int __devexit sdhci_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int sdhci_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct spear_sdhci *sdhci = dev_get_platdata(dev); + int ret; + + ret = sdhci_suspend_host(host); + if (!ret) + clk_disable(sdhci->clk); + + return ret; +} + +static int sdhci_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct spear_sdhci *sdhci = dev_get_platdata(dev); + int ret; + + ret = clk_enable(sdhci->clk); + if (ret) { + dev_dbg(dev, "Resume: Error enabling clock\n"); + return ret; + } + + return sdhci_resume_host(host); +} + +const struct dev_pm_ops sdhci_pm_ops = { + .suspend = sdhci_suspend, + .resume = sdhci_resume, +}; +#endif + static struct platform_driver sdhci_driver = { .driver = { .name = "sdhci", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &sdhci_pm_ops, +#endif }, .probe = sdhci_probe, .remove = __devexit_p(sdhci_remove), }; -static int __init sdhci_init(void) -{ - return platform_driver_register(&sdhci_driver); -} -module_init(sdhci_init); - -static void __exit sdhci_exit(void) -{ - platform_driver_unregister(&sdhci_driver); -} -module_exit(sdhci_exit); +module_platform_driver(sdhci_driver); MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index e2e18d3f949c..78a36eba4df0 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -324,17 +324,7 @@ static struct platform_driver sdhci_tegra_driver = { .remove = __devexit_p(sdhci_tegra_remove), }; -static int __init sdhci_tegra_init(void) -{ - return platform_driver_register(&sdhci_tegra_driver); -} -module_init(sdhci_tegra_init); - -static void __exit sdhci_tegra_exit(void) -{ - platform_driver_unregister(&sdhci_tegra_driver); -} -module_exit(sdhci_tegra_exit); +module_platform_driver(sdhci_tegra_driver); MODULE_DESCRIPTION("SDHCI driver for Tegra"); MODULE_AUTHOR(" Google, Inc."); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 19ed580f2cab..8d66706824a6 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -49,7 +49,7 @@ static void sdhci_finish_data(struct sdhci_host *); static void sdhci_send_command(struct sdhci_host *, struct mmc_command *); static void sdhci_finish_command(struct sdhci_host *); -static int sdhci_execute_tuning(struct mmc_host *mmc); +static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_tuning_timer(unsigned long data); #ifdef CONFIG_PM_RUNTIME @@ -146,10 +146,8 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) { u32 present, irqs; - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) - return; - - if (host->quirks2 & SDHCI_QUIRK2_OWN_CARD_DETECTION) + if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || + !mmc_card_is_removable(host->mmc)) return; present = sdhci_readl(host, SDHCI_PRESENT_STATE) & @@ -214,6 +212,11 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); + + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { + if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL)) + host->ops->enable_dma(host); + } } static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); @@ -423,12 +426,12 @@ static void sdhci_transfer_pio(struct sdhci_host *host) static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); - return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + return kmap_atomic(sg_page(sg)) + sg->offset; } static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) { - kunmap_atomic(buffer, KM_BIO_SRC_IRQ); + kunmap_atomic(buffer); local_irq_restore(*flags); } @@ -1016,7 +1019,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) flags |= SDHCI_CMD_INDEX; /* CMD19 is special in that the Data Present Select should be set */ - if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK)) + if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK || + cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) flags |= SDHCI_CMD_DATA; sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); @@ -1066,12 +1070,15 @@ static void sdhci_finish_command(struct sdhci_host *host) static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { int div = 0; /* Initialized for compiler warning */ + int real_div = div, clk_mul = 1; u16 clk = 0; unsigned long timeout; - if (clock == host->clock) + if (clock && clock == host->clock) return; + host->mmc->actual_clock = 0; + if (host->ops->set_clock) { host->ops->set_clock(host, clock); if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) @@ -1109,6 +1116,8 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) * Control register. */ clk = SDHCI_PROG_CLOCK_MODE; + real_div = div; + clk_mul = host->clk_mul; div--; } } else { @@ -1122,6 +1131,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) break; } } + real_div = div; div >>= 1; } } else { @@ -1130,9 +1140,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) if ((host->max_clk / div) <= clock) break; } + real_div = div; div >>= 1; } + if (real_div) + host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div; + clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; @@ -1160,7 +1174,7 @@ out: host->clock = clock; } -static void sdhci_set_power(struct sdhci_host *host, unsigned short power) +static int sdhci_set_power(struct sdhci_host *host, unsigned short power) { u8 pwr = 0; @@ -1183,13 +1197,13 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) } if (host->pwr == pwr) - return; + return -1; host->pwr = pwr; if (pwr == 0) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - return; + return 0; } /* @@ -1216,6 +1230,8 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) */ if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) mdelay(10); + + return power; } /*****************************************************************************\ @@ -1277,7 +1293,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) if ((host->flags & SDHCI_NEEDS_RETUNING) && !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { spin_unlock_irqrestore(&host->lock, flags); - sdhci_execute_tuning(mmc); + sdhci_execute_tuning(mmc, mrq->cmd->opcode); spin_lock_irqsave(&host->lock, flags); /* Restore original mmc_request structure */ @@ -1297,12 +1313,17 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) { unsigned long flags; + int vdd_bit = -1; u8 ctrl; spin_lock_irqsave(&host->lock, flags); - if (host->flags & SDHCI_DEVICE_DEAD) - goto out; + if (host->flags & SDHCI_DEVICE_DEAD) { + spin_unlock_irqrestore(&host->lock, flags); + if (host->vmmc && ios->power_mode == MMC_POWER_OFF) + mmc_regulator_set_ocr(host->mmc, host->vmmc, 0); + return; + } /* * Reset the chip on each power off. @@ -1316,9 +1337,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) sdhci_set_clock(host, ios->clock); if (ios->power_mode == MMC_POWER_OFF) - sdhci_set_power(host, -1); + vdd_bit = sdhci_set_power(host, -1); else - sdhci_set_power(host, ios->vdd); + vdd_bit = sdhci_set_power(host, ios->vdd); + + if (host->vmmc && vdd_bit != -1) { + spin_unlock_irqrestore(&host->lock, flags); + mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit); + spin_lock_irqsave(&host->lock, flags); + } if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); @@ -1361,11 +1388,11 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) unsigned int clock; /* In case of UHS-I modes, set High Speed Enable */ - if ((ios->timing == MMC_TIMING_UHS_SDR50) || + if ((ios->timing == MMC_TIMING_MMC_HS200) || + (ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || (ios->timing == MMC_TIMING_UHS_DDR50) || - (ios->timing == MMC_TIMING_UHS_SDR25) || - (ios->timing == MMC_TIMING_UHS_SDR12)) + (ios->timing == MMC_TIMING_UHS_SDR25)) ctrl |= SDHCI_CTRL_HISPD; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -1415,7 +1442,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; - if (ios->timing == MMC_TIMING_UHS_SDR12) + if (ios->timing == MMC_TIMING_MMC_HS200) + ctrl_2 |= SDHCI_CTRL_HS_SDR200; + else if (ios->timing == MMC_TIMING_UHS_SDR12) ctrl_2 |= SDHCI_CTRL_UHS_SDR12; else if (ios->timing == MMC_TIMING_UHS_SDR25) ctrl_2 |= SDHCI_CTRL_UHS_SDR25; @@ -1443,7 +1472,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); -out: mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -1663,7 +1691,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return err; } -static int sdhci_execute_tuning(struct mmc_host *mmc) +static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host; u16 ctrl; @@ -1671,6 +1699,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) int tuning_loop_counter = MAX_TUNING_LOOP; unsigned long timeout; int err = 0; + bool requires_tuning_nonuhs = false; host = mmc_priv(mmc); @@ -1681,13 +1710,19 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* - * Host Controller needs tuning only in case of SDR104 mode - * and for SDR50 mode when Use Tuning for SDR50 is set in + * The Host Controller needs tuning only in case of SDR104 mode + * and for SDR50 mode when Use Tuning for SDR50 is set in the * Capabilities register. + * If the Host Controller supports the HS200 mode then the + * tuning function has to be executed. */ + if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && + (host->flags & SDHCI_SDR50_NEEDS_TUNING || + host->flags & SDHCI_HS200_NEEDS_TUNING)) + requires_tuning_nonuhs = true; + if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) || - (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && - (host->flags & SDHCI_SDR50_NEEDS_TUNING))) + requires_tuning_nonuhs) ctrl |= SDHCI_CTRL_EXEC_TUNING; else { spin_unlock(&host->lock); @@ -1723,7 +1758,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) if (!tuning_loop_counter && !timeout) break; - cmd.opcode = MMC_SEND_TUNING_BLOCK; + cmd.opcode = opcode; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.retries = 0; @@ -1738,7 +1773,17 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) * block to the Host Controller. So we set the block size * to 64 here. */ - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE); + if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) { + if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), + SDHCI_BLOCK_SIZE); + else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), + SDHCI_BLOCK_SIZE); + } else { + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), + SDHCI_BLOCK_SIZE); + } /* * The tuning block is sent by the card to the host controller. @@ -2121,12 +2166,14 @@ static void sdhci_show_adma_error(struct sdhci_host *host) { } static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { + u32 command; BUG_ON(intmask == 0); /* CMD19 generates _only_ Buffer Read Ready interrupt */ if (intmask & SDHCI_INT_DATA_AVAIL) { - if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) == - MMC_SEND_TUNING_BLOCK) { + command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); + if (command == MMC_SEND_TUNING_BLOCK || + command == MMC_SEND_TUNING_BLOCK_HS200) { host->tuning_done = 1; wake_up(&host->buf_ready_int); return; @@ -2330,26 +2377,33 @@ out: int sdhci_suspend_host(struct sdhci_host *host) { int ret; + bool has_tuning_timer; sdhci_disable_card_detection(host); /* Disable tuning since we are suspending */ - if (host->version >= SDHCI_SPEC_300 && host->tuning_count && - host->tuning_mode == SDHCI_TUNING_MODE_1) { + has_tuning_timer = host->version >= SDHCI_SPEC_300 && + host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1; + if (has_tuning_timer) { + del_timer_sync(&host->tuning_timer); host->flags &= ~SDHCI_NEEDS_RETUNING; - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); } ret = mmc_suspend_host(host->mmc); - if (ret) + if (ret) { + if (has_tuning_timer) { + host->flags |= SDHCI_NEEDS_RETUNING; + mod_timer(&host->tuning_timer, jiffies + + host->tuning_count * HZ); + } + + sdhci_enable_card_detection(host); + return ret; + } free_irq(host->irq, host); - if (host->vmmc) - ret = regulator_disable(host->vmmc); - return ret; } @@ -2359,12 +2413,6 @@ int sdhci_resume_host(struct sdhci_host *host) { int ret; - if (host->vmmc) { - int ret = regulator_enable(host->vmmc); - if (ret) - return ret; - } - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) host->ops->enable_dma(host); @@ -2727,10 +2775,14 @@ int sdhci_add_host(struct sdhci_host *host) if (caps[1] & SDHCI_SUPPORT_DDR50) mmc->caps |= MMC_CAP_UHS_DDR50; - /* Does the host needs tuning for SDR50? */ + /* Does the host need tuning for SDR50? */ if (caps[1] & SDHCI_USE_SDR50_TUNING) host->flags |= SDHCI_SDR50_NEEDS_TUNING; + /* Does the host need tuning for HS200? */ + if (mmc->caps2 & MMC_CAP2_HS200) + host->flags |= SDHCI_HS200_NEEDS_TUNING; + /* Driver Type(s) (A, C, D) supported by the host */ if (caps[1] & SDHCI_DRIVER_TYPE_A) mmc->caps |= MMC_CAP_DRIVER_TYPE_A; @@ -2926,8 +2978,6 @@ int sdhci_add_host(struct sdhci_host *host) if (IS_ERR(host->vmmc)) { pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; - } else { - regulator_enable(host->vmmc); } sdhci_init(host, 0); @@ -3016,10 +3066,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_kill(&host->card_tasklet); tasklet_kill(&host->finish_tasklet); - if (host->vmmc) { - regulator_disable(host->vmmc); + if (host->vmmc) regulator_put(host->vmmc); - } kfree(host->adma_desc); kfree(host->align_buffer); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index a04d4d0c6fd2..ad265b96b75b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -158,6 +158,7 @@ #define SDHCI_CTRL_UHS_SDR50 0x0002 #define SDHCI_CTRL_UHS_SDR104 0x0003 #define SDHCI_CTRL_UHS_DDR50 0x0004 +#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */ #define SDHCI_CTRL_VDD_180 0x0008 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_B 0x0000 diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index d5505f3fe2a1..f5d8b53be333 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -16,6 +16,33 @@ * */ +/* + * The MMCIF driver is now processing MMC requests asynchronously, according + * to the Linux MMC API requirement. + * + * The MMCIF driver processes MMC requests in up to 3 stages: command, optional + * data, and optional stop. To achieve asynchronous processing each of these + * stages is split into two halves: a top and a bottom half. The top half + * initialises the hardware, installs a timeout handler to handle completion + * timeouts, and returns. In case of the command stage this immediately returns + * control to the caller, leaving all further processing to run asynchronously. + * All further request processing is performed by the bottom halves. + * + * The bottom half further consists of a "hard" IRQ handler, an IRQ handler + * thread, a DMA completion callback, if DMA is used, a timeout work, and + * request- and stage-specific handler methods. + * + * Each bottom half run begins with either a hardware interrupt, a DMA callback + * invocation, or a timeout work run. In case of an error or a successful + * processing completion, the MMC core is informed and the request processing is + * finished. In case processing has to continue, i.e., if data has to be read + * from or written to the card, or if a stop command has to be sent, the next + * top half is called, which performs the necessary hardware handling and + * reschedules the timeout work. This returns the driver state machine into the + * bottom half waiting state. + */ + +#include <linux/bitops.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> @@ -123,6 +150,11 @@ #define MASK_MRBSYTO (1 << 1) #define MASK_MRSPTO (1 << 0) +#define MASK_START_CMD (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \ + MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \ + MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \ + MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO) + /* CE_HOST_STS1 */ #define STS1_CMDSEQ (1 << 31) @@ -162,9 +194,21 @@ enum mmcif_state { STATE_IOS, }; +enum mmcif_wait_for { + MMCIF_WAIT_FOR_REQUEST, + MMCIF_WAIT_FOR_CMD, + MMCIF_WAIT_FOR_MREAD, + MMCIF_WAIT_FOR_MWRITE, + MMCIF_WAIT_FOR_READ, + MMCIF_WAIT_FOR_WRITE, + MMCIF_WAIT_FOR_READ_END, + MMCIF_WAIT_FOR_WRITE_END, + MMCIF_WAIT_FOR_STOP, +}; + struct sh_mmcif_host { struct mmc_host *mmc; - struct mmc_data *data; + struct mmc_request *mrq; struct platform_device *pd; struct sh_dmae_slave dma_slave_tx; struct sh_dmae_slave dma_slave_rx; @@ -172,11 +216,17 @@ struct sh_mmcif_host { unsigned int clk; int bus_width; bool sd_error; + bool dying; long timeout; void __iomem *addr; - struct completion intr_wait; + u32 *pio_ptr; + spinlock_t lock; /* protect sh_mmcif_host::state */ enum mmcif_state state; - spinlock_t lock; + enum mmcif_wait_for wait_for; + struct delayed_work timeout_work; + size_t blocksize; + int sg_idx; + int sg_blkidx; bool power; bool card_present; @@ -202,19 +252,21 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, static void mmcif_dma_complete(void *arg) { struct sh_mmcif_host *host = arg; + struct mmc_data *data = host->mrq->data; + dev_dbg(&host->pd->dev, "Command completed\n"); - if (WARN(!host->data, "%s: NULL data in DMA completion!\n", + if (WARN(!data, "%s: NULL data in DMA completion!\n", dev_name(&host->pd->dev))) return; - if (host->data->flags & MMC_DATA_READ) + if (data->flags & MMC_DATA_READ) dma_unmap_sg(host->chan_rx->device->dev, - host->data->sg, host->data->sg_len, + data->sg, data->sg_len, DMA_FROM_DEVICE); else dma_unmap_sg(host->chan_tx->device->dev, - host->data->sg, host->data->sg_len, + data->sg, data->sg_len, DMA_TO_DEVICE); complete(&host->dma_complete); @@ -222,18 +274,19 @@ static void mmcif_dma_complete(void *arg) static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) { - struct scatterlist *sg = host->data->sg; + struct mmc_data *data = host->mrq->data; + struct scatterlist *sg = data->sg; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; dma_cookie_t cookie = -EINVAL; int ret; - ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, + ret = dma_map_sg(chan->device->dev, sg, data->sg_len, DMA_FROM_DEVICE); if (ret > 0) { host->dma_active = true; desc = chan->device->device_prep_slave_sg(chan, sg, ret, - DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } if (desc) { @@ -244,7 +297,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) dma_async_issue_pending(chan); } dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", - __func__, host->data->sg_len, ret, cookie); + __func__, data->sg_len, ret, cookie); if (!desc) { /* DMA failed, fall back to PIO */ @@ -265,23 +318,24 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) } dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, - desc, cookie, host->data->sg_len); + desc, cookie, data->sg_len); } static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) { - struct scatterlist *sg = host->data->sg; + struct mmc_data *data = host->mrq->data; + struct scatterlist *sg = data->sg; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; dma_cookie_t cookie = -EINVAL; int ret; - ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, + ret = dma_map_sg(chan->device->dev, sg, data->sg_len, DMA_TO_DEVICE); if (ret > 0) { host->dma_active = true; desc = chan->device->device_prep_slave_sg(chan, sg, ret, - DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } if (desc) { @@ -292,7 +346,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) dma_async_issue_pending(chan); } dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", - __func__, host->data->sg_len, ret, cookie); + __func__, data->sg_len, ret, cookie); if (!desc) { /* DMA failed, fall back to PIO */ @@ -399,7 +453,7 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); else sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & - (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16)); + ((fls(host->clk / clk) - 1) << 16)); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); } @@ -421,7 +475,7 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) static int sh_mmcif_error_manage(struct sh_mmcif_host *host) { u32 state1, state2; - int ret, timeout = 10000000; + int ret, timeout; host->sd_error = false; @@ -433,155 +487,212 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); - while (1) { - timeout--; - if (timeout < 0) { - dev_err(&host->pd->dev, - "Forceed end of command sequence timeout err\n"); - return -EIO; - } + for (timeout = 10000000; timeout; timeout--) { if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) - & STS1_CMDSEQ)) + & STS1_CMDSEQ)) break; mdelay(1); } + if (!timeout) { + dev_err(&host->pd->dev, + "Forced end of command sequence timeout err\n"); + return -EIO; + } sh_mmcif_sync_reset(host); dev_dbg(&host->pd->dev, "Forced end of command sequence\n"); return -EIO; } if (state2 & STS2_CRC_ERR) { - dev_dbg(&host->pd->dev, ": Happened CRC error\n"); + dev_dbg(&host->pd->dev, ": CRC error\n"); ret = -EIO; } else if (state2 & STS2_TIMEOUT_ERR) { - dev_dbg(&host->pd->dev, ": Happened Timeout error\n"); + dev_dbg(&host->pd->dev, ": Timeout\n"); ret = -ETIMEDOUT; } else { - dev_dbg(&host->pd->dev, ": Happened End/Index error\n"); + dev_dbg(&host->pd->dev, ": End/Index error\n"); ret = -EIO; } return ret; } -static int sh_mmcif_single_read(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p) { - struct mmc_data *data = mrq->data; - long time; - u32 blocksize, i, *p = sg_virt(data->sg); + struct mmc_data *data = host->mrq->data; + + host->sg_blkidx += host->blocksize; + + /* data->sg->length must be a multiple of host->blocksize? */ + BUG_ON(host->sg_blkidx > data->sg->length); + + if (host->sg_blkidx == data->sg->length) { + host->sg_blkidx = 0; + if (++host->sg_idx < data->sg_len) + host->pio_ptr = sg_virt(++data->sg); + } else { + host->pio_ptr = p; + } + + if (host->sg_idx == data->sg_len) + return false; + + return true; +} + +static void sh_mmcif_single_read(struct sh_mmcif_host *host, + struct mmc_request *mrq) +{ + host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & + BLOCK_SIZE_MASK) + 3; + + host->wait_for = MMCIF_WAIT_FOR_READ; + schedule_delayed_work(&host->timeout_work, host->timeout); /* buf read enable */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); - - blocksize = (BLOCK_SIZE_MASK & - sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; - for (i = 0; i < blocksize / 4; i++) +} + +static bool sh_mmcif_read_block(struct sh_mmcif_host *host) +{ + struct mmc_data *data = host->mrq->data; + u32 *p = sg_virt(data->sg); + int i; + + if (host->sd_error) { + data->error = sh_mmcif_error_manage(host); + return false; + } + + for (i = 0; i < host->blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); /* buffer read end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); + host->wait_for = MMCIF_WAIT_FOR_READ_END; - return 0; + return true; } -static int sh_mmcif_multi_read(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static void sh_mmcif_multi_read(struct sh_mmcif_host *host, + struct mmc_request *mrq) { struct mmc_data *data = mrq->data; - long time; - u32 blocksize, i, j, sec, *p; - - blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, - MMCIF_CE_BLOCK_SET); - for (j = 0; j < data->sg_len; j++) { - p = sg_virt(data->sg); - for (sec = 0; sec < data->sg->length / blocksize; sec++) { - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); - /* buf read enable */ - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); - - for (i = 0; i < blocksize / 4; i++) - *p++ = sh_mmcif_readl(host->addr, - MMCIF_CE_DATA); - } - if (j < data->sg_len - 1) - data->sg++; + + if (!data->sg_len || !data->sg->length) + return; + + host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & + BLOCK_SIZE_MASK; + + host->wait_for = MMCIF_WAIT_FOR_MREAD; + host->sg_idx = 0; + host->sg_blkidx = 0; + host->pio_ptr = sg_virt(data->sg); + schedule_delayed_work(&host->timeout_work, host->timeout); + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); +} + +static bool sh_mmcif_mread_block(struct sh_mmcif_host *host) +{ + struct mmc_data *data = host->mrq->data; + u32 *p = host->pio_ptr; + int i; + + if (host->sd_error) { + data->error = sh_mmcif_error_manage(host); + return false; } - return 0; + + BUG_ON(!data->sg->length); + + for (i = 0; i < host->blocksize / 4; i++) + *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); + + if (!sh_mmcif_next_block(host, p)) + return false; + + schedule_delayed_work(&host->timeout_work, host->timeout); + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); + + return true; } -static int sh_mmcif_single_write(struct sh_mmcif_host *host, +static void sh_mmcif_single_write(struct sh_mmcif_host *host, struct mmc_request *mrq) { - struct mmc_data *data = mrq->data; - long time; - u32 blocksize, i, *p = sg_virt(data->sg); + host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & + BLOCK_SIZE_MASK) + 3; - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); + host->wait_for = MMCIF_WAIT_FOR_WRITE; + schedule_delayed_work(&host->timeout_work, host->timeout); /* buf write enable */ - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); - - blocksize = (BLOCK_SIZE_MASK & - sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; - for (i = 0; i < blocksize / 4; i++) + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); +} + +static bool sh_mmcif_write_block(struct sh_mmcif_host *host) +{ + struct mmc_data *data = host->mrq->data; + u32 *p = sg_virt(data->sg); + int i; + + if (host->sd_error) { + data->error = sh_mmcif_error_manage(host); + return false; + } + + for (i = 0; i < host->blocksize / 4; i++) sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); /* buffer write end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); + host->wait_for = MMCIF_WAIT_FOR_WRITE_END; - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); - - return 0; + return true; } -static int sh_mmcif_multi_write(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static void sh_mmcif_multi_write(struct sh_mmcif_host *host, + struct mmc_request *mrq) { struct mmc_data *data = mrq->data; - long time; - u32 i, sec, j, blocksize, *p; - blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, - MMCIF_CE_BLOCK_SET); + if (!data->sg_len || !data->sg->length) + return; - for (j = 0; j < data->sg_len; j++) { - p = sg_virt(data->sg); - for (sec = 0; sec < data->sg->length / blocksize; sec++) { - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); - /* buf write enable*/ - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); + host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & + BLOCK_SIZE_MASK; - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); + host->wait_for = MMCIF_WAIT_FOR_MWRITE; + host->sg_idx = 0; + host->sg_blkidx = 0; + host->pio_ptr = sg_virt(data->sg); + schedule_delayed_work(&host->timeout_work, host->timeout); + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); +} - for (i = 0; i < blocksize / 4; i++) - sh_mmcif_writel(host->addr, - MMCIF_CE_DATA, *p++); - } - if (j < data->sg_len - 1) - data->sg++; +static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host) +{ + struct mmc_data *data = host->mrq->data; + u32 *p = host->pio_ptr; + int i; + + if (host->sd_error) { + data->error = sh_mmcif_error_manage(host); + return false; } - return 0; + + BUG_ON(!data->sg->length); + + for (i = 0; i < host->blocksize / 4; i++) + sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); + + if (!sh_mmcif_next_block(host, p)) + return false; + + schedule_delayed_work(&host->timeout_work, host->timeout); + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); + + return true; } static void sh_mmcif_get_response(struct sh_mmcif_host *host, @@ -603,8 +714,11 @@ static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, } static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq, struct mmc_command *cmd, u32 opc) + struct mmc_request *mrq) { + struct mmc_data *data = mrq->data; + struct mmc_command *cmd = mrq->cmd; + u32 opc = cmd->opcode; u32 tmp = 0; /* Response Type check */ @@ -636,7 +750,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, break; } /* WDAT / DATW */ - if (host->data) { + if (data) { tmp |= CMD_SET_WDAT; switch (host->bus_width) { case MMC_BUS_WIDTH_1: @@ -660,7 +774,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, - mrq->data->blocks << 16); + data->blocks << 16); } /* RIDXC[1:0] check bits */ if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID || @@ -674,68 +788,60 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, opc == MMC_SEND_CSD || opc == MMC_SEND_CID) tmp |= CMD_SET_CRC7C_INTERNAL; - return opc = ((opc << 24) | tmp); + return (opc << 24) | tmp; } static int sh_mmcif_data_trans(struct sh_mmcif_host *host, - struct mmc_request *mrq, u32 opc) + struct mmc_request *mrq, u32 opc) { - int ret; - switch (opc) { case MMC_READ_MULTIPLE_BLOCK: - ret = sh_mmcif_multi_read(host, mrq); - break; + sh_mmcif_multi_read(host, mrq); + return 0; case MMC_WRITE_MULTIPLE_BLOCK: - ret = sh_mmcif_multi_write(host, mrq); - break; + sh_mmcif_multi_write(host, mrq); + return 0; case MMC_WRITE_BLOCK: - ret = sh_mmcif_single_write(host, mrq); - break; + sh_mmcif_single_write(host, mrq); + return 0; case MMC_READ_SINGLE_BLOCK: case MMC_SEND_EXT_CSD: - ret = sh_mmcif_single_read(host, mrq); - break; + sh_mmcif_single_read(host, mrq); + return 0; default: dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc); - ret = -EINVAL; - break; + return -EINVAL; } - return ret; } static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq, struct mmc_command *cmd) + struct mmc_request *mrq) { - long time; - int ret = 0, mask = 0; + struct mmc_command *cmd = mrq->cmd; u32 opc = cmd->opcode; + u32 mask; switch (opc) { - /* respons busy check */ + /* response busy check */ case MMC_SWITCH: case MMC_STOP_TRANSMISSION: case MMC_SET_WRITE_PROT: case MMC_CLR_WRITE_PROT: case MMC_ERASE: case MMC_GEN_CMD: - mask = MASK_MRBSYE; + mask = MASK_START_CMD | MASK_MRBSYE; break; default: - mask = MASK_MCRSPE; + mask = MASK_START_CMD | MASK_MCRSPE; break; } - mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | - MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | - MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | - MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; - if (host->data) { + if (mrq->data) { sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0); sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, mrq->data->blksz); } - opc = sh_mmcif_set_cmd(host, mrq, cmd, opc); + opc = sh_mmcif_set_cmd(host, mrq); sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); @@ -744,80 +850,28 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, /* set cmd */ sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0) { - cmd->error = sh_mmcif_error_manage(host); - return; - } - if (host->sd_error) { - switch (cmd->opcode) { - case MMC_ALL_SEND_CID: - case MMC_SELECT_CARD: - case MMC_APP_CMD: - cmd->error = -ETIMEDOUT; - break; - default: - dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n", - cmd->opcode); - cmd->error = sh_mmcif_error_manage(host); - break; - } - host->sd_error = false; - return; - } - if (!(cmd->flags & MMC_RSP_PRESENT)) { - cmd->error = 0; - return; - } - sh_mmcif_get_response(host, cmd); - if (host->data) { - if (!host->dma_active) { - ret = sh_mmcif_data_trans(host, mrq, cmd->opcode); - } else { - long time = - wait_for_completion_interruptible_timeout(&host->dma_complete, - host->timeout); - if (!time) - ret = -ETIMEDOUT; - else if (time < 0) - ret = time; - sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, - BUF_ACC_DMAREN | BUF_ACC_DMAWEN); - host->dma_active = false; - } - if (ret < 0) - mrq->data->bytes_xfered = 0; - else - mrq->data->bytes_xfered = - mrq->data->blocks * mrq->data->blksz; - } - cmd->error = ret; + host->wait_for = MMCIF_WAIT_FOR_CMD; + schedule_delayed_work(&host->timeout_work, host->timeout); } static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq, struct mmc_command *cmd) + struct mmc_request *mrq) { - long time; - - if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) + switch (mrq->cmd->opcode) { + case MMC_READ_MULTIPLE_BLOCK: sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); - else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) + break; + case MMC_WRITE_MULTIPLE_BLOCK: sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); - else { + break; + default: dev_err(&host->pd->dev, "unsupported stop cmd\n"); - cmd->error = sh_mmcif_error_manage(host); + mrq->stop->error = sh_mmcif_error_manage(host); return; } - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) { - cmd->error = sh_mmcif_error_manage(host); - return; - } - sh_mmcif_get_cmd12response(host, cmd); - cmd->error = 0; + host->wait_for = MMCIF_WAIT_FOR_STOP; + schedule_delayed_work(&host->timeout_work, host->timeout); } static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) @@ -856,23 +910,10 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) default: break; } - host->data = mrq->data; - if (mrq->data) { - if (mrq->data->flags & MMC_DATA_READ) { - if (host->chan_rx) - sh_mmcif_start_dma_rx(host); - } else { - if (host->chan_tx) - sh_mmcif_start_dma_tx(host); - } - } - sh_mmcif_start_cmd(host, mrq, mrq->cmd); - host->data = NULL; - if (!mrq->cmd->error && mrq->stop) - sh_mmcif_stop_cmd(host, mrq, mrq->stop); - host->state = STATE_IDLE; - mmc_request_done(mmc, mrq); + host->mrq = mrq; + + sh_mmcif_start_cmd(host, mrq); } static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -947,9 +988,156 @@ static struct mmc_host_ops sh_mmcif_ops = { .get_cd = sh_mmcif_get_cd, }; -static void sh_mmcif_detect(struct mmc_host *mmc) +static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) { - mmc_detect_change(mmc, 0); + struct mmc_command *cmd = host->mrq->cmd; + struct mmc_data *data = host->mrq->data; + long time; + + if (host->sd_error) { + switch (cmd->opcode) { + case MMC_ALL_SEND_CID: + case MMC_SELECT_CARD: + case MMC_APP_CMD: + cmd->error = -ETIMEDOUT; + host->sd_error = false; + break; + default: + cmd->error = sh_mmcif_error_manage(host); + dev_dbg(&host->pd->dev, "Cmd(d'%d) error %d\n", + cmd->opcode, cmd->error); + break; + } + return false; + } + if (!(cmd->flags & MMC_RSP_PRESENT)) { + cmd->error = 0; + return false; + } + + sh_mmcif_get_response(host, cmd); + + if (!data) + return false; + + if (data->flags & MMC_DATA_READ) { + if (host->chan_rx) + sh_mmcif_start_dma_rx(host); + } else { + if (host->chan_tx) + sh_mmcif_start_dma_tx(host); + } + + if (!host->dma_active) { + data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode); + if (!data->error) + return true; + return false; + } + + /* Running in the IRQ thread, can sleep */ + time = wait_for_completion_interruptible_timeout(&host->dma_complete, + host->timeout); + if (host->sd_error) { + dev_err(host->mmc->parent, + "Error IRQ while waiting for DMA completion!\n"); + /* Woken up by an error IRQ: abort DMA */ + if (data->flags & MMC_DATA_READ) + dmaengine_terminate_all(host->chan_rx); + else + dmaengine_terminate_all(host->chan_tx); + data->error = sh_mmcif_error_manage(host); + } else if (!time) { + data->error = -ETIMEDOUT; + } else if (time < 0) { + data->error = time; + } + sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, + BUF_ACC_DMAREN | BUF_ACC_DMAWEN); + host->dma_active = false; + + if (data->error) + data->bytes_xfered = 0; + + return false; +} + +static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) +{ + struct sh_mmcif_host *host = dev_id; + struct mmc_request *mrq = host->mrq; + struct mmc_data *data = mrq->data; + + cancel_delayed_work_sync(&host->timeout_work); + + /* + * All handlers return true, if processing continues, and false, if the + * request has to be completed - successfully or not + */ + switch (host->wait_for) { + case MMCIF_WAIT_FOR_REQUEST: + /* We're too late, the timeout has already kicked in */ + return IRQ_HANDLED; + case MMCIF_WAIT_FOR_CMD: + if (sh_mmcif_end_cmd(host)) + /* Wait for data */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_MREAD: + if (sh_mmcif_mread_block(host)) + /* Wait for more data */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_READ: + if (sh_mmcif_read_block(host)) + /* Wait for data end */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_MWRITE: + if (sh_mmcif_mwrite_block(host)) + /* Wait data to write */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_WRITE: + if (sh_mmcif_write_block(host)) + /* Wait for data end */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_STOP: + if (host->sd_error) { + mrq->stop->error = sh_mmcif_error_manage(host); + break; + } + sh_mmcif_get_cmd12response(host, mrq->stop); + mrq->stop->error = 0; + break; + case MMCIF_WAIT_FOR_READ_END: + case MMCIF_WAIT_FOR_WRITE_END: + if (host->sd_error) + data->error = sh_mmcif_error_manage(host); + break; + default: + BUG(); + } + + if (host->wait_for != MMCIF_WAIT_FOR_STOP) { + if (!mrq->cmd->error && data && !data->error) + data->bytes_xfered = + data->blocks * data->blksz; + + if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) { + sh_mmcif_stop_cmd(host, mrq); + if (!mrq->stop->error) + return IRQ_HANDLED; + } + } + + host->wait_for = MMCIF_WAIT_FOR_REQUEST; + host->state = STATE_IDLE; + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); + + return IRQ_HANDLED; } static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) @@ -960,7 +1148,12 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); - if (state & INT_RBSYE) { + if (state & INT_ERR_STS) { + /* error interrupts - process first */ + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); + sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); + err = 1; + } else if (state & INT_RBSYE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); @@ -988,11 +1181,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12RBE | INT_CMD12CRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); - } else if (state & INT_ERR_STS) { - /* err interrupts */ - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); - err = 1; } else { dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state); sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); @@ -1003,14 +1191,57 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) host->sd_error = true; dev_dbg(&host->pd->dev, "int err state = %08x\n", state); } - if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) - complete(&host->intr_wait); - else + if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { + if (!host->dma_active) + return IRQ_WAKE_THREAD; + else if (host->sd_error) + mmcif_dma_complete(host); + } else { dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state); + } return IRQ_HANDLED; } +static void mmcif_timeout_work(struct work_struct *work) +{ + struct delayed_work *d = container_of(work, struct delayed_work, work); + struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work); + struct mmc_request *mrq = host->mrq; + + if (host->dying) + /* Don't run after mmc_remove_host() */ + return; + + /* + * Handle races with cancel_delayed_work(), unless + * cancel_delayed_work_sync() is used + */ + switch (host->wait_for) { + case MMCIF_WAIT_FOR_CMD: + mrq->cmd->error = sh_mmcif_error_manage(host); + break; + case MMCIF_WAIT_FOR_STOP: + mrq->stop->error = sh_mmcif_error_manage(host); + break; + case MMCIF_WAIT_FOR_MREAD: + case MMCIF_WAIT_FOR_MWRITE: + case MMCIF_WAIT_FOR_READ: + case MMCIF_WAIT_FOR_WRITE: + case MMCIF_WAIT_FOR_READ_END: + case MMCIF_WAIT_FOR_WRITE_END: + mrq->data->error = sh_mmcif_error_manage(host); + break; + default: + BUG(); + } + + host->state = STATE_IDLE; + host->wait_for = MMCIF_WAIT_FOR_REQUEST; + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); +} + static int __devinit sh_mmcif_probe(struct platform_device *pdev) { int ret = 0, irq[2]; @@ -1064,7 +1295,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) host->clk = clk_get_rate(host->hclk); host->pd = pdev; - init_completion(&host->intr_wait); spin_lock_init(&host->lock); mmc->ops = &sh_mmcif_ops; @@ -1101,19 +1331,21 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host); + ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host); if (ret) { dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n"); goto clean_up3; } - ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host); + ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); if (ret) { free_irq(irq[0], host); dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); goto clean_up3; } - sh_mmcif_detect(host->mmc); + INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); + + mmc_detect_change(host->mmc, 0); dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); dev_dbg(&pdev->dev, "chip ver H'%04x\n", @@ -1139,11 +1371,19 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) struct sh_mmcif_host *host = platform_get_drvdata(pdev); int irq[2]; + host->dying = true; pm_runtime_get_sync(&pdev->dev); mmc_remove_host(host->mmc); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); + /* + * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the + * mmc_remove_host() call above. But swapping order doesn't help either + * (a query on the linux-mmc mailing list didn't bring any replies). + */ + cancel_delayed_work_sync(&host->timeout_work); + if (host->addr) iounmap(host->addr); @@ -1206,19 +1446,7 @@ static struct platform_driver sh_mmcif_driver = { }, }; -static int __init sh_mmcif_init(void) -{ - return platform_driver_register(&sh_mmcif_driver); -} - -static void __exit sh_mmcif_exit(void) -{ - platform_driver_unregister(&sh_mmcif_driver); -} - -module_init(sh_mmcif_init); -module_exit(sh_mmcif_exit); - +module_platform_driver(sh_mmcif_driver); MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 41ae6466bd83..58da3c44acc5 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -282,18 +282,7 @@ static struct platform_driver sh_mobile_sdhi_driver = { .remove = __devexit_p(sh_mobile_sdhi_remove), }; -static int __init sh_mobile_sdhi_init(void) -{ - return platform_driver_register(&sh_mobile_sdhi_driver); -} - -static void __exit sh_mobile_sdhi_exit(void) -{ - platform_driver_unregister(&sh_mobile_sdhi_driver); -} - -module_init(sh_mobile_sdhi_init); -module_exit(sh_mobile_sdhi_exit); +module_platform_driver(sh_mobile_sdhi_driver); MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); MODULE_AUTHOR("Magnus Damm"); diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index f70d04664cac..43d962829f8e 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -22,8 +22,8 @@ #define DRIVER_NAME "tifm_sd" #define DRIVER_VERSION "0.8" -static int no_dma = 0; -static int fixed_timeout = 0; +static bool no_dma = 0; +static bool fixed_timeout = 0; module_param(no_dma, bool, 0644); module_param(fixed_timeout, bool, 0644); @@ -118,7 +118,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off; + buf = kmap_atomic(pg) + off; if (host->cmd_flags & DATA_CARRY) { buf[pos++] = host->bounce_buf_data[0]; host->cmd_flags &= ~DATA_CARRY; @@ -134,7 +134,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, } buf[pos++] = (val >> 8) & 0xff; } - kunmap_atomic(buf - off, KM_BIO_DST_IRQ); + kunmap_atomic(buf - off); } static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, @@ -144,7 +144,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off; + buf = kmap_atomic(pg) + off; if (host->cmd_flags & DATA_CARRY) { val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); writel(val, sock->addr + SOCK_MMCSD_DATA); @@ -161,7 +161,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, val |= (buf[pos++] << 8) & 0xff00; writel(val, sock->addr + SOCK_MMCSD_DATA); } - kunmap_atomic(buf - off, KM_BIO_SRC_IRQ); + kunmap_atomic(buf - off); } static void tifm_sd_transfer_data(struct tifm_sd *host) @@ -212,13 +212,13 @@ static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off, struct page *src, unsigned int src_off, unsigned int count) { - unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off; - unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off; + unsigned char *src_buf = kmap_atomic(src) + src_off; + unsigned char *dst_buf = kmap_atomic(dst) + dst_off; memcpy(dst_buf, src_buf, count); - kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ); - kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ); + kunmap_atomic(dst_buf - dst_off); + kunmap_atomic(src_buf - src_off); } static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data) diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index a4ea10242787..113ce6c9cf32 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -138,19 +138,7 @@ static struct platform_driver tmio_mmc_driver = { .resume = tmio_mmc_resume, }; - -static int __init tmio_mmc_init(void) -{ - return platform_driver_register(&tmio_mmc_driver); -} - -static void __exit tmio_mmc_exit(void) -{ - platform_driver_unregister(&tmio_mmc_driver); -} - -module_init(tmio_mmc_init); -module_exit(tmio_mmc_exit); +module_platform_driver(tmio_mmc_driver); MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 3020f98218f0..a95e6d901726 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -105,13 +105,13 @@ static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); - return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + return kmap_atomic(sg_page(sg)) + sg->offset; } static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt) { - kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ); + kunmap_atomic(virt - sg->offset); local_irq_restore(*flags); } diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 86f259cdfcbc..7a6e6cc8f8b8 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -77,7 +77,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); if (ret > 0) desc = chan->device->device_prep_slave_sg(chan, sg, ret, - DMA_FROM_DEVICE, DMA_CTRL_ACK); + DMA_DEV_TO_MEM, DMA_CTRL_ACK); if (desc) { cookie = dmaengine_submit(desc); @@ -158,7 +158,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); if (ret > 0) desc = chan->device->device_prep_slave_sg(chan, sg, ret, - DMA_TO_DEVICE, DMA_CTRL_ACK); + DMA_MEM_TO_DEV, DMA_CTRL_ACK); if (desc) { cookie = dmaengine_submit(desc); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 4208b3958069..abad01b37cfb 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -800,8 +800,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } else if (ios->power_mode != MMC_POWER_UP) { if (host->set_pwr && ios->power_mode == MMC_POWER_OFF) host->set_pwr(host->pdev, 0); - if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && - pdata->power) { + if (pdata->power) { pdata->power = false; pm_runtime_put(&host->pdev->dev); } @@ -915,6 +914,23 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, if (ret < 0) goto pm_disable; + /* + * There are 4 different scenarios for the card detection: + * 1) an external gpio irq handles the cd (best for power savings) + * 2) internal sdhi irq handles the cd + * 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL + * 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE + * + * While we increment the rtpm counter for all scenarios when the mmc + * core activates us by calling an appropriate set_ios(), we must + * additionally ensure that in case 2) the tmio mmc hardware stays + * powered on during runtime for the card detection to work. + */ + if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD + || mmc->caps & MMC_CAP_NEEDS_POLL + || mmc->caps & MMC_CAP_NONREMOVABLE)) + pm_runtime_get_noresume(&pdev->dev); + tmio_mmc_clk_stop(_host); tmio_mmc_reset(_host); @@ -933,12 +949,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, /* See if we also get DMA */ tmio_mmc_request_dma(_host, pdata); - /* We have to keep the device powered for its card detection to work */ - if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) { - pdata->power = true; - pm_runtime_get_noresume(&pdev->dev); - } - mmc_add_host(mmc); /* Unmask the IRQs we want to know about */ @@ -974,7 +984,9 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) * the controller, the runtime PM is suspended and pdata->power == false, * so, our .runtime_resume() will not try to detect a card in the slot. */ - if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD) + if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD + || host->mmc->caps & MMC_CAP_NEEDS_POLL + || host->mmc->caps & MMC_CAP_NONREMOVABLE) pm_runtime_get_sync(&pdev->dev); mmc_remove_host(host->mmc); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 2ec978bc32ba..3135a1a5d75d 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -223,25 +223,25 @@ enum SD_RESPONSE_TYPE { #define FUN(c) (0x000007 & (c->arg>>28)) #define REG(c) (0x01FFFF & (c->arg>>9)) -static int limit_speed_to_24_MHz; +static bool limit_speed_to_24_MHz; module_param(limit_speed_to_24_MHz, bool, 0644); MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz"); -static int pad_input_to_usb_pkt; +static bool pad_input_to_usb_pkt; module_param(pad_input_to_usb_pkt, bool, 0644); MODULE_PARM_DESC(pad_input_to_usb_pkt, "Pad USB data input transfers to whole USB Packet"); -static int disable_offload_processing; +static bool disable_offload_processing; module_param(disable_offload_processing, bool, 0644); MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing"); -static int force_1_bit_data_xfers; +static bool force_1_bit_data_xfers; module_param(force_1_bit_data_xfers, bool, 0644); MODULE_PARM_DESC(force_1_bit_data_xfers, "Force SDIO Data Transfers to 1-bit Mode"); -static int force_polling_for_irqs; +static bool force_polling_for_irqs; module_param(force_polling_for_irqs, bool, 0644); MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts"); diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 7dd3700f2303..73abbc3e093e 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -17,35 +17,19 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/platform_device.h> #include <asm/io.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1550nd.h> -#ifdef CONFIG_MIPS_PB1550 -#include <asm/mach-pb1x00/pb1550.h> -#elif defined(CONFIG_MIPS_DB1550) -#include <asm/mach-db1x00/db1x00.h> -#endif -#include <asm/mach-db1x00/bcsr.h> -/* - * MTD structure for NAND controller - */ -static struct mtd_info *au1550_mtd = NULL; -static void __iomem *p_nand; -static int nand_width = 1; /* default x8 */ -static void (*au1550_write_byte)(struct mtd_info *, u_char); +struct au1550nd_ctx { + struct mtd_info info; + struct nand_chip chip; -/* - * Define partitions for flash device - */ -static const struct mtd_partition partition_info[] = { - { - .name = "NAND FS 0", - .offset = 0, - .size = 8 * 1024 * 1024}, - { - .name = "NAND FS 1", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL} + int cs; + void __iomem *base; + void (*write_byte)(struct mtd_info *, u_char); }; /** @@ -259,24 +243,25 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) { - register struct nand_chip *this = mtd->priv; + struct au1550nd_ctx *ctx = container_of(mtd, struct au1550nd_ctx, info); + struct nand_chip *this = mtd->priv; switch (cmd) { case NAND_CTL_SETCLE: - this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; + this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD; break; case NAND_CTL_CLRCLE: - this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; + this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA; break; case NAND_CTL_SETALE: - this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; + this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR; break; case NAND_CTL_CLRALE: - this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; + this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA; /* FIXME: Nobody knows why this is necessary, * but it works only that way */ udelay(1); @@ -284,7 +269,7 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) case NAND_CTL_SETNCE: /* assert (force assert) chip enable */ - au_writel((1 << (4 + NAND_CS)), MEM_STNDCTL); + au_writel((1 << (4 + ctx->cs)), MEM_STNDCTL); break; case NAND_CTL_CLRNCE: @@ -331,9 +316,10 @@ static void au1550_select_chip(struct mtd_info *mtd, int chip) */ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) { - register struct nand_chip *this = mtd->priv; + struct au1550nd_ctx *ctx = container_of(mtd, struct au1550nd_ctx, info); + struct nand_chip *this = mtd->priv; int ce_override = 0, i; - ulong flags; + unsigned long flags = 0; /* Begin command latch cycle */ au1550_hwcontrol(mtd, NAND_CTL_SETCLE); @@ -354,9 +340,9 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i column -= 256; readcmd = NAND_CMD_READ1; } - au1550_write_byte(mtd, readcmd); + ctx->write_byte(mtd, readcmd); } - au1550_write_byte(mtd, command); + ctx->write_byte(mtd, command); /* Set ALE and clear CLE to start address cycle */ au1550_hwcontrol(mtd, NAND_CTL_CLRCLE); @@ -369,10 +355,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; - au1550_write_byte(mtd, column); + ctx->write_byte(mtd, column); } if (page_addr != -1) { - au1550_write_byte(mtd, (u8)(page_addr & 0xff)); + ctx->write_byte(mtd, (u8)(page_addr & 0xff)); if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || @@ -390,11 +376,12 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i au1550_hwcontrol(mtd, NAND_CTL_SETNCE); } - au1550_write_byte(mtd, (u8)(page_addr >> 8)); + ctx->write_byte(mtd, (u8)(page_addr >> 8)); /* One more address cycle for devices > 32MiB */ if (this->chipsize > (32 << 20)) - au1550_write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); + ctx->write_byte(mtd, + ((page_addr >> 16) & 0x0f)); } /* Latch in address */ au1550_hwcontrol(mtd, NAND_CTL_CLRALE); @@ -440,121 +427,79 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i while(!this->dev_ready(mtd)); } - -/* - * Main initialization routine - */ -static int __init au1xxx_nand_init(void) +static int __devinit find_nand_cs(unsigned long nand_base) { - struct nand_chip *this; - u16 boot_swapboot = 0; /* default value */ - int retval; - u32 mem_staddr; - u32 nand_phys; - - /* Allocate memory for MTD device structure and private data */ - au1550_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); - if (!au1550_mtd) { - printk("Unable to allocate NAND MTD dev structure.\n"); - return -ENOMEM; - } - - /* Get pointer to private data */ - this = (struct nand_chip *)(&au1550_mtd[1]); - - /* Link the private data with the MTD structure */ - au1550_mtd->priv = this; - au1550_mtd->owner = THIS_MODULE; - + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR); + unsigned long addr, staddr, start, mask, end; + int i; - /* MEM_STNDCTL: disable ints, disable nand boot */ - au_writel(0, MEM_STNDCTL); + for (i = 0; i < 4; i++) { + addr = 0x1000 + (i * 0x10); /* CSx */ + staddr = __raw_readl(base + addr + 0x08); /* STADDRx */ + /* figure out the decoded range of this CS */ + start = (staddr << 4) & 0xfffc0000; + mask = (staddr << 18) & 0xfffc0000; + end = (start | (start - 1)) & ~(start ^ mask); + if ((nand_base >= start) && (nand_base < end)) + return i; + } -#ifdef CONFIG_MIPS_PB1550 - /* set gpio206 high */ - gpio_direction_input(206); + return -ENODEV; +} - boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1); +static int __devinit au1550nd_probe(struct platform_device *pdev) +{ + struct au1550nd_platdata *pd; + struct au1550nd_ctx *ctx; + struct nand_chip *this; + struct resource *r; + int ret, cs; - switch (boot_swapboot) { - case 0: - case 2: - case 8: - case 0xC: - case 0xD: - /* x16 NAND Flash */ - nand_width = 0; - break; - case 1: - case 9: - case 3: - case 0xE: - case 0xF: - /* x8 NAND Flash */ - nand_width = 1; - break; - default: - printk("Pb1550 NAND: bad boot:swap\n"); - retval = -EINVAL; - goto outmem; + pd = pdev->dev.platform_data; + if (!pd) { + dev_err(&pdev->dev, "missing platform data\n"); + return -ENODEV; } -#endif - - /* Configure chip-select; normally done by boot code, e.g. YAMON */ -#ifdef NAND_STCFG - if (NAND_CS == 0) { - au_writel(NAND_STCFG, MEM_STCFG0); - au_writel(NAND_STTIME, MEM_STTIME0); - au_writel(NAND_STADDR, MEM_STADDR0); - } - if (NAND_CS == 1) { - au_writel(NAND_STCFG, MEM_STCFG1); - au_writel(NAND_STTIME, MEM_STTIME1); - au_writel(NAND_STADDR, MEM_STADDR1); + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + dev_err(&pdev->dev, "no memory for NAND context\n"); + return -ENOMEM; } - if (NAND_CS == 2) { - au_writel(NAND_STCFG, MEM_STCFG2); - au_writel(NAND_STTIME, MEM_STTIME2); - au_writel(NAND_STADDR, MEM_STADDR2); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no NAND memory resource\n"); + ret = -ENODEV; + goto out1; } - if (NAND_CS == 3) { - au_writel(NAND_STCFG, MEM_STCFG3); - au_writel(NAND_STTIME, MEM_STTIME3); - au_writel(NAND_STADDR, MEM_STADDR3); + if (request_mem_region(r->start, resource_size(r), "au1550-nand")) { + dev_err(&pdev->dev, "cannot claim NAND memory area\n"); + ret = -ENOMEM; + goto out1; } -#endif - - /* Locate NAND chip-select in order to determine NAND phys address */ - mem_staddr = 0x00000000; - if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0)) - mem_staddr = au_readl(MEM_STADDR0); - else if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1)) - mem_staddr = au_readl(MEM_STADDR1); - else if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2)) - mem_staddr = au_readl(MEM_STADDR2); - else if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3)) - mem_staddr = au_readl(MEM_STADDR3); - - if (mem_staddr == 0x00000000) { - printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECT\n"); - kfree(au1550_mtd); - return 1; + + ctx->base = ioremap_nocache(r->start, 0x1000); + if (!ctx->base) { + dev_err(&pdev->dev, "cannot remap NAND memory area\n"); + ret = -ENODEV; + goto out2; } - nand_phys = (mem_staddr << 4) & 0xFFFC0000; - p_nand = ioremap(nand_phys, 0x1000); + this = &ctx->chip; + ctx->info.priv = this; + ctx->info.owner = THIS_MODULE; - /* make controller and MTD agree */ - if (NAND_CS == 0) - nand_width = au_readl(MEM_STCFG0) & (1 << 22); - if (NAND_CS == 1) - nand_width = au_readl(MEM_STCFG1) & (1 << 22); - if (NAND_CS == 2) - nand_width = au_readl(MEM_STCFG2) & (1 << 22); - if (NAND_CS == 3) - nand_width = au_readl(MEM_STCFG3) & (1 << 22); + /* figure out which CS# r->start belongs to */ + cs = find_nand_cs(r->start); + if (cs < 0) { + dev_err(&pdev->dev, "cannot detect NAND chipselect\n"); + ret = -ENODEV; + goto out3; + } + ctx->cs = cs; - /* Set address of hardware control function */ this->dev_ready = au1550_device_ready; this->select_chip = au1550_select_chip; this->cmdfunc = au1550_command; @@ -565,54 +510,57 @@ static int __init au1xxx_nand_init(void) this->options = NAND_NO_AUTOINCR; - if (!nand_width) + if (pd->devwidth) this->options |= NAND_BUSWIDTH_16; - this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte; - au1550_write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; + this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte; + ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte; this->read_word = au_read_word; - this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf; - this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf; - this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf; - - /* Scan to find existence of the device */ - if (nand_scan(au1550_mtd, 1)) { - retval = -ENXIO; - goto outio; + this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf; + this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf; + this->verify_buf = (pd->devwidth) ? au_verify_buf16 : au_verify_buf; + + ret = nand_scan(&ctx->info, 1); + if (ret) { + dev_err(&pdev->dev, "NAND scan failed with %d\n", ret); + goto out3; } - /* Register the partitions */ - mtd_device_register(au1550_mtd, partition_info, - ARRAY_SIZE(partition_info)); + mtd_device_register(&ctx->info, pd->parts, pd->num_parts); return 0; - outio: - iounmap(p_nand); - - outmem: - kfree(au1550_mtd); - return retval; +out3: + iounmap(ctx->base); +out2: + release_mem_region(r->start, resource_size(r)); +out1: + kfree(ctx); + return ret; } -module_init(au1xxx_nand_init); - -/* - * Clean up routine - */ -static void __exit au1550_cleanup(void) +static int __devexit au1550nd_remove(struct platform_device *pdev) { - /* Release resources, unregister device */ - nand_release(au1550_mtd); + struct au1550nd_ctx *ctx = platform_get_drvdata(pdev); + struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - /* Free the MTD device structure */ - kfree(au1550_mtd); - - /* Unmap */ - iounmap(p_nand); + nand_release(&ctx->info); + iounmap(ctx->base); + release_mem_region(r->start, 0x1000); + kfree(ctx); + return 0; } -module_exit(au1550_cleanup); +static struct platform_driver au1550nd_driver = { + .driver = { + .name = "au1550-nand", + .owner = THIS_MODULE, + }, + .probe = au1550nd_probe, + .remove = __devexit_p(au1550nd_remove), +}; + +module_platform_driver(au1550nd_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Embedded Edge, LLC"); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 2a56fc6f399a..7f680420bfab 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -827,7 +827,7 @@ int gpmi_send_command(struct gpmi_nand_data *this) pio[1] = pio[2] = 0; desc = channel->device->device_prep_slave_sg(channel, (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_NONE, 0); + ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); if (!desc) { pr_err("step 1 error\n"); return -1; @@ -839,7 +839,7 @@ int gpmi_send_command(struct gpmi_nand_data *this) sg_init_one(sgl, this->cmd_buffer, this->command_length); dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE); desc = channel->device->device_prep_slave_sg(channel, - sgl, 1, DMA_TO_DEVICE, 1); + sgl, 1, DMA_MEM_TO_DEV, 1); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -872,7 +872,7 @@ int gpmi_send_data(struct gpmi_nand_data *this) pio[1] = 0; desc = channel->device->device_prep_slave_sg(channel, (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_NONE, 0); + ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); if (!desc) { pr_err("step 1 error\n"); return -1; @@ -881,7 +881,7 @@ int gpmi_send_data(struct gpmi_nand_data *this) /* [2] send DMA request */ prepare_data_dma(this, DMA_TO_DEVICE); desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, - 1, DMA_TO_DEVICE, 1); + 1, DMA_MEM_TO_DEV, 1); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -908,7 +908,7 @@ int gpmi_read_data(struct gpmi_nand_data *this) pio[1] = 0; desc = channel->device->device_prep_slave_sg(channel, (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_NONE, 0); + ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); if (!desc) { pr_err("step 1 error\n"); return -1; @@ -917,7 +917,7 @@ int gpmi_read_data(struct gpmi_nand_data *this) /* [2] : send DMA request */ prepare_data_dma(this, DMA_FROM_DEVICE); desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, - 1, DMA_FROM_DEVICE, 1); + 1, DMA_DEV_TO_MEM, 1); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -964,7 +964,7 @@ int gpmi_send_page(struct gpmi_nand_data *this, desc = channel->device->device_prep_slave_sg(channel, (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_NONE, 0); + ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -998,7 +998,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, | BF_GPMI_CTRL0_XFER_COUNT(0); pio[1] = 0; desc = channel->device->device_prep_slave_sg(channel, - (struct scatterlist *)pio, 2, DMA_NONE, 0); + (struct scatterlist *)pio, 2, + DMA_TRANS_NONE, 0); if (!desc) { pr_err("step 1 error\n"); return -1; @@ -1027,7 +1028,7 @@ int gpmi_read_page(struct gpmi_nand_data *this, pio[5] = auxiliary; desc = channel->device->device_prep_slave_sg(channel, (struct scatterlist *)pio, - ARRAY_SIZE(pio), DMA_NONE, 1); + ARRAY_SIZE(pio), DMA_TRANS_NONE, 1); if (!desc) { pr_err("step 2 error\n"); return -1; @@ -1045,7 +1046,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); pio[1] = 0; desc = channel->device->device_prep_slave_sg(channel, - (struct scatterlist *)pio, 2, DMA_NONE, 1); + (struct scatterlist *)pio, 2, + DMA_TRANS_NONE, 1); if (!desc) { pr_err("step 3 error\n"); return -1; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 8544d6bf50a0..5c3d719c37e6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -185,7 +185,7 @@ struct pxa3xx_nand_info { uint32_t ndcb2; }; -static int use_dma = 1; +static bool use_dma = 1; module_param(use_dma, bool, 0444); MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW"); diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index f20f393bfda6..769a4e096b3c 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -22,7 +22,7 @@ #include "r852.h" -static int r852_enable_dma = 1; +static bool r852_enable_dma = 1; module_param(r852_enable_dma, bool, S_IRUGO); MODULE_PARM_DESC(r852_enable_dma, "Enable usage of the DMA (default)"); diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 3320a50ba4f0..ad76592fb2f4 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -632,6 +632,9 @@ static int verify_mkvol_req(const struct ubi_device *ubi, if (req->alignment != 1 && n) goto bad; + if (!req->name[0] || !req->name_len) + goto bad; + if (req->name_len > UBI_VOL_NAME_MAX) { err = -ENAMETOOLONG; goto bad; diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 64fbb0021825..ead2cd16ba75 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -43,7 +43,10 @@ pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__) /* Just a debugging messages not related to any specific UBI subsystem */ -#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__) +#define dbg_msg(fmt, ...) \ + printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ + current->pid, __func__, ##__VA_ARGS__) + /* General debugging messages */ #define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__) /* Messages from the eraseblock association sub-system */ diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 9ad18da1891d..17cec0c01544 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -306,7 +306,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, int copy, void *vtbl) { int err, tries = 0; - static struct ubi_vid_hdr *vid_hdr; + struct ubi_vid_hdr *vid_hdr; struct ubi_scan_leb *new_seb; ubi_msg("create volume table (copy #%d)", copy + 1); @@ -322,7 +322,7 @@ retry: goto out_free; } - vid_hdr->vol_type = UBI_VID_DYNAMIC; + vid_hdr->vol_type = UBI_LAYOUT_VOLUME_TYPE; vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID); vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; vid_hdr->data_size = vid_hdr->used_ebs = @@ -632,7 +632,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, return -ENOMEM; vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS; - vol->alignment = 1; + vol->alignment = UBI_LAYOUT_VOLUME_ALIGN; vol->vol_type = UBI_DYNAMIC_VOLUME; vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1; memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 342626f4bc46..f820b26b9db3 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -909,16 +909,12 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) } } -/* hw is a boolean parameter that determines whether we should try and - * set the hw address of the device as well as the hw address of the - * net_device - */ -static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) +static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[]) { struct net_device *dev = slave->dev; struct sockaddr s_addr; - if (!hw) { + if (slave->bond->params.mode == BOND_MODE_TLB) { memcpy(dev->dev_addr, addr, dev->addr_len); return 0; } @@ -948,8 +944,8 @@ static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct u8 tmp_mac_addr[ETH_ALEN]; memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN); - alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled); - alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr); + alb_set_slave_mac_addr(slave2, tmp_mac_addr); } @@ -1096,8 +1092,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav /* Try setting slave mac to bond address and fall-through to code handling that situation below... */ - alb_set_slave_mac_addr(slave, bond->dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave, bond->dev->dev_addr); } /* The slave's address is equal to the address of the bond. @@ -1133,8 +1128,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } if (free_mac_slave) { - alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr); pr_warning("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n", bond->dev->name, slave->dev->name, @@ -1491,8 +1485,7 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) { int res; - res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, - bond->alb_info.rlb_enabled); + res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr); if (res) { return res; } @@ -1643,8 +1636,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave alb_swap_mac_addr(bond, swap_slave, new_slave); } else { /* set the new_slave to the bond mac address */ - alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr); } if (swap_slave) { @@ -1704,8 +1696,7 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave); } else { - alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr); read_lock(&bond->lock); alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr); diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 7fc4e81d4d43..325391d19bad 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c @@ -9,6 +9,7 @@ */ #include <linux/list.h> +#include <linux/module.h> #include <linux/netdevice.h> #include <linux/phy.h> #include <net/dsa.h> diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index c0a458fc698f..c17c75b9f531 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c @@ -9,6 +9,7 @@ */ #include <linux/list.h> +#include <linux/module.h> #include <linux/netdevice.h> #include <linux/phy.h> #include <net/dsa.h> @@ -20,12 +21,25 @@ static char *mv88e6123_61_65_probe(struct mii_bus *bus, int sw_addr) ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); if (ret >= 0) { - ret &= 0xfff0; - if (ret == 0x1210) + if (ret == 0x1212) + return "Marvell 88E6123 (A1)"; + if (ret == 0x1213) + return "Marvell 88E6123 (A2)"; + if ((ret & 0xfff0) == 0x1210) return "Marvell 88E6123"; - if (ret == 0x1610) + + if (ret == 0x1612) + return "Marvell 88E6161 (A1)"; + if (ret == 0x1613) + return "Marvell 88E6161 (A2)"; + if ((ret & 0xfff0) == 0x1610) return "Marvell 88E6161"; - if (ret == 0x1650) + + if (ret == 0x1652) + return "Marvell 88E6165 (A1)"; + if (ret == 0x1653) + return "Marvell 88e6165 (A2)"; + if ((ret & 0xfff0) == 0x1650) return "Marvell 88E6165"; } diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index e0eb68243834..55888b06d8b4 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -9,6 +9,7 @@ */ #include <linux/list.h> +#include <linux/module.h> #include <linux/netdevice.h> #include <linux/phy.h> #include <net/dsa.h> diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 5467c040824a..a2c62c2f30ee 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -9,6 +9,7 @@ */ #include <linux/list.h> +#include <linux/module.h> #include <linux/netdevice.h> #include <linux/phy.h> #include <net/dsa.h> diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 2b731b253598..03f3935fd8c2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3117,7 +3117,7 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) int rx_ring_size = 0; #ifdef BCM_CNIC - if (IS_MF_ISCSI_SD(bp)) { + if (!bp->rx_ring_size && IS_MF_ISCSI_SD(bp)) { rx_ring_size = MIN_RX_SIZE_NONTPA; bp->rx_ring_size = rx_ring_size; } else diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index f99c6e312a5d..31a8b38ab15e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1738,7 +1738,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode) struct bnx2x_fp_txdata *txdata = &fp_tx->txdata[0]; u16 tx_start_idx, tx_idx; u16 rx_start_idx, rx_idx; - u16 pkt_prod, bd_prod, rx_comp_cons; + u16 pkt_prod, bd_prod; struct sw_tx_bd *tx_buf; struct eth_tx_start_bd *tx_start_bd; struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; @@ -1873,8 +1873,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode) if (rx_idx != rx_start_idx + num_pkts) goto test_loopback_exit; - rx_comp_cons = le16_to_cpu(fp_rx->rx_comp_cons); - cqe = &fp_rx->rx_comp_ring[RCQ_BD(rx_comp_cons)]; + cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)]; cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; cqe_fp_type = cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE; if (!CQE_TYPE_FAST(cqe_fp_type) || (cqe_fp_flags & ETH_RX_ERROR_FALGS)) @@ -2121,18 +2120,16 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset) case ETH_SS_STATS: if (is_multi(bp)) { num_stats = bnx2x_num_stat_queues(bp) * - BNX2X_NUM_Q_STATS; - if (!IS_MF_MODE_STAT(bp)) - num_stats += BNX2X_NUM_STATS; - } else { - if (IS_MF_MODE_STAT(bp)) { - num_stats = 0; - for (i = 0; i < BNX2X_NUM_STATS; i++) - if (IS_FUNC_STAT(i)) - num_stats++; - } else - num_stats = BNX2X_NUM_STATS; - } + BNX2X_NUM_Q_STATS; + } else + num_stats = 0; + if (IS_MF_MODE_STAT(bp)) { + for (i = 0; i < BNX2X_NUM_STATS; i++) + if (IS_FUNC_STAT(i)) + num_stats++; + } else + num_stats += BNX2X_NUM_STATS; + return num_stats; case ETH_SS_TEST: @@ -2151,8 +2148,8 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) switch (stringset) { case ETH_SS_STATS: + k = 0; if (is_multi(bp)) { - k = 0; for_each_eth_queue(bp, i) { memset(queue_name, 0, sizeof(queue_name)); sprintf(queue_name, "%d", i); @@ -2163,20 +2160,17 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) queue_name); k += BNX2X_NUM_Q_STATS; } - if (IS_MF_MODE_STAT(bp)) - break; - for (j = 0; j < BNX2X_NUM_STATS; j++) - strcpy(buf + (k + j)*ETH_GSTRING_LEN, - bnx2x_stats_arr[j].string); - } else { - for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { - if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i)) - continue; - strcpy(buf + j*ETH_GSTRING_LEN, - bnx2x_stats_arr[i].string); - j++; - } } + + + for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { + if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i)) + continue; + strcpy(buf + (k + j)*ETH_GSTRING_LEN, + bnx2x_stats_arr[i].string); + j++; + } + break; case ETH_SS_TEST: @@ -2190,10 +2184,9 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, { struct bnx2x *bp = netdev_priv(dev); u32 *hw_stats, *offset; - int i, j, k; + int i, j, k = 0; if (is_multi(bp)) { - k = 0; for_each_eth_queue(bp, i) { hw_stats = (u32 *)&bp->fp[i].eth_q_stats; for (j = 0; j < BNX2X_NUM_Q_STATS; j++) { @@ -2214,46 +2207,28 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, } k += BNX2X_NUM_Q_STATS; } - if (IS_MF_MODE_STAT(bp)) - return; - hw_stats = (u32 *)&bp->eth_stats; - for (j = 0; j < BNX2X_NUM_STATS; j++) { - if (bnx2x_stats_arr[j].size == 0) { - /* skip this counter */ - buf[k + j] = 0; - continue; - } - offset = (hw_stats + bnx2x_stats_arr[j].offset); - if (bnx2x_stats_arr[j].size == 4) { - /* 4-byte counter */ - buf[k + j] = (u64) *offset; - continue; - } - /* 8-byte counter */ - buf[k + j] = HILO_U64(*offset, *(offset + 1)); + } + + hw_stats = (u32 *)&bp->eth_stats; + for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { + if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i)) + continue; + if (bnx2x_stats_arr[i].size == 0) { + /* skip this counter */ + buf[k + j] = 0; + j++; + continue; } - } else { - hw_stats = (u32 *)&bp->eth_stats; - for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { - if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i)) - continue; - if (bnx2x_stats_arr[i].size == 0) { - /* skip this counter */ - buf[j] = 0; - j++; - continue; - } - offset = (hw_stats + bnx2x_stats_arr[i].offset); - if (bnx2x_stats_arr[i].size == 4) { - /* 4-byte counter */ - buf[j] = (u64) *offset; - j++; - continue; - } - /* 8-byte counter */ - buf[j] = HILO_U64(*offset, *(offset + 1)); + offset = (hw_stats + bnx2x_stats_arr[i].offset); + if (bnx2x_stats_arr[i].size == 4) { + /* 4-byte counter */ + buf[k + j] = (u64) *offset; j++; + continue; } + /* 8-byte counter */ + buf[k + j] = HILO_U64(*offset, *(offset + 1)); + j++; } } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index ffeaaa95ed96..1e3f978ee6da 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -941,7 +941,7 @@ void bnx2x_panic_dump(struct bnx2x *bp) struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j]; BNX2X_ERR("fp%d: rx_bd[%x]=[%x:%x] sw_bd=[%p]\n", - i, j, rx_bd[1], rx_bd[0], sw_bd->skb); + i, j, rx_bd[1], rx_bd[0], sw_bd->data); } start = RX_SGE(fp->rx_sge_prod); @@ -10536,6 +10536,9 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, { struct bnx2x *bp; int rc; + bool chip_is_e1x = (board_type == BCM57710 || + board_type == BCM57711 || + board_type == BCM57711E); SET_NETDEV_DEV(dev, &pdev->dev); bp = netdev_priv(dev); @@ -10624,7 +10627,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0); - if (CHIP_IS_E1x(bp)) { + if (chip_is_e1x) { REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0); @@ -10635,9 +10638,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, * Enable internal target-read (in case we are probed after PF FLR). * Must be done prior to any BAR read access. Only for 57712 and up */ - if (board_type != BCM57710 && - board_type != BCM57711 && - board_type != BCM57711E) + if (!chip_is_e1x) REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1); /* Reset the load counter */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 5ac616093f9f..cb6339c35571 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -50,6 +50,7 @@ static inline void bnx2x_exe_queue_init(struct bnx2x *bp, int exe_len, union bnx2x_qable_obj *owner, exe_q_validate validate, + exe_q_remove remove, exe_q_optimize optimize, exe_q_execute exec, exe_q_get get) @@ -66,6 +67,7 @@ static inline void bnx2x_exe_queue_init(struct bnx2x *bp, /* Owner specific callbacks */ o->validate = validate; + o->remove = remove; o->optimize = optimize; o->execute = exec; o->get = get; @@ -1340,6 +1342,35 @@ static int bnx2x_validate_vlan_mac(struct bnx2x *bp, } } +static int bnx2x_remove_vlan_mac(struct bnx2x *bp, + union bnx2x_qable_obj *qo, + struct bnx2x_exeq_elem *elem) +{ + int rc = 0; + + /* If consumption wasn't required, nothing to do */ + if (test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, + &elem->cmd_data.vlan_mac.vlan_mac_flags)) + return 0; + + switch (elem->cmd_data.vlan_mac.cmd) { + case BNX2X_VLAN_MAC_ADD: + case BNX2X_VLAN_MAC_MOVE: + rc = qo->vlan_mac.put_credit(&qo->vlan_mac); + break; + case BNX2X_VLAN_MAC_DEL: + rc = qo->vlan_mac.get_credit(&qo->vlan_mac); + break; + default: + return -EINVAL; + } + + if (rc != true) + return -EINVAL; + + return 0; +} + /** * bnx2x_wait_vlan_mac - passivly wait for 5 seconds until all work completes. * @@ -1801,8 +1832,14 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp, list_for_each_entry_safe(exeq_pos, exeq_pos_n, &exeq->exe_queue, link) { if (exeq_pos->cmd_data.vlan_mac.vlan_mac_flags == - *vlan_mac_flags) + *vlan_mac_flags) { + rc = exeq->remove(bp, exeq->owner, exeq_pos); + if (rc) { + BNX2X_ERR("Failed to remove command\n"); + return rc; + } list_del(&exeq_pos->link); + } } spin_unlock_bh(&exeq->lock); @@ -1908,6 +1945,7 @@ void bnx2x_init_mac_obj(struct bnx2x *bp, bnx2x_exe_queue_init(bp, &mac_obj->exe_queue, 1, qable_obj, bnx2x_validate_vlan_mac, + bnx2x_remove_vlan_mac, bnx2x_optimize_vlan_mac, bnx2x_execute_vlan_mac, bnx2x_exeq_get_mac); @@ -1924,6 +1962,7 @@ void bnx2x_init_mac_obj(struct bnx2x *bp, bnx2x_exe_queue_init(bp, &mac_obj->exe_queue, CLASSIFY_RULES_COUNT, qable_obj, bnx2x_validate_vlan_mac, + bnx2x_remove_vlan_mac, bnx2x_optimize_vlan_mac, bnx2x_execute_vlan_mac, bnx2x_exeq_get_mac); @@ -1963,6 +2002,7 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp, bnx2x_exe_queue_init(bp, &vlan_obj->exe_queue, CLASSIFY_RULES_COUNT, qable_obj, bnx2x_validate_vlan_mac, + bnx2x_remove_vlan_mac, bnx2x_optimize_vlan_mac, bnx2x_execute_vlan_mac, bnx2x_exeq_get_vlan); @@ -2009,6 +2049,7 @@ void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, bnx2x_exe_queue_init(bp, &vlan_mac_obj->exe_queue, 1, qable_obj, bnx2x_validate_vlan_mac, + bnx2x_remove_vlan_mac, bnx2x_optimize_vlan_mac, bnx2x_execute_vlan_mac, bnx2x_exeq_get_vlan_mac); @@ -2025,6 +2066,7 @@ void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, &vlan_mac_obj->exe_queue, CLASSIFY_RULES_COUNT, qable_obj, bnx2x_validate_vlan_mac, + bnx2x_remove_vlan_mac, bnx2x_optimize_vlan_mac, bnx2x_execute_vlan_mac, bnx2x_exeq_get_vlan_mac); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index 992308ff82e8..66da39f0c84a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -161,6 +161,10 @@ typedef int (*exe_q_validate)(struct bnx2x *bp, union bnx2x_qable_obj *o, struct bnx2x_exeq_elem *elem); +typedef int (*exe_q_remove)(struct bnx2x *bp, + union bnx2x_qable_obj *o, + struct bnx2x_exeq_elem *elem); + /** * @return positive is entry was optimized, 0 - if not, negative * in case of an error. @@ -203,11 +207,18 @@ struct bnx2x_exe_queue_obj { */ exe_q_validate validate; + /** + * Called before removing pending commands, cleaning allocated + * resources (e.g., credits from validate) + */ + exe_q_remove remove; /** * This will try to cancel the current pending commands list * considering the new command. * + * Returns the number of optimized commands or a negative error code + * * Must run under exe_queue->lock */ exe_q_optimize optimize; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index d529af99157d..a1f2e0fed78b 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6667,14 +6667,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) iph = ip_hdr(skb); tcp_opt_len = tcp_optlen(skb); - if (skb_is_gso_v6(skb)) { - hdr_len = skb_headlen(skb) - ETH_HLEN; - } else { - u32 ip_tcp_len; - - ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr); - hdr_len = ip_tcp_len + tcp_opt_len; + hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb) - ETH_HLEN; + if (!skb_is_gso_v6(skb)) { iph->check = 0; iph->tot_len = htons(mss + hdr_len); } diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index fe0c29acdbe6..ee93a2087fe6 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -32,7 +32,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.1.1.28" +#define DRV_VERSION "2.1.1.31" #define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 2fd9db4b1be5..ab3f67f980d8 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -57,11 +57,13 @@ #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ +#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ /* Supported devices */ static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = { { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) }, { 0, } /* end of table */ }; @@ -132,6 +134,11 @@ int enic_sriov_enabled(struct enic *enic) return (enic->priv_flags & ENIC_SRIOV_ENABLED) ? 1 : 0; } +static int enic_is_sriov_vf(struct enic *enic) +{ + return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF; +} + int enic_is_valid_vf(struct enic *enic, int vf) { #ifdef CONFIG_PCI_IOV @@ -437,7 +444,7 @@ static void enic_mtu_check(struct enic *enic) if (mtu && mtu != enic->port_mtu) { enic->port_mtu = mtu; - if (enic_is_dynamic(enic)) { + if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) { mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, mtu)); if (mtu != netdev->mtu) @@ -849,7 +856,7 @@ static int enic_set_mac_addr(struct net_device *netdev, char *addr) { struct enic *enic = netdev_priv(netdev); - if (enic_is_dynamic(enic)) { + if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) { if (!is_valid_ether_addr(addr) && !is_zero_ether_addr(addr)) return -EADDRNOTAVAIL; } else { @@ -1608,7 +1615,7 @@ static int enic_open(struct net_device *netdev) for (i = 0; i < enic->rq_count; i++) vnic_rq_enable(&enic->rq[i]); - if (!enic_is_dynamic(enic)) + if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) enic_dev_add_station_addr(enic); enic_set_rx_mode(netdev); @@ -1659,7 +1666,7 @@ static int enic_stop(struct net_device *netdev) netif_carrier_off(netdev); netif_tx_disable(netdev); - if (!enic_is_dynamic(enic)) + if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) enic_dev_del_station_addr(enic); for (i = 0; i < enic->wq_count; i++) { @@ -1696,7 +1703,7 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu) if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU) return -EINVAL; - if (enic_is_dynamic(enic)) + if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) return -EOPNOTSUPP; if (running) @@ -2263,10 +2270,10 @@ static int __devinit enic_probe(struct pci_dev *pdev, int using_dac = 0; unsigned int i; int err; - int num_pps = 1; #ifdef CONFIG_PCI_IOV int pos = 0; #endif + int num_pps = 1; /* Allocate net device structure and initialize. Private * instance data is initialized to zero. @@ -2376,14 +2383,14 @@ static int __devinit enic_probe(struct pci_dev *pdev, num_pps = enic->num_vfs; } } - #endif + /* Allocate structure for port profiles */ enic->pp = kcalloc(num_pps, sizeof(*enic->pp), GFP_KERNEL); if (!enic->pp) { pr_err("port profile alloc failed, aborting\n"); err = -ENOMEM; - goto err_out_disable_sriov; + goto err_out_disable_sriov_pp; } /* Issue device open to get device in known state @@ -2392,7 +2399,7 @@ static int __devinit enic_probe(struct pci_dev *pdev, err = enic_dev_open(enic); if (err) { dev_err(dev, "vNIC dev open failed, aborting\n"); - goto err_out_free_pp; + goto err_out_disable_sriov; } /* Setup devcmd lock @@ -2426,7 +2433,7 @@ static int __devinit enic_probe(struct pci_dev *pdev, * called later by an upper layer. */ - if (!enic_is_dynamic(enic)) { + if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) { err = vnic_dev_init(enic->vdev, 0); if (err) { dev_err(dev, "vNIC dev init failed, aborting\n"); @@ -2460,8 +2467,7 @@ static int __devinit enic_probe(struct pci_dev *pdev, (void)enic_change_mtu(netdev, enic->port_mtu); #ifdef CONFIG_PCI_IOV - if (enic_is_dynamic(enic) && pdev->is_virtfn && - is_zero_ether_addr(enic->mac_addr)) + if (enic_is_sriov_vf(enic) && is_zero_ether_addr(enic->mac_addr)) random_ether_addr(enic->mac_addr); #endif @@ -2474,7 +2480,7 @@ static int __devinit enic_probe(struct pci_dev *pdev, enic->tx_coalesce_usecs = enic->config.intr_timer_usec; enic->rx_coalesce_usecs = enic->tx_coalesce_usecs; - if (enic_is_dynamic(enic)) + if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) netdev->netdev_ops = &enic_netdev_dynamic_ops; else netdev->netdev_ops = &enic_netdev_ops; @@ -2516,17 +2522,17 @@ err_out_dev_deinit: enic_dev_deinit(enic); err_out_dev_close: vnic_dev_close(enic->vdev); -err_out_free_pp: - kfree(enic->pp); err_out_disable_sriov: + kfree(enic->pp); +err_out_disable_sriov_pp: #ifdef CONFIG_PCI_IOV if (enic_sriov_enabled(enic)) { pci_disable_sriov(pdev); enic->priv_flags &= ~ENIC_SRIOV_ENABLED; } err_out_vnic_unregister: - vnic_dev_unregister(enic->vdev); #endif + vnic_dev_unregister(enic->vdev); err_out_iounmap: enic_iounmap(enic); err_out_release_regions: diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a6bcdb5cd2be..e703d64434f8 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1786,8 +1786,7 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) static u32 be_num_rxqs_want(struct be_adapter *adapter) { if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && - !sriov_enabled(adapter) && be_physfn(adapter) && - !be_is_mc(adapter)) { + !sriov_enabled(adapter) && be_physfn(adapter)) { return 1 + MAX_RSS_QS; /* one default non-RSS queue */ } else { dev_warn(&adapter->pdev->dev, diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index fb5579a3b19d..47f85c337cf7 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -25,6 +25,7 @@ #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> #include <linux/netdevice.h> diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index a127cb2476c7..bb336a0959c9 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -25,6 +25,7 @@ #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/mii.h> #include <linux/module.h> diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile index c6e4621b6262..6565c463185c 100644 --- a/drivers/net/ethernet/intel/igb/Makefile +++ b/drivers/net/ethernet/intel/igb/Makefile @@ -1,7 +1,7 @@ ################################################################################ # # Intel 82575 PCI-Express Ethernet Linux driver -# Copyright(c) 1999 - 2011 Intel Corporation. +# Copyright(c) 1999 - 2012 Intel Corporation. # # This program is free software; you can redistribute it and/or modify it # under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index b8e20f037d0a..08bdc33715ee 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index 08a757eb6608..b927d79ab536 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index f5fc5725ea94..aed217449f0d 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index 4519a1367170..f67cbd3fa307 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c index 73aac082c44d..f57338afd71f 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.c +++ b/drivers/net/ethernet/intel/igb/e1000_mac.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -151,7 +151,7 @@ void igb_clear_vfta_i350(struct e1000_hw *hw) * Writes value at the given offset in the register array which stores * the VLAN filter table. **/ -void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value) +static void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value) { int i; diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h index e45996b4ea34..cbddc4e51e30 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.h +++ b/drivers/net/ethernet/intel/igb/e1000_mac.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.c b/drivers/net/ethernet/intel/igb/e1000_mbx.c index 469d95eaa154..5988b8958baf 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mbx.c +++ b/drivers/net/ethernet/intel/igb/e1000_mbx.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h index eddb0f83dcea..dbcfa3d5caec 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mbx.h +++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c index 40407124e722..fa2c6ba62139 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.c +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h index a2a7ca9fa733..825b0228cac0 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.h +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2011 Intel Corporation. + Copyright(c) 2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index b17d7c20f817..789de5b83aad 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h index 8510797b9d81..4c32ac66ff39 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.h +++ b/drivers/net/ethernet/intel/igb/e1000_phy.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h index 0a860bc1198e..ccdf36d503fd 100644 --- a/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/drivers/net/ethernet/intel/igb/e1000_regs.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 3d12e67eebb4..8e33bdd33eea 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 7998bf4d5946..aa399a8a8f0d 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 01e5e89ef959..e91d73c8aa4e 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2011 Intel Corporation. + Copyright(c) 2007-2012 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -68,7 +68,7 @@ char igb_driver_name[] = "igb"; char igb_driver_version[] = DRV_VERSION; static const char igb_driver_string[] = "Intel(R) Gigabit Ethernet Network Driver"; -static const char igb_copyright[] = "Copyright (c) 2007-2011 Intel Corporation."; +static const char igb_copyright[] = "Copyright (c) 2007-2012 Intel Corporation."; static const struct e1000_info *igb_info_tbl[] = { [board_82575] = &e1000_82575_info, @@ -4003,8 +4003,8 @@ set_itr_now: } } -void igb_tx_ctxtdesc(struct igb_ring *tx_ring, u32 vlan_macip_lens, - u32 type_tucmd, u32 mss_l4len_idx) +static void igb_tx_ctxtdesc(struct igb_ring *tx_ring, u32 vlan_macip_lens, + u32 type_tucmd, u32 mss_l4len_idx) { struct e1000_adv_tx_context_desc *context_desc; u16 i = tx_ring->next_to_use; @@ -5623,7 +5623,7 @@ static irqreturn_t igb_intr(int irq, void *data) return IRQ_HANDLED; } -void igb_ring_irq_enable(struct igb_q_vector *q_vector) +static void igb_ring_irq_enable(struct igb_q_vector *q_vector) { struct igb_adapter *adapter = q_vector->adapter; struct e1000_hw *hw = &adapter->hw; diff --git a/drivers/net/ethernet/intel/igbvf/ethtool.c b/drivers/net/ethernet/intel/igbvf/ethtool.c index 7b600a1f6366..2dba53446064 100644 --- a/drivers/net/ethernet/intel/igbvf/ethtool.c +++ b/drivers/net/ethernet/intel/igbvf/ethtool.c @@ -468,6 +468,5 @@ static const struct ethtool_ops igbvf_ethtool_ops = { void igbvf_set_ethtool_ops(struct net_device *netdev) { - /* have to "undeclare" const on this struct to remove warnings */ - SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&igbvf_ethtool_ops); + SET_ETHTOOL_OPS(netdev, &igbvf_ethtool_ops); } diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index fd3da3076c2f..a4b20c865759 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -1194,11 +1194,6 @@ static int igbvf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) struct igbvf_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - igbvf_irq_disable(adapter); - - if (!test_bit(__IGBVF_DOWN, &adapter->state)) - igbvf_irq_enable(adapter); - if (hw->mac.ops.set_vfta(hw, vid, false)) { dev_err(&adapter->pdev->dev, "Failed to remove vlan id %d\n", vid); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 802bfa0f62cc..775602ef90e5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -161,19 +161,19 @@ /* Receive DMA Registers */ #define IXGBE_RDBAL(_i) (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : \ - (0x0D000 + ((_i - 64) * 0x40))) + (0x0D000 + (((_i) - 64) * 0x40))) #define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : \ - (0x0D004 + ((_i - 64) * 0x40))) + (0x0D004 + (((_i) - 64) * 0x40))) #define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : \ - (0x0D008 + ((_i - 64) * 0x40))) + (0x0D008 + (((_i) - 64) * 0x40))) #define IXGBE_RDH(_i) (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : \ - (0x0D010 + ((_i - 64) * 0x40))) + (0x0D010 + (((_i) - 64) * 0x40))) #define IXGBE_RDT(_i) (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : \ - (0x0D018 + ((_i - 64) * 0x40))) + (0x0D018 + (((_i) - 64) * 0x40))) #define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : \ - (0x0D028 + ((_i - 64) * 0x40))) + (0x0D028 + (((_i) - 64) * 0x40))) #define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \ - (0x0D02C + ((_i - 64) * 0x40))) + (0x0D02C + (((_i) - 64) * 0x40))) #define IXGBE_RSCDBU 0x03028 #define IXGBE_RDDCC 0x02F20 #define IXGBE_RXMEMWRAP 0x03190 @@ -186,7 +186,7 @@ */ #define IXGBE_SRRCTL(_i) (((_i) <= 15) ? (0x02100 + ((_i) * 4)) : \ (((_i) < 64) ? (0x01014 + ((_i) * 0x40)) : \ - (0x0D014 + ((_i - 64) * 0x40)))) + (0x0D014 + (((_i) - 64) * 0x40)))) /* * Rx DCA Control Register: * 00-15 : 0x02200 + n*4 @@ -195,7 +195,7 @@ */ #define IXGBE_DCA_RXCTRL(_i) (((_i) <= 15) ? (0x02200 + ((_i) * 4)) : \ (((_i) < 64) ? (0x0100C + ((_i) * 0x40)) : \ - (0x0D00C + ((_i - 64) * 0x40)))) + (0x0D00C + (((_i) - 64) * 0x40)))) #define IXGBE_RDRXCTL 0x02F00 #define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4)) /* 8 of these 0x03C00 - 0x03C1C */ @@ -344,9 +344,9 @@ #define IXGBE_WUPL 0x05900 #define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ -#define IXGBE_FHFT(_n) (0x09000 + (_n * 0x100)) /* Flex host filter table */ -#define IXGBE_FHFT_EXT(_n) (0x09800 + (_n * 0x100)) /* Ext Flexible Host - * Filter Table */ +#define IXGBE_FHFT(_n) (0x09000 + ((_n) * 0x100)) /* Flex host filter table */ +#define IXGBE_FHFT_EXT(_n) (0x09800 + ((_n) * 0x100)) /* Ext Flexible Host + * Filter Table */ #define IXGBE_FLEXIBLE_FILTER_COUNT_MAX 4 #define IXGBE_EXT_FLEXIBLE_FILTER_COUNT_MAX 2 @@ -1485,7 +1485,7 @@ enum { #define IXGBE_LED_BLINK_BASE 0x00000080 #define IXGBE_LED_MODE_MASK_BASE 0x0000000F #define IXGBE_LED_OFFSET(_base, _i) (_base << (8 * (_i))) -#define IXGBE_LED_MODE_SHIFT(_i) (8*(_i)) +#define IXGBE_LED_MODE_SHIFT(_i) (8 * (_i)) #define IXGBE_LED_IVRT(_i) IXGBE_LED_OFFSET(IXGBE_LED_IVRT_BASE, _i) #define IXGBE_LED_BLINK(_i) IXGBE_LED_OFFSET(IXGBE_LED_BLINK_BASE, _i) #define IXGBE_LED_MODE_MASK(_i) IXGBE_LED_OFFSET(IXGBE_LED_MODE_MASK_BASE, _i) @@ -2068,9 +2068,9 @@ enum { /* SR-IOV specific macros */ #define IXGBE_MBVFICR_INDEX(vf_number) (vf_number >> 4) -#define IXGBE_MBVFICR(_i) (0x00710 + (_i * 4)) -#define IXGBE_VFLRE(_i) (((_i & 1) ? 0x001C0 : 0x00600)) -#define IXGBE_VFLREC(_i) (0x00700 + (_i * 4)) +#define IXGBE_MBVFICR(_i) (0x00710 + ((_i) * 4)) +#define IXGBE_VFLRE(_i) ((((_i) & 1) ? 0x001C0 : 0x00600)) +#define IXGBE_VFLREC(_i) (0x00700 + ((_i) * 4)) enum ixgbe_fdir_pballoc_type { IXGBE_FDIR_PBALLOC_NONE = 0, diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index dc8e6511c640..c85700318147 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -56,7 +56,8 @@ struct ixgbe_stats { offsetof(struct ixgbevf_adapter, m), \ offsetof(struct ixgbevf_adapter, b), \ offsetof(struct ixgbevf_adapter, r) -static struct ixgbe_stats ixgbe_gstrings_stats[] = { + +static const struct ixgbe_stats ixgbe_gstrings_stats[] = { {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc, stats.saved_reset_vfgprc)}, {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc, @@ -671,7 +672,7 @@ static int ixgbevf_nway_reset(struct net_device *netdev) return 0; } -static struct ethtool_ops ixgbevf_ethtool_ops = { +static const struct ethtool_ops ixgbevf_ethtool_ops = { .get_settings = ixgbevf_get_settings, .get_drvinfo = ixgbevf_get_drvinfo, .get_regs_len = ixgbevf_get_regs_len, diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index e6c9d1a927a9..9075c1d61039 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -279,12 +279,12 @@ enum ixgbevf_boards { board_X540_vf, }; -extern struct ixgbevf_info ixgbevf_82599_vf_info; -extern struct ixgbevf_info ixgbevf_X540_vf_info; -extern struct ixgbe_mbx_operations ixgbevf_mbx_ops; +extern const struct ixgbevf_info ixgbevf_82599_vf_info; +extern const struct ixgbevf_info ixgbevf_X540_vf_info; +extern const struct ixgbe_mbx_operations ixgbevf_mbx_ops; /* needed by ethtool.c */ -extern char ixgbevf_driver_name[]; +extern const char ixgbevf_driver_name[]; extern const char ixgbevf_driver_version[]; extern int ixgbevf_up(struct ixgbevf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 891162d1610c..bed411bada21 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -53,7 +53,7 @@ #include "ixgbevf.h" -char ixgbevf_driver_name[] = "ixgbevf"; +const char ixgbevf_driver_name[] = "ixgbevf"; static const char ixgbevf_driver_string[] = "Intel(R) 10 Gigabit PCI Express Virtual Function Network Driver"; @@ -917,31 +917,34 @@ static irqreturn_t ixgbevf_msix_mbx(int irq, void *data) struct ixgbe_hw *hw = &adapter->hw; u32 eicr; u32 msg; + bool got_ack = false; eicr = IXGBE_READ_REG(hw, IXGBE_VTEICS); IXGBE_WRITE_REG(hw, IXGBE_VTEICR, eicr); - if (!hw->mbx.ops.check_for_ack(hw)) { - /* - * checking for the ack clears the PFACK bit. Place - * it back in the v2p_mailbox cache so that anyone - * polling for an ack will not miss it. Also - * avoid the read below because the code to read - * the mailbox will also clear the ack bit. This was - * causing lost acks. Just cache the bit and exit - * the IRQ handler. - */ - hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFACK; - goto out; - } + if (!hw->mbx.ops.check_for_ack(hw)) + got_ack = true; - /* Not an ack interrupt, go ahead and read the message */ - hw->mbx.ops.read(hw, &msg, 1); + if (!hw->mbx.ops.check_for_msg(hw)) { + hw->mbx.ops.read(hw, &msg, 1); - if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) - mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + 1)); + if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 1)); + if (msg & IXGBE_VT_MSGTYPE_NACK) + pr_warn("Last Request of type %2.2x to PF Nacked\n", + msg & 0xFF); + goto out; + } + + /* + * checking for the ack clears the PFACK bit. Place + * it back in the v2p_mailbox cache so that anyone + * polling for an ack will not miss it + */ + if (got_ack) + hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFACK; out: return IRQ_HANDLED; } diff --git a/drivers/net/ethernet/intel/ixgbevf/mbx.c b/drivers/net/ethernet/intel/ixgbevf/mbx.c index 930fa83f2568..13532d9ba72d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/mbx.c +++ b/drivers/net/ethernet/intel/ixgbevf/mbx.c @@ -26,6 +26,7 @@ *******************************************************************************/ #include "mbx.h" +#include "ixgbevf.h" /** * ixgbevf_poll_for_msg - Wait for message notification @@ -328,7 +329,7 @@ static s32 ixgbevf_init_mbx_params_vf(struct ixgbe_hw *hw) return 0; } -struct ixgbe_mbx_operations ixgbevf_mbx_ops = { +const struct ixgbe_mbx_operations ixgbevf_mbx_ops = { .init_params = ixgbevf_init_mbx_params_vf, .read = ixgbevf_read_mbx_vf, .write = ixgbevf_write_mbx_vf, diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c index 21533e300367..d0138d7a31a1 100644 --- a/drivers/net/ethernet/intel/ixgbevf/vf.c +++ b/drivers/net/ethernet/intel/ixgbevf/vf.c @@ -26,6 +26,7 @@ *******************************************************************************/ #include "vf.h" +#include "ixgbevf.h" /** * ixgbevf_start_hw_vf - Prepare hardware for Tx/Rx @@ -401,7 +402,7 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw, return 0; } -static struct ixgbe_mac_operations ixgbevf_mac_ops = { +static const struct ixgbe_mac_operations ixgbevf_mac_ops = { .init_hw = ixgbevf_init_hw_vf, .reset_hw = ixgbevf_reset_hw_vf, .start_hw = ixgbevf_start_hw_vf, @@ -415,12 +416,12 @@ static struct ixgbe_mac_operations ixgbevf_mac_ops = { .set_vfta = ixgbevf_set_vfta_vf, }; -struct ixgbevf_info ixgbevf_82599_vf_info = { +const struct ixgbevf_info ixgbevf_82599_vf_info = { .mac = ixgbe_mac_82599_vf, .mac_ops = &ixgbevf_mac_ops, }; -struct ixgbevf_info ixgbevf_X540_vf_info = { +const struct ixgbevf_info ixgbevf_X540_vf_info = { .mac = ixgbe_mac_X540_vf, .mac_ops = &ixgbevf_mac_ops, }; diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.h b/drivers/net/ethernet/intel/ixgbevf/vf.h index 10306b492ee6..d556619a9212 100644 --- a/drivers/net/ethernet/intel/ixgbevf/vf.h +++ b/drivers/net/ethernet/intel/ixgbevf/vf.h @@ -167,7 +167,7 @@ struct ixgbevf_hw_stats { struct ixgbevf_info { enum ixgbe_mac_type mac; - struct ixgbe_mac_operations *mac_ops; + const struct ixgbe_mac_operations *mac_ops; }; #endif /* __IXGBE_VF_H__ */ diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 9c049d2cb97d..9edecfa1f0f4 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -136,6 +136,8 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define INT_MASK 0x0068 #define INT_MASK_EXT 0x006c #define TX_FIFO_URGENT_THRESHOLD 0x0074 +#define RX_DISCARD_FRAME_CNT 0x0084 +#define RX_OVERRUN_FRAME_CNT 0x0088 #define TXQ_FIX_PRIO_CONF_MOVED 0x00dc #define TX_BW_RATE_MOVED 0x00e0 #define TX_BW_MTU_MOVED 0x00e8 @@ -334,6 +336,9 @@ struct mib_counters { u32 bad_crc_event; u32 collision; u32 late_collision; + /* Non MIB hardware counters */ + u32 rx_discard; + u32 rx_overrun; }; struct lro_counters { @@ -1225,6 +1230,10 @@ static void mib_counters_clear(struct mv643xx_eth_private *mp) for (i = 0; i < 0x80; i += 4) mib_read(mp, i); + + /* Clear non MIB hw counters also */ + rdlp(mp, RX_DISCARD_FRAME_CNT); + rdlp(mp, RX_OVERRUN_FRAME_CNT); } static void mib_counters_update(struct mv643xx_eth_private *mp) @@ -1262,6 +1271,9 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) p->bad_crc_event += mib_read(mp, 0x74); p->collision += mib_read(mp, 0x78); p->late_collision += mib_read(mp, 0x7c); + /* Non MIB hardware counters */ + p->rx_discard += rdlp(mp, RX_DISCARD_FRAME_CNT); + p->rx_overrun += rdlp(mp, RX_OVERRUN_FRAME_CNT); spin_unlock_bh(&mp->mib_counters_lock); mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ); @@ -1413,6 +1425,8 @@ static const struct mv643xx_eth_stats mv643xx_eth_stats[] = { MIBSTAT(bad_crc_event), MIBSTAT(collision), MIBSTAT(late_collision), + MIBSTAT(rx_discard), + MIBSTAT(rx_overrun), LROSTAT(lro_aggregated), LROSTAT(lro_flushed), LROSTAT(lro_no_desc), diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index 18a87a57fc0a..edb9bda55d55 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -931,17 +931,20 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base) } /* Allocate and setup a new buffer for receiving */ -static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, - struct sk_buff *skb, unsigned int bufsize) +static int skge_rx_setup(struct pci_dev *pdev, + struct skge_element *e, + struct sk_buff *skb, unsigned int bufsize) { struct skge_rx_desc *rd = e->desc; - u64 map; + dma_addr_t map; - map = pci_map_single(skge->hw->pdev, skb->data, bufsize, + map = pci_map_single(pdev, skb->data, bufsize, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(pdev, map)) + goto mapping_error; - rd->dma_lo = map; - rd->dma_hi = map >> 32; + rd->dma_lo = lower_32_bits(map); + rd->dma_hi = upper_32_bits(map); e->skb = skb; rd->csum1_start = ETH_HLEN; rd->csum2_start = ETH_HLEN; @@ -953,6 +956,13 @@ static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize; dma_unmap_addr_set(e, mapaddr, map); dma_unmap_len_set(e, maplen, bufsize); + return 0; + +mapping_error: + if (net_ratelimit()) + dev_warn(&pdev->dev, "%s: rx mapping error\n", + skb->dev->name); + return -EIO; } /* Resume receiving using existing skb, @@ -1014,7 +1024,11 @@ static int skge_rx_fill(struct net_device *dev) return -ENOMEM; skb_reserve(skb, NET_IP_ALIGN); - skge_rx_setup(skge, e, skb, skge->rx_buf_size); + if (skge_rx_setup(skge->hw->pdev, e, skb, skge->rx_buf_size)) { + kfree_skb(skb); + return -ENOMEM; + } + } while ((e = e->next) != ring->start); ring->to_clean = ring->start; @@ -2576,6 +2590,7 @@ static int skge_up(struct net_device *dev) } /* Initialize MAC */ + netif_carrier_off(dev); spin_lock_bh(&hw->phy_lock); if (is_genesis(hw)) genesis_mac_init(hw, port); @@ -2728,7 +2743,7 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, struct skge_tx_desc *td; int i; u32 control, len; - u64 map; + dma_addr_t map; if (skb_padto(skb, ETH_ZLEN)) return NETDEV_TX_OK; @@ -2742,11 +2757,14 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, e->skb = skb; len = skb_headlen(skb); map = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(hw->pdev, map)) + goto mapping_error; + dma_unmap_addr_set(e, mapaddr, map); dma_unmap_len_set(e, maplen, len); - td->dma_lo = map; - td->dma_hi = map >> 32; + td->dma_lo = lower_32_bits(map); + td->dma_hi = upper_32_bits(map); if (skb->ip_summed == CHECKSUM_PARTIAL) { const int offset = skb_checksum_start_offset(skb); @@ -2777,14 +2795,16 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, map = skb_frag_dma_map(&hw->pdev->dev, frag, 0, skb_frag_size(frag), DMA_TO_DEVICE); + if (dma_mapping_error(&hw->pdev->dev, map)) + goto mapping_unwind; e = e->next; e->skb = skb; tf = e->desc; BUG_ON(tf->control & BMU_OWN); - tf->dma_lo = map; - tf->dma_hi = (u64) map >> 32; + tf->dma_lo = lower_32_bits(map); + tf->dma_hi = upper_32_bits(map); dma_unmap_addr_set(e, mapaddr, map); dma_unmap_len_set(e, maplen, skb_frag_size(frag)); @@ -2797,6 +2817,8 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, td->control = BMU_OWN | BMU_SW | BMU_STF | control | len; wmb(); + netdev_sent_queue(dev, skb->len); + skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_START); netif_printk(skge, tx_queued, KERN_DEBUG, skge->netdev, @@ -2812,15 +2834,35 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, } return NETDEV_TX_OK; + +mapping_unwind: + /* unroll any pages that were already mapped. */ + if (e != skge->tx_ring.to_use) { + struct skge_element *u; + + for (u = skge->tx_ring.to_use->next; u != e; u = u->next) + pci_unmap_page(hw->pdev, dma_unmap_addr(u, mapaddr), + dma_unmap_len(u, maplen), + PCI_DMA_TODEVICE); + e = skge->tx_ring.to_use; + } + /* undo the mapping for the skb header */ + pci_unmap_single(hw->pdev, dma_unmap_addr(e, mapaddr), + dma_unmap_len(e, maplen), + PCI_DMA_TODEVICE); +mapping_error: + /* mapping error causes error message and packet to be discarded. */ + if (net_ratelimit()) + dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name); + dev_kfree_skb(skb); + return NETDEV_TX_OK; } /* Free resources associated with this reing element */ -static void skge_tx_free(struct skge_port *skge, struct skge_element *e, - u32 control) +static inline void skge_tx_unmap(struct pci_dev *pdev, struct skge_element *e, + u32 control) { - struct pci_dev *pdev = skge->hw->pdev; - /* skb header vs. fragment */ if (control & BMU_STF) pci_unmap_single(pdev, dma_unmap_addr(e, mapaddr), @@ -2830,13 +2872,6 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e, pci_unmap_page(pdev, dma_unmap_addr(e, mapaddr), dma_unmap_len(e, maplen), PCI_DMA_TODEVICE); - - if (control & BMU_EOF) { - netif_printk(skge, tx_done, KERN_DEBUG, skge->netdev, - "tx done slot %td\n", e - skge->tx_ring.start); - - dev_kfree_skb(e->skb); - } } /* Free all buffers in transmit ring */ @@ -2847,10 +2882,15 @@ static void skge_tx_clean(struct net_device *dev) for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) { struct skge_tx_desc *td = e->desc; - skge_tx_free(skge, e, td->control); + + skge_tx_unmap(skge->hw->pdev, e, td->control); + + if (td->control & BMU_EOF) + dev_kfree_skb(e->skb); td->control = 0; } + netdev_reset_queue(dev); skge->tx_ring.to_clean = e; } @@ -3059,13 +3099,17 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, if (!nskb) goto resubmit; + if (unlikely(skge_rx_setup(skge->hw->pdev, e, nskb, skge->rx_buf_size))) { + dev_kfree_skb(nskb); + goto resubmit; + } + pci_unmap_single(skge->hw->pdev, dma_unmap_addr(e, mapaddr), dma_unmap_len(e, maplen), PCI_DMA_FROMDEVICE); skb = e->skb; prefetch(skb->data); - skge_rx_setup(skge, e, nskb, skge->rx_buf_size); } skb_put(skb, len); @@ -3111,6 +3155,7 @@ static void skge_tx_done(struct net_device *dev) struct skge_port *skge = netdev_priv(dev); struct skge_ring *ring = &skge->tx_ring; struct skge_element *e; + unsigned int bytes_compl = 0, pkts_compl = 0; skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); @@ -3120,8 +3165,20 @@ static void skge_tx_done(struct net_device *dev) if (control & BMU_OWN) break; - skge_tx_free(skge, e, control); + skge_tx_unmap(skge->hw->pdev, e, control); + + if (control & BMU_EOF) { + netif_printk(skge, tx_done, KERN_DEBUG, skge->netdev, + "tx done slot %td\n", + e - skge->tx_ring.start); + + pkts_compl++; + bytes_compl += e->skb->len; + + dev_kfree_skb(e->skb); + } } + netdev_completed_queue(dev, pkts_compl, bytes_compl); skge->tx_ring.to_clean = e; /* Can run lockless until we need to synchronize to restart queue. */ diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 978f593094c0..405e6ac3faf6 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1247,6 +1247,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, u32 reply; u32 slave_status = 0; u8 is_going_down = 0; + int i; slave_state[slave].comm_toggle ^= 1; reply = (u32) slave_state[slave].comm_toggle << 31; @@ -1258,6 +1259,10 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, if (cmd == MLX4_COMM_CMD_RESET) { mlx4_warn(dev, "Received reset from slave:%d\n", slave); slave_state[slave].active = false; + for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) { + slave_state[slave].event_eq[i].eqn = -1; + slave_state[slave].event_eq[i].token = 0; + } /*check if we are in the middle of FLR process, if so return "retry" status to the slave*/ if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) { @@ -1452,7 +1457,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_slave_state *s_state; - int i, err, port; + int i, j, err, port; priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, &priv->mfunc.vhcr_dma, @@ -1485,6 +1490,8 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) for (i = 0; i < dev->num_slaves; ++i) { s_state = &priv->mfunc.master.slave_state[i]; s_state->last_cmd = MLX4_COMM_CMD_RESET; + for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j) + s_state->event_eq[j].eqn = -1; __raw_writel((__force u32) 0, &priv->mfunc.comm[i].slave_write); __raw_writel((__force u32) 0, diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index 475f9d6af955..7e64033d7de3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -96,7 +96,7 @@ void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type) static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, int cq_num) { - return mlx4_cmd(dev, mailbox->dma | dev->caps.function, cq_num, 0, + return mlx4_cmd(dev, mailbox->dma, cq_num, 0, MLX4_CMD_SW2HW_CQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } @@ -111,7 +111,7 @@ static int mlx4_MODIFY_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, int cq_num) { - return mlx4_cmd_box(dev, dev->caps.function, mailbox ? mailbox->dma : 0, + return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, cq_num, mailbox ? 0 : 1, MLX4_CMD_HW2SW_CQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 7dbc6a230779..70346fd7f9c4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -183,10 +183,11 @@ static int mlx4_en_set_wol(struct net_device *netdev, static int mlx4_en_get_sset_count(struct net_device *dev, int sset) { struct mlx4_en_priv *priv = netdev_priv(dev); + int bit_count = hweight64(priv->stats_bitmap); switch (sset) { case ETH_SS_STATS: - return NUM_ALL_STATS + + return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) + (priv->tx_ring_num + priv->rx_ring_num) * 2; case ETH_SS_TEST: return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.flags @@ -201,14 +202,34 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); int index = 0; - int i; + int i, j = 0; spin_lock_bh(&priv->stats_lock); - for (i = 0; i < NUM_MAIN_STATS; i++) - data[index++] = ((unsigned long *) &priv->stats)[i]; - for (i = 0; i < NUM_PORT_STATS; i++) - data[index++] = ((unsigned long *) &priv->port_stats)[i]; + if (!(priv->stats_bitmap)) { + for (i = 0; i < NUM_MAIN_STATS; i++) + data[index++] = + ((unsigned long *) &priv->stats)[i]; + for (i = 0; i < NUM_PORT_STATS; i++) + data[index++] = + ((unsigned long *) &priv->port_stats)[i]; + for (i = 0; i < NUM_PKT_STATS; i++) + data[index++] = + ((unsigned long *) &priv->pkstats)[i]; + } else { + for (i = 0; i < NUM_MAIN_STATS; i++) { + if ((priv->stats_bitmap >> j) & 1) + data[index++] = + ((unsigned long *) &priv->stats)[i]; + j++; + } + for (i = 0; i < NUM_PORT_STATS; i++) { + if ((priv->stats_bitmap >> j) & 1) + data[index++] = + ((unsigned long *) &priv->port_stats)[i]; + j++; + } + } for (i = 0; i < priv->tx_ring_num; i++) { data[index++] = priv->tx_ring[i].packets; data[index++] = priv->tx_ring[i].bytes; @@ -217,8 +238,6 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev, data[index++] = priv->rx_ring[i].packets; data[index++] = priv->rx_ring[i].bytes; } - for (i = 0; i < NUM_PKT_STATS; i++) - data[index++] = ((unsigned long *) &priv->pkstats)[i]; spin_unlock_bh(&priv->stats_lock); } @@ -247,11 +266,29 @@ static void mlx4_en_get_strings(struct net_device *dev, case ETH_SS_STATS: /* Add main counters */ - for (i = 0; i < NUM_MAIN_STATS; i++) - strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]); - for (i = 0; i< NUM_PORT_STATS; i++) - strcpy(data + (index++) * ETH_GSTRING_LEN, - main_strings[i + NUM_MAIN_STATS]); + if (!priv->stats_bitmap) { + for (i = 0; i < NUM_MAIN_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, + main_strings[i]); + for (i = 0; i < NUM_PORT_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, + main_strings[i + + NUM_MAIN_STATS]); + for (i = 0; i < NUM_PKT_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, + main_strings[i + + NUM_MAIN_STATS + + NUM_PORT_STATS]); + } else + for (i = 0; i < NUM_MAIN_STATS + NUM_PORT_STATS; i++) { + if ((priv->stats_bitmap >> i) & 1) { + strcpy(data + + (index++) * ETH_GSTRING_LEN, + main_strings[i]); + } + if (!(priv->stats_bitmap >> i)) + break; + } for (i = 0; i < priv->tx_ring_num; i++) { sprintf(data + (index++) * ETH_GSTRING_LEN, "tx%d_packets", i); @@ -264,9 +301,6 @@ static void mlx4_en_get_strings(struct net_device *dev, sprintf(data + (index++) * ETH_GSTRING_LEN, "rx%d_bytes", i); } - for (i = 0; i< NUM_PKT_STATS; i++) - strcpy(data + (index++) * ETH_GSTRING_LEN, - main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]); break; } } @@ -479,6 +513,95 @@ static void mlx4_en_get_ringparam(struct net_device *dev, param->tx_pending = priv->tx_ring[0].size; } +static u32 mlx4_en_get_rxfh_indir_size(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + return priv->rx_ring_num; +} + +static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_rss_map *rss_map = &priv->rss_map; + int rss_rings; + size_t n = priv->rx_ring_num; + int err = 0; + + rss_rings = priv->prof->rss_rings ?: priv->rx_ring_num; + + while (n--) { + ring_index[n] = rss_map->qps[n % rss_rings].qpn - + rss_map->base_qpn; + } + + return err; +} + +static int mlx4_en_set_rxfh_indir(struct net_device *dev, + const u32 *ring_index) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int port_up = 0; + int err = 0; + int i; + int rss_rings = 0; + + /* Calculate RSS table size and make sure flows are spread evenly + * between rings + */ + for (i = 0; i < priv->rx_ring_num; i++) { + if (i > 0 && !ring_index[i] && !rss_rings) + rss_rings = i; + + if (ring_index[i] != (i % (rss_rings ?: priv->rx_ring_num))) + return -EINVAL; + } + + if (!rss_rings) + rss_rings = priv->rx_ring_num; + + /* RSS table size must be an order of 2 */ + if (!is_power_of_2(rss_rings)) + return -EINVAL; + + mutex_lock(&mdev->state_lock); + if (priv->port_up) { + port_up = 1; + mlx4_en_stop_port(dev); + } + + priv->prof->rss_rings = rss_rings; + + if (port_up) { + err = mlx4_en_start_port(dev); + if (err) + en_err(priv, "Failed starting port\n"); + } + + mutex_unlock(&mdev->state_lock); + return err; +} + +static int mlx4_en_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, + u32 *rule_locs) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int err = 0; + + switch (cmd->cmd) { + case ETHTOOL_GRXRINGS: + cmd->data = priv->rx_ring_num; + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + const struct ethtool_ops mlx4_en_ethtool_ops = { .get_drvinfo = mlx4_en_get_drvinfo, .get_settings = mlx4_en_get_settings, @@ -498,6 +621,10 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .set_pauseparam = mlx4_en_set_pauseparam, .get_ringparam = mlx4_en_get_ringparam, .set_ringparam = mlx4_en_set_ringparam, + .get_rxnfc = mlx4_en_get_rxnfc, + .get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, + .get_rxfh_indir = mlx4_en_get_rxfh_indir, + .set_rxfh_indir = mlx4_en_set_rxfh_indir, }; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index a06096fcc0b8..2097a7d3c5b8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -62,10 +62,6 @@ static const char mlx4_en_version[] = * Device scope module parameters */ - -/* Enable RSS TCP traffic */ -MLX4_EN_PARM_INT(tcp_rss, 1, - "Enable RSS for incomming TCP traffic or disabled (0)"); /* Enable RSS UDP traffic */ MLX4_EN_PARM_INT(udp_rss, 1, "Enable RSS for incomming UDP traffic or disabled (0)"); @@ -104,7 +100,6 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) struct mlx4_en_profile *params = &mdev->profile; int i; - params->tcp_rss = tcp_rss; params->udp_rss = udp_rss; if (params->udp_rss && !(mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UDP_RSS)) { @@ -120,6 +115,7 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; params->prof[i].tx_ring_num = MLX4_EN_NUM_TX_RINGS + (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS; + params->prof[i].rss_rings = 0; } return 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 72fa807b69ce..467ae5824875 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -702,6 +702,8 @@ int mlx4_en_start_port(struct net_device *dev) /* Schedule multicast task to populate multicast list */ queue_work(mdev->workqueue, &priv->mcast_task); + mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap); + priv->port_up = true; netif_tx_start_all_queues(dev); return 0; @@ -807,38 +809,50 @@ static void mlx4_en_restart(struct work_struct *work) mutex_unlock(&mdev->state_lock); } - -static int mlx4_en_open(struct net_device *dev) +static void mlx4_en_clear_stats(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; int i; - int err = 0; - - mutex_lock(&mdev->state_lock); - - if (!mdev->device_up) { - en_err(priv, "Cannot open - device down/disabled\n"); - err = -EBUSY; - goto out; - } - /* Reset HW statistics and performance counters */ if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) en_dbg(HW, priv, "Failed dumping statistics\n"); memset(&priv->stats, 0, sizeof(priv->stats)); memset(&priv->pstats, 0, sizeof(priv->pstats)); + memset(&priv->pkstats, 0, sizeof(priv->pkstats)); + memset(&priv->port_stats, 0, sizeof(priv->port_stats)); for (i = 0; i < priv->tx_ring_num; i++) { priv->tx_ring[i].bytes = 0; priv->tx_ring[i].packets = 0; + priv->tx_ring[i].tx_csum = 0; } for (i = 0; i < priv->rx_ring_num; i++) { priv->rx_ring[i].bytes = 0; priv->rx_ring[i].packets = 0; + priv->rx_ring[i].csum_ok = 0; + priv->rx_ring[i].csum_none = 0; + } +} + +static int mlx4_en_open(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int err = 0; + + mutex_lock(&mdev->state_lock); + + if (!mdev->device_up) { + en_err(priv, "Cannot open - device down/disabled\n"); + err = -EBUSY; + goto out; } + /* Reset HW statistics and SW counters */ + mlx4_en_clear_stats(dev); + err = mlx4_en_start_port(dev); if (err) en_err(priv, "Failed starting port:%d\n", priv->port); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index e8d6ad2dce0a..971d4b6b8dfe 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -853,6 +853,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) struct mlx4_en_rss_map *rss_map = &priv->rss_map; struct mlx4_qp_context context; struct mlx4_rss_context *rss_context; + int rss_rings; void *ptr; u8 rss_mask = (MLX4_RSS_IPV4 | MLX4_RSS_TCP_IPV4 | MLX4_RSS_IPV6 | MLX4_RSS_TCP_IPV6); @@ -893,10 +894,15 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, priv->rx_ring[0].cqn, &context); + if (!priv->prof->rss_rings || priv->prof->rss_rings > priv->rx_ring_num) + rss_rings = priv->rx_ring_num; + else + rss_rings = priv->prof->rss_rings; + ptr = ((void *) &context) + offsetof(struct mlx4_qp_context, pri_path) + MLX4_RSS_OFFSET_IN_QPC_PRI_PATH; rss_context = ptr; - rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 | + rss_context->base_qpn = cpu_to_be32(ilog2(rss_rings) << 24 | (rss_map->base_qpn)); rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); if (priv->mdev->profile.udp_rss) { diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 1e9b55eb7217..55d7bd4e210a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -513,25 +513,22 @@ int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave, { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_slave_event_eq_info *event_eq = - &priv->mfunc.master.slave_state[slave].event_eq; + priv->mfunc.master.slave_state[slave].event_eq; u32 in_modifier = vhcr->in_modifier; u32 eqn = in_modifier & 0x1FF; u64 in_param = vhcr->in_param; int err = 0; + int i; if (slave == dev->caps.function) err = mlx4_cmd(dev, in_param, (in_modifier & 0x80000000) | eqn, 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - if (!err) { - if (in_modifier >> 31) { - /* unmap */ - event_eq->event_type &= ~in_param; - } else { - event_eq->eqn = eqn; - event_eq->event_type = in_param; - } - } + if (!err) + for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) + if (in_param & (1LL << i)) + event_eq[i].eqn = in_modifier >> 31 ? -1 : eqn; + return err; } @@ -546,7 +543,7 @@ static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, int eq_num) { - return mlx4_cmd(dev, mailbox->dma | dev->caps.function, eq_num, 0, + return mlx4_cmd(dev, mailbox->dma, eq_num, 0, MLX4_CMD_SW2HW_EQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } @@ -554,7 +551,7 @@ static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, int eq_num) { - return mlx4_cmd_box(dev, dev->caps.function, mailbox->dma, eq_num, + return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, 0, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index a424a19280cc..8a21e10952ea 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -158,7 +158,6 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, #define QUERY_FUNC_CAP_FLAGS_OFFSET 0x0 #define QUERY_FUNC_CAP_NUM_PORTS_OFFSET 0x1 -#define QUERY_FUNC_CAP_FUNCTION_OFFSET 0x3 #define QUERY_FUNC_CAP_PF_BHVR_OFFSET 0x4 #define QUERY_FUNC_CAP_QP_QUOTA_OFFSET 0x10 #define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET 0x14 @@ -182,9 +181,6 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, field = 1 << 7; /* enable only ethernet interface */ MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET); - field = slave; - MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FUNCTION_OFFSET); - field = dev->caps.num_ports; MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET); @@ -249,9 +245,6 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, struct mlx4_func_cap *func_cap) goto out; } - MLX4_GET(field, outbox, QUERY_FUNC_CAP_FUNCTION_OFFSET); - func_cap->function = field; - MLX4_GET(field, outbox, QUERY_FUNC_CAP_NUM_PORTS_OFFSET); func_cap->num_ports = field; diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index 119e0cc9fab3..e1a5fa56bcbc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -119,7 +119,6 @@ struct mlx4_dev_cap { }; struct mlx4_func_cap { - u8 function; u8 num_ports; u8 flags; u32 pf_context_behaviour; diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 6bb62c580e2d..678558b502fc 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -108,7 +108,7 @@ static struct mlx4_profile default_profile = { .num_cq = 1 << 16, .num_mcg = 1 << 13, .num_mpt = 1 << 19, - .num_mtt = 1 << 20, + .num_mtt = 1 << 20, /* It is really num mtt segements */ }; static int log_num_mac = 7; @@ -471,7 +471,6 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) return -ENOSYS; } - dev->caps.function = func_cap.function; dev->caps.num_ports = func_cap.num_ports; dev->caps.num_qps = func_cap.qp_quota; dev->caps.num_srqs = func_cap.srq_quota; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index a80121a2b519..c92269f8c057 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -388,9 +388,8 @@ struct mlx4_slave_eqe { }; struct mlx4_slave_event_eq_info { - u32 eqn; + int eqn; u16 token; - u64 event_type; }; struct mlx4_profile { @@ -449,6 +448,8 @@ struct mlx4_steer_index { struct list_head duplicates; }; +#define MLX4_EVENT_TYPES_NUM 64 + struct mlx4_slave_state { u8 comm_toggle; u8 last_cmd; @@ -461,7 +462,8 @@ struct mlx4_slave_state { struct mlx4_slave_eqe eq[MLX4_MFUNC_MAX_EQES]; struct list_head mcast_filters[MLX4_MAX_PORTS + 1]; struct mlx4_vlan_fltr *vlan_filter[MLX4_MAX_PORTS + 1]; - struct mlx4_slave_event_eq_info event_eq; + /* event type to eq number lookup */ + struct mlx4_slave_event_eq_info event_eq[MLX4_EVENT_TYPES_NUM]; u16 eq_pi; u16 eq_ci; spinlock_t lock; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index f2a8e65f5f88..35f08840813c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -325,11 +325,11 @@ struct mlx4_en_port_profile { u8 rx_ppp; u8 tx_pause; u8 tx_ppp; + int rss_rings; }; struct mlx4_en_profile { int rss_xor; - int tcp_rss; int udp_rss; u8 rss_mask; u32 active_ports; @@ -476,6 +476,7 @@ struct mlx4_en_priv { struct mlx4_en_perf_stats pstats; struct mlx4_en_pkt_stats pkstats; struct mlx4_en_port_stats port_stats; + u64 stats_bitmap; char *mc_addrs; int mc_addrs_cnt; struct mlx4_en_stat_out_mbox hw_stats; diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index 01df5567e16e..8deeef98280c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -291,7 +291,7 @@ static u32 key_to_hw_index(u32 key) static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, int mpt_index) { - return mlx4_cmd(dev, mailbox->dma | dev->caps.function , mpt_index, + return mlx4_cmd(dev, mailbox->dma, mpt_index, 0, MLX4_CMD_SW2HW_MPT, MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); } diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c index 5c9a54df17ab..db4746d0dca7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/pd.c +++ b/drivers/net/ethernet/mellanox/mlx4/pd.c @@ -52,8 +52,7 @@ int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) *pdn = mlx4_bitmap_alloc(&priv->pd_bitmap); if (*pdn == -1) return -ENOMEM; - if (mlx4_is_mfunc(dev)) - *pdn |= (dev->caps.function + 1) << NOT_MASKED_PD_BITS; + return 0; } EXPORT_SYMBOL_GPL(mlx4_pd_alloc); diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 88b52e547524..f44ae555bf43 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -44,6 +44,11 @@ #define MLX4_VLAN_VALID (1u << 31) #define MLX4_VLAN_MASK 0xfff +#define MLX4_STATS_TRAFFIC_COUNTERS_MASK 0xfULL +#define MLX4_STATS_TRAFFIC_DROPS_MASK 0xc0ULL +#define MLX4_STATS_ERROR_COUNTERS_MASK 0x1ffc30ULL +#define MLX4_STATS_PORT_COUNTERS_MASK 0x1fe00000ULL + void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) { int i; @@ -898,6 +903,24 @@ int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_mailbox *outbox, struct mlx4_cmd_info *cmd) { + if (slave != dev->caps.function) + return 0; return mlx4_common_dump_eth_stats(dev, slave, vhcr->in_modifier, outbox); } + +void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap) +{ + if (!mlx4_is_mfunc(dev)) { + *stats_bitmap = 0; + return; + } + + *stats_bitmap = (MLX4_STATS_TRAFFIC_COUNTERS_MASK | + MLX4_STATS_TRAFFIC_DROPS_MASK | + MLX4_STATS_PORT_COUNTERS_MASK); + + if (mlx4_is_master(dev)) + *stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK; +} +EXPORT_SYMBOL(mlx4_set_stats_bitmap); diff --git a/drivers/net/ethernet/mellanox/mlx4/profile.c b/drivers/net/ethernet/mellanox/mlx4/profile.c index 66f91ca7a7c6..1129677daa62 100644 --- a/drivers/net/ethernet/mellanox/mlx4/profile.c +++ b/drivers/net/ethernet/mellanox/mlx4/profile.c @@ -110,7 +110,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, MAX_MSIX); profile[MLX4_RES_DMPT].num = request->num_mpt; profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; - profile[MLX4_RES_MTT].num = request->num_mtt; + profile[MLX4_RES_MTT].num = request->num_mtt * (1 << log_mtts_per_seg); profile[MLX4_RES_MCG].num = request->num_mcg; for (i = 0; i < MLX4_RES_NUM; ++i) { diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 6b03ac8b9002..738f950a1ce5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -162,7 +162,7 @@ static int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, ((struct mlx4_qp_context *) (mailbox->buf + 8))->local_qpn = cpu_to_be32(qp->qpn); - ret = mlx4_cmd(dev, mailbox->dma | dev->caps.function, + ret = mlx4_cmd(dev, mailbox->dma, qp->qpn | (!!sqd_event << 31), new_state == MLX4_QP_STATE_RST ? 2 : 0, op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C, native); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index ed20751a057d..dcd819bfb2f0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -1561,11 +1561,6 @@ static int mr_get_mtt_size(struct mlx4_mpt_entry *mpt) return be32_to_cpu(mpt->mtt_sz); } -static int mr_get_pdn(struct mlx4_mpt_entry *mpt) -{ - return be32_to_cpu(mpt->pd_flags) & 0xffffff; -} - static int qp_get_mtt_addr(struct mlx4_qp_context *qpc) { return be32_to_cpu(qpc->mtt_base_addr_l) & 0xfffffff8; @@ -1602,16 +1597,6 @@ static int qp_get_mtt_size(struct mlx4_qp_context *qpc) return total_pages; } -static int qp_get_pdn(struct mlx4_qp_context *qpc) -{ - return be32_to_cpu(qpc->pd) & 0xffffff; -} - -static int pdn2slave(int pdn) -{ - return (pdn >> NOT_MASKED_PD_BITS) - 1; -} - static int check_mtt_range(struct mlx4_dev *dev, int slave, int start, int size, struct res_mtt *mtt) { @@ -1656,11 +1641,6 @@ int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave, mpt->mtt = mtt; } - if (pdn2slave(mr_get_pdn(inbox->buf)) != slave) { - err = -EPERM; - goto ex_put; - } - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); if (err) goto ex_put; @@ -1792,11 +1772,6 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, if (err) goto ex_put_mtt; - if (pdn2slave(qp_get_pdn(qpc)) != slave) { - err = -EPERM; - goto ex_put_mtt; - } - err = get_res(dev, slave, rcqn, RES_CQ, &rcq); if (err) goto ex_put_mtt; @@ -2048,10 +2023,10 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) if (!priv->mfunc.master.slave_state) return -EINVAL; - event_eq = &priv->mfunc.master.slave_state[slave].event_eq; + event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; /* Create the event only if the slave is registered */ - if ((event_eq->event_type & (1 << eqe->type)) == 0) + if (event_eq->eqn < 0) return 0; mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); @@ -2289,11 +2264,6 @@ ex_put: return err; } -static int srq_get_pdn(struct mlx4_srq_context *srqc) -{ - return be32_to_cpu(srqc->pd) & 0xffffff; -} - static int srq_get_mtt_size(struct mlx4_srq_context *srqc) { int log_srq_size = (be32_to_cpu(srqc->state_logsize_srqn) >> 24) & 0xf; @@ -2333,11 +2303,6 @@ int mlx4_SW2HW_SRQ_wrapper(struct mlx4_dev *dev, int slave, if (err) goto ex_put_mtt; - if (pdn2slave(srq_get_pdn(srqc)) != slave) { - err = -EPERM; - goto ex_put_mtt; - } - err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); if (err) goto ex_put_mtt; diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c index 2823fffc6383..feda6c00829f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/srq.c +++ b/drivers/net/ethernet/mellanox/mlx4/srq.c @@ -67,7 +67,7 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type) static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, int srq_num) { - return mlx4_cmd(dev, mailbox->dma | dev->caps.function, srq_num, 0, + return mlx4_cmd(dev, mailbox->dma, srq_num, 0, MLX4_CMD_SW2HW_SRQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); } diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c index 75ec87a822b8..0a85690a1321 100644 --- a/drivers/net/ethernet/micrel/ks8842.c +++ b/drivers/net/ethernet/micrel/ks8842.c @@ -459,7 +459,7 @@ static int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev) sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4; ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan, - &ctl->sg, 1, DMA_TO_DEVICE, + &ctl->sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); if (!ctl->adesc) return NETDEV_TX_BUSY; @@ -571,7 +571,7 @@ static int __ks8842_start_new_rx_dma(struct net_device *netdev) sg_dma_len(sg) = DMA_BUFFER_SIZE; ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan, - sg, 1, DMA_FROM_DEVICE, + sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP); if (!ctl->adesc) diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 964e9c0948bc..3ead111111e1 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -1745,6 +1745,12 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter) struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring; int err; + /* Ensure we have a valid MAC */ + if (!is_valid_ether_addr(adapter->hw.mac.addr)) { + pr_err("Error: Invalid MAC address\n"); + return -EINVAL; + } + /* hardware has been reset, we need to reload some things */ pch_gbe_set_multi(netdev); @@ -2468,9 +2474,14 @@ static int pch_gbe_probe(struct pci_dev *pdev, memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len); if (!is_valid_ether_addr(netdev->dev_addr)) { - dev_err(&pdev->dev, "Invalid MAC Address\n"); - ret = -EIO; - goto err_free_adapter; + /* + * If the MAC is invalid (or just missing), display a warning + * but do not abort setting up the device. pch_gbe_up will + * prevent the interface from being brought up until a valid MAC + * is set. + */ + dev_err(&pdev->dev, "Invalid MAC address, " + "interface disabled.\n"); } setup_timer(&adapter->watchdog_timer, pch_gbe_watchdog, (unsigned long)adapter); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index da4a1042523a..73195329aa46 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -154,7 +154,7 @@ int stmmac_mdio_register(struct net_device *ndev) else irqlist = priv->mii_irq; - new_bus->name = "STMMAC MII Bus"; + new_bus->name = "stmmac"; new_bus->read = &stmmac_mdio_read; new_bus->write = &stmmac_mdio_write; new_bus->reset = &stmmac_mdio_reset; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 54a819a36487..c796de9eed72 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -170,9 +170,9 @@ static int stmmac_pci_resume(struct pci_dev *pdev) #define STMMAC_DEVICE_ID 0x1108 static DEFINE_PCI_DEVICE_TABLE(stmmac_id_table) = { - { - PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)}, { - } + {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)}, + {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)}, + {} }; MODULE_DEVICE_TABLE(pci, stmmac_id_table); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 462d05f05e84..1a1ca6cfc74a 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -68,11 +68,11 @@ static void do_set_multicast(struct work_struct *w) nvdev = hv_get_drvdata(ndevctx->device_ctx); if (nvdev == NULL) - return; + goto out; rdev = nvdev->extension; if (rdev == NULL) - return; + goto out; if (net->flags & IFF_PROMISC) rndis_filter_set_packet_filter(rdev, @@ -83,6 +83,7 @@ static void do_set_multicast(struct work_struct *w) NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_DIRECTED); +out: kfree(w); } diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index d423d18b4ad6..e535137eb2d0 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -313,8 +313,12 @@ config TOSHIBA_FIR donauboe. config AU1000_FIR - tristate "Alchemy Au1000 SIR/FIR" + tristate "Alchemy IrDA SIR/FIR" depends on IRDA && MIPS_ALCHEMY + help + Say Y/M here to build suppor the the IrDA peripheral on the + Alchemy Au1000 and Au1100 SoCs. + Say M to build a module; it will be called au1k_ir.ko config SMC_IRCC_FIR tristate "SMSC IrCC (EXPERIMENTAL)" diff --git a/drivers/net/irda/au1000_ircc.h b/drivers/net/irda/au1000_ircc.h deleted file mode 100644 index c072c09a8d91..000000000000 --- a/drivers/net/irda/au1000_ircc.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Au1000 IrDA driver. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.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. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef AU1000_IRCC_H -#define AU1000_IRCC_H - -#include <linux/time.h> - -#include <linux/spinlock.h> -#include <linux/pm.h> -#include <asm/io.h> - -#define NUM_IR_IFF 1 -#define NUM_IR_DESC 64 -#define RING_SIZE_4 0x0 -#define RING_SIZE_16 0x3 -#define RING_SIZE_64 0xF -#define MAX_NUM_IR_DESC 64 -#define MAX_BUF_SIZE 2048 - -#define BPS_115200 0 -#define BPS_57600 1 -#define BPS_38400 2 -#define BPS_19200 5 -#define BPS_9600 11 -#define BPS_2400 47 - -/* Ring descriptor flags */ -#define AU_OWN (1<<7) /* tx,rx */ - -#define IR_DIS_CRC (1<<6) /* tx */ -#define IR_BAD_CRC (1<<5) /* tx */ -#define IR_NEED_PULSE (1<<4) /* tx */ -#define IR_FORCE_UNDER (1<<3) /* tx */ -#define IR_DISABLE_TX (1<<2) /* tx */ -#define IR_HW_UNDER (1<<0) /* tx */ -#define IR_TX_ERROR (IR_DIS_CRC|IR_BAD_CRC|IR_HW_UNDER) - -#define IR_PHY_ERROR (1<<6) /* rx */ -#define IR_CRC_ERROR (1<<5) /* rx */ -#define IR_MAX_LEN (1<<4) /* rx */ -#define IR_FIFO_OVER (1<<3) /* rx */ -#define IR_SIR_ERROR (1<<2) /* rx */ -#define IR_RX_ERROR (IR_PHY_ERROR|IR_CRC_ERROR| \ - IR_MAX_LEN|IR_FIFO_OVER|IR_SIR_ERROR) - -typedef struct db_dest { - struct db_dest *pnext; - volatile u32 *vaddr; - dma_addr_t dma_addr; -} db_dest_t; - - -typedef struct ring_desc { - u8 count_0; /* 7:0 */ - u8 count_1; /* 12:8 */ - u8 reserved; - u8 flags; - u8 addr_0; /* 7:0 */ - u8 addr_1; /* 15:8 */ - u8 addr_2; /* 23:16 */ - u8 addr_3; /* 31:24 */ -} ring_dest_t; - - -/* Private data for each instance */ -struct au1k_private { - - db_dest_t *pDBfree; - db_dest_t db[2*NUM_IR_DESC]; - volatile ring_dest_t *rx_ring[NUM_IR_DESC]; - volatile ring_dest_t *tx_ring[NUM_IR_DESC]; - db_dest_t *rx_db_inuse[NUM_IR_DESC]; - db_dest_t *tx_db_inuse[NUM_IR_DESC]; - u32 rx_head; - u32 tx_head; - u32 tx_tail; - u32 tx_full; - - iobuff_t rx_buff; - - struct net_device *netdev; - - struct timeval stamp; - struct timeval now; - struct qos_info qos; - struct irlap_cb *irlap; - - u8 open; - u32 speed; - u32 newspeed; - - u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */ - struct timer_list timer; - - spinlock_t lock; /* For serializing operations */ -}; -#endif /* AU1000_IRCC_H */ diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index a3d696a9456a..fc503aa5288e 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -18,104 +18,220 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. */ -#include <linux/module.h> -#include <linux/types.h> + #include <linux/init.h> -#include <linux/errno.h> +#include <linux/module.h> #include <linux/netdevice.h> -#include <linux/slab.h> -#include <linux/rtnetlink.h> #include <linux/interrupt.h> -#include <linux/pm.h> -#include <linux/bitops.h> - -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/au1000.h> -#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) -#include <asm/pb1000.h> -#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) -#include <asm/db1x00.h> -#include <asm/mach-db1x00/bcsr.h> -#else -#error au1k_ir: unsupported board -#endif +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/types.h> #include <net/irda/irda.h> #include <net/irda/irmod.h> #include <net/irda/wrapper.h> #include <net/irda/irda_device.h> -#include "au1000_ircc.h" +#include <asm/mach-au1x00/au1000.h> + +/* registers */ +#define IR_RING_PTR_STATUS 0x00 +#define IR_RING_BASE_ADDR_H 0x04 +#define IR_RING_BASE_ADDR_L 0x08 +#define IR_RING_SIZE 0x0C +#define IR_RING_PROMPT 0x10 +#define IR_RING_ADDR_CMPR 0x14 +#define IR_INT_CLEAR 0x18 +#define IR_CONFIG_1 0x20 +#define IR_SIR_FLAGS 0x24 +#define IR_STATUS 0x28 +#define IR_READ_PHY_CONFIG 0x2C +#define IR_WRITE_PHY_CONFIG 0x30 +#define IR_MAX_PKT_LEN 0x34 +#define IR_RX_BYTE_CNT 0x38 +#define IR_CONFIG_2 0x3C +#define IR_ENABLE 0x40 + +/* Config1 */ +#define IR_RX_INVERT_LED (1 << 0) +#define IR_TX_INVERT_LED (1 << 1) +#define IR_ST (1 << 2) +#define IR_SF (1 << 3) +#define IR_SIR (1 << 4) +#define IR_MIR (1 << 5) +#define IR_FIR (1 << 6) +#define IR_16CRC (1 << 7) +#define IR_TD (1 << 8) +#define IR_RX_ALL (1 << 9) +#define IR_DMA_ENABLE (1 << 10) +#define IR_RX_ENABLE (1 << 11) +#define IR_TX_ENABLE (1 << 12) +#define IR_LOOPBACK (1 << 14) +#define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \ + IR_RX_ALL | IR_RX_ENABLE | IR_SF | \ + IR_16CRC) + +/* ir_status */ +#define IR_RX_STATUS (1 << 9) +#define IR_TX_STATUS (1 << 10) +#define IR_PHYEN (1 << 15) + +/* ir_write_phy_config */ +#define IR_BR(x) (((x) & 0x3f) << 10) /* baud rate */ +#define IR_PW(x) (((x) & 0x1f) << 5) /* pulse width */ +#define IR_P(x) ((x) & 0x1f) /* preamble bits */ + +/* Config2 */ +#define IR_MODE_INV (1 << 0) +#define IR_ONE_PIN (1 << 1) +#define IR_PHYCLK_40MHZ (0 << 2) +#define IR_PHYCLK_48MHZ (1 << 2) +#define IR_PHYCLK_56MHZ (2 << 2) +#define IR_PHYCLK_64MHZ (3 << 2) +#define IR_DP (1 << 4) +#define IR_DA (1 << 5) +#define IR_FLT_HIGH (0 << 6) +#define IR_FLT_MEDHI (1 << 6) +#define IR_FLT_MEDLO (2 << 6) +#define IR_FLT_LO (3 << 6) +#define IR_IEN (1 << 8) + +/* ir_enable */ +#define IR_HC (1 << 3) /* divide SBUS clock by 2 */ +#define IR_CE (1 << 2) /* clock enable */ +#define IR_C (1 << 1) /* coherency bit */ +#define IR_BE (1 << 0) /* set in big endian mode */ + +#define NUM_IR_DESC 64 +#define RING_SIZE_4 0x0 +#define RING_SIZE_16 0x3 +#define RING_SIZE_64 0xF +#define MAX_NUM_IR_DESC 64 +#define MAX_BUF_SIZE 2048 + +/* Ring descriptor flags */ +#define AU_OWN (1 << 7) /* tx,rx */ +#define IR_DIS_CRC (1 << 6) /* tx */ +#define IR_BAD_CRC (1 << 5) /* tx */ +#define IR_NEED_PULSE (1 << 4) /* tx */ +#define IR_FORCE_UNDER (1 << 3) /* tx */ +#define IR_DISABLE_TX (1 << 2) /* tx */ +#define IR_HW_UNDER (1 << 0) /* tx */ +#define IR_TX_ERROR (IR_DIS_CRC | IR_BAD_CRC | IR_HW_UNDER) + +#define IR_PHY_ERROR (1 << 6) /* rx */ +#define IR_CRC_ERROR (1 << 5) /* rx */ +#define IR_MAX_LEN (1 << 4) /* rx */ +#define IR_FIFO_OVER (1 << 3) /* rx */ +#define IR_SIR_ERROR (1 << 2) /* rx */ +#define IR_RX_ERROR (IR_PHY_ERROR | IR_CRC_ERROR | \ + IR_MAX_LEN | IR_FIFO_OVER | IR_SIR_ERROR) + +struct db_dest { + struct db_dest *pnext; + volatile u32 *vaddr; + dma_addr_t dma_addr; +}; -static int au1k_irda_net_init(struct net_device *); -static int au1k_irda_start(struct net_device *); -static int au1k_irda_stop(struct net_device *dev); -static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *); -static int au1k_irda_rx(struct net_device *); -static void au1k_irda_interrupt(int, void *); -static void au1k_tx_timeout(struct net_device *); -static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int); -static int au1k_irda_set_speed(struct net_device *dev, int speed); +struct ring_dest { + u8 count_0; /* 7:0 */ + u8 count_1; /* 12:8 */ + u8 reserved; + u8 flags; + u8 addr_0; /* 7:0 */ + u8 addr_1; /* 15:8 */ + u8 addr_2; /* 23:16 */ + u8 addr_3; /* 31:24 */ +}; -static void *dma_alloc(size_t, dma_addr_t *); -static void dma_free(void *, size_t); +/* Private data for each instance */ +struct au1k_private { + void __iomem *iobase; + int irq_rx, irq_tx; + + struct db_dest *pDBfree; + struct db_dest db[2 * NUM_IR_DESC]; + volatile struct ring_dest *rx_ring[NUM_IR_DESC]; + volatile struct ring_dest *tx_ring[NUM_IR_DESC]; + struct db_dest *rx_db_inuse[NUM_IR_DESC]; + struct db_dest *tx_db_inuse[NUM_IR_DESC]; + u32 rx_head; + u32 tx_head; + u32 tx_tail; + u32 tx_full; + + iobuff_t rx_buff; + + struct net_device *netdev; + struct timeval stamp; + struct timeval now; + struct qos_info qos; + struct irlap_cb *irlap; + + u8 open; + u32 speed; + u32 newspeed; + + struct timer_list timer; + + struct resource *ioarea; + struct au1k_irda_platform_data *platdata; +}; static int qos_mtt_bits = 0x07; /* 1 ms or more */ -static struct net_device *ir_devs[NUM_IR_IFF]; -static char version[] __devinitdata = - "au1k_ircc:1.2 ppopov@mvista.com\n"; #define RUN_AT(x) (jiffies + (x)) -static DEFINE_SPINLOCK(ir_lock); +static void au1k_irda_plat_set_phy_mode(struct au1k_private *p, int mode) +{ + if (p->platdata && p->platdata->set_phy_mode) + p->platdata->set_phy_mode(mode); +} -/* - * IrDA peripheral bug. You have to read the register - * twice to get the right value. - */ -u32 read_ir_reg(u32 addr) -{ - readl(addr); - return readl(addr); +static inline unsigned long irda_read(struct au1k_private *p, + unsigned long ofs) +{ + /* + * IrDA peripheral bug. You have to read the register + * twice to get the right value. + */ + (void)__raw_readl(p->iobase + ofs); + return __raw_readl(p->iobase + ofs); } +static inline void irda_write(struct au1k_private *p, unsigned long ofs, + unsigned long val) +{ + __raw_writel(val, p->iobase + ofs); + wmb(); +} /* * Buffer allocation/deallocation routines. The buffer descriptor returned - * has the virtual and dma address of a buffer suitable for + * has the virtual and dma address of a buffer suitable for * both, receive and transmit operations. */ -static db_dest_t *GetFreeDB(struct au1k_private *aup) +static struct db_dest *GetFreeDB(struct au1k_private *aup) { - db_dest_t *pDB; - pDB = aup->pDBfree; - - if (pDB) { - aup->pDBfree = pDB->pnext; - } - return pDB; -} + struct db_dest *db; + db = aup->pDBfree; -static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB) -{ - db_dest_t *pDBfree = aup->pDBfree; - if (pDBfree) - pDBfree->pnext = pDB; - aup->pDBfree = pDB; + if (db) + aup->pDBfree = db->pnext; + return db; } - /* DMA memory allocation, derived from pci_alloc_consistent. However, the Au1000 data cache is coherent (when programmed so), therefore we return KSEG0 address, not KSEG1. */ -static void *dma_alloc(size_t size, dma_addr_t * dma_handle) +static void *dma_alloc(size_t size, dma_addr_t *dma_handle) { void *ret; int gfp = GFP_ATOMIC | GFP_DMA; - ret = (void *) __get_free_pages(gfp, get_order(size)); + ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret != NULL) { memset(ret, 0, size); @@ -125,7 +241,6 @@ static void *dma_alloc(size_t size, dma_addr_t * dma_handle) return ret; } - static void dma_free(void *vaddr, size_t size) { vaddr = (void *)KSEG0ADDR(vaddr); @@ -133,206 +248,306 @@ static void dma_free(void *vaddr, size_t size) } -static void -setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) +static void setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) { int i; - for (i=0; i<NUM_IR_DESC; i++) { - aup->rx_ring[i] = (volatile ring_dest_t *) - (rx_base + sizeof(ring_dest_t)*i); + for (i = 0; i < NUM_IR_DESC; i++) { + aup->rx_ring[i] = (volatile struct ring_dest *) + (rx_base + sizeof(struct ring_dest) * i); } - for (i=0; i<NUM_IR_DESC; i++) { - aup->tx_ring[i] = (volatile ring_dest_t *) - (tx_base + sizeof(ring_dest_t)*i); + for (i = 0; i < NUM_IR_DESC; i++) { + aup->tx_ring[i] = (volatile struct ring_dest *) + (tx_base + sizeof(struct ring_dest) * i); } } -static int au1k_irda_init(void) -{ - static unsigned version_printed = 0; - struct au1k_private *aup; - struct net_device *dev; - int err; - - if (version_printed++ == 0) printk(version); - - dev = alloc_irdadev(sizeof(struct au1k_private)); - if (!dev) - return -ENOMEM; - - dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */ - err = au1k_irda_net_init(dev); - if (err) - goto out; - err = register_netdev(dev); - if (err) - goto out1; - ir_devs[0] = dev; - printk(KERN_INFO "IrDA: Registered device %s\n", dev->name); - return 0; - -out1: - aup = netdev_priv(dev); - dma_free((void *)aup->db[0].vaddr, - MAX_BUF_SIZE * 2*NUM_IR_DESC); - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); - kfree(aup->rx_buff.head); -out: - free_netdev(dev); - return err; -} - static int au1k_irda_init_iobuf(iobuff_t *io, int size) { io->head = kmalloc(size, GFP_KERNEL); if (io->head != NULL) { - io->truesize = size; - io->in_frame = FALSE; - io->state = OUTSIDE_FRAME; - io->data = io->head; + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; } return io->head ? 0 : -ENOMEM; } -static const struct net_device_ops au1k_irda_netdev_ops = { - .ndo_open = au1k_irda_start, - .ndo_stop = au1k_irda_stop, - .ndo_start_xmit = au1k_irda_hard_xmit, - .ndo_tx_timeout = au1k_tx_timeout, - .ndo_do_ioctl = au1k_irda_ioctl, -}; - -static int au1k_irda_net_init(struct net_device *dev) +/* + * Set the IrDA communications speed. + */ +static int au1k_irda_set_speed(struct net_device *dev, int speed) { struct au1k_private *aup = netdev_priv(dev); - int i, retval = 0, err; - db_dest_t *pDB, *pDBfree; - dma_addr_t temp; + volatile struct ring_dest *ptxd; + unsigned long control; + int ret = 0, timeout = 10, i; - err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); - if (err) - goto out1; + if (speed == aup->speed) + return ret; - dev->netdev_ops = &au1k_irda_netdev_ops; + /* disable PHY first */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN); - irda_init_max_qos_capabilies(&aup->qos); + /* disable RX/TX */ + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~(IR_RX_ENABLE | IR_TX_ENABLE)); + msleep(20); + while (irda_read(aup, IR_STATUS) & (IR_RX_STATUS | IR_TX_STATUS)) { + msleep(20); + if (!timeout--) { + printk(KERN_ERR "%s: rx/tx disable timeout\n", + dev->name); + break; + } + } - /* The only value we must override it the baudrate */ - aup->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|IR_576000 |(IR_4000000 << 8); - - aup->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&aup->qos); + /* disable DMA */ + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~IR_DMA_ENABLE); + msleep(20); - retval = -ENOMEM; + /* After we disable tx/rx. the index pointers go back to zero. */ + aup->tx_head = aup->tx_tail = aup->rx_head = 0; + for (i = 0; i < NUM_IR_DESC; i++) { + ptxd = aup->tx_ring[i]; + ptxd->flags = 0; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + } - /* Tx ring follows rx ring + 512 bytes */ - /* we need a 1k aligned buffer */ - aup->rx_ring[0] = (ring_dest_t *) - dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)), &temp); - if (!aup->rx_ring[0]) - goto out2; + for (i = 0; i < NUM_IR_DESC; i++) { + ptxd = aup->rx_ring[i]; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + ptxd->flags = AU_OWN; + } - /* allocate the data buffers */ - aup->db[0].vaddr = - (void *)dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC, &temp); - if (!aup->db[0].vaddr) - goto out3; + if (speed == 4000000) + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_FIR); + else + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR); - setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); + switch (speed) { + case 9600: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(11) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 19200: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(5) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 38400: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(2) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 57600: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(1) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 115200: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 4000000: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_P(15)); + irda_write(aup, IR_CONFIG_1, IR_FIR | IR_DMA_ENABLE | + IR_RX_ENABLE); + break; + default: + printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed); + ret = -EINVAL; + break; + } - pDBfree = NULL; - pDB = aup->db; - for (i=0; i<(2*NUM_IR_DESC); i++) { - pDB->pnext = pDBfree; - pDBfree = pDB; - pDB->vaddr = - (u32 *)((unsigned)aup->db[0].vaddr + MAX_BUF_SIZE*i); - pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); - pDB++; + aup->speed = speed; + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) | IR_PHYEN); + + control = irda_read(aup, IR_STATUS); + irda_write(aup, IR_RING_PROMPT, 0); + + if (control & (1 << 14)) { + printk(KERN_ERR "%s: configuration error\n", dev->name); + } else { + if (control & (1 << 11)) + printk(KERN_DEBUG "%s Valid SIR config\n", dev->name); + if (control & (1 << 12)) + printk(KERN_DEBUG "%s Valid MIR config\n", dev->name); + if (control & (1 << 13)) + printk(KERN_DEBUG "%s Valid FIR config\n", dev->name); + if (control & (1 << 10)) + printk(KERN_DEBUG "%s TX enabled\n", dev->name); + if (control & (1 << 9)) + printk(KERN_DEBUG "%s RX enabled\n", dev->name); } - aup->pDBfree = pDBfree; - /* attach a data buffer to each descriptor */ - for (i=0; i<NUM_IR_DESC; i++) { - pDB = GetFreeDB(aup); - if (!pDB) goto out; - aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); - aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); - aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); - aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); - aup->rx_db_inuse[i] = pDB; + return ret; +} + +static void update_rx_stats(struct net_device *dev, u32 status, u32 count) +{ + struct net_device_stats *ps = &dev->stats; + + ps->rx_packets++; + + if (status & IR_RX_ERROR) { + ps->rx_errors++; + if (status & (IR_PHY_ERROR | IR_FIFO_OVER)) + ps->rx_missed_errors++; + if (status & IR_MAX_LEN) + ps->rx_length_errors++; + if (status & IR_CRC_ERROR) + ps->rx_crc_errors++; + } else + ps->rx_bytes += count; +} + +static void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +{ + struct net_device_stats *ps = &dev->stats; + + ps->tx_packets++; + ps->tx_bytes += pkt_len; + + if (status & IR_TX_ERROR) { + ps->tx_errors++; + ps->tx_aborted_errors++; } - for (i=0; i<NUM_IR_DESC; i++) { - pDB = GetFreeDB(aup); - if (!pDB) goto out; - aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); - aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); - aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); - aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); - aup->tx_ring[i]->count_0 = 0; - aup->tx_ring[i]->count_1 = 0; - aup->tx_ring[i]->flags = 0; - aup->tx_db_inuse[i] = pDB; +} + +static void au1k_tx_ack(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + volatile struct ring_dest *ptxd; + + ptxd = aup->tx_ring[aup->tx_tail]; + while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { + update_tx_stats(dev, ptxd->flags, + (ptxd->count_1 << 8) | ptxd->count_0); + ptxd->count_0 = 0; + ptxd->count_1 = 0; + wmb(); + aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); + ptxd = aup->tx_ring[aup->tx_tail]; + + if (aup->tx_full) { + aup->tx_full = 0; + netif_wake_queue(dev); + } } -#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) - /* power on */ - bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK, - BCSR_RESETS_IRDA_MODE_FULL); -#endif + if (aup->tx_tail == aup->tx_head) { + if (aup->newspeed) { + au1k_irda_set_speed(dev, aup->newspeed); + aup->newspeed = 0; + } else { + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~IR_TX_ENABLE); + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) | IR_RX_ENABLE); + irda_write(aup, IR_RING_PROMPT, 0); + } + } +} - return 0; +static int au1k_irda_rx(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + volatile struct ring_dest *prxd; + struct sk_buff *skb; + struct db_dest *pDB; + u32 flags, count; -out3: - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); -out2: - kfree(aup->rx_buff.head); -out1: - printk(KERN_ERR "au1k_init_module failed. Returns %d\n", retval); - return retval; + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + while (!(flags & AU_OWN)) { + pDB = aup->rx_db_inuse[aup->rx_head]; + count = (prxd->count_1 << 8) | prxd->count_0; + if (!(flags & IR_RX_ERROR)) { + /* good frame */ + update_rx_stats(dev, flags, count); + skb = alloc_skb(count + 1, GFP_ATOMIC); + if (skb == NULL) { + dev->stats.rx_dropped++; + continue; + } + skb_reserve(skb, 1); + if (aup->speed == 4000000) + skb_put(skb, count); + else + skb_put(skb, count - 2); + skb_copy_to_linear_data(skb, (void *)pDB->vaddr, + count - 2); + skb->dev = dev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + prxd->count_0 = 0; + prxd->count_1 = 0; + } + prxd->flags |= AU_OWN; + aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); + irda_write(aup, IR_RING_PROMPT, 0); + + /* next descriptor */ + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + } + return 0; } +static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id) +{ + struct net_device *dev = dev_id; + struct au1k_private *aup = netdev_priv(dev); + + irda_write(aup, IR_INT_CLEAR, 0); /* ack irda interrupts */ + + au1k_irda_rx(dev); + au1k_tx_ack(dev); + + return IRQ_HANDLED; +} static int au1k_init(struct net_device *dev) { struct au1k_private *aup = netdev_priv(dev); + u32 enable, ring_address; int i; - u32 control; - u32 ring_address; - /* bring the device out of reset */ - control = 0xe; /* coherent, clock enable, one half system clock */ - + enable = IR_HC | IR_CE | IR_C; #ifndef CONFIG_CPU_LITTLE_ENDIAN - control |= 1; + enable |= IR_BE; #endif aup->tx_head = 0; aup->tx_tail = 0; aup->rx_head = 0; - for (i=0; i<NUM_IR_DESC; i++) { + for (i = 0; i < NUM_IR_DESC; i++) aup->rx_ring[i]->flags = AU_OWN; - } - writel(control, IR_INTERFACE_CONFIG); - au_sync_delay(10); + irda_write(aup, IR_ENABLE, enable); + msleep(20); - writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); /* disable PHY */ - au_sync_delay(1); + /* disable PHY */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN); + msleep(20); - writel(MAX_BUF_SIZE, IR_MAX_PKT_LEN); + irda_write(aup, IR_MAX_PKT_LEN, MAX_BUF_SIZE); ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]); - writel(ring_address >> 26, IR_RING_BASE_ADDR_H); - writel((ring_address >> 10) & 0xffff, IR_RING_BASE_ADDR_L); + irda_write(aup, IR_RING_BASE_ADDR_H, ring_address >> 26); + irda_write(aup, IR_RING_BASE_ADDR_L, (ring_address >> 10) & 0xffff); - writel(RING_SIZE_64<<8 | RING_SIZE_64<<12, IR_RING_SIZE); + irda_write(aup, IR_RING_SIZE, + (RING_SIZE_64 << 8) | (RING_SIZE_64 << 12)); - writel(1<<2 | IR_ONE_PIN, IR_CONFIG_2); /* 48MHz */ - writel(0, IR_RING_ADDR_CMPR); + irda_write(aup, IR_CONFIG_2, IR_PHYCLK_48MHZ | IR_ONE_PIN); + irda_write(aup, IR_RING_ADDR_CMPR, 0); au1k_irda_set_speed(dev, 9600); return 0; @@ -340,25 +555,28 @@ static int au1k_init(struct net_device *dev) static int au1k_irda_start(struct net_device *dev) { - int retval; - char hwname[32]; struct au1k_private *aup = netdev_priv(dev); + char hwname[32]; + int retval; - if ((retval = au1k_init(dev))) { + retval = au1k_init(dev); + if (retval) { printk(KERN_ERR "%s: error in au1k_init\n", dev->name); return retval; } - if ((retval = request_irq(AU1000_IRDA_TX_INT, au1k_irda_interrupt, - 0, dev->name, dev))) { - printk(KERN_ERR "%s: unable to get IRQ %d\n", + retval = request_irq(aup->irq_tx, &au1k_irda_interrupt, 0, + dev->name, dev); + if (retval) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); return retval; } - if ((retval = request_irq(AU1000_IRDA_RX_INT, au1k_irda_interrupt, - 0, dev->name, dev))) { - free_irq(AU1000_IRDA_TX_INT, dev); - printk(KERN_ERR "%s: unable to get IRQ %d\n", + retval = request_irq(aup->irq_rx, &au1k_irda_interrupt, 0, + dev->name, dev); + if (retval) { + free_irq(aup->irq_tx, dev); + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); return retval; } @@ -368,9 +586,13 @@ static int au1k_irda_start(struct net_device *dev) aup->irlap = irlap_open(dev, &aup->qos, hwname); netif_start_queue(dev); - writel(read_ir_reg(IR_CONFIG_2) | 1<<8, IR_CONFIG_2); /* int enable */ + /* int enable */ + irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) | IR_IEN); + + /* power up */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR); - aup->timer.expires = RUN_AT((3*HZ)); + aup->timer.expires = RUN_AT((3 * HZ)); aup->timer.data = (unsigned long)dev; return 0; } @@ -379,11 +601,12 @@ static int au1k_irda_stop(struct net_device *dev) { struct au1k_private *aup = netdev_priv(dev); + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + /* disable interrupts */ - writel(read_ir_reg(IR_CONFIG_2) & ~(1<<8), IR_CONFIG_2); - writel(0, IR_CONFIG_1); - writel(0, IR_INTERFACE_CONFIG); /* disable clock */ - au_sync(); + irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) & ~IR_IEN); + irda_write(aup, IR_CONFIG_1, 0); + irda_write(aup, IR_ENABLE, 0); /* disable clock */ if (aup->irlap) { irlap_close(aup->irlap); @@ -394,83 +617,12 @@ static int au1k_irda_stop(struct net_device *dev) del_timer(&aup->timer); /* disable the interrupt */ - free_irq(AU1000_IRDA_TX_INT, dev); - free_irq(AU1000_IRDA_RX_INT, dev); - return 0; -} - -static void __exit au1k_irda_exit(void) -{ - struct net_device *dev = ir_devs[0]; - struct au1k_private *aup = netdev_priv(dev); + free_irq(aup->irq_tx, dev); + free_irq(aup->irq_rx, dev); - unregister_netdev(dev); - - dma_free((void *)aup->db[0].vaddr, - MAX_BUF_SIZE * 2*NUM_IR_DESC); - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); - kfree(aup->rx_buff.head); - free_netdev(dev); -} - - -static inline void -update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) -{ - struct au1k_private *aup = netdev_priv(dev); - struct net_device_stats *ps = &aup->stats; - - ps->tx_packets++; - ps->tx_bytes += pkt_len; - - if (status & IR_TX_ERROR) { - ps->tx_errors++; - ps->tx_aborted_errors++; - } -} - - -static void au1k_tx_ack(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - volatile ring_dest_t *ptxd; - - ptxd = aup->tx_ring[aup->tx_tail]; - while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { - update_tx_stats(dev, ptxd->flags, - ptxd->count_1<<8 | ptxd->count_0); - ptxd->count_0 = 0; - ptxd->count_1 = 0; - au_sync(); - - aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); - ptxd = aup->tx_ring[aup->tx_tail]; - - if (aup->tx_full) { - aup->tx_full = 0; - netif_wake_queue(dev); - } - } - - if (aup->tx_tail == aup->tx_head) { - if (aup->newspeed) { - au1k_irda_set_speed(dev, aup->newspeed); - aup->newspeed = 0; - } - else { - writel(read_ir_reg(IR_CONFIG_1) & ~IR_TX_ENABLE, - IR_CONFIG_1); - au_sync(); - writel(read_ir_reg(IR_CONFIG_1) | IR_RX_ENABLE, - IR_CONFIG_1); - writel(0, IR_RING_PROMPT); - au_sync(); - } - } + return 0; } - /* * Au1000 transmit routine. */ @@ -478,15 +630,12 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct au1k_private *aup = netdev_priv(dev); int speed = irda_get_next_speed(skb); - volatile ring_dest_t *ptxd; - u32 len; - - u32 flags; - db_dest_t *pDB; + volatile struct ring_dest *ptxd; + struct db_dest *pDB; + u32 len, flags; - if (speed != aup->speed && speed != -1) { + if (speed != aup->speed && speed != -1) aup->newspeed = speed; - } if ((skb->len == 0) && (aup->newspeed)) { if (aup->tx_tail == aup->tx_head) { @@ -504,138 +653,47 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return NETDEV_TX_BUSY; - } - else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { + return 1; + } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return NETDEV_TX_BUSY; + return 1; } pDB = aup->tx_db_inuse[aup->tx_head]; #if 0 - if (read_ir_reg(IR_RX_BYTE_CNT) != 0) { - printk("tx warning: rx byte cnt %x\n", - read_ir_reg(IR_RX_BYTE_CNT)); + if (irda_read(aup, IR_RX_BYTE_CNT) != 0) { + printk(KERN_DEBUG "tx warning: rx byte cnt %x\n", + irda_read(aup, IR_RX_BYTE_CNT)); } #endif - + if (aup->speed == 4000000) { /* FIR */ - skb_copy_from_linear_data(skb, pDB->vaddr, skb->len); + skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len); ptxd->count_0 = skb->len & 0xff; ptxd->count_1 = (skb->len >> 8) & 0xff; - - } - else { + } else { /* SIR */ len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE); ptxd->count_0 = len & 0xff; ptxd->count_1 = (len >> 8) & 0xff; ptxd->flags |= IR_DIS_CRC; - au_writel(au_readl(0xae00000c) & ~(1<<13), 0xae00000c); } ptxd->flags |= AU_OWN; - au_sync(); + wmb(); - writel(read_ir_reg(IR_CONFIG_1) | IR_TX_ENABLE, IR_CONFIG_1); - writel(0, IR_RING_PROMPT); - au_sync(); + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) | IR_TX_ENABLE); + irda_write(aup, IR_RING_PROMPT, 0); dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); return NETDEV_TX_OK; } - -static inline void -update_rx_stats(struct net_device *dev, u32 status, u32 count) -{ - struct au1k_private *aup = netdev_priv(dev); - struct net_device_stats *ps = &aup->stats; - - ps->rx_packets++; - - if (status & IR_RX_ERROR) { - ps->rx_errors++; - if (status & (IR_PHY_ERROR|IR_FIFO_OVER)) - ps->rx_missed_errors++; - if (status & IR_MAX_LEN) - ps->rx_length_errors++; - if (status & IR_CRC_ERROR) - ps->rx_crc_errors++; - } - else - ps->rx_bytes += count; -} - -/* - * Au1000 receive routine. - */ -static int au1k_irda_rx(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - struct sk_buff *skb; - volatile ring_dest_t *prxd; - u32 flags, count; - db_dest_t *pDB; - - prxd = aup->rx_ring[aup->rx_head]; - flags = prxd->flags; - - while (!(flags & AU_OWN)) { - pDB = aup->rx_db_inuse[aup->rx_head]; - count = prxd->count_1<<8 | prxd->count_0; - if (!(flags & IR_RX_ERROR)) { - /* good frame */ - update_rx_stats(dev, flags, count); - skb=alloc_skb(count+1,GFP_ATOMIC); - if (skb == NULL) { - aup->netdev->stats.rx_dropped++; - continue; - } - skb_reserve(skb, 1); - if (aup->speed == 4000000) - skb_put(skb, count); - else - skb_put(skb, count-2); - skb_copy_to_linear_data(skb, pDB->vaddr, count - 2); - skb->dev = dev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - prxd->count_0 = 0; - prxd->count_1 = 0; - } - prxd->flags |= AU_OWN; - aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); - writel(0, IR_RING_PROMPT); - au_sync(); - - /* next descriptor */ - prxd = aup->rx_ring[aup->rx_head]; - flags = prxd->flags; - - } - return 0; -} - - -static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id) -{ - struct net_device *dev = dev_id; - - writel(0, IR_INT_CLEAR); /* ack irda interrupts */ - - au1k_irda_rx(dev); - au1k_tx_ack(dev); - - return IRQ_HANDLED; -} - - /* * The Tx ring has been full longer than the watchdog timeout * value. The transmitter must be hung? @@ -653,142 +711,7 @@ static void au1k_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } - -/* - * Set the IrDA communications speed. - */ -static int -au1k_irda_set_speed(struct net_device *dev, int speed) -{ - unsigned long flags; - struct au1k_private *aup = netdev_priv(dev); - u32 control; - int ret = 0, timeout = 10, i; - volatile ring_dest_t *ptxd; -#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) - unsigned long irda_resets; -#endif - - if (speed == aup->speed) - return ret; - - spin_lock_irqsave(&ir_lock, flags); - - /* disable PHY first */ - writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); - - /* disable RX/TX */ - writel(read_ir_reg(IR_CONFIG_1) & ~(IR_RX_ENABLE|IR_TX_ENABLE), - IR_CONFIG_1); - au_sync_delay(1); - while (read_ir_reg(IR_ENABLE) & (IR_RX_STATUS | IR_TX_STATUS)) { - mdelay(1); - if (!timeout--) { - printk(KERN_ERR "%s: rx/tx disable timeout\n", - dev->name); - break; - } - } - - /* disable DMA */ - writel(read_ir_reg(IR_CONFIG_1) & ~IR_DMA_ENABLE, IR_CONFIG_1); - au_sync_delay(1); - - /* - * After we disable tx/rx. the index pointers - * go back to zero. - */ - aup->tx_head = aup->tx_tail = aup->rx_head = 0; - for (i=0; i<NUM_IR_DESC; i++) { - ptxd = aup->tx_ring[i]; - ptxd->flags = 0; - ptxd->count_0 = 0; - ptxd->count_1 = 0; - } - - for (i=0; i<NUM_IR_DESC; i++) { - ptxd = aup->rx_ring[i]; - ptxd->count_0 = 0; - ptxd->count_1 = 0; - ptxd->flags = AU_OWN; - } - - if (speed == 4000000) { -#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) - bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_FIR_SEL); -#else /* Pb1000 and Pb1100 */ - writel(1<<13, CPLD_AUX1); -#endif - } - else { -#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) - bcsr_mod(BCSR_RESETS, BCSR_RESETS_FIR_SEL, 0); -#else /* Pb1000 and Pb1100 */ - writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1); -#endif - } - - switch (speed) { - case 9600: - writel(11<<10 | 12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 19200: - writel(5<<10 | 12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 38400: - writel(2<<10 | 12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 57600: - writel(1<<10 | 12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 115200: - writel(12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 4000000: - writel(0xF, IR_WRITE_PHY_CONFIG); - writel(IR_FIR|IR_DMA_ENABLE|IR_RX_ENABLE, IR_CONFIG_1); - break; - default: - printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed); - ret = -EINVAL; - break; - } - - aup->speed = speed; - writel(read_ir_reg(IR_ENABLE) | 0x8000, IR_ENABLE); - au_sync(); - - control = read_ir_reg(IR_ENABLE); - writel(0, IR_RING_PROMPT); - au_sync(); - - if (control & (1<<14)) { - printk(KERN_ERR "%s: configuration error\n", dev->name); - } - else { - if (control & (1<<11)) - printk(KERN_DEBUG "%s Valid SIR config\n", dev->name); - if (control & (1<<12)) - printk(KERN_DEBUG "%s Valid MIR config\n", dev->name); - if (control & (1<<13)) - printk(KERN_DEBUG "%s Valid FIR config\n", dev->name); - if (control & (1<<10)) - printk(KERN_DEBUG "%s TX enabled\n", dev->name); - if (control & (1<<9)) - printk(KERN_DEBUG "%s RX enabled\n", dev->name); - } - - spin_unlock_irqrestore(&ir_lock, flags); - return ret; -} - -static int -au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +static int au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) { struct if_irda_req *rq = (struct if_irda_req *)ifreq; struct au1k_private *aup = netdev_priv(dev); @@ -829,8 +752,218 @@ au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) return ret; } +static const struct net_device_ops au1k_irda_netdev_ops = { + .ndo_open = au1k_irda_start, + .ndo_stop = au1k_irda_stop, + .ndo_start_xmit = au1k_irda_hard_xmit, + .ndo_tx_timeout = au1k_tx_timeout, + .ndo_do_ioctl = au1k_irda_ioctl, +}; + +static int __devinit au1k_irda_net_init(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + struct db_dest *pDB, *pDBfree; + int i, err, retval = 0; + dma_addr_t temp; + + err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); + if (err) + goto out1; + + dev->netdev_ops = &au1k_irda_netdev_ops; + + irda_init_max_qos_capabilies(&aup->qos); + + /* The only value we must override it the baudrate */ + aup->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 | + IR_57600 | IR_115200 | IR_576000 | (IR_4000000 << 8); + + aup->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&aup->qos); + + retval = -ENOMEM; + + /* Tx ring follows rx ring + 512 bytes */ + /* we need a 1k aligned buffer */ + aup->rx_ring[0] = (struct ring_dest *) + dma_alloc(2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)), + &temp); + if (!aup->rx_ring[0]) + goto out2; + + /* allocate the data buffers */ + aup->db[0].vaddr = + (void *)dma_alloc(MAX_BUF_SIZE * 2 * NUM_IR_DESC, &temp); + if (!aup->db[0].vaddr) + goto out3; + + setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); + + pDBfree = NULL; + pDB = aup->db; + for (i = 0; i < (2 * NUM_IR_DESC); i++) { + pDB->pnext = pDBfree; + pDBfree = pDB; + pDB->vaddr = + (u32 *)((unsigned)aup->db[0].vaddr + (MAX_BUF_SIZE * i)); + pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); + pDB++; + } + aup->pDBfree = pDBfree; + + /* attach a data buffer to each descriptor */ + for (i = 0; i < NUM_IR_DESC; i++) { + pDB = GetFreeDB(aup); + if (!pDB) + goto out3; + aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff); + aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff); + aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff); + aup->rx_db_inuse[i] = pDB; + } + for (i = 0; i < NUM_IR_DESC; i++) { + pDB = GetFreeDB(aup); + if (!pDB) + goto out3; + aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff); + aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff); + aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff); + aup->tx_ring[i]->count_0 = 0; + aup->tx_ring[i]->count_1 = 0; + aup->tx_ring[i]->flags = 0; + aup->tx_db_inuse[i] = pDB; + } + + return 0; + +out3: + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); +out2: + kfree(aup->rx_buff.head); +out1: + printk(KERN_ERR "au1k_irda_net_init() failed. Returns %d\n", retval); + return retval; +} + +static int __devinit au1k_irda_probe(struct platform_device *pdev) +{ + struct au1k_private *aup; + struct net_device *dev; + struct resource *r; + int err; + + dev = alloc_irdadev(sizeof(struct au1k_private)); + if (!dev) + return -ENOMEM; + + aup = netdev_priv(dev); + + aup->platdata = pdev->dev.platform_data; + + err = -EINVAL; + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!r) + goto out; + + aup->irq_tx = r->start; + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!r) + goto out; + + aup->irq_rx = r->start; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + goto out; + + err = -EBUSY; + aup->ioarea = request_mem_region(r->start, r->end - r->start + 1, + pdev->name); + if (!aup->ioarea) + goto out; + + aup->iobase = ioremap_nocache(r->start, r->end - r->start + 1); + if (!aup->iobase) + goto out2; + + dev->irq = aup->irq_rx; + + err = au1k_irda_net_init(dev); + if (err) + goto out3; + err = register_netdev(dev); + if (err) + goto out4; + + platform_set_drvdata(pdev, dev); + + printk(KERN_INFO "IrDA: Registered device %s\n", dev->name); + return 0; + +out4: + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2 * NUM_IR_DESC); + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); + kfree(aup->rx_buff.head); +out3: + iounmap(aup->iobase); +out2: + release_resource(aup->ioarea); + kfree(aup->ioarea); +out: + free_netdev(dev); + return err; +} + +static int __devexit au1k_irda_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct au1k_private *aup = netdev_priv(dev); + + unregister_netdev(dev); + + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2 * NUM_IR_DESC); + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); + kfree(aup->rx_buff.head); + + iounmap(aup->iobase); + release_resource(aup->ioarea); + kfree(aup->ioarea); + + free_netdev(dev); + + return 0; +} + +static struct platform_driver au1k_irda_driver = { + .driver = { + .name = "au1000-irda", + .owner = THIS_MODULE, + }, + .probe = au1k_irda_probe, + .remove = __devexit_p(au1k_irda_remove), +}; + +static int __init au1k_irda_load(void) +{ + return platform_driver_register(&au1k_irda_driver); +} + +static void __exit au1k_irda_unload(void) +{ + return platform_driver_unregister(&au1k_irda_driver); +} + MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>"); MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); -module_init(au1k_irda_init); -module_exit(au1k_irda_exit); +module_init(au1k_irda_load); +module_exit(au1k_irda_unload); diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index f2f820c4b40a..9ea99217f116 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -173,6 +173,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) skb = ip_check_defrag(skb, IP_DEFRAG_MACVLAN); if (!skb) return RX_HANDLER_CONSUMED; + eth = eth_hdr(skb); src = macvlan_hash_lookup(port, eth->h_source); if (!src) /* frame comes from an external address */ diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 88cc5db9affd..8985cc62cf41 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -38,12 +38,11 @@ /** * mdiobus_alloc_size - allocate a mii_bus structure + * @size: extra amount of memory to allocate for private storage. + * If non-zero, then bus->priv is points to that memory. * * Description: called by a bus driver to allocate an mii_bus * structure to fill in. - * - * 'size' is an an extra amount of memory to allocate for private storage. - * If non-zero, then bus->priv is points to that memory. */ struct mii_bus *mdiobus_alloc_size(size_t size) { diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index ed2a862b835d..6b678f38e5ce 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -92,9 +92,9 @@ struct team_option *__team_find_option(struct team *team, const char *opt_name) return NULL; } -int team_options_register(struct team *team, - const struct team_option *option, - size_t option_count) +int __team_options_register(struct team *team, + const struct team_option *option, + size_t option_count) { int i; struct team_option **dst_opts; @@ -116,8 +116,11 @@ int team_options_register(struct team *team, } } - for (i = 0; i < option_count; i++) + for (i = 0; i < option_count; i++) { + dst_opts[i]->changed = true; + dst_opts[i]->removed = false; list_add_tail(&dst_opts[i]->list, &team->option_list); + } kfree(dst_opts); return 0; @@ -130,10 +133,22 @@ rollback: return err; } -EXPORT_SYMBOL(team_options_register); +static void __team_options_mark_removed(struct team *team, + const struct team_option *option, + size_t option_count) +{ + int i; + + for (i = 0; i < option_count; i++, option++) { + struct team_option *del_opt; -static void __team_options_change_check(struct team *team, - struct team_option *changed_option); + del_opt = __team_find_option(team, option->name); + if (del_opt) { + del_opt->changed = true; + del_opt->removed = true; + } + } +} static void __team_options_unregister(struct team *team, const struct team_option *option, @@ -152,12 +167,29 @@ static void __team_options_unregister(struct team *team, } } +static void __team_options_change_check(struct team *team); + +int team_options_register(struct team *team, + const struct team_option *option, + size_t option_count) +{ + int err; + + err = __team_options_register(team, option, option_count); + if (err) + return err; + __team_options_change_check(team); + return 0; +} +EXPORT_SYMBOL(team_options_register); + void team_options_unregister(struct team *team, const struct team_option *option, size_t option_count) { + __team_options_mark_removed(team, option, option_count); + __team_options_change_check(team); __team_options_unregister(team, option, option_count); - __team_options_change_check(team, NULL); } EXPORT_SYMBOL(team_options_unregister); @@ -176,7 +208,8 @@ static int team_option_set(struct team *team, struct team_option *option, if (err) return err; - __team_options_change_check(team, option); + option->changed = true; + __team_options_change_check(team); return err; } @@ -653,6 +686,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev) return -ENOENT; } + port->removed = true; __team_port_change_check(port, false); team_port_list_del_port(team, port); team_adjust_ops(team); @@ -1200,10 +1234,9 @@ err_fill: return err; } -static int team_nl_fill_options_get_changed(struct sk_buff *skb, - u32 pid, u32 seq, int flags, - struct team *team, - struct team_option *changed_option) +static int team_nl_fill_options_get(struct sk_buff *skb, + u32 pid, u32 seq, int flags, + struct team *team, bool fillall) { struct nlattr *option_list; void *hdr; @@ -1223,12 +1256,19 @@ static int team_nl_fill_options_get_changed(struct sk_buff *skb, struct nlattr *option_item; long arg; + /* Include only changed options if fill all mode is not on */ + if (!fillall && !option->changed) + continue; option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION); if (!option_item) goto nla_put_failure; NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_NAME, option->name); - if (option == changed_option) + if (option->changed) { NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_CHANGED); + option->changed = false; + } + if (option->removed) + NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_REMOVED); switch (option->type) { case TEAM_OPTION_TYPE_U32: NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32); @@ -1255,13 +1295,13 @@ nla_put_failure: return -EMSGSIZE; } -static int team_nl_fill_options_get(struct sk_buff *skb, - struct genl_info *info, int flags, - struct team *team) +static int team_nl_fill_options_get_all(struct sk_buff *skb, + struct genl_info *info, int flags, + struct team *team) { - return team_nl_fill_options_get_changed(skb, info->snd_pid, - info->snd_seq, NLM_F_ACK, - team, NULL); + return team_nl_fill_options_get(skb, info->snd_pid, + info->snd_seq, NLM_F_ACK, + team, true); } static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info) @@ -1273,7 +1313,7 @@ static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info) if (!team) return -EINVAL; - err = team_nl_send_generic(info, team, team_nl_fill_options_get); + err = team_nl_send_generic(info, team, team_nl_fill_options_get_all); team_nl_team_put(team); @@ -1365,10 +1405,10 @@ team_put: return err; } -static int team_nl_fill_port_list_get_changed(struct sk_buff *skb, - u32 pid, u32 seq, int flags, - struct team *team, - struct team_port *changed_port) +static int team_nl_fill_port_list_get(struct sk_buff *skb, + u32 pid, u32 seq, int flags, + struct team *team, + bool fillall) { struct nlattr *port_list; void *hdr; @@ -1387,12 +1427,19 @@ static int team_nl_fill_port_list_get_changed(struct sk_buff *skb, list_for_each_entry(port, &team->port_list, list) { struct nlattr *port_item; + /* Include only changed ports if fill all mode is not on */ + if (!fillall && !port->changed) + continue; port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT); if (!port_item) goto nla_put_failure; NLA_PUT_U32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex); - if (port == changed_port) + if (port->changed) { NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_CHANGED); + port->changed = false; + } + if (port->removed) + NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_REMOVED); if (port->linkup) NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_LINKUP); NLA_PUT_U32(skb, TEAM_ATTR_PORT_SPEED, port->speed); @@ -1408,13 +1455,13 @@ nla_put_failure: return -EMSGSIZE; } -static int team_nl_fill_port_list_get(struct sk_buff *skb, - struct genl_info *info, int flags, - struct team *team) +static int team_nl_fill_port_list_get_all(struct sk_buff *skb, + struct genl_info *info, int flags, + struct team *team) { - return team_nl_fill_port_list_get_changed(skb, info->snd_pid, - info->snd_seq, NLM_F_ACK, - team, NULL); + return team_nl_fill_port_list_get(skb, info->snd_pid, + info->snd_seq, NLM_F_ACK, + team, true); } static int team_nl_cmd_port_list_get(struct sk_buff *skb, @@ -1427,7 +1474,7 @@ static int team_nl_cmd_port_list_get(struct sk_buff *skb, if (!team) return -EINVAL; - err = team_nl_send_generic(info, team, team_nl_fill_port_list_get); + err = team_nl_send_generic(info, team, team_nl_fill_port_list_get_all); team_nl_team_put(team); @@ -1464,8 +1511,7 @@ static struct genl_multicast_group team_change_event_mcgrp = { .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, }; -static int team_nl_send_event_options_get(struct team *team, - struct team_option *changed_option) +static int team_nl_send_event_options_get(struct team *team) { struct sk_buff *skb; int err; @@ -1475,8 +1521,7 @@ static int team_nl_send_event_options_get(struct team *team, if (!skb) return -ENOMEM; - err = team_nl_fill_options_get_changed(skb, 0, 0, 0, team, - changed_option); + err = team_nl_fill_options_get(skb, 0, 0, 0, team, false); if (err < 0) goto err_fill; @@ -1489,18 +1534,17 @@ err_fill: return err; } -static int team_nl_send_event_port_list_get(struct team_port *port) +static int team_nl_send_event_port_list_get(struct team *team) { struct sk_buff *skb; int err; - struct net *net = dev_net(port->team->dev); + struct net *net = dev_net(team->dev); skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb) return -ENOMEM; - err = team_nl_fill_port_list_get_changed(skb, 0, 0, 0, - port->team, port); + err = team_nl_fill_port_list_get(skb, 0, 0, 0, team, false); if (err < 0) goto err_fill; @@ -1544,12 +1588,11 @@ static void team_nl_fini(void) * Change checkers ******************/ -static void __team_options_change_check(struct team *team, - struct team_option *changed_option) +static void __team_options_change_check(struct team *team) { int err; - err = team_nl_send_event_options_get(team, changed_option); + err = team_nl_send_event_options_get(team); if (err) netdev_warn(team->dev, "Failed to send options change via netlink\n"); } @@ -1559,9 +1602,10 @@ static void __team_port_change_check(struct team_port *port, bool linkup) { int err; - if (port->linkup == linkup) + if (!port->removed && port->linkup == linkup) return; + port->changed = true; port->linkup = linkup; if (linkup) { struct ethtool_cmd ecmd; @@ -1577,7 +1621,7 @@ static void __team_port_change_check(struct team_port *port, bool linkup) port->duplex = 0; send_event: - err = team_nl_send_event_port_list_get(port); + err = team_nl_send_event_port_list_get(port->team); if (err) netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink\n", port->dev->name); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ee7759575050..87db1ee1c298 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1037,13 +1037,16 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) /* * Workaround for early ACK timeouts, add an offset to match the - * initval's 64us ack timeout value. + * initval's 64us ack timeout value. Use 48us for the CTS timeout. * This was initially only meant to work around an issue with delayed * BA frames in some implementations, but it has been found to fix ACK * timeout issues in other cases as well. */ - if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) + if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ) { acktimeout += 64 - sifstime - ah->slottime; + ctstimeout += 48 - sifstime - ah->slottime; + } + ath9k_hw_set_sifs_time(ah, sifstime); ath9k_hw_setslottime(ah, slottime); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index abf943557dee..53a005d288aa 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -822,6 +822,11 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, ARRAY_SIZE(ath9k_tpt_blink)); #endif + INIT_WORK(&sc->hw_reset_work, ath_reset_work); + INIT_WORK(&sc->hw_check_work, ath_hw_check); + INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); + INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); + /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) @@ -840,10 +845,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, goto error_world; } - INIT_WORK(&sc->hw_reset_work, ath_reset_work); - INIT_WORK(&sc->hw_check_work, ath_hw_check); - INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); - INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 635b592ad961..a427a16bb739 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1346,7 +1346,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, fc = hdr->frame_control; for (i = 0; i < sc->hw->max_rates; i++) { struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; - if (!rate->count) + if (rate->idx < 0 || !rate->count) break; final_ts_idx = i; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 0e666fbe0842..7e1a91af1497 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -822,6 +822,14 @@ static bool ath9k_rx_accept(struct ath_common *common, (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | ATH9K_RXERR_KEYMISS)); + /* + * Key miss events are only relevant for pairwise keys where the + * descriptor does contain a valid key index. This has been observed + * mostly with CCMP encryption. + */ + if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID) + rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; + if (!rx_stats->rs_datalen) return false; /* diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a8c6880af34b..64f8db685dc5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -91,6 +91,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { + tx_cmd->tid_tspec = IWL_TID_NON_QOS; if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; else @@ -620,7 +621,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = sta_priv->max_agg_bufsize; - IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n", + IWL_DEBUG_HT(priv, "Tx aggregation enabled on ra = %pM tid = %d\n", sta->addr, tid); return iwl_send_lq_cmd(priv, ctx, @@ -808,6 +809,8 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, u32 status = le16_to_cpu(tx_resp->status.status); int i; + WARN_ON(tid == IWL_TID_NON_QOS); + if (agg->wait_for_ba) IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n"); @@ -1035,10 +1038,13 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, } __skb_queue_head_init(&skbs); - priv->tid_data[sta_id][tid].next_reclaimed = next_reclaimed; - IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d", - next_reclaimed); + if (tid != IWL_TID_NON_QOS) { + priv->tid_data[sta_id][tid].next_reclaimed = + next_reclaimed; + IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d", + next_reclaimed); + } /*we can free until ssn % q.n_bd not inclusive */ WARN_ON(iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id, diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index b4779c25a4b3..c20618d92268 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -815,6 +815,7 @@ struct iwl_qosparam_cmd { #define IWL_INVALID_STATION 255 #define IWL_MAX_TID_COUNT 8 +#define IWL_TID_NON_QOS IWL_MAX_TID_COUNT #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) #define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 836caf9c68b3..f5cb5d3cd926 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -1554,6 +1554,7 @@ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, txq->time_stamp = jiffies; if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE && + tid != IWL_TID_NON_QOS && txq_id != trans_pcie->agg_txq[sta_id][tid])) { /* * FIXME: this is a uCode bug which need to be addressed, diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 478d2f12c024..8d8ee639fe56 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -867,7 +867,12 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, ret = mwifiex_set_rf_channel(priv, channel, priv->adapter->channel_type); - ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */ + /* As this is new association, clear locally stored + * keys and security related flags */ + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + priv->wep_key_curr_index = 0; + ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); if (mode == NL80211_IFTYPE_ADHOC) { /* "privacy" is set only for ad-hoc mode */ @@ -912,6 +917,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, dev_dbg(priv->adapter->dev, "info: setting wep encryption" " with key len %d\n", sme->key_len); + priv->wep_key_curr_index = sme->key_idx; ret = mwifiex_set_encode(priv, sme->key, sme->key_len, sme->key_idx, 0); } diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 83cc10fca4bd..ca59cc0d013e 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -383,7 +383,8 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter) adapter->if_ops.cleanup_if(adapter); - dev_kfree_skb_any(adapter->sleep_cfm); + if (adapter->sleep_cfm) + dev_kfree_skb_any(adapter->sleep_cfm); } /* diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 80e44566bf6e..790a3796483c 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -811,7 +811,9 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) continue; rtnl_lock(); - mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); + if (priv->wdev && priv->netdev) + mwifiex_del_virtual_intf(priv->wdev->wiphy, + priv->netdev); rtnl_unlock(); } @@ -819,9 +821,11 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) if (!priv) goto exit_remove; - wiphy_unregister(priv->wdev->wiphy); - wiphy_free(priv->wdev->wiphy); - kfree(priv->wdev); + if (priv->wdev) { + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + kfree(priv->wdev); + } mwifiex_terminate_workqueue(adapter); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 470ca75ec250..b0fbf5d4fea0 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -54,7 +54,7 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { bool cancel_flag = false; - int status = adapter->cmd_wait_q.status; + int status; struct cmd_ctrl_node *cmd_queued; if (!adapter->cmd_queued) @@ -79,6 +79,8 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) mwifiex_cancel_pending_ioctl(adapter); dev_dbg(adapter->dev, "cmd cancel\n"); } + + status = adapter->cmd_wait_q.status; adapter->cmd_wait_q.status = 0; return status; @@ -240,6 +242,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, if (!netif_queue_stopped(priv->netdev)) mwifiex_stop_net_dev_queue(priv->netdev, adapter); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); /* Clear any past association response stored for * application retrieval */ @@ -271,6 +275,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, if (!netif_queue_stopped(priv->netdev)) mwifiex_stop_net_dev_queue(priv->netdev, adapter); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); if (!ret) { dev_dbg(adapter->dev, "info: network found in scan" diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 52728be65271..772d4aec303a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -513,9 +513,9 @@ EXPORT_SYMBOL_GPL(rt2800_write_tx_data); static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2) { - int rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0); - int rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1); - int rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2); + s8 rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0); + s8 rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1); + s8 rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2); u16 eeprom; u8 offset0; u8 offset1; @@ -551,7 +551,7 @@ static int rt2800_agc_to_rssi(struct rt2x00_dev *rt2x00dev, u32 rxwi_w2) * which gives less energy... */ rssi0 = max(rssi0, rssi1); - return max(rssi0, rssi2); + return (int)max(rssi0, rssi2); } void rt2800_process_rxwi(struct queue_entry *entry, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 0a70149df3fc..98a574a4a465 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -866,6 +866,14 @@ static int fill_ctrlset(struct zd_mac *mac, ZD_ASSERT(frag_len <= 0xffff); + /* + * Firmware computes the duration itself (for all frames except PSPoll) + * and needs the field set to 0 at input, otherwise firmware messes up + * duration_id and sets bits 14 and 15 on. + */ + if (!ieee80211_is_pspoll(hdr->frame_control)) + hdr->duration_id = 0; + txrate = ieee80211_get_tx_rate(mac->hw, info); cs->modulation = txrate->hw_value; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index fa679057630f..698b905058dd 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -68,7 +68,7 @@ struct netfront_cb { #define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) #define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE) -#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) +#define TX_MAX_TARGET min_t(int, NET_TX_RING_SIZE, 256) struct netfront_stats { u64 rx_packets; diff --git a/drivers/of/address.c b/drivers/of/address.c index 72c33fbe451d..66d96f14c274 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -14,7 +14,7 @@ static struct of_bus *of_match_bus(struct device_node *np); static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, - struct resource *r); + const char *name, struct resource *r); /* Debug utility */ #ifdef DEBUG @@ -215,7 +215,7 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, addrp = of_get_pci_address(dev, bar, &size, &flags); if (addrp == NULL) return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); + return __of_address_to_resource(dev, addrp, size, flags, NULL, r); } EXPORT_SYMBOL_GPL(of_pci_address_to_resource); #endif /* CONFIG_PCI */ @@ -529,7 +529,7 @@ EXPORT_SYMBOL(of_get_address); static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, - struct resource *r) + const char *name, struct resource *r) { u64 taddr; @@ -551,7 +551,8 @@ static int __of_address_to_resource(struct device_node *dev, r->end = taddr + size - 1; } r->flags = flags; - r->name = dev->full_name; + r->name = name ? name : dev->full_name; + return 0; } @@ -569,11 +570,16 @@ int of_address_to_resource(struct device_node *dev, int index, const __be32 *addrp; u64 size; unsigned int flags; + const char *name = NULL; addrp = of_get_address(dev, index, &size, &flags); if (addrp == NULL) return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); + + /* Get optional "reg-names" property to add a name to a resource */ + of_property_read_string_index(dev, "reg-names", index, &name); + + return __of_address_to_resource(dev, addrp, size, flags, name, r); } EXPORT_SYMBOL_GPL(of_address_to_resource); diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 0f0cfa3bca30..9cf00602f566 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -341,9 +341,18 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) /* Only dereference the resource if both the * resource and the irq are valid. */ if (r && irq) { + const char *name = NULL; + + /* + * Get optional "interrupts-names" property to add a name + * to the resource. + */ + of_property_read_string_index(dev, "interrupt-names", index, + &name); + r->start = r->end = irq; r->flags = IORESOURCE_IRQ; - r->name = dev->full_name; + r->name = name ? name : dev->full_name; } return irq; diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c index 0dc34f12f92e..d4716273651e 100644 --- a/drivers/parport/parport_ip32.c +++ b/drivers/parport/parport_ip32.c @@ -135,7 +135,7 @@ #define PARPORT_IP32_ENABLE_EPP (1U << 3) #define PARPORT_IP32_ENABLE_ECP (1U << 4) static unsigned int features = ~0U; -static int verbose_probing = DEFAULT_VERBOSE_PROBING; +static bool verbose_probing = DEFAULT_VERBOSE_PROBING; /* We do not support more than one port. */ static struct parport *this_port = NULL; diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 095f29e13734..2a47e82821da 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -44,7 +44,7 @@ #define METHOD_NAME__SUN "_SUN" #define METHOD_NAME_OSHP "OSHP" -static int debug_acpi; +static bool debug_acpi; static acpi_status decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx) diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index efa9f2de51c1..aa41631e9e02 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -47,7 +47,7 @@ /* name size which is used for entries in pcihpfs */ #define SLOT_NAME_SIZE 21 /* {_SUN} */ -static int debug; +static bool debug; int acpiphp_debug; /* local variables */ diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index e525263210ee..c35e8ad6db01 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -43,7 +43,7 @@ #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver IBM extension" -static int debug; +static bool debug; MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index 41f6a8d79c81..6bf8d2ab164f 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -57,8 +57,8 @@ #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) /* local variables */ -static int debug; -static int poll; +static bool debug; +static bool poll; static struct cpci_hp_controller_ops zt5550_hpc_ops; static struct cpci_hp_controller zt5550_hpc; diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index f1ce99cceac6..187a199da93c 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -57,8 +57,8 @@ struct irq_routing_table *cpqhp_routing_table; static void __iomem *smbios_table; static void __iomem *smbios_start; static void __iomem *cpqhp_rom_start; -static int power_mode; -static int debug; +static bool power_mode; +static bool debug; static int initialized; #define DRIVER_VERSION "0.9.8" diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index d934dd4fa873..5506e0e8fbc0 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -49,7 +49,7 @@ int ibmphp_debug; -static int debug; +static bool debug; module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); MODULE_LICENSE ("GPL"); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 6d2eea93298f..202f4a969eb5 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -51,7 +51,7 @@ /* local variables */ -static int debug; +static bool debug; #define DRIVER_VERSION "0.5" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 9a33fdde2d16..4b7cce1de6ec 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -40,10 +40,10 @@ #define MY_NAME "pciehp" -extern int pciehp_poll_mode; +extern bool pciehp_poll_mode; extern int pciehp_poll_time; -extern int pciehp_debug; -extern int pciehp_force; +extern bool pciehp_debug; +extern bool pciehp_force; extern struct workqueue_struct *pciehp_wq; #define dbg(format, arg...) \ diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index b8c99d35ac97..365c6b96c642 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -38,10 +38,10 @@ #include <linux/time.h> /* Global variables */ -int pciehp_debug; -int pciehp_poll_mode; +bool pciehp_debug; +bool pciehp_poll_mode; int pciehp_poll_time; -int pciehp_force; +bool pciehp_force; struct workqueue_struct *pciehp_wq; #define DRIVER_VERSION "0.4" diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index 5175d9b26f0b..b20ceaaa31f4 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -59,7 +59,7 @@ static LIST_HEAD(slot_list); #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) /* local variables */ -static int debug; +static bool debug; static int num_slots; #define DRIVER_VERSION "0.3" diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 419919a87b0f..df5677440a08 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -46,7 +46,7 @@ #define PRESENT 1 /* Card in slot */ #define MY_NAME "rpaphp" -extern int rpaphp_debug; +extern bool rpaphp_debug; #define dbg(format, arg...) \ do { \ if (rpaphp_debug) \ diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 758adb5f47fd..127d6e600185 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -37,7 +37,7 @@ /* and pci_do_scan_bus */ #include "rpaphp.h" -int rpaphp_debug; +bool rpaphp_debug; LIST_HEAD(rpaphp_slot_head); #define DRIVER_VERSION "0.1" diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index e0c90e643b5f..ca64932e658b 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -43,9 +43,9 @@ #define MY_NAME THIS_MODULE->name #endif -extern int shpchp_poll_mode; +extern bool shpchp_poll_mode; extern int shpchp_poll_time; -extern int shpchp_debug; +extern bool shpchp_debug; extern struct workqueue_struct *shpchp_wq; extern struct workqueue_struct *shpchp_ordered_wq; diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index dd7e0c51a33e..7414fd9ad1d2 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -36,8 +36,8 @@ #include "shpchp.h" /* Global variables */ -int shpchp_debug; -int shpchp_poll_mode; +bool shpchp_debug; +bool shpchp_poll_mode; int shpchp_poll_time; struct workqueue_struct *shpchp_wq; struct workqueue_struct *shpchp_ordered_wq; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 106be0d08f81..a3cd8cad532a 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -432,7 +432,7 @@ pci_read_config(struct file *filp, struct kobject *kobj, u8 *data = (u8*) buf; /* Several chips lock up trying to read undefined config space */ - if (security_capable(&init_user_ns, filp->f_cred, CAP_SYS_ADMIN) == 0) { + if (security_capable(filp->f_cred, &init_user_ns, CAP_SYS_ADMIN) == 0) { size = dev->cfg_size; } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { size = 128; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 97fff785e97e..af295bb21d62 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2802,7 +2802,7 @@ pci_intx(struct pci_dev *pdev, int enable) /** * pci_intx_mask_supported - probe for INTx masking support - * @pdev: the PCI device to operate on + * @dev: the PCI device to operate on * * Check if the device dev support INTx masking via the config space * command word. @@ -2884,7 +2884,7 @@ done: /** * pci_check_and_mask_intx - mask INTx on pending interrupt - * @pdev: the PCI device to operate on + * @dev: the PCI device to operate on * * Check if the device dev has its INTx line asserted, mask it and * return true in that case. False is returned if not interrupt was @@ -2898,7 +2898,7 @@ EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); /** * pci_check_and_mask_intx - unmask INTx of no interrupt is pending - * @pdev: the PCI device to operate on + * @dev: the PCI device to operate on * * Check if the device dev has its INTx line asserted, unmask it if not * and return true. False is returned and the mask remains active if diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index 95489cd9a555..52229863e9fe 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -28,7 +28,7 @@ #include "aerdrv.h" /* Override the existing corrected and uncorrected error masks */ -static int aer_mask_override; +static bool aer_mask_override; module_param(aer_mask_override, bool, 0); struct aer_error_inj { diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 9674e9f30d49..0ca053538146 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -27,8 +27,8 @@ #include <linux/kfifo.h> #include "aerdrv.h" -static int forceload; -static int nosourceid; +static bool forceload; +static bool nosourceid; module_param(forceload, bool, 0); module_param(nosourceid, bool, 0); diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 6e318ce41136..f9e3fb3a285b 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -155,18 +155,14 @@ config PCMCIA_M8XX This driver is also available as a module called m8xx_pcmcia. -config PCMCIA_AU1X00 - tristate "Au1x00 pcmcia support" - depends on MIPS_ALCHEMY && PCMCIA - config PCMCIA_ALCHEMY_DEVBOARD tristate "Alchemy Db/Pb1xxx PCMCIA socket services" depends on MIPS_ALCHEMY && PCMCIA select 64BIT_PHYS_ADDR help Enable this driver of you want PCMCIA support on your Alchemy - Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200 board. - NOT suitable for the PB1000! + Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200, DB1300 + board. NOT suitable for the PB1000! This driver is also available as a module called db1xxx_ss.ko diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 29935ea921df..ec543a4ff2e4 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -29,7 +29,6 @@ obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_base.o sa1100_cs.o obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_base.o sa1111_cs.o obj-$(CONFIG_M32R_PCC) += m32r_pcc.o obj-$(CONFIG_M32R_CFC) += m32r_cfc.o -obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o obj-$(CONFIG_PCMCIA_BCM63XX) += bcm63xx_pcmcia.o obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o @@ -39,9 +38,6 @@ obj-$(CONFIG_AT91_CF) += at91_cf.o obj-$(CONFIG_ELECTRA_CF) += electra_cf.o obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o -au1x00_ss-y += au1000_generic.o -au1x00_ss-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o - sa1111_cs-y += sa1111_generic.o sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_cs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c deleted file mode 100644 index 95dd7c62741f..000000000000 --- a/drivers/pcmcia/au1000_generic.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * - * Alchemy Semi Au1000 pcmcia driver - * - * Copyright 2001-2003 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@embeddedalley.com or source@mvista.com - * - * Copyright 2004 Pete Popov, Embedded Alley Solutions, Inc. - * Updated the driver to 2.6. Followed the sa11xx API and largely - * copied many of the hardware independent functions. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/cpufreq.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/notifier.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> - -#include <asm/mach-au1x00/au1000.h> -#include "au1000_generic.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Pete Popov <ppopov@embeddedalley.com>"); -MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller"); - -#if 0 -#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) -#else -#define debug(x,args...) -#endif - -#define MAP_SIZE 0x100000 -extern struct au1000_pcmcia_socket au1000_pcmcia_socket[]; -#define PCMCIA_SOCKET(x) (au1000_pcmcia_socket + (x)) -#define to_au1000_socket(x) container_of(x, struct au1000_pcmcia_socket, socket) - -/* Some boards like to support CF cards as IDE root devices, so they - * grab pcmcia sockets directly. - */ -u32 *pcmcia_base_vaddrs[2]; -extern const unsigned long mips_io_port_base; - -static DEFINE_MUTEX(pcmcia_sockets_lock); - -static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = { - au1x_board_init, -}; - -static int -au1x00_pcmcia_skt_state(struct au1000_pcmcia_socket *skt) -{ - struct pcmcia_state state; - unsigned int stat; - - memset(&state, 0, sizeof(struct pcmcia_state)); - - skt->ops->socket_state(skt, &state); - - stat = state.detect ? SS_DETECT : 0; - stat |= state.ready ? SS_READY : 0; - stat |= state.wrprot ? SS_WRPROT : 0; - stat |= state.vs_3v ? SS_3VCARD : 0; - stat |= state.vs_Xv ? SS_XVCARD : 0; - stat |= skt->cs_state.Vcc ? SS_POWERON : 0; - - if (skt->cs_state.flags & SS_IOCARD) - stat |= state.bvd1 ? SS_STSCHG : 0; - else { - if (state.bvd1 == 0) - stat |= SS_BATDEAD; - else if (state.bvd2 == 0) - stat |= SS_BATWARN; - } - return stat; -} - -/* - * au100_pcmcia_config_skt - * - * Convert PCMCIA socket state to our socket configure structure. - */ -static int -au1x00_pcmcia_config_skt(struct au1000_pcmcia_socket *skt, socket_state_t *state) -{ - int ret; - - ret = skt->ops->configure_socket(skt, state); - if (ret == 0) { - skt->cs_state = *state; - } - - if (ret < 0) - debug("unable to configure socket %d\n", skt->nr); - - return ret; -} - -/* au1x00_pcmcia_sock_init() - * - * (Re-)Initialise the socket, turning on status interrupts - * and PCMCIA bus. This must wait for power to stabilise - * so that the card status signals report correctly. - * - * Returns: 0 - */ -static int au1x00_pcmcia_sock_init(struct pcmcia_socket *sock) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - - debug("initializing socket %u\n", skt->nr); - - skt->ops->socket_init(skt); - return 0; -} - -/* - * au1x00_pcmcia_suspend() - * - * Remove power on the socket, disable IRQs from the card. - * Turn off status interrupts, and disable the PCMCIA bus. - * - * Returns: 0 - */ -static int au1x00_pcmcia_suspend(struct pcmcia_socket *sock) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - - debug("suspending socket %u\n", skt->nr); - - skt->ops->socket_suspend(skt); - - return 0; -} - -static DEFINE_SPINLOCK(status_lock); - -/* - * au1x00_check_status() - */ -static void au1x00_check_status(struct au1000_pcmcia_socket *skt) -{ - unsigned int events; - - debug("entering PCMCIA monitoring thread\n"); - - do { - unsigned int status; - unsigned long flags; - - status = au1x00_pcmcia_skt_state(skt); - - spin_lock_irqsave(&status_lock, flags); - events = (status ^ skt->status) & skt->cs_state.csc_mask; - skt->status = status; - spin_unlock_irqrestore(&status_lock, flags); - - debug("events: %s%s%s%s%s%s\n", - events == 0 ? "<NONE>" : "", - events & SS_DETECT ? "DETECT " : "", - events & SS_READY ? "READY " : "", - events & SS_BATDEAD ? "BATDEAD " : "", - events & SS_BATWARN ? "BATWARN " : "", - events & SS_STSCHG ? "STSCHG " : ""); - - if (events) - pcmcia_parse_events(&skt->socket, events); - } while (events); -} - -/* - * au1x00_pcmcia_poll_event() - * Let's poll for events in addition to IRQs since IRQ only is unreliable... - */ -static void au1x00_pcmcia_poll_event(unsigned long dummy) -{ - struct au1000_pcmcia_socket *skt = (struct au1000_pcmcia_socket *)dummy; - debug("polling for events\n"); - - mod_timer(&skt->poll_timer, jiffies + AU1000_PCMCIA_POLL_PERIOD); - - au1x00_check_status(skt); -} - -/* au1x00_pcmcia_get_status() - * - * From the sa11xx_core.c: - * Implements the get_status() operation for the in-kernel PCMCIA - * service (formerly SS_GetStatus in Card Services). Essentially just - * fills in bits in `status' according to internal driver state or - * the value of the voltage detect chipselect register. - * - * As a debugging note, during card startup, the PCMCIA core issues - * three set_socket() commands in a row the first with RESET deasserted, - * the second with RESET asserted, and the last with RESET deasserted - * again. Following the third set_socket(), a get_status() command will - * be issued. The kernel is looking for the SS_READY flag (see - * setup_socket(), reset_socket(), and unreset_socket() in cs.c). - * - * Returns: 0 - */ -static int -au1x00_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - - skt->status = au1x00_pcmcia_skt_state(skt); - *status = skt->status; - - return 0; -} - -/* au1x00_pcmcia_set_socket() - * Implements the set_socket() operation for the in-kernel PCMCIA - * service (formerly SS_SetSocket in Card Services). We more or - * less punt all of this work and let the kernel handle the details - * of power configuration, reset, &c. We also record the value of - * `state' in order to regurgitate it to the PCMCIA core later. - * - * Returns: 0 - */ -static int -au1x00_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - - debug("for sock %u\n", skt->nr); - - debug("\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", - (state->csc_mask==0)?"<NONE>":"", - (state->csc_mask&SS_DETECT)?"DETECT ":"", - (state->csc_mask&SS_READY)?"READY ":"", - (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", - (state->csc_mask&SS_BATWARN)?"BATWARN ":"", - (state->csc_mask&SS_STSCHG)?"STSCHG ":"", - (state->flags==0)?"<NONE>":"", - (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", - (state->flags&SS_IOCARD)?"IOCARD ":"", - (state->flags&SS_RESET)?"RESET ":"", - (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); - debug("\tVcc %d Vpp %d irq %d\n", - state->Vcc, state->Vpp, state->io_irq); - - return au1x00_pcmcia_config_skt(skt, state); -} - -int -au1x00_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - unsigned int speed; - - if(map->map>=MAX_IO_WIN){ - debug("map (%d) out of range\n", map->map); - return -1; - } - - if(map->flags&MAP_ACTIVE){ - speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED; - skt->spd_io[map->map] = speed; - } - - map->start=(unsigned int)(u32)skt->virt_io; - map->stop=map->start+MAP_SIZE; - return 0; - -} /* au1x00_pcmcia_set_io_map() */ - - -static int -au1x00_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - unsigned short speed = map->speed; - - if(map->map>=MAX_WIN){ - debug("map (%d) out of range\n", map->map); - return -1; - } - - if (map->flags & MAP_ATTRIB) { - skt->spd_attr[map->map] = speed; - skt->spd_mem[map->map] = 0; - } else { - skt->spd_attr[map->map] = 0; - skt->spd_mem[map->map] = speed; - } - - if (map->flags & MAP_ATTRIB) { - map->static_start = skt->phys_attr + map->card_start; - } - else { - map->static_start = skt->phys_mem + map->card_start; - } - - debug("set_mem_map %d start %08lx card_start %08x\n", - map->map, map->static_start, map->card_start); - return 0; - -} /* au1x00_pcmcia_set_mem_map() */ - -static struct pccard_operations au1x00_pcmcia_operations = { - .init = au1x00_pcmcia_sock_init, - .suspend = au1x00_pcmcia_suspend, - .get_status = au1x00_pcmcia_get_status, - .set_socket = au1x00_pcmcia_set_socket, - .set_io_map = au1x00_pcmcia_set_io_map, - .set_mem_map = au1x00_pcmcia_set_mem_map, -}; - -static const char *skt_names[] = { - "PCMCIA socket 0", - "PCMCIA socket 1", -}; - -struct skt_dev_info { - int nskt; -}; - -int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) -{ - struct skt_dev_info *sinfo; - struct au1000_pcmcia_socket *skt; - int ret, i; - - sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL); - if (!sinfo) { - ret = -ENOMEM; - goto out; - } - - sinfo->nskt = nr; - - /* - * Initialise the per-socket structure. - */ - for (i = 0; i < nr; i++) { - skt = PCMCIA_SOCKET(i); - memset(skt, 0, sizeof(*skt)); - - skt->socket.resource_ops = &pccard_static_ops; - skt->socket.ops = &au1x00_pcmcia_operations; - skt->socket.owner = ops->owner; - skt->socket.dev.parent = dev; - - init_timer(&skt->poll_timer); - skt->poll_timer.function = au1x00_pcmcia_poll_event; - skt->poll_timer.data = (unsigned long)skt; - skt->poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD; - - skt->nr = first + i; - skt->irq = 255; - skt->dev = dev; - skt->ops = ops; - - skt->res_skt.name = skt_names[skt->nr]; - skt->res_io.name = "io"; - skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - skt->res_mem.name = "memory"; - skt->res_mem.flags = IORESOURCE_MEM; - skt->res_attr.name = "attribute"; - skt->res_attr.flags = IORESOURCE_MEM; - - /* - * PCMCIA client drivers use the inb/outb macros to access the - * IO registers. Since mips_io_port_base is added to the - * access address of the mips implementation of inb/outb, - * we need to subtract it here because we want to access the - * I/O or MEM address directly, without going through this - * "mips_io_port_base" mechanism. - */ - if (i == 0) { - skt->virt_io = (void *) - (ioremap((phys_t)AU1X_SOCK0_IO, 0x1000) - - (u32)mips_io_port_base); - skt->phys_attr = AU1X_SOCK0_PHYS_ATTR; - skt->phys_mem = AU1X_SOCK0_PHYS_MEM; - } - else { - skt->virt_io = (void *) - (ioremap((phys_t)AU1X_SOCK1_IO, 0x1000) - - (u32)mips_io_port_base); - skt->phys_attr = AU1X_SOCK1_PHYS_ATTR; - skt->phys_mem = AU1X_SOCK1_PHYS_MEM; - } - pcmcia_base_vaddrs[i] = (u32 *)skt->virt_io; - ret = ops->hw_init(skt); - - skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; - skt->socket.irq_mask = 0; - skt->socket.map_size = MAP_SIZE; - skt->socket.pci_irq = skt->irq; - skt->socket.io_offset = (unsigned long)skt->virt_io; - - skt->status = au1x00_pcmcia_skt_state(skt); - - ret = pcmcia_register_socket(&skt->socket); - if (ret) - goto out_err; - - WARN_ON(skt->socket.sock != i); - - add_timer(&skt->poll_timer); - } - - dev_set_drvdata(dev, sinfo); - return 0; - - -out_err: - ops->hw_shutdown(skt); - while (i-- > 0) { - skt = PCMCIA_SOCKET(i); - - del_timer_sync(&skt->poll_timer); - pcmcia_unregister_socket(&skt->socket); - if (i == 0) { - iounmap(skt->virt_io + (u32)mips_io_port_base); - skt->virt_io = NULL; - } -#ifndef CONFIG_MIPS_XXS1500 - else { - iounmap(skt->virt_io + (u32)mips_io_port_base); - skt->virt_io = NULL; - } -#endif - ops->hw_shutdown(skt); - - } - kfree(sinfo); -out: - return ret; -} - -int au1x00_drv_pcmcia_remove(struct platform_device *dev) -{ - struct skt_dev_info *sinfo = platform_get_drvdata(dev); - int i; - - mutex_lock(&pcmcia_sockets_lock); - platform_set_drvdata(dev, NULL); - - for (i = 0; i < sinfo->nskt; i++) { - struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); - - del_timer_sync(&skt->poll_timer); - pcmcia_unregister_socket(&skt->socket); - skt->ops->hw_shutdown(skt); - au1x00_pcmcia_config_skt(skt, &dead_socket); - iounmap(skt->virt_io + (u32)mips_io_port_base); - skt->virt_io = NULL; - } - - kfree(sinfo); - mutex_unlock(&pcmcia_sockets_lock); - return 0; -} - - -/* - * PCMCIA "Driver" API - */ - -static int au1x00_drv_pcmcia_probe(struct platform_device *dev) -{ - int i, ret = -ENODEV; - - mutex_lock(&pcmcia_sockets_lock); - for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) { - ret = au1x00_pcmcia_hw_init[i](&dev->dev); - if (ret == 0) - break; - } - mutex_unlock(&pcmcia_sockets_lock); - return ret; -} - -static struct platform_driver au1x00_pcmcia_driver = { - .driver = { - .name = "au1x00-pcmcia", - .owner = THIS_MODULE, - }, - .probe = au1x00_drv_pcmcia_probe, - .remove = au1x00_drv_pcmcia_remove, -}; - - -/* au1x00_pcmcia_init() - * - * This routine performs low-level PCMCIA initialization and then - * registers this socket driver with Card Services. - * - * Returns: 0 on success, -ve error code on failure - */ -static int __init au1x00_pcmcia_init(void) -{ - int error = 0; - error = platform_driver_register(&au1x00_pcmcia_driver); - return error; -} - -/* au1x00_pcmcia_exit() - * Invokes the low-level kernel service to free IRQs associated with this - * socket controller and reset GPIO edge detection. - */ -static void __exit au1x00_pcmcia_exit(void) -{ - platform_driver_unregister(&au1x00_pcmcia_driver); -} - -module_init(au1x00_pcmcia_init); -module_exit(au1x00_pcmcia_exit); diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h deleted file mode 100644 index 5c36bda2963b..000000000000 --- a/drivers/pcmcia/au1000_generic.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Alchemy Semi Au1000 pcmcia driver include file - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - */ -#ifndef __ASM_AU1000_PCMCIA_H -#define __ASM_AU1000_PCMCIA_H - -/* include the world */ - -#include <pcmcia/ss.h> -#include <pcmcia/cistpl.h> -#include "cs_internal.h" - -#define AU1000_PCMCIA_POLL_PERIOD (2*HZ) -#define AU1000_PCMCIA_IO_SPEED (255) -#define AU1000_PCMCIA_MEM_SPEED (300) - -#define AU1X_SOCK0_IO 0xF00000000ULL -#define AU1X_SOCK0_PHYS_ATTR 0xF40000000ULL -#define AU1X_SOCK0_PHYS_MEM 0xF80000000ULL - -/* pcmcia socket 1 needs external glue logic so the memory map - * differs from board to board. - */ -#if defined(CONFIG_MIPS_PB1000) -#define AU1X_SOCK1_IO 0xF08000000ULL -#define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL -#define AU1X_SOCK1_PHYS_MEM 0xF88000000ULL -#endif - -struct pcmcia_state { - unsigned detect: 1, - ready: 1, - wrprot: 1, - bvd1: 1, - bvd2: 1, - vs_3v: 1, - vs_Xv: 1; -}; - -struct pcmcia_configure { - unsigned sock: 8, - vcc: 8, - vpp: 8, - output: 1, - speaker: 1, - reset: 1; -}; - -struct pcmcia_irqs { - int sock; - int irq; - const char *str; -}; - - -struct au1000_pcmcia_socket { - struct pcmcia_socket socket; - - /* - * Info from low level handler - */ - struct device *dev; - unsigned int nr; - unsigned int irq; - - /* - * Core PCMCIA state - */ - struct pcmcia_low_level *ops; - - unsigned int status; - socket_state_t cs_state; - - unsigned short spd_io[MAX_IO_WIN]; - unsigned short spd_mem[MAX_WIN]; - unsigned short spd_attr[MAX_WIN]; - - struct resource res_skt; - struct resource res_io; - struct resource res_mem; - struct resource res_attr; - - void * virt_io; - unsigned int phys_io; - unsigned int phys_attr; - unsigned int phys_mem; - unsigned short speed_io, speed_attr, speed_mem; - - unsigned int irq_state; - - struct timer_list poll_timer; -}; - -struct pcmcia_low_level { - struct module *owner; - - int (*hw_init)(struct au1000_pcmcia_socket *); - void (*hw_shutdown)(struct au1000_pcmcia_socket *); - - void (*socket_state)(struct au1000_pcmcia_socket *, struct pcmcia_state *); - int (*configure_socket)(struct au1000_pcmcia_socket *, struct socket_state_t *); - - /* - * Enable card status IRQs on (re-)initialisation. This can - * be called at initialisation, power management event, or - * pcmcia event. - */ - void (*socket_init)(struct au1000_pcmcia_socket *); - - /* - * Disable card status IRQs and PCMCIA bus on suspend. - */ - void (*socket_suspend)(struct au1000_pcmcia_socket *); -}; - -extern int au1x_board_init(struct device *dev); - -#endif /* __ASM_AU1000_PCMCIA_H */ diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c deleted file mode 100644 index b2396647a165..000000000000 --- a/drivers/pcmcia/au1000_pb1x00.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * - * Alchemy Semi Pb1000 boards specific pcmcia routines. - * - * Copyright 2002 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * ######################################################################## - * - * This program is free software; you can distribute 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 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/module.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/proc_fs.h> -#include <linux/types.h> - -#include <pcmcia/ss.h> -#include <pcmcia/cistpl.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> - -#include <asm/au1000.h> -#include <asm/au1000_pcmcia.h> - -#define debug(fmt, arg...) do { } while (0) - -#include <asm/pb1000.h> -#define PCMCIA_IRQ AU1000_GPIO_15 - -static int pb1x00_pcmcia_init(struct pcmcia_init *init) -{ - u16 pcr; - pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; - - au_writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */ - au_sync_delay(100); - au_writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */ - au_sync(); - - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); - au_writel(pcr, PB1000_PCR); - au_sync_delay(20); - - return PCMCIA_NUM_SOCKS; -} - -static int pb1x00_pcmcia_shutdown(void) -{ - u16 pcr; - pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); - au_writel(pcr, PB1000_PCR); - au_sync_delay(20); - return 0; -} - -static int -pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) -{ - u32 inserted0, inserted1; - u16 vs0, vs1; - - vs0 = vs1 = (u16)au_readl(PB1000_ACR1); - inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2)); - inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2)); - vs0 = (vs0 >> 4) & 0x3; - vs1 = (vs1 >> 12) & 0x3; - - state->ready = 0; - state->vs_Xv = 0; - state->vs_3v = 0; - state->detect = 0; - - if (sock == 0) { - if (inserted0) { - switch (vs0) { - case 0: - case 2: - state->vs_3v=1; - break; - case 3: /* 5V */ - break; - default: - /* return without setting 'detect' */ - printk(KERN_ERR "pb1x00 bad VS (%d)\n", - vs0); - return 0; - } - state->detect = 1; - } - } - else { - if (inserted1) { - switch (vs1) { - case 0: - case 2: - state->vs_3v=1; - break; - case 3: /* 5V */ - break; - default: - /* return without setting 'detect' */ - printk(KERN_ERR "pb1x00 bad VS (%d)\n", - vs1); - return 0; - } - state->detect = 1; - } - } - - if (state->detect) { - state->ready = 1; - } - - state->bvd1=1; - state->bvd2=1; - state->wrprot=0; - return 1; -} - - -static int pb1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info) -{ - - if(info->sock > PCMCIA_MAX_SOCK) return -1; - - /* - * Even in the case of the Pb1000, both sockets are connected - * to the same irq line. - */ - info->irq = PCMCIA_IRQ; - - return 0; -} - - -static int -pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) -{ - u16 pcr; - - if(configure->sock > PCMCIA_MAX_SOCK) return -1; - - pcr = au_readl(PB1000_PCR); - - if (configure->sock == 0) { - pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | - PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1); - } - else { - pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | - PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1); - } - - pcr &= ~PCR_SLOT_0_RST; - debug("Vcc %dV Vpp %dV, pcr %x\n", - configure->vcc, configure->vpp, pcr); - switch(configure->vcc){ - case 0: /* Vcc 0 */ - switch(configure->vpp) { - case 0: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND, - configure->sock); - break; - case 12: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V, - configure->sock); - break; - case 50: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V, - configure->sock); - break; - case 33: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V, - configure->sock); - break; - default: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, - configure->sock); - printk("%s: bad Vcc/Vpp (%d:%d)\n", - __func__, - configure->vcc, - configure->vpp); - break; - } - break; - case 50: /* Vcc 5V */ - switch(configure->vpp) { - case 0: - pcr |= SET_VCC_VPP(VCC_5V,VPP_GND, - configure->sock); - break; - case 50: - pcr |= SET_VCC_VPP(VCC_5V,VPP_5V, - configure->sock); - break; - case 12: - pcr |= SET_VCC_VPP(VCC_5V,VPP_12V, - configure->sock); - break; - case 33: - pcr |= SET_VCC_VPP(VCC_5V,VPP_3V, - configure->sock); - break; - default: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, - configure->sock); - printk("%s: bad Vcc/Vpp (%d:%d)\n", - __func__, - configure->vcc, - configure->vpp); - break; - } - break; - case 33: /* Vcc 3.3V */ - switch(configure->vpp) { - case 0: - pcr |= SET_VCC_VPP(VCC_3V,VPP_GND, - configure->sock); - break; - case 50: - pcr |= SET_VCC_VPP(VCC_3V,VPP_5V, - configure->sock); - break; - case 12: - pcr |= SET_VCC_VPP(VCC_3V,VPP_12V, - configure->sock); - break; - case 33: - pcr |= SET_VCC_VPP(VCC_3V,VPP_3V, - configure->sock); - break; - default: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, - configure->sock); - printk("%s: bad Vcc/Vpp (%d:%d)\n", - __func__, - configure->vcc, - configure->vpp); - break; - } - break; - default: /* what's this ? */ - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock); - printk(KERN_ERR "%s: bad Vcc %d\n", - __func__, configure->vcc); - break; - } - - if (configure->sock == 0) { - pcr &= ~(PCR_SLOT_0_RST); - if (configure->reset) - pcr |= PCR_SLOT_0_RST; - } - else { - pcr &= ~(PCR_SLOT_1_RST); - if (configure->reset) - pcr |= PCR_SLOT_1_RST; - } - au_writel(pcr, PB1000_PCR); - au_sync_delay(300); - - return 0; -} - - -struct pcmcia_low_level pb1x00_pcmcia_ops = { - pb1x00_pcmcia_init, - pb1x00_pcmcia_shutdown, - pb1x00_pcmcia_socket_state, - pb1x00_pcmcia_get_irq_info, - pb1x00_pcmcia_configure_socket -}; diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 3e49df6d5e3b..5b7c22784aff 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -7,7 +7,7 @@ /* This is a fairly generic PCMCIA socket driver suitable for the * following Alchemy Development boards: - * Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200. + * Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200, Db1300 * * The Db1000 is used as a reference: Per-socket card-, carddetect- and * statuschange IRQs connected to SoC GPIOs, control and status register @@ -18,6 +18,7 @@ * - Pb1100/Pb1500: single socket only; voltage key bits VS are * at STATUS[5:4] (instead of STATUS[1:0]). * - Au1200-based: additional card-eject irqs, irqs not gpios! + * - Db1300: Db1200-like, no pwr ctrl, single socket (#1). */ #include <linux/delay.h> @@ -59,11 +60,17 @@ struct db1x_pcmcia_sock { #define BOARD_TYPE_DEFAULT 0 /* most boards */ #define BOARD_TYPE_DB1200 1 /* IRQs aren't gpios */ #define BOARD_TYPE_PB1100 2 /* VS bits slightly different */ +#define BOARD_TYPE_DB1300 3 /* no power control */ int board_type; }; #define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket) +static int db1300_card_inserted(struct db1x_pcmcia_sock *sock) +{ + return bcsr_read(BCSR_SIGSTAT) & (1 << 8); +} + /* DB/PB1200: check CPLD SIGSTATUS register bit 10/12 */ static int db1200_card_inserted(struct db1x_pcmcia_sock *sock) { @@ -84,6 +91,8 @@ static int db1x_card_inserted(struct db1x_pcmcia_sock *sock) switch (sock->board_type) { case BOARD_TYPE_DB1200: return db1200_card_inserted(sock); + case BOARD_TYPE_DB1300: + return db1300_card_inserted(sock); default: return db1000_card_inserted(sock); } @@ -160,7 +169,8 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock) * ejection handler have been registered and the currently * active one disabled. */ - if (sock->board_type == BOARD_TYPE_DB1200) { + if ((sock->board_type == BOARD_TYPE_DB1200) || + (sock->board_type == BOARD_TYPE_DB1300)) { ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq, IRQF_DISABLED, "pcmcia_insert", sock); if (ret) @@ -174,7 +184,7 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock) } /* enable the currently silent one */ - if (db1200_card_inserted(sock)) + if (db1x_card_inserted(sock)) enable_irq(sock->eject_irq); else enable_irq(sock->insert_irq); @@ -270,7 +280,8 @@ static int db1x_pcmcia_configure(struct pcmcia_socket *skt, } /* create new voltage code */ - cr_set |= ((v << 2) | p) << (sock->nr * 8); + if (sock->board_type != BOARD_TYPE_DB1300) + cr_set |= ((v << 2) | p) << (sock->nr * 8); changed = state->flags ^ sock->old_flags; @@ -343,6 +354,10 @@ static int db1x_pcmcia_get_status(struct pcmcia_socket *skt, /* if Vcc is not zero, we have applied power to a card */ status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0; + /* DB1300: power always on, but don't tell when no card present */ + if ((sock->board_type == BOARD_TYPE_DB1300) && (status & SS_DETECT)) + status = SS_POWERON | SS_3VCARD | SS_DETECT; + /* reset de-asserted? then we're ready */ status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET; @@ -419,6 +434,9 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev) case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200: sock->board_type = BOARD_TYPE_DB1200; break; + case BCSR_WHOAMI_DB1300: + sock->board_type = BOARD_TYPE_DB1300; + break; default: printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid); ret = -ENODEV; diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 9dc565c615bd..849c0c11d2af 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -24,15 +24,15 @@ #include "yenta_socket.h" #include "i82365.h" -static int disable_clkrun; +static bool disable_clkrun; module_param(disable_clkrun, bool, 0444); MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option"); -static int isa_probe = 1; +static bool isa_probe = 1; module_param(isa_probe, bool, 0444); MODULE_PARM_DESC(isa_probe, "If set ISA interrupts are probed (default). Set to N to disable probing"); -static int pwr_irqs_off; +static bool pwr_irqs_off; module_param(pwr_irqs_off, bool, 0644); MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!"); diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 8877b836d27c..d96734478324 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -189,7 +189,7 @@ struct compal_data{ /* =============== */ /* General globals */ /* =============== */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c index 7f88c7923fc6..6ee0b5c90933 100644 --- a/drivers/platform/x86/intel_oaktrail.c +++ b/drivers/platform/x86/intel_oaktrail.c @@ -95,7 +95,7 @@ #define OT_EC_BL_CONTROL_ON_DATA 0x1A -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index f204643c5052..bb5132128b33 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -89,7 +89,7 @@ static int msi_laptop_resume(struct platform_device *device); #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 09e26bfd4643..fd73ea89b857 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -228,12 +228,12 @@ static struct platform_device *sdev; static struct rfkill *rfk; static bool has_stepping_quirk; -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Disable the DMI check and forces the driver to be loaded"); -static int debug; +static bool debug; module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 62533c105da4..ea0c6075b720 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -378,13 +378,13 @@ static unsigned int bright_maxlvl; /* 0 = unknown */ #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES static int dbg_wlswemul; -static int tpacpi_wlsw_emulstate; +static bool tpacpi_wlsw_emulstate; static int dbg_bluetoothemul; -static int tpacpi_bluetooth_emulstate; +static bool tpacpi_bluetooth_emulstate; static int dbg_wwanemul; -static int tpacpi_wwan_emulstate; +static bool tpacpi_wwan_emulstate; static int dbg_uwbemul; -static int tpacpi_uwb_emulstate; +static bool tpacpi_uwb_emulstate; #endif @@ -6444,7 +6444,7 @@ static struct ibm_struct brightness_driver_data = { static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */ static char *alsa_id = "ThinkPadEC"; -static int alsa_enable = SNDRV_DEFAULT_ENABLE1; +static bool alsa_enable = SNDRV_DEFAULT_ENABLE1; struct tpacpi_alsa_data { struct snd_card *card; @@ -6487,7 +6487,7 @@ static enum tpacpi_volume_access_mode volume_mode = TPACPI_VOL_MODE_MAX; static enum tpacpi_volume_capabilities volume_capabilities; -static int volume_control_allowed; +static bool volume_control_allowed; /* * Used to syncronize writers to TP_EC_AUDIO and @@ -7265,7 +7265,7 @@ enum fan_control_commands { * and also watchdog cmd */ }; -static int fan_control_allowed; +static bool fan_control_allowed; static enum fan_status_access_mode fan_status_access_mode; static enum fan_control_access_mode fan_control_access_mode; @@ -8437,7 +8437,7 @@ static struct proc_dir_entry *proc_dir; * Module and infrastructure proble, init and exit handling */ -static int force_load; +static bool force_load; #ifdef CONFIG_THINKPAD_ACPI_DEBUG static const char * __init str_supported(int is_supported) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index a134c26870b0..42a4dcc25f92 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -82,12 +82,12 @@ struct wmi_block { #define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */ #define ACPI_WMI_EVENT 0x8 /* GUID is an event */ -static int debug_event; +static bool debug_event; module_param(debug_event, bool, 0444); MODULE_PARM_DESC(debug_event, "Log WMI Events [0/1]"); -static int debug_dump_wdg; +static bool debug_dump_wdg; module_param(debug_dump_wdg, bool, 0444); MODULE_PARM_DESC(debug_dump_wdg, "Dump available WMI interfaces [0/1]"); diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index 545874b1df9e..076e211a40b7 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -64,7 +64,7 @@ static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); -static unsigned int pmod_enabled; +static bool pmod_enabled; module_param(pmod_enabled, bool, 0644); MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit"); diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index e91b8ddc2793..c9b92531ae60 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -16,8 +16,8 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/platform_device.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/ab8500.h> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ca86f39a0fdc..e9a83f84adaf 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2731,6 +2731,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) * @dev: struct device for the regulator * @init_data: platform provided init data, passed through by driver * @driver_data: private regulator data + * @of_node: OpenFirmware node to parse for device tree bindings (may be + * NULL). * * Called by regulator drivers to register a regulator. * Returns 0 on success. diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index a0a9810adf0b..4bcf9ca2818a 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -15,7 +15,7 @@ #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/delay.h> #define AB8500_RTC_SOFF_STAT_REG 0x00 diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 4a5529346b47..2d71943bc436 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -261,6 +261,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) /* XXX - isn't this redundant? */ platform_set_drvdata(pdev, info); + device_init_wakeup(&pdev->dev, 1); + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, &max8925_rtc_ops, THIS_MODULE); ret = PTR_ERR(info->rtc_dev); @@ -290,10 +292,34 @@ static int __devexit max8925_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int max8925_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + + if (device_may_wakeup(dev)) + chip->wakeup_flag |= 1 << MAX8925_IRQ_RTC_ALARM0; + return 0; +} +static int max8925_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + + if (device_may_wakeup(dev)) + chip->wakeup_flag &= ~(1 << MAX8925_IRQ_RTC_ALARM0); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_resume); + static struct platform_driver max8925_rtc_driver = { .driver = { .name = "max8925-rtc", .owner = THIS_MODULE, + .pm = &max8925_rtc_pm_ops, }, .probe = max8925_rtc_probe, .remove = __devexit_p(max8925_rtc_remove), diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index e5cb9248a442..f3b8bb84faf2 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -75,7 +75,7 @@ static LIST_HEAD(raw3270_devices); static int raw3270_registered; /* Module parameters */ -static int tubxcorrect = 0; +static bool tubxcorrect = 0; module_param(tubxcorrect, bool, 0); /* diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 11312f401c70..2211277a1079 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -28,9 +28,9 @@ #define MAX_CMDLEN 240 #define MIN_INTERVAL 15 static char vmwdt_cmd[MAX_CMDLEN] = "IPL"; -static int vmwdt_conceal; +static bool vmwdt_conceal; -static int vmwdt_nowayout = WATCHDOG_NOWAYOUT; +static bool vmwdt_nowayout = WATCHDOG_NOWAYOUT; MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 2985eb439485..204ca728e7fd 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -98,7 +98,7 @@ enum cmb_format { * enum cmb_format. */ static int format = CMF_AUTODETECT; -module_param(format, bool, 0444); +module_param(format, bint, 0444); /** * struct cmb_operations - functions to use depending on cmb_format diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 06ea3bcfdd2a..16570aa84aac 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -830,16 +830,11 @@ config SCSI_ISCI tristate "Intel(R) C600 Series Chipset SAS Controller" depends on PCI && SCSI depends on X86 - # (temporary): known alpha quality driver - depends on EXPERIMENTAL select SCSI_SAS_LIBSAS - select SCSI_SAS_HOST_SMP ---help--- This driver supports the 6Gb/s SAS capabilities of the storage control unit found in the Intel(R) C600 series chipset. - The experimental tag will be removed after the driver exits alpha - config SCSI_GENERIC_NCR5380 tristate "Generic NCR5380/53c400 SCSI PIO support" depends on ISA && SCSI diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 195823a51aab..ed119cedaae0 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -102,7 +102,7 @@ static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 }; */ #if defined(MODULE) -static int isapnp = 0; +static bool isapnp = 0; static int aha1542[] = {0x330, 11, 4, -1}; module_param_array(aha1542, int, NULL, 0); module_param(isapnp, bool, 0); diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h index 78963be2c4fb..cb07c628b2f1 100644 --- a/drivers/scsi/bfa/bfa_defs_svc.h +++ b/drivers/scsi/bfa/bfa_defs_svc.h @@ -673,12 +673,7 @@ struct bfa_itnim_iostats_s { u32 tm_iocdowns; /* TM cleaned-up due to IOC down */ u32 tm_cleanups; /* TM cleanup requests */ u32 tm_cleanup_comps; /* TM cleanup completions */ - u32 lm_lun_across_sg; /* LM lun is across sg data buf */ - u32 lm_lun_not_sup; /* LM lun not supported */ - u32 lm_rpl_data_changed; /* LM report-lun data changed */ - u32 lm_wire_residue_changed; /* LM report-lun rsp residue changed */ - u32 lm_small_buf_addresidue; /* LM buf smaller than reported cnt */ - u32 lm_lun_not_rdy; /* LM lun not ready */ + u32 rsvd[6]; }; /* Modify char* port_stt[] in bfal_port.c if a new state was added */ diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h index 50b6a1c86195..8d0b88f67a38 100644 --- a/drivers/scsi/bfa/bfa_fc.h +++ b/drivers/scsi/bfa/bfa_fc.h @@ -56,161 +56,6 @@ struct scsi_cdb_s { #define SCSI_MAX_ALLOC_LEN 0xFF /* maximum allocarion length */ -#define SCSI_SENSE_CUR_ERR 0x70 -#define SCSI_SENSE_DEF_ERR 0x71 - -/* - * SCSI additional sense codes - */ -#define SCSI_ASC_LUN_NOT_READY 0x04 -#define SCSI_ASC_LUN_NOT_SUPPORTED 0x25 -#define SCSI_ASC_TOCC 0x3F - -/* - * SCSI additional sense code qualifiers - */ -#define SCSI_ASCQ_MAN_INTR_REQ 0x03 /* manual intervention req */ -#define SCSI_ASCQ_RL_DATA_CHANGED 0x0E /* report luns data changed */ - -/* - * Methods of reporting informational exceptions - */ -#define SCSI_MP_IEC_UNIT_ATTN 0x2 /* generate unit attention */ - -struct scsi_report_luns_data_s { - u32 lun_list_length; /* length of LUN list length */ - u32 reserved; - struct scsi_lun lun[1]; /* first LUN in lun list */ -}; - -struct scsi_inquiry_vendor_s { - u8 vendor_id[8]; -}; - -struct scsi_inquiry_prodid_s { - u8 product_id[16]; -}; - -struct scsi_inquiry_prodrev_s { - u8 product_rev[4]; -}; - -struct scsi_inquiry_data_s { -#ifdef __BIG_ENDIAN - u8 peripheral_qual:3; /* peripheral qualifier */ - u8 device_type:5; /* peripheral device type */ - u8 rmb:1; /* removable medium bit */ - u8 device_type_mod:7; /* device type modifier */ - u8 version; - u8 aenc:1; /* async evt notification capability */ - u8 trm_iop:1; /* terminate I/O process */ - u8 norm_aca:1; /* normal ACA supported */ - u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */ - u8 rsp_data_format:4; - u8 additional_len; - u8 sccs:1; - u8 reserved1:7; - u8 reserved2:1; - u8 enc_serv:1; /* enclosure service component */ - u8 reserved3:1; - u8 multi_port:1; /* multi-port device */ - u8 m_chngr:1; /* device in medium transport element */ - u8 ack_req_q:1; /* SIP specific bit */ - u8 addr32:1; /* SIP specific bit */ - u8 addr16:1; /* SIP specific bit */ - u8 rel_adr:1; /* relative address */ - u8 w_bus32:1; - u8 w_bus16:1; - u8 synchronous:1; - u8 linked_commands:1; - u8 trans_dis:1; - u8 cmd_queue:1; /* command queueing supported */ - u8 soft_reset:1; /* soft reset alternative (VS) */ -#else - u8 device_type:5; /* peripheral device type */ - u8 peripheral_qual:3; /* peripheral qualifier */ - u8 device_type_mod:7; /* device type modifier */ - u8 rmb:1; /* removable medium bit */ - u8 version; - u8 rsp_data_format:4; - u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */ - u8 norm_aca:1; /* normal ACA supported */ - u8 terminate_iop:1;/* terminate I/O process */ - u8 aenc:1; /* async evt notification capability */ - u8 additional_len; - u8 reserved1:7; - u8 sccs:1; - u8 addr16:1; /* SIP specific bit */ - u8 addr32:1; /* SIP specific bit */ - u8 ack_req_q:1; /* SIP specific bit */ - u8 m_chngr:1; /* device in medium transport element */ - u8 multi_port:1; /* multi-port device */ - u8 reserved3:1; /* TBD - Vendor Specific */ - u8 enc_serv:1; /* enclosure service component */ - u8 reserved2:1; - u8 soft_seset:1; /* soft reset alternative (VS) */ - u8 cmd_queue:1; /* command queueing supported */ - u8 trans_dis:1; - u8 linked_commands:1; - u8 synchronous:1; - u8 w_bus16:1; - u8 w_bus32:1; - u8 rel_adr:1; /* relative address */ -#endif - struct scsi_inquiry_vendor_s vendor_id; - struct scsi_inquiry_prodid_s product_id; - struct scsi_inquiry_prodrev_s product_rev; - u8 vendor_specific[20]; - u8 reserved4[40]; -}; - -/* - * SCSI sense data format - */ -struct scsi_sense_s { -#ifdef __BIG_ENDIAN - u8 valid:1; - u8 rsp_code:7; -#else - u8 rsp_code:7; - u8 valid:1; -#endif - u8 seg_num; -#ifdef __BIG_ENDIAN - u8 file_mark:1; - u8 eom:1; /* end of media */ - u8 ili:1; /* incorrect length indicator */ - u8 reserved:1; - u8 sense_key:4; -#else - u8 sense_key:4; - u8 reserved:1; - u8 ili:1; /* incorrect length indicator */ - u8 eom:1; /* end of media */ - u8 file_mark:1; -#endif - u8 information[4]; /* device-type or cmd specific info */ - u8 add_sense_length; /* additional sense length */ - u8 command_info[4];/* command specific information */ - u8 asc; /* additional sense code */ - u8 ascq; /* additional sense code qualifier */ - u8 fru_code; /* field replaceable unit code */ -#ifdef __BIG_ENDIAN - u8 sksv:1; /* sense key specific valid */ - u8 c_d:1; /* command/data bit */ - u8 res1:2; - u8 bpv:1; /* bit pointer valid */ - u8 bpointer:3; /* bit pointer */ -#else - u8 bpointer:3; /* bit pointer */ - u8 bpv:1; /* bit pointer valid */ - u8 res1:2; - u8 c_d:1; /* command/data bit */ - u8 sksv:1; /* sense key specific valid */ -#endif - u8 fpointer[2]; /* field pointer */ -}; - /* * Fibre Channel Header Structure (FCHS) definition */ diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index e07bd4745d8b..f0f80e282e39 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -24,8 +24,6 @@ BFA_TRC_FILE(HAL, FCPIM); * BFA ITNIM Related definitions */ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim); -static bfa_boolean_t bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim); -static bfa_boolean_t bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim); static void bfa_ioim_lm_init(struct bfa_s *bfa); #define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \ @@ -60,14 +58,6 @@ static void bfa_ioim_lm_init(struct bfa_s *bfa); } \ } while (0) -#define bfa_ioim_rp_wwn(__ioim) \ - (((struct bfa_fcs_rport_s *) \ - (__ioim)->itnim->rport->rport_drv)->pwwn) - -#define bfa_ioim_lp_wwn(__ioim) \ - ((BFA_LPS_FROM_TAG(BFA_LPS_MOD((__ioim)->bfa), \ - (__ioim)->itnim->rport->rport_info.lp_tag))->pwwn) \ - #define bfa_itnim_sler_cb(__itnim) do { \ if ((__itnim)->bfa->fcs) \ bfa_cb_itnim_sler((__itnim)->ditn); \ @@ -77,13 +67,6 @@ static void bfa_ioim_lm_init(struct bfa_s *bfa); } \ } while (0) -enum bfa_ioim_lm_status { - BFA_IOIM_LM_PRESENT = 1, - BFA_IOIM_LM_LUN_NOT_SUP = 2, - BFA_IOIM_LM_RPL_DATA_CHANGED = 3, - BFA_IOIM_LM_LUN_NOT_RDY = 4, -}; - enum bfa_ioim_lm_ua_status { BFA_IOIM_LM_UA_RESET = 0, BFA_IOIM_LM_UA_SET = 1, @@ -145,9 +128,6 @@ enum bfa_ioim_event { BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */ BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */ BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */ - BFA_IOIM_SM_LM_LUN_NOT_SUP = 19,/* lunmask lun not supported */ - BFA_IOIM_SM_LM_RPL_DC = 20, /* lunmask report-lun data changed */ - BFA_IOIM_SM_LM_LUN_NOT_RDY = 21,/* lunmask lun not ready */ }; @@ -245,9 +225,6 @@ static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete); static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete); static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete); static bfa_boolean_t bfa_ioim_is_abortable(struct bfa_ioim_s *ioim); -static void __bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete); /* * forward declaration of BFA IO state machine @@ -445,12 +422,6 @@ bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats, bfa_fcpim_add_iostats(lstats, rstats, output_reqs); bfa_fcpim_add_iostats(lstats, rstats, rd_throughput); bfa_fcpim_add_iostats(lstats, rstats, wr_throughput); - bfa_fcpim_add_iostats(lstats, rstats, lm_lun_across_sg); - bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_sup); - bfa_fcpim_add_iostats(lstats, rstats, lm_rpl_data_changed); - bfa_fcpim_add_iostats(lstats, rstats, lm_wire_residue_changed); - bfa_fcpim_add_iostats(lstats, rstats, lm_small_buf_addresidue); - bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_rdy); } bfa_status_t @@ -1580,27 +1551,6 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) __bfa_cb_ioim_abort, ioim); break; - case BFA_IOIM_SM_LM_LUN_NOT_SUP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_lm_lun_not_sup, ioim); - break; - - case BFA_IOIM_SM_LM_RPL_DC: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_lm_rpl_dc, ioim); - break; - - case BFA_IOIM_SM_LM_LUN_NOT_RDY: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_lm_lun_not_rdy, ioim); - break; - default: bfa_sm_fault(ioim->bfa, event); } @@ -2160,243 +2110,6 @@ bfa_ioim_lm_init(struct bfa_s *bfa) } } -/* - * Validate LUN for LUN masking - */ -static enum bfa_ioim_lm_status -bfa_ioim_lm_check(struct bfa_ioim_s *ioim, struct bfa_lps_s *lps, - struct bfa_rport_s *rp, struct scsi_lun lun) -{ - u8 i; - struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa); - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio; - struct scsi_cdb_s *cdb = (struct scsi_cdb_s *)cmnd->cmnd; - - if ((cdb->scsi_cdb[0] == REPORT_LUNS) && - (scsilun_to_int((struct scsi_lun *)&lun) == 0)) { - ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data; - return BFA_IOIM_LM_PRESENT; - } - - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - - if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE) - continue; - - if ((scsilun_to_int((struct scsi_lun *)&lun_list[i].lun) == - scsilun_to_int((struct scsi_lun *)&lun)) - && (rp->rport_tag == lun_list[i].rp_tag) - && ((u8)ioim->itnim->rport->rport_info.lp_tag == - lun_list[i].lp_tag)) { - bfa_trc(ioim->bfa, lun_list[i].rp_tag); - bfa_trc(ioim->bfa, lun_list[i].lp_tag); - bfa_trc(ioim->bfa, scsilun_to_int( - (struct scsi_lun *)&lun_list[i].lun)); - - if ((lun_list[i].ua == BFA_IOIM_LM_UA_SET) && - ((cdb->scsi_cdb[0] != INQUIRY) || - (cdb->scsi_cdb[0] != REPORT_LUNS))) { - lun_list[i].ua = BFA_IOIM_LM_UA_RESET; - return BFA_IOIM_LM_RPL_DATA_CHANGED; - } - - if (cdb->scsi_cdb[0] == REPORT_LUNS) - ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data; - - return BFA_IOIM_LM_PRESENT; - } - } - - if ((cdb->scsi_cdb[0] == INQUIRY) && - (scsilun_to_int((struct scsi_lun *)&lun) == 0)) { - ioim->proc_rsp_data = bfa_ioim_lm_proc_inq_data; - return BFA_IOIM_LM_PRESENT; - } - - if (cdb->scsi_cdb[0] == TEST_UNIT_READY) - return BFA_IOIM_LM_LUN_NOT_RDY; - - return BFA_IOIM_LM_LUN_NOT_SUP; -} - -static bfa_boolean_t -bfa_ioim_lm_proc_rsp_data_dummy(struct bfa_ioim_s *ioim) -{ - return BFA_TRUE; -} - -static void -bfa_ioim_lm_fetch_lun(struct bfa_ioim_s *ioim, u8 *rl_data, int offset, - int buf_lun_cnt) -{ - struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa); - struct scsi_lun *lun_data = (struct scsi_lun *)(rl_data + offset); - struct scsi_lun lun; - int i, j; - - bfa_trc(ioim->bfa, buf_lun_cnt); - for (j = 0; j < buf_lun_cnt; j++) { - lun = *((struct scsi_lun *)(lun_data + j)); - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE) - continue; - if ((lun_list[i].rp_wwn == bfa_ioim_rp_wwn(ioim)) && - (lun_list[i].lp_wwn == bfa_ioim_lp_wwn(ioim)) && - (scsilun_to_int((struct scsi_lun *)&lun_list[i].lun) - == scsilun_to_int((struct scsi_lun *)&lun))) { - lun_list[i].state = BFA_IOIM_LUN_MASK_FETCHED; - break; - } - } /* next lun in mask DB */ - } /* next lun in buf */ -} - -static int -bfa_ioim_lm_update_lun_sg(struct bfa_ioim_s *ioim, u32 *pgdlen, - struct scsi_report_luns_data_s *rl) -{ - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio; - struct scatterlist *sg = scsi_sglist(cmnd); - struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa); - struct scsi_lun *prev_rl_data = NULL, *base_rl_data; - int i, j, sgeid, lun_fetched_cnt = 0, prev_sg_len = 0, base_count; - int lun_across_sg_bytes, bytes_from_next_buf; - u64 last_lun, temp_last_lun; - - /* fetch luns from the first sg element */ - bfa_ioim_lm_fetch_lun(ioim, (u8 *)(rl->lun), 0, - (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1); - - /* fetch luns from multiple sg elements */ - scsi_for_each_sg(cmnd, sg, scsi_sg_count(cmnd), sgeid) { - if (sgeid == 0) { - prev_sg_len = sg_dma_len(sg); - prev_rl_data = (struct scsi_lun *) - phys_to_virt(sg_dma_address(sg)); - continue; - } - - /* if the buf is having more data */ - lun_across_sg_bytes = prev_sg_len % sizeof(struct scsi_lun); - if (lun_across_sg_bytes) { - bfa_trc(ioim->bfa, lun_across_sg_bytes); - bfa_stats(ioim->itnim, lm_lun_across_sg); - bytes_from_next_buf = sizeof(struct scsi_lun) - - lun_across_sg_bytes; - - /* from next buf take higher bytes */ - temp_last_lun = *((u64 *) - phys_to_virt(sg_dma_address(sg))); - last_lun |= temp_last_lun >> - (lun_across_sg_bytes * BITS_PER_BYTE); - - /* from prev buf take higher bytes */ - temp_last_lun = *((u64 *)(prev_rl_data + - (prev_sg_len - lun_across_sg_bytes))); - temp_last_lun >>= bytes_from_next_buf * BITS_PER_BYTE; - last_lun = last_lun | (temp_last_lun << - (bytes_from_next_buf * BITS_PER_BYTE)); - - bfa_ioim_lm_fetch_lun(ioim, (u8 *)&last_lun, 0, 1); - } else - bytes_from_next_buf = 0; - - *pgdlen += sg_dma_len(sg); - prev_sg_len = sg_dma_len(sg); - prev_rl_data = (struct scsi_lun *) - phys_to_virt(sg_dma_address(sg)); - bfa_ioim_lm_fetch_lun(ioim, (u8 *)prev_rl_data, - bytes_from_next_buf, - sg_dma_len(sg) / sizeof(struct scsi_lun)); - } - - /* update the report luns data - based on fetched luns */ - sg = scsi_sglist(cmnd); - base_rl_data = (struct scsi_lun *)rl->lun; - base_count = (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1; - for (i = 0, j = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lun_list[i].state == BFA_IOIM_LUN_MASK_FETCHED) { - base_rl_data[j] = lun_list[i].lun; - lun_list[i].state = BFA_IOIM_LUN_MASK_ACTIVE; - j++; - lun_fetched_cnt++; - } - - if (j > base_count) { - j = 0; - sg = sg_next(sg); - base_rl_data = (struct scsi_lun *) - phys_to_virt(sg_dma_address(sg)); - base_count = sg_dma_len(sg) / sizeof(struct scsi_lun); - } - } - - bfa_trc(ioim->bfa, lun_fetched_cnt); - return lun_fetched_cnt; -} - -static bfa_boolean_t -bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim) -{ - struct scsi_inquiry_data_s *inq; - struct scatterlist *sg = scsi_sglist((struct scsi_cmnd *)ioim->dio); - - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; - inq = (struct scsi_inquiry_data_s *)phys_to_virt(sg_dma_address(sg)); - - bfa_trc(ioim->bfa, inq->device_type); - inq->peripheral_qual = SCSI_INQ_PQ_NOT_CON; - return 0; -} - -static bfa_boolean_t -bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim) -{ - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio; - struct scatterlist *sg = scsi_sglist(cmnd); - struct bfi_ioim_rsp_s *m; - struct scsi_report_luns_data_s *rl = NULL; - int lun_count = 0, lun_fetched_cnt = 0; - u32 residue, pgdlen = 0; - - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; - if (bfa_get_lun_mask_status(ioim->bfa) != BFA_LUNMASK_ENABLED) - return BFA_TRUE; - - m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg; - if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION) - return BFA_TRUE; - - pgdlen = sg_dma_len(sg); - bfa_trc(ioim->bfa, pgdlen); - rl = (struct scsi_report_luns_data_s *)phys_to_virt(sg_dma_address(sg)); - lun_count = cpu_to_be32(rl->lun_list_length) / sizeof(struct scsi_lun); - lun_fetched_cnt = bfa_ioim_lm_update_lun_sg(ioim, &pgdlen, rl); - - if (lun_count == lun_fetched_cnt) - return BFA_TRUE; - - bfa_trc(ioim->bfa, lun_count); - bfa_trc(ioim->bfa, lun_fetched_cnt); - bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length)); - - if (be32_to_cpu(rl->lun_list_length) <= pgdlen) - rl->lun_list_length = be32_to_cpu(lun_fetched_cnt) * - sizeof(struct scsi_lun); - else - bfa_stats(ioim->itnim, lm_small_buf_addresidue); - - bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length)); - bfa_trc(ioim->bfa, be32_to_cpu(m->residue)); - - residue = be32_to_cpu(m->residue); - residue += (lun_count - lun_fetched_cnt) * sizeof(struct scsi_lun); - bfa_stats(ioim->itnim, lm_wire_residue_changed); - m->residue = be32_to_cpu(residue); - bfa_trc(ioim->bfa, ioim->nsges); - return BFA_FALSE; -} - static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete) { @@ -2454,83 +2167,6 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete) m->scsi_status, sns_len, snsinfo, residue); } -static void -__bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - int sns_len = 0xD; - u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio); - struct scsi_sense_s *snsinfo; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG( - ioim->fcpim->fcp, ioim->iotag); - snsinfo->rsp_code = SCSI_SENSE_CUR_ERR; - snsinfo->add_sense_length = 0xa; - snsinfo->asc = SCSI_ASC_LUN_NOT_SUPPORTED; - snsinfo->sense_key = ILLEGAL_REQUEST; - bfa_trc(ioim->bfa, residue); - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK, - SCSI_STATUS_CHECK_CONDITION, sns_len, - (u8 *)snsinfo, residue); -} - -static void -__bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - int sns_len = 0xD; - u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio); - struct scsi_sense_s *snsinfo; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(ioim->fcpim->fcp, - ioim->iotag); - snsinfo->rsp_code = SCSI_SENSE_CUR_ERR; - snsinfo->sense_key = SCSI_MP_IEC_UNIT_ATTN; - snsinfo->asc = SCSI_ASC_TOCC; - snsinfo->add_sense_length = 0x6; - snsinfo->ascq = SCSI_ASCQ_RL_DATA_CHANGED; - bfa_trc(ioim->bfa, residue); - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK, - SCSI_STATUS_CHECK_CONDITION, sns_len, - (u8 *)snsinfo, residue); -} - -static void -__bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - int sns_len = 0xD; - u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio); - struct scsi_sense_s *snsinfo; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG( - ioim->fcpim->fcp, ioim->iotag); - snsinfo->rsp_code = SCSI_SENSE_CUR_ERR; - snsinfo->add_sense_length = 0xa; - snsinfo->sense_key = NOT_READY; - snsinfo->asc = SCSI_ASC_LUN_NOT_READY; - snsinfo->ascq = SCSI_ASCQ_MAN_INTR_REQ; - bfa_trc(ioim->bfa, residue); - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK, - SCSI_STATUS_CHECK_CONDITION, sns_len, - (u8 *)snsinfo, residue); -} - void bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn, wwn_t rp_wwn, u16 rp_tag, u8 lp_tag) @@ -2647,7 +2283,8 @@ bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn, if (port) { *pwwn = port->port_cfg.pwwn; rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn); - rp = rp_fcs->bfa_rport; + if (rp_fcs) + rp = rp_fcs->bfa_rport; } lunm_list = bfa_get_lun_mask_list(bfa); @@ -2715,7 +2352,8 @@ bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn, if (port) { *pwwn = port->port_cfg.pwwn; rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn); - rp = rp_fcs->bfa_rport; + if (rp_fcs) + rp = rp_fcs->bfa_rport; } } @@ -2757,7 +2395,6 @@ __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete) return; } - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED, 0, 0, NULL, 0); } @@ -2773,7 +2410,6 @@ __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete) return; } - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV, 0, 0, NULL, 0); } @@ -2788,7 +2424,6 @@ __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete) return; } - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio); } @@ -3132,7 +2767,6 @@ bfa_ioim_attach(struct bfa_fcpim_s *fcpim) ioim->bfa = fcpim->bfa; ioim->fcpim = fcpim; ioim->iosp = iosp; - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; INIT_LIST_HEAD(&ioim->sgpg_q); bfa_reqq_winit(&ioim->iosp->reqq_wait, bfa_ioim_qresume, ioim); @@ -3170,7 +2804,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) evt = BFA_IOIM_SM_DONE; else evt = BFA_IOIM_SM_COMP; - ioim->proc_rsp_data(ioim); break; case BFI_IOIM_STS_TIMEDOUT: @@ -3206,7 +2839,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) if (rsp->abort_tag != ioim->abort_tag) { bfa_trc(ioim->bfa, rsp->abort_tag); bfa_trc(ioim->bfa, ioim->abort_tag); - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; return; } @@ -3225,7 +2857,6 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) WARN_ON(1); } - ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy; bfa_sm_send_event(ioim, evt); } @@ -3244,15 +2875,7 @@ bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m) bfa_ioim_cb_profile_comp(fcpim, ioim); - if (bfa_get_lun_mask_status(bfa) != BFA_LUNMASK_ENABLED) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); - return; - } - - if (ioim->proc_rsp_data(ioim) == BFA_TRUE) - bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); - else - bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP); + bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); } /* @@ -3364,35 +2987,6 @@ bfa_ioim_free(struct bfa_ioim_s *ioim) void bfa_ioim_start(struct bfa_ioim_s *ioim) { - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio; - struct bfa_lps_s *lps; - enum bfa_ioim_lm_status status; - struct scsi_lun scsilun; - - if (bfa_get_lun_mask_status(ioim->bfa) == BFA_LUNMASK_ENABLED) { - lps = BFA_IOIM_TO_LPS(ioim); - int_to_scsilun(cmnd->device->lun, &scsilun); - status = bfa_ioim_lm_check(ioim, lps, - ioim->itnim->rport, scsilun); - if (status == BFA_IOIM_LM_LUN_NOT_RDY) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_RDY); - bfa_stats(ioim->itnim, lm_lun_not_rdy); - return; - } - - if (status == BFA_IOIM_LM_LUN_NOT_SUP) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_SUP); - bfa_stats(ioim->itnim, lm_lun_not_sup); - return; - } - - if (status == BFA_IOIM_LM_RPL_DATA_CHANGED) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_RPL_DC); - bfa_stats(ioim->itnim, lm_rpl_data_changed); - return; - } - } - bfa_ioim_cb_profile_start(ioim->fcpim, ioim); /* diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h index 1080bcb81cb7..36f26da80f76 100644 --- a/drivers/scsi/bfa/bfa_fcpim.h +++ b/drivers/scsi/bfa/bfa_fcpim.h @@ -110,7 +110,6 @@ struct bfad_ioim_s; struct bfad_tskim_s; typedef void (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim); -typedef bfa_boolean_t (*bfa_ioim_lm_proc_rsp_data_t) (struct bfa_ioim_s *ioim); struct bfa_fcpim_s { struct bfa_s *bfa; @@ -124,7 +123,6 @@ struct bfa_fcpim_s { u32 path_tov; u16 q_depth; u8 reqq; /* Request queue to be used */ - u8 lun_masking_pending; struct list_head itnim_q; /* queue of active itnim */ struct list_head ioim_resfree_q; /* IOs waiting for f/w */ struct list_head ioim_comp_q; /* IO global comp Q */ @@ -181,7 +179,6 @@ struct bfa_ioim_s { u8 reqq; /* Request queue for I/O */ u8 mode; /* IO is passthrough or not */ u64 start_time; /* IO's Profile start val */ - bfa_ioim_lm_proc_rsp_data_t proc_rsp_data; /* RSP data adjust */ }; struct bfa_ioim_sp_s { @@ -261,10 +258,6 @@ struct bfa_itnim_s { (__ioim)->iotag |= k << BFA_IOIM_RETRY_TAG_OFFSET; \ } while (0) -#define BFA_IOIM_TO_LPS(__ioim) \ - BFA_LPS_FROM_TAG(BFA_LPS_MOD(__ioim->bfa), \ - __ioim->itnim->rport->rport_info.lp_tag) - static inline bfa_boolean_t bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim) { diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h index 95adb86d3769..b52cbb6bcd5a 100644 --- a/drivers/scsi/bfa/bfa_svc.h +++ b/drivers/scsi/bfa/bfa_svc.h @@ -582,11 +582,6 @@ void bfa_cb_rport_qos_scn_prio(void *rport, #define BFA_LP_TAG_INVALID 0xff void bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp); void bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp); -bfa_boolean_t bfa_rport_lunmask_active(struct bfa_rport_s *rp); -wwn_t bfa_rport_get_pwwn(struct bfa_s *bfa, struct bfa_rport_s *rp); -struct bfa_rport_s *bfa_rport_get_by_wwn(struct bfa_s *bfa, u16 vf_id, - wwn_t *lpwwn, wwn_t rpwwn); -void *bfa_cb_get_rp_by_wwn(void *arg, u16 vf_id, wwn_t *lpwwn, wwn_t rpwwn); /* * bfa fcxp API functions diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 66fb72531b34..404fd10ddb21 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -674,6 +674,7 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id, spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_fcs_vport_start(&vport->fcs_vport); + list_add_tail(&vport->list_entry, &bfad->vport_list); spin_unlock_irqrestore(&bfad->bfad_lock, flags); return BFA_STATUS_OK; @@ -1404,6 +1405,7 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) bfad->ref_count = 0; bfad->pport.bfad = bfad; INIT_LIST_HEAD(&bfad->pbc_vport_list); + INIT_LIST_HEAD(&bfad->vport_list); /* Setup the debugfs node for this bfad */ if (bfa_debugfs_enable) diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index 9d95844ab463..1938fe0473e9 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -491,7 +491,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport) free_scsi_host: bfad_scsi_host_free(bfad, im_port); - + list_del(&vport->list_entry); kfree(vport); return 0; diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 06fc00caeb41..530de2b1200a 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -2394,6 +2394,21 @@ out: return 0; } +/* Function to reset the LUN SCAN mode */ +static void +bfad_iocmd_lunmask_reset_lunscan_mode(struct bfad_s *bfad, int lunmask_cfg) +{ + struct bfad_im_port_s *pport_im = bfad->pport.im_port; + struct bfad_vport_s *vport = NULL; + + /* Set the scsi device LUN SCAN flags for base port */ + bfad_reset_sdev_bflags(pport_im, lunmask_cfg); + + /* Set the scsi device LUN SCAN flags for the vports */ + list_for_each_entry(vport, &bfad->vport_list, list_entry) + bfad_reset_sdev_bflags(vport->drv_port.im_port, lunmask_cfg); +} + int bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd) { @@ -2401,11 +2416,17 @@ bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd) unsigned long flags; spin_lock_irqsave(&bfad->bfad_lock, flags); - if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE) + if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE) { iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_TRUE); - else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE) + /* Set the LUN Scanning mode to be Sequential scan */ + if (iocmd->status == BFA_STATUS_OK) + bfad_iocmd_lunmask_reset_lunscan_mode(bfad, BFA_TRUE); + } else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE) { iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_FALSE); - else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR) + /* Set the LUN Scanning mode to default REPORT_LUNS scan */ + if (iocmd->status == BFA_STATUS_OK) + bfad_iocmd_lunmask_reset_lunscan_mode(bfad, BFA_FALSE); + } else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR) iocmd->status = bfa_fcpim_lunmask_clear(&bfad->bfa); spin_unlock_irqrestore(&bfad->bfad_lock, flags); return 0; diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 5e19a5f820ec..dc5b9d99c450 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -43,6 +43,7 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_bsg_fc.h> +#include <scsi/scsi_devinfo.h> #include "bfa_modules.h" #include "bfa_fcs.h" @@ -227,6 +228,7 @@ struct bfad_s { struct list_head active_aen_q; struct bfa_aen_entry_s aen_list[BFA_AEN_MAX_ENTRY]; spinlock_t bfad_aen_spinlock; + struct list_head vport_list; }; /* BFAD state machine events */ diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index e5db649e8eb7..3153923f5b60 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -918,16 +918,70 @@ bfad_get_itnim(struct bfad_im_port_s *im_port, int id) } /* + * Function is invoked from the SCSI Host Template slave_alloc() entry point. + * Has the logic to query the LUN Mask database to check if this LUN needs to + * be made visible to the SCSI mid-layer or not. + * + * Returns BFA_STATUS_OK if this LUN needs to be added to the OS stack. + * Returns -ENXIO to notify SCSI mid-layer to not add this LUN to the OS stack. + */ +static int +bfad_im_check_if_make_lun_visible(struct scsi_device *sdev, + struct fc_rport *rport) +{ + struct bfad_itnim_data_s *itnim_data = + (struct bfad_itnim_data_s *) rport->dd_data; + struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa; + struct bfa_rport_s *bfa_rport = itnim_data->itnim->bfa_itnim->rport; + struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(bfa); + int i = 0, ret = -ENXIO; + + for (i = 0; i < MAX_LUN_MASK_CFG; i++) { + if (lun_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE && + scsilun_to_int(&lun_list[i].lun) == sdev->lun && + lun_list[i].rp_tag == bfa_rport->rport_tag && + lun_list[i].lp_tag == (u8)bfa_rport->rport_info.lp_tag) { + ret = BFA_STATUS_OK; + break; + } + } + return ret; +} + +/* * Scsi_Host template entry slave_alloc */ static int bfad_im_slave_alloc(struct scsi_device *sdev) { struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct bfad_itnim_data_s *itnim_data = + (struct bfad_itnim_data_s *) rport->dd_data; + struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa; if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; + if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_ENABLED) { + /* + * We should not mask LUN 0 - since this will translate + * to no LUN / TARGET for SCSI ml resulting no scan. + */ + if (sdev->lun == 0) { + sdev->sdev_bflags |= BLIST_NOREPORTLUN | + BLIST_SPARSELUN; + goto done; + } + + /* + * Query LUN Mask configuration - to expose this LUN + * to the SCSI mid-layer or to mask it. + */ + if (bfad_im_check_if_make_lun_visible(sdev, rport) != + BFA_STATUS_OK) + return -ENXIO; + } +done: sdev->hostdata = rport->dd_data; return 0; @@ -1037,6 +1091,8 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim) && (fc_rport->scsi_target_id < MAX_FCP_TARGET)) itnim->scsi_tgt_id = fc_rport->scsi_target_id; + itnim->channel = fc_rport->channel; + return; } diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h index 004b6cf848d9..0814367ef101 100644 --- a/drivers/scsi/bfa/bfad_im.h +++ b/drivers/scsi/bfa/bfad_im.h @@ -91,6 +91,7 @@ struct bfad_itnim_s { struct fc_rport *fc_rport; struct bfa_itnim_s *bfa_itnim; u16 scsi_tgt_id; + u16 channel; u16 queue_work; unsigned long last_ramp_up_time; unsigned long last_queue_full_time; @@ -166,4 +167,30 @@ irqreturn_t bfad_intx(int irq, void *dev_id); int bfad_im_bsg_request(struct fc_bsg_job *job); int bfad_im_bsg_timeout(struct fc_bsg_job *job); +/* + * Macro to set the SCSI device sdev_bflags - sdev_bflags are used by the + * SCSI mid-layer to choose LUN Scanning mode REPORT_LUNS vs. Sequential Scan + * + * Internally iterate's over all the ITNIM's part of the im_port & set's the + * sdev_bflags for the scsi_device associated with LUN #0. + */ +#define bfad_reset_sdev_bflags(__im_port, __lunmask_cfg) do { \ + struct scsi_device *__sdev = NULL; \ + struct bfad_itnim_s *__itnim = NULL; \ + u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; \ + list_for_each_entry(__itnim, &((__im_port)->itnim_mapped_list), \ + list_entry) { \ + __sdev = scsi_device_lookup((__im_port)->shost, \ + __itnim->channel, \ + __itnim->scsi_tgt_id, 0); \ + if (__sdev) { \ + if ((__lunmask_cfg) == BFA_TRUE) \ + __sdev->sdev_bflags |= scan_flags; \ + else \ + __sdev->sdev_bflags &= ~scan_flags; \ + scsi_device_put(__sdev); \ + } \ + } \ +} while (0) + #endif diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index c5360ffb4bed..d3ff9cd40234 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -1868,8 +1868,9 @@ int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) tdata->skb = alloc_skb(cdev->skb_tx_rsvd + headroom, GFP_ATOMIC); if (!tdata->skb) { - pr_warn("alloc skb %u+%u, opcode 0x%x failed.\n", - cdev->skb_tx_rsvd, headroom, opcode); + struct cxgbi_sock *csk = cconn->cep->csk; + struct net_device *ndev = cdev->ports[csk->port_id]; + ndev->stats.tx_dropped++; return -ENOMEM; } diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index f5b718d3c31b..13aeca3d51f2 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -546,7 +546,7 @@ static struct ParameterData __devinitdata cfg_data[] = { * command line overrides will be used. If set to 1 then safe and * slow settings will be used. */ -static int use_safe_settings = 0; +static bool use_safe_settings = 0; module_param_named(safe, use_safe_settings, bool, 0); MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false"); diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 4ef021291a4d..04c5cea47a22 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -466,6 +466,11 @@ static int alua_check_sense(struct scsi_device *sdev, * Power On, Reset, or Bus Device Reset, just retry. */ return ADD_TO_MLQUEUE; + if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01) + /* + * Mode Parameters Changed + */ + return ADD_TO_MLQUEUE; if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) /* * ALUA state changed diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 841ebf4a6788..53a31c753cb1 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -953,6 +953,8 @@ static int __init rdac_init(void) if (!kmpath_rdacd) { scsi_unregister_device_handler(&rdac_dh); printk(KERN_ERR "kmpath_rdacd creation failed.\n"); + + r = -EINVAL; } done: return r; diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 8d67467dd9ce..e9599600aa23 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -58,7 +58,11 @@ module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ "Direct Data Placement (DDP)."); -DEFINE_MUTEX(fcoe_config_mutex); +unsigned int fcoe_debug_logging; +module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); + +static DEFINE_MUTEX(fcoe_config_mutex); static struct workqueue_struct *fcoe_wq; @@ -67,8 +71,8 @@ static DECLARE_COMPLETION(fcoe_flush_completion); /* fcoe host list */ /* must only by accessed under the RTNL mutex */ -LIST_HEAD(fcoe_hostlist); -DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); +static LIST_HEAD(fcoe_hostlist); +static DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); /* Function Prototypes */ static int fcoe_reset(struct Scsi_Host *); @@ -157,7 +161,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { .lport_set_port_id = fcoe_set_port_id, }; -struct fc_function_template fcoe_nport_fc_functions = { +static struct fc_function_template fcoe_nport_fc_functions = { .show_host_node_name = 1, .show_host_port_name = 1, .show_host_supported_classes = 1, @@ -197,7 +201,7 @@ struct fc_function_template fcoe_nport_fc_functions = { .bsg_request = fc_lport_bsg_request, }; -struct fc_function_template fcoe_vport_fc_functions = { +static struct fc_function_template fcoe_vport_fc_functions = { .show_host_node_name = 1, .show_host_port_name = 1, .show_host_supported_classes = 1, @@ -433,7 +437,7 @@ static inline void fcoe_interface_put(struct fcoe_interface *fcoe) * * Caller must be holding the RTNL mutex */ -void fcoe_interface_cleanup(struct fcoe_interface *fcoe) +static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) { struct net_device *netdev = fcoe->netdev; struct fcoe_ctlr *fip = &fcoe->ctlr; @@ -748,7 +752,7 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) * * Returns: True for read types I/O, otherwise returns false. */ -bool fcoe_oem_match(struct fc_frame *fp) +static bool fcoe_oem_match(struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); struct fcp_cmnd *fcp; @@ -756,11 +760,12 @@ bool fcoe_oem_match(struct fc_frame *fp) if (fc_fcp_is_read(fr_fsp(fp)) && (fr_fsp(fp)->data_len > fcoe_ddp_min)) return true; - else if (!(ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)) { + else if ((fr_fsp(fp) == NULL) && + (fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) && + (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) { fcp = fc_frame_payload_get(fp, sizeof(*fcp)); - if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN && - fcp && (ntohl(fcp->fc_dl) > fcoe_ddp_min) && - (fcp->fc_flags & FCP_CFL_WRDATA)) + if ((fcp->fc_flags & FCP_CFL_WRDATA) && + (ntohl(fcp->fc_dl) > fcoe_ddp_min)) return true; } return false; @@ -1106,7 +1111,7 @@ static int __init fcoe_if_init(void) * * Returns: 0 on success */ -int __exit fcoe_if_exit(void) +static int __exit fcoe_if_exit(void) { fc_release_transport(fcoe_nport_scsi_transport); fc_release_transport(fcoe_vport_scsi_transport); @@ -1295,7 +1300,7 @@ static inline unsigned int fcoe_select_cpu(void) * * Returns: 0 for success */ -int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, +static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, struct packet_type *ptype, struct net_device *olddev) { struct fc_lport *lport; @@ -1451,7 +1456,7 @@ static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen) * * Return: 0 for success */ -int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) +static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) { int wlen; u32 crc; @@ -1671,8 +1676,7 @@ static void fcoe_recv_frame(struct sk_buff *skb) skb->dev ? skb->dev->name : "<NULL>"); port = lport_priv(lport); - if (skb_is_nonlinear(skb)) - skb_linearize(skb); /* not ideal */ + skb_linearize(skb); /* check for skb_is_nonlinear is within skb_linearize */ /* * Frame length checks and setting up the header pointers @@ -1728,7 +1732,7 @@ drop: * * Return: 0 for success */ -int fcoe_percpu_receive_thread(void *arg) +static int fcoe_percpu_receive_thread(void *arg) { struct fcoe_percpu_s *p = arg; struct sk_buff *skb; @@ -2146,7 +2150,7 @@ out_nortnl: * Returns: 0 if the ethtool query was successful * -1 if the ethtool query failed */ -int fcoe_link_speed_update(struct fc_lport *lport) +static int fcoe_link_speed_update(struct fc_lport *lport) { struct net_device *netdev = fcoe_netdev(lport); struct ethtool_cmd ecmd; @@ -2180,7 +2184,7 @@ int fcoe_link_speed_update(struct fc_lport *lport) * Returns: 0 if link is UP and OK, -1 if not * */ -int fcoe_link_ok(struct fc_lport *lport) +static int fcoe_link_ok(struct fc_lport *lport) { struct net_device *netdev = fcoe_netdev(lport); @@ -2200,7 +2204,7 @@ int fcoe_link_ok(struct fc_lport *lport) * there no packets that will be handled by the lport, but also that any * threads already handling packet have returned. */ -void fcoe_percpu_clean(struct fc_lport *lport) +static void fcoe_percpu_clean(struct fc_lport *lport) { struct fcoe_percpu_s *pp; struct fcoe_rcv_info *fr; @@ -2251,7 +2255,7 @@ void fcoe_percpu_clean(struct fc_lport *lport) * * Returns: Always 0 (return value required by FC transport template) */ -int fcoe_reset(struct Scsi_Host *shost) +static int fcoe_reset(struct Scsi_Host *shost) { struct fc_lport *lport = shost_priv(shost); struct fcoe_port *port = lport_priv(lport); diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 6c6884bcf840..bcc89e639495 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h @@ -40,9 +40,7 @@ #define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ #define FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */ -unsigned int fcoe_debug_logging; -module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); +extern unsigned int fcoe_debug_logging; #define FCOE_LOGGING 0x01 /* General logging, not categorized */ #define FCOE_NETDEV_LOGGING 0x02 /* Netdevice logging */ diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 5140f5d0fd6b..b96962c39449 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4271,7 +4271,9 @@ static void stop_controller_lockup_detector(struct ctlr_info *h) remove_ctlr_from_lockup_detector_list(h); /* If the list of ctlr's to monitor is empty, stop the thread */ if (list_empty(&hpsa_ctlr_list)) { + spin_unlock_irqrestore(&lockup_detector_lock, flags); kthread_stop(hpsa_lockup_detector); + spin_lock_irqsave(&lockup_detector_lock, flags); hpsa_lockup_detector = NULL; } spin_unlock_irqrestore(&lockup_detector_lock, flags); diff --git a/drivers/scsi/isci/firmware/Makefile b/drivers/scsi/isci/firmware/Makefile deleted file mode 100644 index 5f54461cabc5..000000000000 --- a/drivers/scsi/isci/firmware/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Makefile for create_fw -# -CC=gcc -CFLAGS=-c -Wall -O2 -g -LDFLAGS= -SOURCES=create_fw.c -OBJECTS=$(SOURCES:.cpp=.o) -EXECUTABLE=create_fw - -all: $(SOURCES) $(EXECUTABLE) - -$(EXECUTABLE): $(OBJECTS) - $(CC) $(LDFLAGS) $(OBJECTS) -o $@ - -.c.o: - $(CC) $(CFLAGS) $< -O $@ - -clean: - rm -f *.o $(EXECUTABLE) diff --git a/drivers/scsi/isci/firmware/README b/drivers/scsi/isci/firmware/README deleted file mode 100644 index 8056d2bd233b..000000000000 --- a/drivers/scsi/isci/firmware/README +++ /dev/null @@ -1,36 +0,0 @@ -This defines the temporary binary blow we are to pass to the SCU -driver to emulate the binary firmware that we will eventually be -able to access via NVRAM on the SCU controller. - -The current size of the binary blob is expected to be 149 bytes or larger - -Header Types: -0x1: Phy Masks -0x2: Phy Gens -0x3: SAS Addrs -0xff: End of Data - -ID string - u8[12]: "#SCU MAGIC#\0" -Version - u8: 1 -SubVersion - u8: 0 - -Header Type - u8: 0x1 -Size - u8: 8 -Phy Mask - u32[8] - -Header Type - u8: 0x2 -Size - u8: 8 -Phy Gen - u32[8] - -Header Type - u8: 0x3 -Size - u8: 8 -Sas Addr - u64[8] - -Header Type - u8: 0xf - - -============================================================================== - -Place isci_firmware.bin in /lib/firmware -Be sure to recreate the initramfs image to include the firmware. - diff --git a/drivers/scsi/isci/firmware/create_fw.c b/drivers/scsi/isci/firmware/create_fw.c deleted file mode 100644 index c7a2887a7e95..000000000000 --- a/drivers/scsi/isci/firmware/create_fw.c +++ /dev/null @@ -1,99 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include <asm/types.h> -#include <strings.h> -#include <stdint.h> - -#include "create_fw.h" -#include "../probe_roms.h" - -int write_blob(struct isci_orom *isci_orom) -{ - FILE *fd; - int err; - size_t count; - - fd = fopen(blob_name, "w+"); - if (!fd) { - perror("Open file for write failed"); - fclose(fd); - return -EIO; - } - - count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd); - if (count != 1) { - perror("Write data failed"); - fclose(fd); - return -EIO; - } - - fclose(fd); - - return 0; -} - -void set_binary_values(struct isci_orom *isci_orom) -{ - int ctrl_idx, phy_idx, port_idx; - - /* setting OROM signature */ - strncpy(isci_orom->hdr.signature, sig, strlen(sig)); - isci_orom->hdr.version = version; - isci_orom->hdr.total_block_length = sizeof(struct isci_orom); - isci_orom->hdr.hdr_length = sizeof(struct sci_bios_oem_param_block_hdr); - isci_orom->hdr.num_elements = num_elements; - - for (ctrl_idx = 0; ctrl_idx < 2; ctrl_idx++) { - isci_orom->ctrl[ctrl_idx].controller.mode_type = mode_type; - isci_orom->ctrl[ctrl_idx].controller.max_concurrent_dev_spin_up = - max_num_concurrent_dev_spin_up; - isci_orom->ctrl[ctrl_idx].controller.do_enable_ssc = - enable_ssc; - - for (port_idx = 0; port_idx < 4; port_idx++) - isci_orom->ctrl[ctrl_idx].ports[port_idx].phy_mask = - phy_mask[ctrl_idx][port_idx]; - - for (phy_idx = 0; phy_idx < 4; phy_idx++) { - isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.high = - (__u32)(sas_addr[ctrl_idx][phy_idx] >> 32); - isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.low = - (__u32)(sas_addr[ctrl_idx][phy_idx]); - - isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control0 = - afe_tx_amp_control0; - isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control1 = - afe_tx_amp_control1; - isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control2 = - afe_tx_amp_control2; - isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control3 = - afe_tx_amp_control3; - } - } -} - -int main(void) -{ - int err; - struct isci_orom *isci_orom; - - isci_orom = malloc(sizeof(struct isci_orom)); - memset(isci_orom, 0, sizeof(struct isci_orom)); - - set_binary_values(isci_orom); - - err = write_blob(isci_orom); - if (err < 0) { - free(isci_orom); - return err; - } - - free(isci_orom); - return 0; -} diff --git a/drivers/scsi/isci/firmware/create_fw.h b/drivers/scsi/isci/firmware/create_fw.h deleted file mode 100644 index 5f298828d22e..000000000000 --- a/drivers/scsi/isci/firmware/create_fw.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _CREATE_FW_H_ -#define _CREATE_FW_H_ -#include "../probe_roms.h" - - -/* we are configuring for 2 SCUs */ -static const int num_elements = 2; - -/* - * For all defined arrays: - * elements 0-3 are for SCU0, ports 0-3 - * elements 4-7 are for SCU1, ports 0-3 - * - * valid configurations for one SCU are: - * P0 P1 P2 P3 - * ---------------- - * 0xF,0x0,0x0,0x0 # 1 x4 port - * 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1 - * # ports - * 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2 - * # port - * 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port - * 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration) - * - * if there is a port/phy on which you do not wish to override the default - * values, use the value assigned to UNINIT_PARAM (255). - */ - -/* discovery mode type (port auto config mode by default ) */ - -/* - * if there is a port/phy on which you do not wish to override the default - * values, use the value "0000000000000000". SAS address of zero's is - * considered invalid and will not be used. - */ -#ifdef MPC -static const int mode_type = SCIC_PORT_MANUAL_CONFIGURATION_MODE; -static const __u8 phy_mask[2][4] = { {1, 2, 4, 8}, - {1, 2, 4, 8} }; -static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000001ULL, - 0x5FCFFFFFF0000002ULL, - 0x5FCFFFFFF0000003ULL, - 0x5FCFFFFFF0000004ULL }, - { 0x5FCFFFFFF0000005ULL, - 0x5FCFFFFFF0000006ULL, - 0x5FCFFFFFF0000007ULL, - 0x5FCFFFFFF0000008ULL } }; -#else /* APC (default) */ -static const int mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; -static const __u8 phy_mask[2][4]; -static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFF00000001ULL, - 0x5FCFFFFF00000001ULL, - 0x5FCFFFFF00000001ULL, - 0x5FCFFFFF00000001ULL }, - { 0x5FCFFFFF00000002ULL, - 0x5FCFFFFF00000002ULL, - 0x5FCFFFFF00000002ULL, - 0x5FCFFFFF00000002ULL } }; -#endif - -/* Maximum number of concurrent device spin up */ -static const int max_num_concurrent_dev_spin_up = 1; - -/* enable of ssc operation */ -static const int enable_ssc; - -/* AFE_TX_AMP_CONTROL */ -static const unsigned int afe_tx_amp_control0 = 0x000bdd08; -static const unsigned int afe_tx_amp_control1 = 0x000ffc00; -static const unsigned int afe_tx_amp_control2 = 0x000b7c09; -static const unsigned int afe_tx_amp_control3 = 0x000afc6e; - -static const char blob_name[] = "isci_firmware.bin"; -static const char sig[] = "ISCUOEMB"; -static const unsigned char version = 0x10; - -#endif diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index e7fe9c4c85b8..1a65d6514237 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -899,7 +899,8 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost) */ if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) || (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) || - (iphy->is_in_link_training == true && is_phy_starting(iphy))) { + (iphy->is_in_link_training == true && is_phy_starting(iphy)) || + (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) { is_controller_start_complete = false; break; } @@ -1666,6 +1667,9 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost /* Default to no SSC operation. */ ihost->oem_parameters.controller.do_enable_ssc = false; + /* Default to short cables on all phys. */ + ihost->oem_parameters.controller.cable_selection_mask = 0; + /* Initialize all of the port parameter information to narrow ports. */ for (index = 0; index < SCI_MAX_PORTS; index++) { ihost->oem_parameters.ports[index].phy_mask = 0; @@ -1673,8 +1677,9 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost /* Initialize all of the phy parameter information. */ for (index = 0; index < SCI_MAX_PHYS; index++) { - /* Default to 6G (i.e. Gen 3) for now. */ - ihost->user_parameters.phys[index].max_speed_generation = 3; + /* Default to 3G (i.e. Gen 2). */ + ihost->user_parameters.phys[index].max_speed_generation = + SCIC_SDS_PARM_GEN2_SPEED; /* the frequencies cannot be 0 */ ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f; @@ -1694,7 +1699,7 @@ static void sci_controller_set_default_config_parameters(struct isci_host *ihost ihost->user_parameters.ssp_inactivity_timeout = 5; ihost->user_parameters.stp_max_occupancy_timeout = 5; ihost->user_parameters.ssp_max_occupancy_timeout = 20; - ihost->user_parameters.no_outbound_task_timeout = 20; + ihost->user_parameters.no_outbound_task_timeout = 2; } static void controller_timeout(unsigned long data) @@ -1759,7 +1764,7 @@ static enum sci_status sci_controller_construct(struct isci_host *ihost, return sci_controller_reset(ihost); } -int sci_oem_parameters_validate(struct sci_oem_params *oem) +int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version) { int i; @@ -1791,18 +1796,61 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem) oem->controller.max_concurr_spin_up < 1) return -EINVAL; + if (oem->controller.do_enable_ssc) { + if (version < ISCI_ROM_VER_1_1 && oem->controller.do_enable_ssc != 1) + return -EINVAL; + + if (version >= ISCI_ROM_VER_1_1) { + u8 test = oem->controller.ssc_sata_tx_spread_level; + + switch (test) { + case 0: + case 2: + case 3: + case 6: + case 7: + break; + default: + return -EINVAL; + } + + test = oem->controller.ssc_sas_tx_spread_level; + if (oem->controller.ssc_sas_tx_type == 0) { + switch (test) { + case 0: + case 2: + case 3: + break; + default: + return -EINVAL; + } + } else if (oem->controller.ssc_sas_tx_type == 1) { + switch (test) { + case 0: + case 3: + case 6: + break; + default: + return -EINVAL; + } + } + } + } + return 0; } static enum sci_status sci_oem_parameters_set(struct isci_host *ihost) { u32 state = ihost->sm.current_state_id; + struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); if (state == SCIC_RESET || state == SCIC_INITIALIZING || state == SCIC_INITIALIZED) { - if (sci_oem_parameters_validate(&ihost->oem_parameters)) + if (sci_oem_parameters_validate(&ihost->oem_parameters, + pci_info->orom->hdr.version)) return SCI_FAILURE_INVALID_PARAMETER_VALUE; return SCI_SUCCESS; @@ -1857,6 +1905,31 @@ static void power_control_timeout(unsigned long data) ihost->power_control.phys_waiting--; ihost->power_control.phys_granted_power++; sci_phy_consume_power_handler(iphy); + + if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { + u8 j; + + for (j = 0; j < SCI_MAX_PHYS; j++) { + struct isci_phy *requester = ihost->power_control.requesters[j]; + + /* + * Search the power_control queue to see if there are other phys + * attached to the same remote device. If found, take all of + * them out of await_sas_power state. + */ + if (requester != NULL && requester != iphy) { + u8 other = memcmp(requester->frame_rcvd.iaf.sas_addr, + iphy->frame_rcvd.iaf.sas_addr, + sizeof(requester->frame_rcvd.iaf.sas_addr)); + + if (other == 0) { + ihost->power_control.requesters[j] = NULL; + ihost->power_control.phys_waiting--; + sci_phy_consume_power_handler(requester); + } + } + } + } } /* @@ -1891,9 +1964,34 @@ void sci_controller_power_control_queue_insert(struct isci_host *ihost, ihost->power_control.timer_started = true; } else { - /* Add the phy in the waiting list */ - ihost->power_control.requesters[iphy->phy_index] = iphy; - ihost->power_control.phys_waiting++; + /* + * There are phys, attached to the same sas address as this phy, are + * already in READY state, this phy don't need wait. + */ + u8 i; + struct isci_phy *current_phy; + + for (i = 0; i < SCI_MAX_PHYS; i++) { + u8 other; + current_phy = &ihost->phys[i]; + + other = memcmp(current_phy->frame_rcvd.iaf.sas_addr, + iphy->frame_rcvd.iaf.sas_addr, + sizeof(current_phy->frame_rcvd.iaf.sas_addr)); + + if (current_phy->sm.current_state_id == SCI_PHY_READY && + current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS && + other == 0) { + sci_phy_consume_power_handler(iphy); + break; + } + } + + if (i == SCI_MAX_PHYS) { + /* Add the phy in the waiting list */ + ihost->power_control.requesters[iphy->phy_index] = iphy; + ihost->power_control.phys_waiting++; + } } } @@ -1908,162 +2006,250 @@ void sci_controller_power_control_queue_remove(struct isci_host *ihost, ihost->power_control.requesters[iphy->phy_index] = NULL; } +static int is_long_cable(int phy, unsigned char selection_byte) +{ + return !!(selection_byte & (1 << phy)); +} + +static int is_medium_cable(int phy, unsigned char selection_byte) +{ + return !!(selection_byte & (1 << (phy + 4))); +} + +static enum cable_selections decode_selection_byte( + int phy, + unsigned char selection_byte) +{ + return ((selection_byte & (1 << phy)) ? 1 : 0) + + (selection_byte & (1 << (phy + 4)) ? 2 : 0); +} + +static unsigned char *to_cable_select(struct isci_host *ihost) +{ + if (is_cable_select_overridden()) + return ((unsigned char *)&cable_selection_override) + + ihost->id; + else + return &ihost->oem_parameters.controller.cable_selection_mask; +} + +enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy) +{ + return decode_selection_byte(phy, *to_cable_select(ihost)); +} + +char *lookup_cable_names(enum cable_selections selection) +{ + static char *cable_names[] = { + [short_cable] = "short", + [long_cable] = "long", + [medium_cable] = "medium", + [undefined_cable] = "<undefined, assumed long>" /* bit 0==1 */ + }; + return (selection <= undefined_cable) ? cable_names[selection] + : cable_names[undefined_cable]; +} + #define AFE_REGISTER_WRITE_DELAY 10 -/* Initialize the AFE for this phy index. We need to read the AFE setup from - * the OEM parameters - */ static void sci_controller_afe_initialization(struct isci_host *ihost) { + struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; const struct sci_oem_params *oem = &ihost->oem_parameters; struct pci_dev *pdev = ihost->pdev; u32 afe_status; u32 phy_id; + unsigned char cable_selection_mask = *to_cable_select(ihost); /* Clear DFX Status registers */ - writel(0x0081000f, &ihost->scu_registers->afe.afe_dfx_master_control0); + writel(0x0081000f, &afe->afe_dfx_master_control0); udelay(AFE_REGISTER_WRITE_DELAY); - if (is_b0(pdev)) { + if (is_b0(pdev) || is_c0(pdev) || is_c1(pdev)) { /* PM Rx Equalization Save, PM SPhy Rx Acknowledgement - * Timer, PM Stagger Timer */ - writel(0x0007BFFF, &ihost->scu_registers->afe.afe_pmsn_master_control2); + * Timer, PM Stagger Timer + */ + writel(0x0007FFFF, &afe->afe_pmsn_master_control2); udelay(AFE_REGISTER_WRITE_DELAY); } /* Configure bias currents to normal */ if (is_a2(pdev)) - writel(0x00005A00, &ihost->scu_registers->afe.afe_bias_control); + writel(0x00005A00, &afe->afe_bias_control); else if (is_b0(pdev) || is_c0(pdev)) - writel(0x00005F00, &ihost->scu_registers->afe.afe_bias_control); + writel(0x00005F00, &afe->afe_bias_control); + else if (is_c1(pdev)) + writel(0x00005500, &afe->afe_bias_control); udelay(AFE_REGISTER_WRITE_DELAY); /* Enable PLL */ - if (is_b0(pdev) || is_c0(pdev)) - writel(0x80040A08, &ihost->scu_registers->afe.afe_pll_control0); - else - writel(0x80040908, &ihost->scu_registers->afe.afe_pll_control0); + if (is_a2(pdev)) + writel(0x80040908, &afe->afe_pll_control0); + else if (is_b0(pdev) || is_c0(pdev)) + writel(0x80040A08, &afe->afe_pll_control0); + else if (is_c1(pdev)) { + writel(0x80000B08, &afe->afe_pll_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + writel(0x00000B08, &afe->afe_pll_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + writel(0x80000B08, &afe->afe_pll_control0); + } udelay(AFE_REGISTER_WRITE_DELAY); /* Wait for the PLL to lock */ do { - afe_status = readl(&ihost->scu_registers->afe.afe_common_block_status); + afe_status = readl(&afe->afe_common_block_status); udelay(AFE_REGISTER_WRITE_DELAY); } while ((afe_status & 0x00001000) == 0); if (is_a2(pdev)) { - /* Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us) */ - writel(0x7bcc96ad, &ihost->scu_registers->afe.afe_pmsn_master_control0); + /* Shorten SAS SNW lock time (RxLock timer value from 76 + * us to 50 us) + */ + writel(0x7bcc96ad, &afe->afe_pmsn_master_control0); udelay(AFE_REGISTER_WRITE_DELAY); } for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { + struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_id]; const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id]; + int cable_length_long = + is_long_cable(phy_id, cable_selection_mask); + int cable_length_medium = + is_medium_cable(phy_id, cable_selection_mask); - if (is_b0(pdev)) { - /* Configure transmitter SSC parameters */ - writel(0x00030000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_ssc_control); + if (is_a2(pdev)) { + /* All defaults, except the Receive Word + * Alignament/Comma Detect Enable....(0xe800) + */ + writel(0x00004512, &xcvr->afe_xcvr_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(0x0050100F, &xcvr->afe_xcvr_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + } else if (is_b0(pdev)) { + /* Configure transmitter SSC parameters */ + writel(0x00030000, &xcvr->afe_tx_ssc_control); udelay(AFE_REGISTER_WRITE_DELAY); } else if (is_c0(pdev)) { - /* Configure transmitter SSC parameters */ - writel(0x0003000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_ssc_control); + /* Configure transmitter SSC parameters */ + writel(0x00010202, &xcvr->afe_tx_ssc_control); udelay(AFE_REGISTER_WRITE_DELAY); - /* - * All defaults, except the Receive Word Alignament/Comma Detect - * Enable....(0xe800) */ - writel(0x00004500, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0); + /* All defaults, except the Receive Word + * Alignament/Comma Detect Enable....(0xe800) + */ + writel(0x00014500, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); - } else { - /* - * All defaults, except the Receive Word Alignament/Comma Detect - * Enable....(0xe800) */ - writel(0x00004512, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0); + } else if (is_c1(pdev)) { + /* Configure transmitter SSC parameters */ + writel(0x00010202, &xcvr->afe_tx_ssc_control); udelay(AFE_REGISTER_WRITE_DELAY); - writel(0x0050100F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control1); + /* All defaults, except the Receive Word + * Alignament/Comma Detect Enable....(0xe800) + */ + writel(0x0001C500, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); } - /* - * Power up TX and RX out from power down (PWRDNTX and PWRDNRX) - * & increase TX int & ext bias 20%....(0xe85c) */ + /* Power up TX and RX out from power down (PWRDNTX and + * PWRDNRX) & increase TX int & ext bias 20%....(0xe85c) + */ if (is_a2(pdev)) - writel(0x000003F0, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); + writel(0x000003F0, &xcvr->afe_channel_control); else if (is_b0(pdev)) { - /* Power down TX and RX (PWRDNTX and PWRDNRX) */ - writel(0x000003D7, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); + writel(0x000003D7, &xcvr->afe_channel_control); udelay(AFE_REGISTER_WRITE_DELAY); - /* - * Power up TX and RX out from power down (PWRDNTX and PWRDNRX) - * & increase TX int & ext bias 20%....(0xe85c) */ - writel(0x000003D4, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); - } else { - writel(0x000001E7, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); + writel(0x000003D4, &xcvr->afe_channel_control); + } else if (is_c0(pdev)) { + writel(0x000001E7, &xcvr->afe_channel_control); udelay(AFE_REGISTER_WRITE_DELAY); - /* - * Power up TX and RX out from power down (PWRDNTX and PWRDNRX) - * & increase TX int & ext bias 20%....(0xe85c) */ - writel(0x000001E4, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_channel_control); + writel(0x000001E4, &xcvr->afe_channel_control); + } else if (is_c1(pdev)) { + writel(cable_length_long ? 0x000002F7 : 0x000001F7, + &xcvr->afe_channel_control); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(cable_length_long ? 0x000002F4 : 0x000001F4, + &xcvr->afe_channel_control); } udelay(AFE_REGISTER_WRITE_DELAY); if (is_a2(pdev)) { /* Enable TX equalization (0xe824) */ - writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control); + writel(0x00040000, &xcvr->afe_tx_control); udelay(AFE_REGISTER_WRITE_DELAY); } - /* - * RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On), - * RDD=0x0(RX Detect Enabled) ....(0xe800) */ - writel(0x00004100, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_xcvr_control0); + if (is_a2(pdev) || is_b0(pdev)) + /* RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, + * TPD=0x0(TX Power On), RDD=0x0(RX Detect + * Enabled) ....(0xe800) + */ + writel(0x00004100, &xcvr->afe_xcvr_control0); + else if (is_c0(pdev)) + writel(0x00014100, &xcvr->afe_xcvr_control0); + else if (is_c1(pdev)) + writel(0x0001C100, &xcvr->afe_xcvr_control0); udelay(AFE_REGISTER_WRITE_DELAY); /* Leave DFE/FFE on */ if (is_a2(pdev)) - writel(0x3F11103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0); + writel(0x3F11103F, &xcvr->afe_rx_ssc_control0); else if (is_b0(pdev)) { - writel(0x3F11103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0); + writel(0x3F11103F, &xcvr->afe_rx_ssc_control0); udelay(AFE_REGISTER_WRITE_DELAY); /* Enable TX equalization (0xe824) */ - writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control); - } else { - writel(0x0140DF0F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control1); + writel(0x00040000, &xcvr->afe_tx_control); + } else if (is_c0(pdev)) { + writel(0x01400C0F, &xcvr->afe_rx_ssc_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(0x3F6F103F, &xcvr->afe_rx_ssc_control0); + udelay(AFE_REGISTER_WRITE_DELAY); + + /* Enable TX equalization (0xe824) */ + writel(0x00040000, &xcvr->afe_tx_control); + } else if (is_c1(pdev)) { + writel(cable_length_long ? 0x01500C0C : + cable_length_medium ? 0x01400C0D : 0x02400C0D, + &xcvr->afe_xcvr_control1); + udelay(AFE_REGISTER_WRITE_DELAY); + + writel(0x000003E0, &xcvr->afe_dfx_rx_control1); udelay(AFE_REGISTER_WRITE_DELAY); - writel(0x3F6F103F, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_rx_ssc_control0); + writel(cable_length_long ? 0x33091C1F : + cable_length_medium ? 0x3315181F : 0x2B17161F, + &xcvr->afe_rx_ssc_control0); udelay(AFE_REGISTER_WRITE_DELAY); /* Enable TX equalization (0xe824) */ - writel(0x00040000, &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_control); + writel(0x00040000, &xcvr->afe_tx_control); } udelay(AFE_REGISTER_WRITE_DELAY); - writel(oem_phy->afe_tx_amp_control0, - &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control0); + writel(oem_phy->afe_tx_amp_control0, &xcvr->afe_tx_amp_control0); udelay(AFE_REGISTER_WRITE_DELAY); - writel(oem_phy->afe_tx_amp_control1, - &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control1); + writel(oem_phy->afe_tx_amp_control1, &xcvr->afe_tx_amp_control1); udelay(AFE_REGISTER_WRITE_DELAY); - writel(oem_phy->afe_tx_amp_control2, - &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control2); + writel(oem_phy->afe_tx_amp_control2, &xcvr->afe_tx_amp_control2); udelay(AFE_REGISTER_WRITE_DELAY); - writel(oem_phy->afe_tx_amp_control3, - &ihost->scu_registers->afe.scu_afe_xcvr[phy_id].afe_tx_amp_control3); + writel(oem_phy->afe_tx_amp_control3, &xcvr->afe_tx_amp_control3); udelay(AFE_REGISTER_WRITE_DELAY); } /* Transfer control to the PEs */ - writel(0x00010f00, &ihost->scu_registers->afe.afe_dfx_master_control0); + writel(0x00010f00, &afe->afe_dfx_master_control0); udelay(AFE_REGISTER_WRITE_DELAY); } diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 646051afd3cb..5477f0fa8233 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -435,11 +435,36 @@ static inline bool is_b0(struct pci_dev *pdev) static inline bool is_c0(struct pci_dev *pdev) { - if (pdev->revision >= 5) + if (pdev->revision == 5) return true; return false; } +static inline bool is_c1(struct pci_dev *pdev) +{ + if (pdev->revision >= 6) + return true; + return false; +} + +enum cable_selections { + short_cable = 0, + long_cable = 1, + medium_cable = 2, + undefined_cable = 3 +}; + +#define CABLE_OVERRIDE_DISABLED (0x10000) + +static inline int is_cable_select_overridden(void) +{ + return cable_selection_override < CABLE_OVERRIDE_DISABLED; +} + +enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy); +void validate_cable_selections(struct isci_host *ihost); +char *lookup_cable_names(enum cable_selections); + /* set hw control for 'activity', even though active enclosures seem to drive * the activity led on their own. Skip setting FSENG control on 'status' due * to unexpected operation and 'error' due to not being a supported automatic diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index a97edabcb85a..17c4c2c89c2e 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -65,7 +65,7 @@ #include "probe_roms.h" #define MAJ 1 -#define MIN 0 +#define MIN 1 #define BUILD 0 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) @@ -94,7 +94,7 @@ MODULE_DEVICE_TABLE(pci, isci_id_table); /* linux isci specific settings */ -unsigned char no_outbound_task_to = 20; +unsigned char no_outbound_task_to = 2; module_param(no_outbound_task_to, byte, 0); MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)"); @@ -114,7 +114,7 @@ u16 stp_inactive_to = 5; module_param(stp_inactive_to, ushort, 0); MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)"); -unsigned char phy_gen = 3; +unsigned char phy_gen = SCIC_SDS_PARM_GEN2_SPEED; module_param(phy_gen, byte, 0); MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)"); @@ -122,6 +122,14 @@ unsigned char max_concurr_spinup; module_param(max_concurr_spinup, byte, 0); MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup"); +uint cable_selection_override = CABLE_OVERRIDE_DISABLED; +module_param(cable_selection_override, uint, 0); + +MODULE_PARM_DESC(cable_selection_override, + "This field indicates length of the SAS/SATA cable between " + "host and device. If any bits > 15 are set (default) " + "indicates \"use platform defaults\""); + static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev); @@ -412,6 +420,14 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) return NULL; isci_host->shost = shost; + dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: " + "{%s, %s, %s, %s}\n", + (is_cable_select_overridden() ? "* " : ""), isci_host->id, + lookup_cable_names(decode_cable_selection(isci_host, 3)), + lookup_cable_names(decode_cable_selection(isci_host, 2)), + lookup_cable_names(decode_cable_selection(isci_host, 1)), + lookup_cable_names(decode_cable_selection(isci_host, 0))); + err = isci_host_init(isci_host); if (err) goto err_shost; @@ -466,7 +482,8 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic orom = isci_request_oprom(pdev); for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) { - if (sci_oem_parameters_validate(&orom->ctrl[i])) { + if (sci_oem_parameters_validate(&orom->ctrl[i], + orom->hdr.version)) { dev_warn(&pdev->dev, "[%d]: invalid oem parameters detected, falling back to firmware\n", i); devm_kfree(&pdev->dev, orom); diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index 8efeb6b08321..234ab46fce33 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h @@ -480,6 +480,7 @@ extern u16 ssp_inactive_to; extern u16 stp_inactive_to; extern unsigned char phy_gen; extern unsigned char max_concurr_spinup; +extern uint cable_selection_override; irqreturn_t isci_msix_isr(int vec, void *data); irqreturn_t isci_intx_isr(int vec, void *data); diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 35f50c2183e1..fe18acfd6eb3 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -91,22 +91,23 @@ sci_phy_transport_layer_initialization(struct isci_phy *iphy, static enum sci_status sci_phy_link_layer_initialization(struct isci_phy *iphy, - struct scu_link_layer_registers __iomem *reg) + struct scu_link_layer_registers __iomem *llr) { struct isci_host *ihost = iphy->owning_port->owning_controller; + struct sci_phy_user_params *phy_user; + struct sci_phy_oem_params *phy_oem; int phy_idx = iphy->phy_index; - struct sci_phy_user_params *phy_user = &ihost->user_parameters.phys[phy_idx]; - struct sci_phy_oem_params *phy_oem = - &ihost->oem_parameters.phys[phy_idx]; - u32 phy_configuration; struct sci_phy_cap phy_cap; + u32 phy_configuration; u32 parity_check = 0; u32 parity_count = 0; u32 llctl, link_rate; u32 clksm_value = 0; u32 sp_timeouts = 0; - iphy->link_layer_registers = reg; + phy_user = &ihost->user_parameters.phys[phy_idx]; + phy_oem = &ihost->oem_parameters.phys[phy_idx]; + iphy->link_layer_registers = llr; /* Set our IDENTIFY frame data */ #define SCI_END_DEVICE 0x01 @@ -116,32 +117,26 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, SCU_SAS_TIID_GEN_BIT(STP_INITIATOR) | SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST) | SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE), - &iphy->link_layer_registers->transmit_identification); + &llr->transmit_identification); /* Write the device SAS Address */ - writel(0xFEDCBA98, - &iphy->link_layer_registers->sas_device_name_high); - writel(phy_idx, &iphy->link_layer_registers->sas_device_name_low); + writel(0xFEDCBA98, &llr->sas_device_name_high); + writel(phy_idx, &llr->sas_device_name_low); /* Write the source SAS Address */ - writel(phy_oem->sas_address.high, - &iphy->link_layer_registers->source_sas_address_high); - writel(phy_oem->sas_address.low, - &iphy->link_layer_registers->source_sas_address_low); + writel(phy_oem->sas_address.high, &llr->source_sas_address_high); + writel(phy_oem->sas_address.low, &llr->source_sas_address_low); /* Clear and Set the PHY Identifier */ - writel(0, &iphy->link_layer_registers->identify_frame_phy_id); - writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), - &iphy->link_layer_registers->identify_frame_phy_id); + writel(0, &llr->identify_frame_phy_id); + writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), &llr->identify_frame_phy_id); /* Change the initial state of the phy configuration register */ - phy_configuration = - readl(&iphy->link_layer_registers->phy_configuration); + phy_configuration = readl(&llr->phy_configuration); /* Hold OOB state machine in reset */ phy_configuration |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET); - writel(phy_configuration, - &iphy->link_layer_registers->phy_configuration); + writel(phy_configuration, &llr->phy_configuration); /* Configure the SNW capabilities */ phy_cap.all = 0; @@ -149,15 +144,64 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, phy_cap.gen3_no_ssc = 1; phy_cap.gen2_no_ssc = 1; phy_cap.gen1_no_ssc = 1; - if (ihost->oem_parameters.controller.do_enable_ssc == true) { + if (ihost->oem_parameters.controller.do_enable_ssc) { + struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; + struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_idx]; + struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); + bool en_sas = false; + bool en_sata = false; + u32 sas_type = 0; + u32 sata_spread = 0x2; + u32 sas_spread = 0x2; + phy_cap.gen3_ssc = 1; phy_cap.gen2_ssc = 1; phy_cap.gen1_ssc = 1; + + if (pci_info->orom->hdr.version < ISCI_ROM_VER_1_1) + en_sas = en_sata = true; + else { + sata_spread = ihost->oem_parameters.controller.ssc_sata_tx_spread_level; + sas_spread = ihost->oem_parameters.controller.ssc_sas_tx_spread_level; + + if (sata_spread) + en_sata = true; + + if (sas_spread) { + en_sas = true; + sas_type = ihost->oem_parameters.controller.ssc_sas_tx_type; + } + + } + + if (en_sas) { + u32 reg; + + reg = readl(&xcvr->afe_xcvr_control0); + reg |= (0x00100000 | (sas_type << 19)); + writel(reg, &xcvr->afe_xcvr_control0); + + reg = readl(&xcvr->afe_tx_ssc_control); + reg |= sas_spread << 8; + writel(reg, &xcvr->afe_tx_ssc_control); + } + + if (en_sata) { + u32 reg; + + reg = readl(&xcvr->afe_tx_ssc_control); + reg |= sata_spread; + writel(reg, &xcvr->afe_tx_ssc_control); + + reg = readl(&llr->stp_control); + reg |= 1 << 12; + writel(reg, &llr->stp_control); + } } - /* - * The SAS specification indicates that the phy_capabilities that - * are transmitted shall have an even parity. Calculate the parity. */ + /* The SAS specification indicates that the phy_capabilities that + * are transmitted shall have an even parity. Calculate the parity. + */ parity_check = phy_cap.all; while (parity_check != 0) { if (parity_check & 0x1) @@ -165,20 +209,20 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, parity_check >>= 1; } - /* - * If parity indicates there are an odd number of bits set, then - * set the parity bit to 1 in the phy capabilities. */ + /* If parity indicates there are an odd number of bits set, then + * set the parity bit to 1 in the phy capabilities. + */ if ((parity_count % 2) != 0) phy_cap.parity = 1; - writel(phy_cap.all, &iphy->link_layer_registers->phy_capabilities); + writel(phy_cap.all, &llr->phy_capabilities); /* Set the enable spinup period but disable the ability to send * notify enable spinup */ writel(SCU_ENSPINUP_GEN_VAL(COUNT, phy_user->notify_enable_spin_up_insertion_frequency), - &iphy->link_layer_registers->notify_enable_spinup_control); + &llr->notify_enable_spinup_control); /* Write the ALIGN Insertion Ferequency for connected phy and * inpendent of connected state @@ -189,11 +233,13 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(GENERAL, phy_user->align_insertion_frequency); - writel(clksm_value, &iphy->link_layer_registers->clock_skew_management); + writel(clksm_value, &llr->clock_skew_management); - /* @todo Provide a way to write this register correctly */ - writel(0x02108421, - &iphy->link_layer_registers->afe_lookup_table_control); + if (is_c0(ihost->pdev) || is_c1(ihost->pdev)) { + writel(0x04210400, &llr->afe_lookup_table_control); + writel(0x020A7C05, &llr->sas_primitive_timeout); + } else + writel(0x02108421, &llr->afe_lookup_table_control); llctl = SCU_SAS_LLCTL_GEN_VAL(NO_OUTBOUND_TASK_TIMEOUT, (u8)ihost->user_parameters.no_outbound_task_timeout); @@ -210,9 +256,9 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, break; } llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate); - writel(llctl, &iphy->link_layer_registers->link_layer_control); + writel(llctl, &llr->link_layer_control); - sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts); + sp_timeouts = readl(&llr->sas_phy_timeouts); /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */ sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF); @@ -222,20 +268,23 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, */ sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B); - writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts); + writel(sp_timeouts, &llr->sas_phy_timeouts); if (is_a2(ihost->pdev)) { - /* Program the max ARB time for the PHY to 700us so we inter-operate with - * the PMC expander which shuts down PHYs if the expander PHY generates too - * many breaks. This time value will guarantee that the initiator PHY will - * generate the break. + /* Program the max ARB time for the PHY to 700us so we + * inter-operate with the PMC expander which shuts down + * PHYs if the expander PHY generates too many breaks. + * This time value will guarantee that the initiator PHY + * will generate the break. */ writel(SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME, - &iphy->link_layer_registers->maximum_arbitration_wait_timer_timeout); + &llr->maximum_arbitration_wait_timer_timeout); } - /* Disable link layer hang detection, rely on the OS timeout for I/O timeouts. */ - writel(0, &iphy->link_layer_registers->link_layer_hang_detection_timeout); + /* Disable link layer hang detection, rely on the OS timeout for + * I/O timeouts. + */ + writel(0, &llr->link_layer_hang_detection_timeout); /* We can exit the initial state to the stopped state */ sci_change_state(&iphy->sm, SCI_PHY_STOPPED); @@ -1049,24 +1098,25 @@ static void scu_link_layer_stop_protocol_engine( writel(enable_spinup_value, &iphy->link_layer_registers->notify_enable_spinup_control); } -/** - * - * - * This method will start the OOB/SN state machine for this struct isci_phy object. - */ -static void scu_link_layer_start_oob( - struct isci_phy *iphy) +static void scu_link_layer_start_oob(struct isci_phy *iphy) { - u32 scu_sas_pcfg_value; - - scu_sas_pcfg_value = - readl(&iphy->link_layer_registers->phy_configuration); - scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); - scu_sas_pcfg_value &= - ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | - SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); - writel(scu_sas_pcfg_value, - &iphy->link_layer_registers->phy_configuration); + struct scu_link_layer_registers __iomem *ll = iphy->link_layer_registers; + u32 val; + + /** Reset OOB sequence - start */ + val = readl(&ll->phy_configuration); + val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | + SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); + writel(val, &ll->phy_configuration); + readl(&ll->phy_configuration); /* flush */ + /** Reset OOB sequence - end */ + + /** Start OOB sequence - start */ + val = readl(&ll->phy_configuration); + val |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); + writel(val, &ll->phy_configuration); + readl(&ll->phy_configuration); /* flush */ + /** Start OOB sequence - end */ } /** diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index ac7f27749f97..7c6ac58a5c4c 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c @@ -114,7 +114,7 @@ static u32 sci_port_get_phys(struct isci_port *iport) * value is returned if the specified port is not valid. When this value is * returned, no data is copied to the properties output parameter. */ -static enum sci_status sci_port_get_properties(struct isci_port *iport, +enum sci_status sci_port_get_properties(struct isci_port *iport, struct sci_port_properties *prop) { if (!iport || iport->logical_port_index == SCIC_SDS_DUMMY_PORT) @@ -647,19 +647,26 @@ void sci_port_setup_transports(struct isci_port *iport, u32 device_id) } } -static void sci_port_activate_phy(struct isci_port *iport, struct isci_phy *iphy, - bool do_notify_user) +static void sci_port_resume_phy(struct isci_port *iport, struct isci_phy *iphy) +{ + sci_phy_resume(iphy); + iport->enabled_phy_mask |= 1 << iphy->phy_index; +} + +static void sci_port_activate_phy(struct isci_port *iport, + struct isci_phy *iphy, + u8 flags) { struct isci_host *ihost = iport->owning_controller; - if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) + if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA && (flags & PF_RESUME)) sci_phy_resume(iphy); iport->active_phy_mask |= 1 << iphy->phy_index; sci_controller_clear_invalid_phy(ihost, iphy); - if (do_notify_user == true) + if (flags & PF_NOTIFY) isci_port_link_up(ihost, iport, iphy); } @@ -669,14 +676,19 @@ void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy, struct isci_host *ihost = iport->owning_controller; iport->active_phy_mask &= ~(1 << iphy->phy_index); + iport->enabled_phy_mask &= ~(1 << iphy->phy_index); if (!iport->active_phy_mask) iport->last_active_phy = iphy->phy_index; iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; - /* Re-assign the phy back to the LP as if it were a narrow port */ - writel(iphy->phy_index, - &iport->port_pe_configuration_register[iphy->phy_index]); + /* Re-assign the phy back to the LP as if it were a narrow port for APC + * mode. For MPC mode, the phy will remain in the port. + */ + if (iport->owning_controller->oem_parameters.controller.mode_type == + SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) + writel(iphy->phy_index, + &iport->port_pe_configuration_register[iphy->phy_index]); if (do_notify_user == true) isci_port_link_down(ihost, iphy, iport); @@ -701,18 +713,16 @@ static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *i * sci_port_general_link_up_handler - phy can be assigned to port? * @sci_port: sci_port object for which has a phy that has gone link up. * @sci_phy: This is the struct isci_phy object that has gone link up. - * @do_notify_user: This parameter specifies whether to inform the user (via - * sci_port_link_up()) as to the fact that a new phy as become ready. + * @flags: PF_RESUME, PF_NOTIFY to sci_port_activate_phy * - * Determine if this phy can be assigned to this - * port . If the phy is not a valid PHY for - * this port then the function will notify the user. A PHY can only be - * part of a port if it's attached SAS ADDRESS is the same as all other PHYs in - * the same port. none + * Determine if this phy can be assigned to this port . If the phy is + * not a valid PHY for this port then the function will notify the user. + * A PHY can only be part of a port if it's attached SAS ADDRESS is the + * same as all other PHYs in the same port. */ static void sci_port_general_link_up_handler(struct isci_port *iport, - struct isci_phy *iphy, - bool do_notify_user) + struct isci_phy *iphy, + u8 flags) { struct sci_sas_address port_sas_address; struct sci_sas_address phy_sas_address; @@ -730,7 +740,7 @@ static void sci_port_general_link_up_handler(struct isci_port *iport, iport->active_phy_mask == 0) { struct sci_base_state_machine *sm = &iport->sm; - sci_port_activate_phy(iport, iphy, do_notify_user); + sci_port_activate_phy(iport, iphy, flags); if (sm->current_state_id == SCI_PORT_RESETTING) port_state_machine_change(iport, SCI_PORT_READY); } else @@ -781,11 +791,16 @@ bool sci_port_link_detected( struct isci_phy *iphy) { if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) && - (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) && - sci_port_is_wide(iport)) { - sci_port_invalid_link_up(iport, iphy); - - return false; + (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)) { + if (sci_port_is_wide(iport)) { + sci_port_invalid_link_up(iport, iphy); + return false; + } else { + struct isci_host *ihost = iport->owning_controller; + struct isci_port *dst_port = &(ihost->ports[iphy->phy_index]); + writel(iphy->phy_index, + &dst_port->port_pe_configuration_register[iphy->phy_index]); + } } return true; @@ -975,6 +990,13 @@ static void sci_port_ready_substate_waiting_enter(struct sci_base_state_machine } } +static void scic_sds_port_ready_substate_waiting_exit( + struct sci_base_state_machine *sm) +{ + struct isci_port *iport = container_of(sm, typeof(*iport), sm); + sci_port_resume_port_task_scheduler(iport); +} + static void sci_port_ready_substate_operational_enter(struct sci_base_state_machine *sm) { u32 index; @@ -988,13 +1010,13 @@ static void sci_port_ready_substate_operational_enter(struct sci_base_state_mach writel(iport->physical_port_index, &iport->port_pe_configuration_register[ iport->phy_table[index]->phy_index]); + if (((iport->active_phy_mask^iport->enabled_phy_mask) & (1 << index)) != 0) + sci_port_resume_phy(iport, iport->phy_table[index]); } } sci_port_update_viit_entry(iport); - sci_port_resume_port_task_scheduler(iport); - /* * Post the dummy task for the port so the hardware can schedule * io correctly @@ -1061,20 +1083,9 @@ static void sci_port_ready_substate_configuring_enter(struct sci_base_state_mach if (iport->active_phy_mask == 0) { isci_port_not_ready(ihost, iport); - port_state_machine_change(iport, - SCI_PORT_SUB_WAITING); - } else if (iport->started_request_count == 0) - port_state_machine_change(iport, - SCI_PORT_SUB_OPERATIONAL); -} - -static void sci_port_ready_substate_configuring_exit(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - - sci_port_suspend_port_task_scheduler(iport); - if (iport->ready_exit) - sci_port_invalidate_dummy_remote_node(iport); + port_state_machine_change(iport, SCI_PORT_SUB_WAITING); + } else + port_state_machine_change(iport, SCI_PORT_SUB_OPERATIONAL); } enum sci_status sci_port_start(struct isci_port *iport) @@ -1252,7 +1263,7 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, if (status != SCI_SUCCESS) return status; - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME); iport->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; port_state_machine_change(iport, SCI_PORT_SUB_CONFIGURING); @@ -1262,7 +1273,7 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, if (status != SCI_SUCCESS) return status; - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY); /* Re-enter the configuring state since this may be the last phy in * the port. @@ -1338,13 +1349,13 @@ enum sci_status sci_port_link_up(struct isci_port *iport, /* Since this is the first phy going link up for the port we * can just enable it and continue */ - sci_port_activate_phy(iport, iphy, true); + sci_port_activate_phy(iport, iphy, PF_NOTIFY|PF_RESUME); port_state_machine_change(iport, SCI_PORT_SUB_OPERATIONAL); return SCI_SUCCESS; case SCI_PORT_SUB_OPERATIONAL: - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME); return SCI_SUCCESS; case SCI_PORT_RESETTING: /* TODO We should make sure that the phy that has gone @@ -1361,7 +1372,7 @@ enum sci_status sci_port_link_up(struct isci_port *iport, /* In the resetting state we don't notify the user regarding * link up and link down notifications. */ - sci_port_general_link_up_handler(iport, iphy, false); + sci_port_general_link_up_handler(iport, iphy, PF_RESUME); return SCI_SUCCESS; default: dev_warn(sciport_to_dev(iport), @@ -1584,14 +1595,14 @@ static const struct sci_base_state sci_port_state_table[] = { }, [SCI_PORT_SUB_WAITING] = { .enter_state = sci_port_ready_substate_waiting_enter, + .exit_state = scic_sds_port_ready_substate_waiting_exit, }, [SCI_PORT_SUB_OPERATIONAL] = { .enter_state = sci_port_ready_substate_operational_enter, .exit_state = sci_port_ready_substate_operational_exit }, [SCI_PORT_SUB_CONFIGURING] = { - .enter_state = sci_port_ready_substate_configuring_enter, - .exit_state = sci_port_ready_substate_configuring_exit + .enter_state = sci_port_ready_substate_configuring_enter }, [SCI_PORT_RESETTING] = { .exit_state = sci_port_resetting_state_exit @@ -1609,6 +1620,7 @@ void sci_port_construct(struct isci_port *iport, u8 index, iport->logical_port_index = SCIC_SDS_DUMMY_PORT; iport->physical_port_index = index; iport->active_phy_mask = 0; + iport->enabled_phy_mask = 0; iport->last_active_phy = 0; iport->ready_exit = false; diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h index cb5ffbc38603..08116090eb70 100644 --- a/drivers/scsi/isci/port.h +++ b/drivers/scsi/isci/port.h @@ -63,6 +63,9 @@ #define SCIC_SDS_DUMMY_PORT 0xFF +#define PF_NOTIFY (1 << 0) +#define PF_RESUME (1 << 1) + struct isci_phy; struct isci_host; @@ -83,6 +86,8 @@ enum isci_status { * @logical_port_index: software port index * @physical_port_index: hardware port index * @active_phy_mask: identifies phy members + * @enabled_phy_mask: phy mask for the port + * that are already part of the port * @reserved_tag: * @reserved_rni: reserver for port task scheduler workaround * @started_request_count: reference count for outstanding commands @@ -104,6 +109,7 @@ struct isci_port { u8 logical_port_index; u8 physical_port_index; u8 active_phy_mask; + u8 enabled_phy_mask; u8 last_active_phy; u16 reserved_rni; u16 reserved_tag; @@ -250,6 +256,10 @@ bool sci_port_link_detected( struct isci_port *iport, struct isci_phy *iphy); +enum sci_status sci_port_get_properties( + struct isci_port *iport, + struct sci_port_properties *prop); + enum sci_status sci_port_link_up(struct isci_port *iport, struct isci_phy *iphy); enum sci_status sci_port_link_down(struct isci_port *iport, diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c index 38a99d281141..6d1e9544cbe5 100644 --- a/drivers/scsi/isci/port_config.c +++ b/drivers/scsi/isci/port_config.c @@ -57,7 +57,7 @@ #define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) #define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) -#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (100) +#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250) enum SCIC_SDS_APC_ACTIVITY { SCIC_SDS_APC_SKIP_PHY, @@ -466,6 +466,23 @@ sci_apc_agent_validate_phy_configuration(struct isci_host *ihost, return sci_port_configuration_agent_validate_ports(ihost, port_agent); } +/* + * This routine will restart the automatic port configuration timeout + * timer for the next time period. This could be caused by either a link + * down event or a link up event where we can not yet tell to which a phy + * belongs. + */ +static void sci_apc_agent_start_timer( + struct sci_port_configuration_agent *port_agent, + u32 timeout) +{ + if (port_agent->timer_pending) + sci_del_timer(&port_agent->timer); + + port_agent->timer_pending = true; + sci_mod_timer(&port_agent->timer, timeout); +} + static void sci_apc_agent_configure_ports(struct isci_host *ihost, struct sci_port_configuration_agent *port_agent, struct isci_phy *iphy, @@ -565,17 +582,8 @@ static void sci_apc_agent_configure_ports(struct isci_host *ihost, break; case SCIC_SDS_APC_START_TIMER: - /* - * This can occur for either a link down event, or a link - * up event where we cannot yet tell the port to which a - * phy belongs. - */ - if (port_agent->timer_pending) - sci_del_timer(&port_agent->timer); - - port_agent->timer_pending = true; - sci_mod_timer(&port_agent->timer, - SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); + sci_apc_agent_start_timer(port_agent, + SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); break; case SCIC_SDS_APC_SKIP_PHY: @@ -607,7 +615,8 @@ static void sci_apc_agent_link_up(struct isci_host *ihost, if (!iport) { /* the phy is not the part of this port */ port_agent->phy_ready_mask |= 1 << phy_index; - sci_apc_agent_configure_ports(ihost, port_agent, iphy, true); + sci_apc_agent_start_timer(port_agent, + SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); } else { /* the phy is already the part of the port */ u32 port_state = iport->sm.current_state_id; diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c index b5f4341de243..9b8117b9d756 100644 --- a/drivers/scsi/isci/probe_roms.c +++ b/drivers/scsi/isci/probe_roms.c @@ -147,7 +147,7 @@ struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmw memcpy(orom, fw->data, fw->size); - if (is_c0(pdev)) + if (is_c0(pdev) || is_c1(pdev)) goto out; /* diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h index 2c75248ca326..bb0e9d4d97c9 100644 --- a/drivers/scsi/isci/probe_roms.h +++ b/drivers/scsi/isci/probe_roms.h @@ -152,7 +152,7 @@ struct sci_user_parameters { #define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4 struct sci_oem_params; -int sci_oem_parameters_validate(struct sci_oem_params *oem); +int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version); struct isci_orom; struct isci_orom *isci_request_oprom(struct pci_dev *pdev); @@ -191,6 +191,11 @@ struct isci_oem_hdr { 0x1a, 0x04, 0xc6) #define ISCI_EFI_VAR_NAME "RstScuO" +#define ISCI_ROM_VER_1_0 0x10 +#define ISCI_ROM_VER_1_1 0x11 +#define ISCI_ROM_VER_1_3 0x13 +#define ISCI_ROM_VER_LATEST ISCI_ROM_VER_1_3 + /* Allowed PORT configuration modes APC Automatic PORT configuration mode is * defined by the OEM configuration parameters providing no PHY_MASK parameters * for any PORT. i.e. There are no phys assigned to any of the ports at start. @@ -220,8 +225,86 @@ struct sci_oem_params { struct { uint8_t mode_type; uint8_t max_concurr_spin_up; - uint8_t do_enable_ssc; - uint8_t reserved; + /* + * This bitfield indicates the OEM's desired default Tx + * Spread Spectrum Clocking (SSC) settings for SATA and SAS. + * NOTE: Default SSC Modulation Frequency is 31.5KHz. + */ + union { + struct { + /* + * NOTE: Max spread for SATA is +0 / -5000 PPM. + * Down-spreading SSC (only method allowed for SATA): + * SATA SSC Tx Disabled = 0x0 + * SATA SSC Tx at +0 / -1419 PPM Spread = 0x2 + * SATA SSC Tx at +0 / -2129 PPM Spread = 0x3 + * SATA SSC Tx at +0 / -4257 PPM Spread = 0x6 + * SATA SSC Tx at +0 / -4967 PPM Spread = 0x7 + */ + uint8_t ssc_sata_tx_spread_level:4; + /* + * SAS SSC Tx Disabled = 0x0 + * + * NOTE: Max spread for SAS down-spreading +0 / + * -2300 PPM + * Down-spreading SSC: + * SAS SSC Tx at +0 / -1419 PPM Spread = 0x2 + * SAS SSC Tx at +0 / -2129 PPM Spread = 0x3 + * + * NOTE: Max spread for SAS center-spreading +2300 / + * -2300 PPM + * Center-spreading SSC: + * SAS SSC Tx at +1064 / -1064 PPM Spread = 0x3 + * SAS SSC Tx at +2129 / -2129 PPM Spread = 0x6 + */ + uint8_t ssc_sas_tx_spread_level:3; + /* + * NOTE: Refer to the SSC section of the SAS 2.x + * Specification for proper setting of this field. + * For standard SAS Initiator SAS PHY operation it + * should be 0 for Down-spreading. + * SAS SSC Tx spread type: + * Down-spreading SSC = 0 + * Center-spreading SSC = 1 + */ + uint8_t ssc_sas_tx_type:1; + }; + uint8_t do_enable_ssc; + }; + /* + * This field indicates length of the SAS/SATA cable between + * host and device. + * This field is used make relationship between analog + * parameters of the phy in the silicon and length of the cable. + * Supported cable attenuation levels: + * "short"- up to 3m, "medium"-3m to 6m, and "long"- more than + * 6m. + * + * This is bit mask field: + * + * BIT: (MSB) 7 6 5 4 + * ASSIGNMENT: <phy3><phy2><phy1><phy0> - Medium cable + * length assignment + * BIT: 3 2 1 0 (LSB) + * ASSIGNMENT: <phy3><phy2><phy1><phy0> - Long cable length + * assignment + * + * BITS 7-4 are set when the cable length is assigned to medium + * BITS 3-0 are set when the cable length is assigned to long + * + * The BIT positions are clear when the cable length is + * assigned to short. + * + * Setting the bits for both long and medium cable length is + * undefined. + * + * A value of 0x84 would assign + * phy3 - medium + * phy2 - long + * phy1 - short + * phy0 - short + */ + uint8_t cable_selection_mask; } controller; struct { diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index b207cd3b15a0..dd74b6ceeb82 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -53,6 +53,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <scsi/sas.h> +#include <linux/bitops.h> #include "isci.h" #include "port.h" #include "remote_device.h" @@ -1101,6 +1102,7 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, struct isci_remote_device *idev) { enum sci_status status; + struct sci_port_properties properties; struct domain_device *dev = idev->domain_dev; sci_remote_device_construct(iport, idev); @@ -1110,6 +1112,11 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, * entries will be needed to store the remote node. */ idev->is_direct_attached = true; + + sci_port_get_properties(iport, &properties); + /* Get accurate port width from port's phy mask for a DA device. */ + idev->device_port_width = hweight32(properties.phy_mask); + status = sci_controller_allocate_remote_node_context(iport->owning_controller, idev, &idev->rnc.remote_node_index); @@ -1125,9 +1132,6 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, idev->connection_rate = sci_port_get_max_allowed_speed(iport); - /* / @todo Should I assign the port width by reading all of the phys on the port? */ - idev->device_port_width = 1; - return SCI_SUCCESS; } diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 66ad3dc89498..f5a3f7d2bdab 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -496,7 +496,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, } } - isci_print_tmf(tmf); + isci_print_tmf(ihost, tmf); if (tmf->status == SCI_SUCCESS) ret = TMF_RESP_FUNC_COMPLETE; diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h index bc78c0a41d5c..1b27b3797c6c 100644 --- a/drivers/scsi/isci/task.h +++ b/drivers/scsi/isci/task.h @@ -106,7 +106,6 @@ struct isci_tmf { } resp; unsigned char lun[8]; u16 io_tag; - struct isci_remote_device *device; enum isci_tmf_function_codes tmf_code; int status; @@ -120,10 +119,10 @@ struct isci_tmf { }; -static inline void isci_print_tmf(struct isci_tmf *tmf) +static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf) { if (SAS_PROTOCOL_SATA == tmf->proto) - dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: status = %x\n" "tmf->resp.d2h_fis.status = %x\n" "tmf->resp.d2h_fis.error = %x\n", @@ -132,7 +131,7 @@ static inline void isci_print_tmf(struct isci_tmf *tmf) tmf->resp.d2h_fis.status, tmf->resp.d2h_fis.error); else - dev_dbg(&tmf->device->isci_port->isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: status = %x\n" "tmf->resp.resp_iu.data_present = %x\n" "tmf->resp.resp_iu.status = %x\n" diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 7269e928824a..1d1b0c9da29b 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -61,7 +61,7 @@ static void fc_disc_restart(struct fc_disc *); * Locking Note: This function expects that the lport mutex is locked before * calling it. */ -void fc_disc_stop_rports(struct fc_disc *disc) +static void fc_disc_stop_rports(struct fc_disc *disc) { struct fc_lport *lport; struct fc_rport_priv *rdata; @@ -682,7 +682,7 @@ static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp) * fc_disc_stop() - Stop discovery for a given lport * @lport: The local port that discovery should stop on */ -void fc_disc_stop(struct fc_lport *lport) +static void fc_disc_stop(struct fc_lport *lport) { struct fc_disc *disc = &lport->disc; @@ -698,7 +698,7 @@ void fc_disc_stop(struct fc_lport *lport) * This function will block until discovery has been * completely stopped and all rports have been deleted. */ -void fc_disc_stop_final(struct fc_lport *lport) +static void fc_disc_stop_final(struct fc_lport *lport) { fc_disc_stop(lport); lport->tt.rport_flush_queue(); diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index fb9161dc4ca6..e17a28d324d0 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -28,6 +28,7 @@ #include <scsi/fc/fc_els.h> #include <scsi/libfc.h> #include <scsi/fc_encode.h> +#include "fc_libfc.h" /** * fc_elsct_send() - Send an ELS or CT frame diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 9de9db27e874..4d70d96fa5dc 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -91,7 +91,7 @@ struct fc_exch_pool { * It manages the allocation of exchange IDs. */ struct fc_exch_mgr { - struct fc_exch_pool *pool; + struct fc_exch_pool __percpu *pool; mempool_t *ep_pool; enum fc_class class; struct kref kref; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 221875ec3d7c..f607314810ac 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -155,6 +155,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp) fsp->xfer_ddp = FC_XID_UNKNOWN; atomic_set(&fsp->ref_cnt, 1); init_timer(&fsp->timer); + fsp->timer.data = (unsigned long)fsp; INIT_LIST_HEAD(&fsp->list); spin_lock_init(&fsp->scsi_pkt_lock); } @@ -1850,9 +1851,6 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd) } put_cpu(); - init_timer(&fsp->timer); - fsp->timer.data = (unsigned long)fsp; - /* * send it to the lower layer * if we get -1 return then put the request in the pending diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index e77094a587ed..83750ebb527f 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -677,7 +677,8 @@ EXPORT_SYMBOL(fc_set_mfs); * @lport: The local port receiving the event * @event: The discovery event */ -void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event) +static void fc_lport_disc_callback(struct fc_lport *lport, + enum fc_disc_event event) { switch (event) { case DISC_EV_SUCCESS: @@ -1568,7 +1569,7 @@ EXPORT_SYMBOL(fc_lport_flogi_resp); * Locking Note: The lport lock is expected to be held before calling * this routine. */ -void fc_lport_enter_flogi(struct fc_lport *lport) +static void fc_lport_enter_flogi(struct fc_lport *lport) { struct fc_frame *fp; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index b9e434844a69..83aa1efec875 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -391,7 +391,7 @@ static void fc_rport_work(struct work_struct *work) * If it appears we are already logged in, ADISC is used to verify * the setup. */ -int fc_rport_login(struct fc_rport_priv *rdata) +static int fc_rport_login(struct fc_rport_priv *rdata) { mutex_lock(&rdata->rp_mutex); @@ -451,7 +451,7 @@ static void fc_rport_enter_delete(struct fc_rport_priv *rdata, * function will hold the rport lock, call an _enter_* * function and then unlock the rport. */ -int fc_rport_logoff(struct fc_rport_priv *rdata) +static int fc_rport_logoff(struct fc_rport_priv *rdata) { mutex_lock(&rdata->rp_mutex); @@ -653,8 +653,8 @@ static int fc_rport_login_complete(struct fc_rport_priv *rdata, * @fp: The FLOGI response frame * @rp_arg: The remote port that received the FLOGI response */ -void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) +static void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rp_arg) { struct fc_rport_priv *rdata = rp_arg; struct fc_lport *lport = rdata->local_port; @@ -1520,7 +1520,7 @@ reject: * * Locking Note: Called with the lport lock held. */ -void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp) +static void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp) { struct fc_seq_els_data els_data; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 5c1776406c96..15eefa1d61fd 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -306,19 +306,22 @@ mega_query_adapter(adapter_t *adapter) adapter->host->sg_tablesize = adapter->sglen; - /* use HP firmware and bios version encoding */ + /* use HP firmware and bios version encoding + Note: fw_version[0|1] and bios_version[0|1] were originally shifted + right 8 bits making them zero. This 0 value was hardcoded to fix + sparse warnings. */ if (adapter->product_info.subsysvid == HP_SUBSYS_VID) { sprintf (adapter->fw_version, "%c%d%d.%d%d", adapter->product_info.fw_version[2], - adapter->product_info.fw_version[1] >> 8, + 0, adapter->product_info.fw_version[1] & 0x0f, - adapter->product_info.fw_version[0] >> 8, + 0, adapter->product_info.fw_version[0] & 0x0f); sprintf (adapter->bios_version, "%c%d%d.%d%d", adapter->product_info.bios_version[2], - adapter->product_info.bios_version[1] >> 8, + 0, adapter->product_info.bios_version[1] & 0x0f, - adapter->product_info.bios_version[0] >> 8, + 0, adapter->product_info.bios_version[0] & 0x0f); } else { memcpy(adapter->fw_version, diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index dd94c7d574fb..e5f416f8042d 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -33,9 +33,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.06.12-rc1" -#define MEGASAS_RELDATE "Oct. 5, 2011" -#define MEGASAS_EXT_VERSION "Wed. Oct. 5 17:00:00 PDT 2011" +#define MEGASAS_VERSION "00.00.06.14-rc1" +#define MEGASAS_RELDATE "Jan. 6, 2012" +#define MEGASAS_EXT_VERSION "Fri. Jan. 6 17:00:00 PDT 2012" /* * Device IDs @@ -773,7 +773,6 @@ struct megasas_ctrl_info { #define MFI_OB_INTR_STATUS_MASK 0x00000002 #define MFI_POLL_TIMEOUT_SECS 60 -#define MEGASAS_COMPLETION_TIMER_INTERVAL (HZ/10) #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 #define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001 @@ -1353,7 +1352,6 @@ struct megasas_instance { u32 mfiStatus; u32 last_seq_num; - struct timer_list io_completion_timer; struct list_head internal_reset_pending_q; /* Ptr to hba specific information */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 29a994f9c4f1..8b300be44284 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -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.12-rc1 + * Version : v00.00.06.14-rc1 * * Authors: LSI Corporation * Sreenivas Bagalkote @@ -59,14 +59,6 @@ #include "megaraid_sas.h" /* - * poll_mode_io:1- schedule complete completion from q cmd - */ -static unsigned int poll_mode_io; -module_param_named(poll_mode_io, poll_mode_io, int, 0); -MODULE_PARM_DESC(poll_mode_io, - "Complete cmds from IO path, (default=0)"); - -/* * Number of sectors per IO command * Will be set in megasas_init_mfi if user does not provide */ @@ -1439,11 +1431,6 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance, instance->instancet->fire_cmd(instance, cmd->frame_phys_addr, cmd->frame_count-1, instance->reg_set); - /* - * Check if we have pend cmds to be completed - */ - if (poll_mode_io && atomic_read(&instance->fw_outstanding)) - tasklet_schedule(&instance->isr_tasklet); return 0; out_return_cmd: @@ -3370,47 +3357,6 @@ fail_fw_init: return -EINVAL; } -/** - * megasas_start_timer - Initializes a timer object - * @instance: Adapter soft state - * @timer: timer object to be initialized - * @fn: timer function - * @interval: time interval between timer function call - */ -static inline void -megasas_start_timer(struct megasas_instance *instance, - struct timer_list *timer, - void *fn, unsigned long interval) -{ - init_timer(timer); - timer->expires = jiffies + interval; - timer->data = (unsigned long)instance; - timer->function = fn; - add_timer(timer); -} - -/** - * megasas_io_completion_timer - Timer fn - * @instance_addr: Address of adapter soft state - * - * Schedules tasklet for cmd completion - * if poll_mode_io is set - */ -static void -megasas_io_completion_timer(unsigned long instance_addr) -{ - struct megasas_instance *instance = - (struct megasas_instance *)instance_addr; - - if (atomic_read(&instance->fw_outstanding)) - tasklet_schedule(&instance->isr_tasklet); - - /* Restart timer */ - if (poll_mode_io) - mod_timer(&instance->io_completion_timer, - jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL); -} - static u32 megasas_init_adapter_mfi(struct megasas_instance *instance) { @@ -3638,11 +3584,6 @@ static int megasas_init_fw(struct megasas_instance *instance) tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, (unsigned long)instance); - /* Initialize the cmd completion timer */ - if (poll_mode_io) - megasas_start_timer(instance, &instance->io_completion_timer, - megasas_io_completion_timer, - MEGASAS_COMPLETION_TIMER_INTERVAL); return 0; fail_init_adapter: @@ -4369,9 +4310,6 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) host = instance->host; instance->unload = 1; - if (poll_mode_io) - del_timer_sync(&instance->io_completion_timer); - megasas_flush_cache(instance); megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); @@ -4511,12 +4449,6 @@ megasas_resume(struct pci_dev *pdev) } instance->instancet->enable_intr(instance->reg_set); - - /* Initialize the cmd completion timer */ - if (poll_mode_io) - megasas_start_timer(instance, &instance->io_completion_timer, - megasas_io_completion_timer, - MEGASAS_COMPLETION_TIMER_INTERVAL); instance->unload = 0; /* @@ -4570,9 +4502,6 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) host = instance->host; fusion = instance->ctrl_context; - if (poll_mode_io) - del_timer_sync(&instance->io_completion_timer); - scsi_remove_host(instance->host); megasas_flush_cache(instance); megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); @@ -4773,6 +4702,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE); cmd->frame->hdr.context = cmd->index; cmd->frame->hdr.pad_0 = 0; + cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 | + MFI_FRAME_SENSE64); /* * The management interface between applications and the fw uses @@ -5219,60 +5150,6 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl, megasas_sysfs_set_dbg_lvl); -static ssize_t -megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf) -{ - return sprintf(buf, "%u\n", poll_mode_io); -} - -static ssize_t -megasas_sysfs_set_poll_mode_io(struct device_driver *dd, - const char *buf, size_t count) -{ - int retval = count; - int tmp = poll_mode_io; - int i; - struct megasas_instance *instance; - - if (sscanf(buf, "%u", &poll_mode_io) < 1) { - printk(KERN_ERR "megasas: could not set poll_mode_io\n"); - retval = -EINVAL; - } - - /* - * Check if poll_mode_io is already set or is same as previous value - */ - if ((tmp && poll_mode_io) || (tmp == poll_mode_io)) - goto out; - - if (poll_mode_io) { - /* - * Start timers for all adapters - */ - for (i = 0; i < megasas_mgmt_info.max_index; i++) { - instance = megasas_mgmt_info.instance[i]; - if (instance) { - megasas_start_timer(instance, - &instance->io_completion_timer, - megasas_io_completion_timer, - MEGASAS_COMPLETION_TIMER_INTERVAL); - } - } - } else { - /* - * Delete timers for all adapters - */ - for (i = 0; i < megasas_mgmt_info.max_index; i++) { - instance = megasas_mgmt_info.instance[i]; - if (instance) - del_timer_sync(&instance->io_completion_timer); - } - } - -out: - return retval; -} - static void megasas_aen_polling(struct work_struct *work) { @@ -5502,11 +5379,6 @@ megasas_aen_polling(struct work_struct *work) kfree(ev); } - -static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR, - megasas_sysfs_show_poll_mode_io, - megasas_sysfs_set_poll_mode_io); - /** * megasas_init - Driver load entry point */ @@ -5566,11 +5438,6 @@ static int __init megasas_init(void) if (rval) goto err_dcf_dbg_lvl; rval = driver_create_file(&megasas_pci_driver.driver, - &driver_attr_poll_mode_io); - if (rval) - goto err_dcf_poll_mode_io; - - rval = driver_create_file(&megasas_pci_driver.driver, &driver_attr_support_device_change); if (rval) goto err_dcf_support_device_change; @@ -5579,10 +5446,6 @@ static int __init megasas_init(void) err_dcf_support_device_change: driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_poll_mode_io); - -err_dcf_poll_mode_io: - driver_remove_file(&megasas_pci_driver.driver, &driver_attr_dbg_lvl); err_dcf_dbg_lvl: driver_remove_file(&megasas_pci_driver.driver, @@ -5607,8 +5470,6 @@ err_pcidrv: static void __exit megasas_exit(void) { driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_poll_mode_io); - driver_remove_file(&megasas_pci_driver.driver, &driver_attr_dbg_lvl); driver_remove_file(&megasas_pci_driver.driver, &driver_attr_support_poll_for_event); diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 5255dd688aca..294abb0defa6 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -282,7 +282,9 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, else { *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */ if ((raid->level >= 5) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER)) + ((instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER && + raid->regTypeReqOnRead != REGION_TYPE_UNUSED))) pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { /* Get alternate Pd. */ diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index f6a50c98c36f..002924963cd8 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -59,11 +59,11 @@ MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra2 #define ASYNC_MODE 1 #define ULTRA20M_MODE 2 -static int auto_param = 0; /* default: ON */ +static bool auto_param = 0; /* default: ON */ module_param (auto_param, bool, 0); MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)"); -static int disc_priv = 1; /* default: OFF */ +static bool disc_priv = 1; /* default: OFF */ module_param (disc_priv, bool, 0); MODULE_PARM_DESC(disc_priv, "disconnection privilege mode (0: ON 1: OFF(default))"); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index ca86721a71b9..b61a753eb896 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -70,7 +70,7 @@ module_param(nsp_burst_mode, int, 0); MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))"); /* Release IO ports after configuration? */ -static int free_ports = 0; +static bool free_ports = 0; module_param(free_ports, bool, 0); MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 22a3ff02e48a..bfe68545203f 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -150,6 +150,8 @@ #define QL4_SESS_RECOVERY_TMO 120 /* iSCSI session */ /* recovery timeout */ +#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8)) +#define LSW(x) ((uint16_t)(x)) #define LSDW(x) ((u32)((u64)(x))) #define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) @@ -671,6 +673,7 @@ struct scsi_qla_host { uint16_t pri_ddb_idx; uint16_t sec_ddb_idx; int is_reset; + uint16_t temperature; }; struct ql4_task_data { diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 1bdfa8120ac8..90614f38b55d 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -697,6 +697,9 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha) writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); + writel(set_rmask(CSR_SCSI_COMPLETION_INTR), + &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) { DEBUG2(printk("scsi%ld: %s: Get firmware " diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index c2593782fbbe..e1e66a45e4d0 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -219,6 +219,13 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, ha->mailbox_timeout_count++; mbx_sts[0] = (-1); set_bit(DPC_RESET_HA, &ha->dpc_flags); + if (is_qla8022(ha)) { + ql4_printk(KERN_INFO, ha, + "disabling pause transmit on port 0 & 1.\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0 | + CRB_NIU_XG_PAUSE_CTL_P1); + } goto mbox_exit; } diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 8d6bc1b2ff17..78f1111158d7 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -1875,6 +1875,11 @@ exit: int qla4_8xxx_load_risc(struct scsi_qla_host *ha) { int retval; + + /* clear the interrupt */ + writel(0, &ha->qla4_8xxx_reg->host_int); + readl(&ha->qla4_8xxx_reg->host_int); + retval = qla4_8xxx_device_state_handler(ha); if (retval == QLA_SUCCESS && !test_bit(AF_INIT_DONE, &ha->flags)) diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h index 35376a1c3f1b..dc45ac923691 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.h +++ b/drivers/scsi/qla4xxx/ql4_nx.h @@ -19,12 +19,28 @@ #define PHAN_PEG_RCV_INITIALIZED 0xff01 /*CRB_RELATED*/ -#define QLA82XX_CRB_BASE QLA82XX_CAM_RAM(0x200) -#define QLA82XX_REG(X) (QLA82XX_CRB_BASE+(X)) - +#define QLA82XX_CRB_BASE (QLA82XX_CAM_RAM(0x200)) +#define QLA82XX_REG(X) (QLA82XX_CRB_BASE+(X)) #define CRB_CMDPEG_STATE QLA82XX_REG(0x50) #define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) #define CRB_DMA_SHIFT QLA82XX_REG(0xcc) +#define CRB_TEMP_STATE QLA82XX_REG(0x1b4) + +#define qla82xx_get_temp_val(x) ((x) >> 16) +#define qla82xx_get_temp_state(x) ((x) & 0xffff) +#define qla82xx_encode_temp(val, state) (((val) << 16) | (state)) + +/* + * Temperature control. + */ +enum { + QLA82XX_TEMP_NORMAL = 0x1, /* Normal operating range */ + QLA82XX_TEMP_WARN, /* Sound alert, temperature getting high */ + QLA82XX_TEMP_PANIC /* Fatal error, hardware has shut down. */ +}; + +#define CRB_NIU_XG_PAUSE_CTL_P0 0x1 +#define CRB_NIU_XG_PAUSE_CTL_P1 0x8 #define QLA82XX_HW_H0_CH_HUB_ADR 0x05 #define QLA82XX_HW_H1_CH_HUB_ADR 0x0E diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index ec393a00c038..ce6d3b7f0c61 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -35,43 +35,44 @@ static struct kmem_cache *srb_cachep; int ql4xdisablesysfsboot = 1; module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xdisablesysfsboot, - "Set to disable exporting boot targets to sysfs\n" - " 0 - Export boot targets\n" - " 1 - Do not export boot targets (Default)"); + " Set to disable exporting boot targets to sysfs.\n" + "\t\t 0 - Export boot targets\n" + "\t\t 1 - Do not export boot targets (Default)"); int ql4xdontresethba = 0; module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xdontresethba, - "Don't reset the HBA for driver recovery \n" - " 0 - It will reset HBA (Default)\n" - " 1 - It will NOT reset HBA"); + " Don't reset the HBA for driver recovery.\n" + "\t\t 0 - It will reset HBA (Default)\n" + "\t\t 1 - It will NOT reset HBA"); -int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ +int ql4xextended_error_logging; module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xextended_error_logging, - "Option to enable extended error logging, " - "Default is 0 - no logging, 1 - debug logging"); + " Option to enable extended error logging.\n" + "\t\t 0 - no logging (Default)\n" + "\t\t 2 - debug logging"); int ql4xenablemsix = 1; module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql4xenablemsix, - "Set to enable MSI or MSI-X interrupt mechanism.\n" - " 0 = enable INTx interrupt mechanism.\n" - " 1 = enable MSI-X interrupt mechanism (Default).\n" - " 2 = enable MSI interrupt mechanism."); + " Set to enable MSI or MSI-X interrupt mechanism.\n" + "\t\t 0 = enable INTx interrupt mechanism.\n" + "\t\t 1 = enable MSI-X interrupt mechanism (Default).\n" + "\t\t 2 = enable MSI interrupt mechanism."); #define QL4_DEF_QDEPTH 32 static int ql4xmaxqdepth = QL4_DEF_QDEPTH; module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xmaxqdepth, - "Maximum queue depth to report for target devices.\n" - " Default: 32."); + " Maximum queue depth to report for target devices.\n" + "\t\t Default: 32."); static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; module_param(ql4xsess_recovery_tmo, int, S_IRUGO); MODULE_PARM_DESC(ql4xsess_recovery_tmo, "Target Session Recovery Timeout.\n" - " Default: 120 sec."); + "\t\t Default: 120 sec."); static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); /* @@ -1630,7 +1631,9 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, /* Update timers after login */ ddb_entry->default_relogin_timeout = - le16_to_cpu(fw_ddb_entry->def_timeout); + (le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) && + (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ? + le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV; ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); @@ -1970,6 +1973,42 @@ mem_alloc_error_exit: } /** + * qla4_8xxx_check_temp - Check the ISP82XX temperature. + * @ha: adapter block pointer. + * + * Note: The caller should not hold the idc lock. + **/ +static int qla4_8xxx_check_temp(struct scsi_qla_host *ha) +{ + uint32_t temp, temp_state, temp_val; + int status = QLA_SUCCESS; + + temp = qla4_8xxx_rd_32(ha, CRB_TEMP_STATE); + + temp_state = qla82xx_get_temp_state(temp); + temp_val = qla82xx_get_temp_val(temp); + + if (temp_state == QLA82XX_TEMP_PANIC) { + ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C" + " exceeds maximum allowed. Hardware has been shut" + " down.\n", temp_val); + status = QLA_ERROR; + } else if (temp_state == QLA82XX_TEMP_WARN) { + if (ha->temperature == QLA82XX_TEMP_NORMAL) + ql4_printk(KERN_WARNING, ha, "Device temperature %d" + " degrees C exceeds operating range." + " Immediate action needed.\n", temp_val); + } else { + if (ha->temperature == QLA82XX_TEMP_WARN) + ql4_printk(KERN_INFO, ha, "Device temperature is" + " now %d degrees C in normal range.\n", + temp_val); + } + ha->temperature = temp_state; + return status; +} + +/** * qla4_8xxx_check_fw_alive - Check firmware health * @ha: Pointer to host adapter structure. * @@ -2040,7 +2079,16 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - if (dev_state == QLA82XX_DEV_NEED_RESET && + + if (qla4_8xxx_check_temp(ha)) { + ql4_printk(KERN_INFO, ha, "disabling pause" + " transmit on port 0 & 1.\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0 | + CRB_NIU_XG_PAUSE_CTL_P1); + set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); + qla4xxx_wake_dpc(ha); + } else if (dev_state == QLA82XX_DEV_NEED_RESET && !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { if (!ql4xdontresethba) { ql4_printk(KERN_INFO, ha, "%s: HW State: " @@ -2057,9 +2105,21 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) } else { /* Check firmware health */ if (qla4_8xxx_check_fw_alive(ha)) { + ql4_printk(KERN_INFO, ha, "disabling pause" + " transmit on port 0 & 1.\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0 | + CRB_NIU_XG_PAUSE_CTL_P1); halt_status = qla4_8xxx_rd_32(ha, QLA82XX_PEG_HALT_STATUS1); + if (LSW(MSB(halt_status)) == 0x67) + ql4_printk(KERN_ERR, ha, "%s:" + " Firmware aborted with" + " error code 0x00006700." + " Device is being reset\n", + __func__); + /* Since we cannot change dev_state in interrupt * context, set appropriate DPC flag then wakeup * DPC */ @@ -2078,7 +2138,7 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) } } -void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) +static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) { struct iscsi_session *sess; struct ddb_entry *ddb_entry; @@ -3826,16 +3886,14 @@ exit_check: return ret; } -static void qla4xxx_free_nt_list(struct list_head *list_nt) +static void qla4xxx_free_ddb_list(struct list_head *list_ddb) { - struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; + struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; - /* Free up the normaltargets list */ - list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { - list_del_init(&nt_ddb_idx->list); - vfree(nt_ddb_idx); + list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { + list_del_init(&ddb_idx->list); + vfree(ddb_idx); } - } static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, @@ -3884,6 +3942,8 @@ static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx) static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) { + uint16_t def_timeout; + ddb_entry->ddb_type = FLASH_DDB; ddb_entry->fw_ddb_index = INVALID_ENTRY; ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; @@ -3894,9 +3954,10 @@ static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); atomic_set(&ddb_entry->relogin_timer, 0); atomic_set(&ddb_entry->relogin_retry_count, 0); - + def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); ddb_entry->default_relogin_timeout = - le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); + (def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ? + def_timeout : LOGIN_TOV; ddb_entry->default_time2wait = le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait); } @@ -3934,7 +3995,6 @@ static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) ip_state == IP_ADDRSTATE_DEPRICATED || ip_state == IP_ADDRSTATE_DISABLING) ip_idx[idx] = -1; - } /* Break if all IP states checked */ @@ -3947,58 +4007,37 @@ static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) } while (time_after(wtime, jiffies)); } -void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) +static void qla4xxx_build_st_list(struct scsi_qla_host *ha, + struct list_head *list_st) { + struct qla_ddb_index *st_ddb_idx; int max_ddbs; + int fw_idx_size; + struct dev_db_entry *fw_ddb_entry; + dma_addr_t fw_ddb_dma; int ret; uint32_t idx = 0, next_idx = 0; uint32_t state = 0, conn_err = 0; - uint16_t conn_id; - struct dev_db_entry *fw_ddb_entry; - struct ddb_entry *ddb_entry = NULL; - dma_addr_t fw_ddb_dma; - struct iscsi_cls_session *cls_sess; - struct iscsi_session *sess; - struct iscsi_cls_conn *cls_conn; - struct iscsi_endpoint *ep; - uint16_t cmds_max = 32, tmo = 0; - uint32_t initial_cmdsn = 0; - struct list_head list_st, list_nt; /* List of sendtargets */ - struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; - int fw_idx_size; - unsigned long wtime; - struct qla_ddb_index *nt_ddb_idx; - - if (!test_bit(AF_LINK_UP, &ha->flags)) { - set_bit(AF_BUILD_DDB_LIST, &ha->flags); - ha->is_reset = is_reset; - return; - } - max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : - MAX_DEV_DB_ENTRIES; + uint16_t conn_id = 0; fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, &fw_ddb_dma); if (fw_ddb_entry == NULL) { DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); - goto exit_ddb_list; + goto exit_st_list; } - INIT_LIST_HEAD(&list_st); - INIT_LIST_HEAD(&list_nt); + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; fw_idx_size = sizeof(struct qla_ddb_index); for (idx = 0; idx < max_ddbs; idx = next_idx) { - ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, - fw_ddb_dma, NULL, - &next_idx, &state, &conn_err, - NULL, &conn_id); + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, + NULL, &next_idx, &state, + &conn_err, NULL, &conn_id); if (ret == QLA_ERROR) break; - if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) - goto continue_next_st; - /* Check if ST, add to the list_st */ if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) goto continue_next_st; @@ -4009,59 +4048,155 @@ void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) st_ddb_idx->fw_ddb_idx = idx; - list_add_tail(&st_ddb_idx->list, &list_st); + list_add_tail(&st_ddb_idx->list, list_st); continue_next_st: if (next_idx == 0) break; } - /* Before issuing conn open mbox, ensure all IPs states are configured - * Note, conn open fails if IPs are not configured +exit_st_list: + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); +} + +/** + * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list + * @ha: pointer to adapter structure + * @list_ddb: List from which failed ddb to be removed + * + * Iterate over the list of DDBs and find and remove DDBs that are either in + * no connection active state or failed state + **/ +static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha, + struct list_head *list_ddb) +{ + struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; + uint32_t next_idx = 0; + uint32_t state = 0, conn_err = 0; + int ret; + + list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { + ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx, + NULL, 0, NULL, &next_idx, &state, + &conn_err, NULL, NULL); + if (ret == QLA_ERROR) + continue; + + if (state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED) { + list_del_init(&ddb_idx->list); + vfree(ddb_idx); + } + } +} + +static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + int is_reset) +{ + struct iscsi_cls_session *cls_sess; + struct iscsi_session *sess; + struct iscsi_cls_conn *cls_conn; + struct iscsi_endpoint *ep; + uint16_t cmds_max = 32; + uint16_t conn_id = 0; + uint32_t initial_cmdsn = 0; + int ret = QLA_SUCCESS; + + struct ddb_entry *ddb_entry = NULL; + + /* Create session object, with INVALID_ENTRY, + * the targer_id would get set when we issue the login */ - qla4xxx_wait_for_ip_configuration(ha); + cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host, + cmds_max, sizeof(struct ddb_entry), + sizeof(struct ql4_task_data), + initial_cmdsn, INVALID_ENTRY); + if (!cls_sess) { + ret = QLA_ERROR; + goto exit_setup; + } - /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ - list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { - qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); + /* + * so calling module_put function to decrement the + * reference count. + **/ + module_put(qla4xxx_iscsi_transport.owner); + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ddb_entry->sess = cls_sess; + + cls_sess->recovery_tmo = ql4xsess_recovery_tmo; + memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, + sizeof(struct dev_db_entry)); + + qla4xxx_setup_flash_ddb_entry(ha, ddb_entry); + + cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id); + + if (!cls_conn) { + ret = QLA_ERROR; + goto exit_setup; } - /* Wait to ensure all sendtargets are done for min 12 sec wait */ - tmo = ((ha->def_timeout < LOGIN_TOV) ? LOGIN_TOV : ha->def_timeout); - DEBUG2(ql4_printk(KERN_INFO, ha, - "Default time to wait for build ddb %d\n", tmo)); + ddb_entry->conn = cls_conn; - wtime = jiffies + (HZ * tmo); - do { - list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, - list) { - ret = qla4xxx_get_fwddb_entry(ha, - st_ddb_idx->fw_ddb_idx, - NULL, 0, NULL, &next_idx, - &state, &conn_err, NULL, - NULL); - if (ret == QLA_ERROR) - continue; + /* Setup ep, for displaying attributes in sysfs */ + ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); + if (ep) { + ep->conn = cls_conn; + cls_conn->ep = ep; + } else { + DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n")); + ret = QLA_ERROR; + goto exit_setup; + } - if (state == DDB_DS_NO_CONNECTION_ACTIVE || - state == DDB_DS_SESSION_FAILED) { - list_del_init(&st_ddb_idx->list); - vfree(st_ddb_idx); - } - } - schedule_timeout_uninterruptible(HZ / 10); - } while (time_after(wtime, jiffies)); + /* Update sess/conn params */ + qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); - /* Free up the sendtargets list */ - list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { - list_del_init(&st_ddb_idx->list); - vfree(st_ddb_idx); + if (is_reset == RESET_ADAPTER) { + iscsi_block_session(cls_sess); + /* Use the relogin path to discover new devices + * by short-circuting the logic of setting + * timer to relogin - instead set the flags + * to initiate login right away. + */ + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); } +exit_setup: + return ret; +} + +static void qla4xxx_build_nt_list(struct scsi_qla_host *ha, + struct list_head *list_nt, int is_reset) +{ + struct dev_db_entry *fw_ddb_entry; + dma_addr_t fw_ddb_dma; + int max_ddbs; + int fw_idx_size; + int ret; + uint32_t idx = 0, next_idx = 0; + uint32_t state = 0, conn_err = 0; + uint16_t conn_id = 0; + struct qla_ddb_index *nt_ddb_idx; + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_nt_list; + } + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + fw_idx_size = sizeof(struct qla_ddb_index); + for (idx = 0; idx < max_ddbs; idx = next_idx) { - ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, - fw_ddb_dma, NULL, - &next_idx, &state, &conn_err, - NULL, &conn_id); + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, + NULL, &next_idx, &state, + &conn_err, NULL, &conn_id); if (ret == QLA_ERROR) break; @@ -4072,107 +4207,113 @@ continue_next_st: if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) goto continue_next_nt; - if (state == DDB_DS_NO_CONNECTION_ACTIVE || - state == DDB_DS_SESSION_FAILED) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Adding DDB to session = 0x%x\n", - idx)); - if (is_reset == INIT_ADAPTER) { - nt_ddb_idx = vmalloc(fw_idx_size); - if (!nt_ddb_idx) - break; - - nt_ddb_idx->fw_ddb_idx = idx; - - memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, - sizeof(struct dev_db_entry)); - - if (qla4xxx_is_flash_ddb_exists(ha, &list_nt, - fw_ddb_entry) == QLA_SUCCESS) { - vfree(nt_ddb_idx); - goto continue_next_nt; - } - list_add_tail(&nt_ddb_idx->list, &list_nt); - } else if (is_reset == RESET_ADAPTER) { - if (qla4xxx_is_session_exists(ha, - fw_ddb_entry) == QLA_SUCCESS) - goto continue_next_nt; - } + if (!(state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED)) + goto continue_next_nt; - /* Create session object, with INVALID_ENTRY, - * the targer_id would get set when we issue the login - */ - cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, - ha->host, cmds_max, - sizeof(struct ddb_entry), - sizeof(struct ql4_task_data), - initial_cmdsn, INVALID_ENTRY); - if (!cls_sess) - goto exit_ddb_list; + DEBUG2(ql4_printk(KERN_INFO, ha, + "Adding DDB to session = 0x%x\n", idx)); + if (is_reset == INIT_ADAPTER) { + nt_ddb_idx = vmalloc(fw_idx_size); + if (!nt_ddb_idx) + break; - /* - * iscsi_session_setup increments the driver reference - * count which wouldn't let the driver to be unloaded. - * so calling module_put function to decrement the - * reference count. - **/ - module_put(qla4xxx_iscsi_transport.owner); - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ddb_entry->sess = cls_sess; + nt_ddb_idx->fw_ddb_idx = idx; - cls_sess->recovery_tmo = ql4xsess_recovery_tmo; - memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, + memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, sizeof(struct dev_db_entry)); - qla4xxx_setup_flash_ddb_entry(ha, ddb_entry); - - cls_conn = iscsi_conn_setup(cls_sess, - sizeof(struct qla_conn), - conn_id); - if (!cls_conn) - goto exit_ddb_list; - - ddb_entry->conn = cls_conn; - - /* Setup ep, for displaying attributes in sysfs */ - ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); - if (ep) { - ep->conn = cls_conn; - cls_conn->ep = ep; - } else { - DEBUG2(ql4_printk(KERN_ERR, ha, - "Unable to get ep\n")); - } - - /* Update sess/conn params */ - qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, - cls_conn); - - if (is_reset == RESET_ADAPTER) { - iscsi_block_session(cls_sess); - /* Use the relogin path to discover new devices - * by short-circuting the logic of setting - * timer to relogin - instead set the flags - * to initiate login right away. - */ - set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); - set_bit(DF_RELOGIN, &ddb_entry->flags); + if (qla4xxx_is_flash_ddb_exists(ha, list_nt, + fw_ddb_entry) == QLA_SUCCESS) { + vfree(nt_ddb_idx); + goto continue_next_nt; } + list_add_tail(&nt_ddb_idx->list, list_nt); + } else if (is_reset == RESET_ADAPTER) { + if (qla4xxx_is_session_exists(ha, fw_ddb_entry) == + QLA_SUCCESS) + goto continue_next_nt; } + + ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset); + if (ret == QLA_ERROR) + goto exit_nt_list; + continue_next_nt: if (next_idx == 0) break; } -exit_ddb_list: - qla4xxx_free_nt_list(&list_nt); + +exit_nt_list: if (fw_ddb_entry) dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); +} + +/** + * qla4xxx_build_ddb_list - Build ddb list and setup sessions + * @ha: pointer to adapter structure + * @is_reset: Is this init path or reset path + * + * Create a list of sendtargets (st) from firmware DDBs, issue send targets + * using connection open, then create the list of normal targets (nt) + * from firmware DDBs. Based on the list of nt setup session and connection + * objects. + **/ +void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) +{ + uint16_t tmo = 0; + struct list_head list_st, list_nt; + struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; + unsigned long wtime; + + if (!test_bit(AF_LINK_UP, &ha->flags)) { + set_bit(AF_BUILD_DDB_LIST, &ha->flags); + ha->is_reset = is_reset; + return; + } + + INIT_LIST_HEAD(&list_st); + INIT_LIST_HEAD(&list_nt); + + qla4xxx_build_st_list(ha, &list_st); + + /* Before issuing conn open mbox, ensure all IPs states are configured + * Note, conn open fails if IPs are not configured + */ + qla4xxx_wait_for_ip_configuration(ha); + + /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { + qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); + } + + /* Wait to ensure all sendtargets are done for min 12 sec wait */ + tmo = ((ha->def_timeout > LOGIN_TOV) && + (ha->def_timeout < LOGIN_TOV * 10) ? + ha->def_timeout : LOGIN_TOV); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Default time to wait for build ddb %d\n", tmo)); + + wtime = jiffies + (HZ * tmo); + do { + if (list_empty(&list_st)) + break; + + qla4xxx_remove_failed_ddb(ha, &list_st); + schedule_timeout_uninterruptible(HZ / 10); + } while (time_after(wtime, jiffies)); + + /* Free up the sendtargets list */ + qla4xxx_free_ddb_list(&list_st); + + qla4xxx_build_nt_list(ha, &list_nt, is_reset); + + qla4xxx_free_ddb_list(&list_nt); qla4xxx_free_ddb_index(ha); } - /** * qla4xxx_probe_adapter - callback function to probe HBA * @pdev: pointer to pci_dev structure diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 26a3fa34a33c..133989b3a9f4 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.02.00-k10" +#define QLA4XXX_DRIVER_VERSION "5.02.00-k12" diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f85cfa6c47b5..b2c95dbe9d65 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1316,15 +1316,10 @@ static inline int scsi_target_queue_ready(struct Scsi_Host *shost, } if (scsi_target_is_busy(starget)) { - if (list_empty(&sdev->starved_entry)) - list_add_tail(&sdev->starved_entry, - &shost->starved_list); + list_move_tail(&sdev->starved_entry, &shost->starved_list); return 0; } - /* We're OK to process the command, so we can't be starved */ - if (!list_empty(&sdev->starved_entry)) - list_del_init(&sdev->starved_entry); return 1; } diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 44f76e8b58af..c77628afbf9f 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -112,7 +112,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) goto next_msg; } - if (security_netlink_recv(skb, CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) { err = -EPERM; goto next_msg; } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b3c6d957fbd8..89da43f73c00 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -297,7 +297,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, kfree(sdev); goto out; } - blk_get_queue(sdev->request_queue); + WARN_ON_ONCE(!blk_get_queue(sdev->request_queue)); sdev->request_queue->queuedata = sdev; scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 1b214910b714..f59d4a05ecd7 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3048,7 +3048,8 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) spin_lock_irqsave(shost->host_lock, flags); rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | - FC_RPORT_DEVLOSS_PENDING); + FC_RPORT_DEVLOSS_PENDING | + FC_RPORT_DEVLOSS_CALLBK_DONE); spin_unlock_irqrestore(shost->host_lock, flags); /* ensure any stgt delete functions are done */ diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7b3f8075e2a5..c691fb50e6cb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1075,6 +1075,10 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " "cmd=0x%x\n", disk->disk_name, cmd)); + error = scsi_verify_blk_ioctl(bdev, cmd); + if (error < 0) + return error; + /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -1097,7 +1101,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, error = scsi_ioctl(sdp, cmd, p); break; default: - error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); + error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); if (error != -ENOTTY) break; error = scsi_ioctl(sdp, cmd, p); @@ -1267,6 +1271,11 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; + int ret; + + ret = scsi_verify_blk_ioctl(bdev, cmd); + if (ret < 0) + return ret; /* * If we are in the middle of error recovery, don't let anyone @@ -1278,8 +1287,6 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, return -ENODEV; if (sdev->host->hostt->compat_ioctl) { - int ret; - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); return ret; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 02d99982a74d..eacd46bb36b9 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2368,16 +2368,15 @@ static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { - int num; - char buff[11]; + int err; + unsigned long num; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - num = (count < 10) ? count : 10; - if (copy_from_user(buff, buffer, num)) - return -EFAULT; - buff[num] = '\0'; - sg_allow_dio = simple_strtoul(buff, NULL, 10) ? 1 : 0; + err = kstrtoul_from_user(buffer, count, 0, &num); + if (err) + return err; + sg_allow_dio = num ? 1 : 0; return count; } @@ -2390,17 +2389,15 @@ static ssize_t sg_proc_write_dressz(struct file *filp, const char __user *buffer, size_t count, loff_t *off) { - int num; + int err; unsigned long k = ULONG_MAX; - char buff[11]; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - num = (count < 10) ? count : 10; - if (copy_from_user(buff, buffer, num)) - return -EFAULT; - buff[num] = '\0'; - k = simple_strtoul(buff, NULL, 10); + + err = kstrtoul_from_user(buffer, count, 0, &k); + if (err) + return err; if (k <= 1048576) { /* limit "big buff" to 1 MB */ sg_big_buff = k; return count; diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index b4543f575f46..36d1ed7817eb 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -839,6 +839,10 @@ static void sym53c8xx_slave_destroy(struct scsi_device *sdev) struct sym_lcb *lp = sym_lp(tp, sdev->lun); unsigned long flags; + /* if slave_alloc returned before allocating a sym_lcb, return */ + if (!lp) + return; + spin_lock_irqsave(np->s.host->host_lock, flags); if (lp->busy_itlq || lp->busy_itl) { diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 56abf55e49da..3f9a47ec67dc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -87,12 +87,12 @@ config SPI_BFIN_SPORT Enable support for a SPI bus via the Blackfin SPORT peripheral. config SPI_AU1550 - tristate "Au1550/Au12x0 SPI Controller" + tristate "Au1550/Au1200/Au1300 SPI Controller" depends on MIPS_ALCHEMY && EXPERIMENTAL select SPI_BITBANG help If you say yes to this option, support will be included for the - Au1550 SPI controller (may also work with Au1200,Au1210,Au1250). + PSC SPI controller found on Au1550, Au1200 and Au1300 series. config SPI_BITBANG tristate "Utilities for Bitbanging SPI masters" @@ -332,8 +332,7 @@ config SPI_STMP3XXX config SPI_TEGRA tristate "Nvidia Tegra SPI controller" - depends on ARCH_TEGRA - select TEGRA_SYSTEM_DMA + depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA help SPI driver for NVidia Tegra SoCs diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index e743a45ee92c..8418eb036651 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -131,7 +131,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) rxchan = dws->rxchan; /* 2. Prepare the TX dma transfer */ - txconf.direction = DMA_TO_DEVICE; + txconf.direction = DMA_MEM_TO_DEV; txconf.dst_addr = dws->dma_addr; txconf.dst_maxburst = LNW_DMA_MSIZE_16; txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -147,13 +147,13 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) txdesc = txchan->device->device_prep_slave_sg(txchan, &dws->tx_sgl, 1, - DMA_TO_DEVICE, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP); txdesc->callback = dw_spi_dma_done; txdesc->callback_param = dws; /* 3. Prepare the RX dma transfer */ - rxconf.direction = DMA_FROM_DEVICE; + rxconf.direction = DMA_DEV_TO_MEM; rxconf.src_addr = dws->dma_addr; rxconf.src_maxburst = LNW_DMA_MSIZE_16; rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -169,7 +169,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) rxdesc = rxchan->device->device_prep_slave_sg(rxchan, &dws->rx_sgl, 1, - DMA_FROM_DEVICE, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP); rxdesc->callback = dw_spi_dma_done; rxdesc->callback_param = dws; diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 0a282e5fcc9c..d46e55c720b7 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -551,6 +551,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) struct dma_async_tx_descriptor *txd; enum dma_slave_buswidth buswidth; struct dma_slave_config conf; + enum dma_transfer_direction slave_dirn; struct scatterlist *sg; struct sg_table *sgt; struct dma_chan *chan; @@ -573,6 +574,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) conf.src_addr = espi->sspdr_phys; conf.src_addr_width = buswidth; + slave_dirn = DMA_DEV_TO_MEM; } else { chan = espi->dma_tx; buf = t->tx_buf; @@ -580,6 +582,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) conf.dst_addr = espi->sspdr_phys; conf.dst_addr_width = buswidth; + slave_dirn = DMA_MEM_TO_DEV; } ret = dmaengine_slave_config(chan, &conf); @@ -631,7 +634,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) return ERR_PTR(-ENOMEM); txd = chan->device->device_prep_slave_sg(chan, sgt->sgl, nents, - dir, DMA_CTRL_ACK); + slave_dirn, DMA_CTRL_ACK); if (!txd) { dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir); return ERR_PTR(-ENOMEM); @@ -979,7 +982,7 @@ static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi) dma_cap_set(DMA_SLAVE, mask); espi->dma_rx_data.port = EP93XX_DMA_SSP; - espi->dma_rx_data.direction = DMA_FROM_DEVICE; + espi->dma_rx_data.direction = DMA_DEV_TO_MEM; espi->dma_rx_data.name = "ep93xx-spi-rx"; espi->dma_rx = dma_request_channel(mask, ep93xx_spi_dma_filter, @@ -990,7 +993,7 @@ static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi) } espi->dma_tx_data.port = EP93XX_DMA_SSP; - espi->dma_tx_data.direction = DMA_TO_DEVICE; + espi->dma_tx_data.direction = DMA_MEM_TO_DEV; espi->dma_tx_data.name = "ep93xx-spi-tx"; espi->dma_tx = dma_request_channel(mask, ep93xx_spi_dma_filter, diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index f1f5efbc3404..2f9cb43a2398 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -900,11 +900,11 @@ static int configure_dma(struct pl022 *pl022) { struct dma_slave_config rx_conf = { .src_addr = SSP_DR(pl022->phybase), - .direction = DMA_FROM_DEVICE, + .direction = DMA_DEV_TO_MEM, }; struct dma_slave_config tx_conf = { .dst_addr = SSP_DR(pl022->phybase), - .direction = DMA_TO_DEVICE, + .direction = DMA_MEM_TO_DEV, }; unsigned int pages; int ret; @@ -1041,7 +1041,7 @@ static int configure_dma(struct pl022 *pl022) rxdesc = rxchan->device->device_prep_slave_sg(rxchan, pl022->sgt_rx.sgl, rx_sglen, - DMA_FROM_DEVICE, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!rxdesc) goto err_rxdesc; @@ -1049,7 +1049,7 @@ static int configure_dma(struct pl022 *pl022) txdesc = txchan->device->device_prep_slave_sg(txchan, pl022->sgt_tx.sgl, tx_sglen, - DMA_TO_DEVICE, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) goto err_txdesc; diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 7086583b9107..2a6429d8c363 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1079,7 +1079,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) } sg = dma->sg_rx_p; desc_rx = dma->chan_rx->device->device_prep_slave_sg(dma->chan_rx, sg, - num, DMA_FROM_DEVICE, + num, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) { dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n", @@ -1124,7 +1124,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) } sg = dma->sg_tx_p; desc_tx = dma->chan_tx->device->device_prep_slave_sg(dma->chan_tx, - sg, num, DMA_TO_DEVICE, + sg, num, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed\n", diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 520e8286db28..49d209173f55 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -75,7 +75,7 @@ static u32 get_cfgspace_addr(struct ssb_pcicore *pc, u32 tmp; /* We do only have one cardbus device behind the bridge. */ - if (pc->cardbusmode && (dev >= 1)) + if (pc->cardbusmode && (dev > 1)) goto out; if (bus == 0) { diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 0d18d80bcd25..9bcf87ae4c00 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -61,7 +61,7 @@ EXPORT_SYMBOL(comedi_debug); module_param(comedi_debug, int, 0644); #endif -int comedi_autoconfig = 1; +bool comedi_autoconfig = 1; module_param(comedi_autoconfig, bool, 0444); static int comedi_num_legacy_minors; diff --git a/drivers/staging/comedi/comedi_fops.h b/drivers/staging/comedi/comedi_fops.h index da4b4f5553f5..006cf14c577a 100644 --- a/drivers/staging/comedi/comedi_fops.h +++ b/drivers/staging/comedi/comedi_fops.h @@ -1,10 +1,11 @@ #ifndef _COMEDI_FOPS_H #define _COMEDI_FOPS_H +#include <linux/types.h> extern struct class *comedi_class; extern const struct file_operations comedi_fops; -extern int comedi_autoconfig; +extern bool comedi_autoconfig; extern struct comedi_driver *comedi_drivers; #endif /* _COMEDI_FOPS_H */ diff --git a/drivers/staging/media/as102/Kconfig b/drivers/staging/media/as102/Kconfig index 5865029db0f6..28aba00dc629 100644 --- a/drivers/staging/media/as102/Kconfig +++ b/drivers/staging/media/as102/Kconfig @@ -1,6 +1,7 @@ config DVB_AS102 tristate "Abilis AS102 DVB receiver" depends on DVB_CORE && USB && I2C && INPUT + select FW_LOADER help Choose Y or M here if you have a device containing an AS102 diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile index e7dbb6f814d5..1bca43e847c7 100644 --- a/drivers/staging/media/as102/Makefile +++ b/drivers/staging/media/as102/Makefile @@ -3,4 +3,4 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ obj-$(CONFIG_DVB_AS102) += dvb-as102.o -EXTRA_CFLAGS += -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index 828526d4c289..aae0505a36c4 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -24,7 +24,7 @@ #include <linux/module.h> #include <linux/mm.h> #include <linux/kref.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/usb.h> /* header file for Usb device driver*/ @@ -56,13 +56,11 @@ int elna_enable = 1; module_param_named(elna_enable, elna_enable, int, 0644); MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)"); -#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#endif static void as102_stop_stream(struct as102_dev_t *dev) { - struct as102_bus_adapter_t *bus_adap; + struct as10x_bus_adapter_t *bus_adap; if (dev != NULL) bus_adap = &dev->bus_adap; @@ -85,7 +83,7 @@ static void as102_stop_stream(struct as102_dev_t *dev) static int as102_start_stream(struct as102_dev_t *dev) { - struct as102_bus_adapter_t *bus_adap; + struct as10x_bus_adapter_t *bus_adap; int ret = -EFAULT; if (dev != NULL) @@ -111,7 +109,7 @@ static int as102_start_stream(struct as102_dev_t *dev) static int as10x_pid_filter(struct as102_dev_t *dev, int index, u16 pid, int onoff) { - struct as102_bus_adapter_t *bus_adap = &dev->bus_adap; + struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap; int ret = -EFAULT; ENTER(); @@ -123,22 +121,22 @@ static int as10x_pid_filter(struct as102_dev_t *dev, switch (onoff) { case 0: - ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); - dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", - index, pid, ret); - break; + ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); + dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", + index, pid, ret); + break; case 1: { - struct as10x_ts_filter filter; + struct as10x_ts_filter filter; - filter.type = TS_PID_TYPE_TS; - filter.idx = 0xFF; - filter.pid = pid; + filter.type = TS_PID_TYPE_TS; + filter.idx = 0xFF; + filter.pid = pid; - ret = as10x_cmd_add_PID_filter(bus_adap, &filter); - dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", - index, filter.idx, filter.pid, ret); - break; + ret = as10x_cmd_add_PID_filter(bus_adap, &filter); + dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", + index, filter.idx, filter.pid, ret); + break; } } @@ -159,10 +157,9 @@ static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) if (mutex_lock_interruptible(&as102_dev->sem)) return -ERESTARTSYS; - if (pid_filtering) { - as10x_pid_filter(as102_dev, - dvbdmxfeed->index, dvbdmxfeed->pid, 1); - } + if (pid_filtering) + as10x_pid_filter(as102_dev, dvbdmxfeed->index, + dvbdmxfeed->pid, 1); if (as102_dev->streaming++ == 0) ret = as102_start_stream(as102_dev); @@ -185,10 +182,9 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) if (--as102_dev->streaming == 0) as102_stop_stream(as102_dev); - if (pid_filtering) { - as10x_pid_filter(as102_dev, - dvbdmxfeed->index, dvbdmxfeed->pid, 0); - } + if (pid_filtering) + as10x_pid_filter(as102_dev, dvbdmxfeed->index, + dvbdmxfeed->pid, 0); mutex_unlock(&as102_dev->sem); LEAVE(); @@ -197,27 +193,16 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int as102_dvb_register(struct as102_dev_t *as102_dev) { - int ret = 0; - ENTER(); + struct device *dev = &as102_dev->bus_adap.usb_dev->dev; + int ret; ret = dvb_register_adapter(&as102_dev->dvb_adap, - as102_dev->name, - THIS_MODULE, -#if defined(CONFIG_AS102_USB) - &as102_dev->bus_adap.usb_dev->dev -#elif defined(CONFIG_AS102_SPI) - &as102_dev->bus_adap.spi_dev->dev -#else -#error >>> dvb_register_adapter <<< -#endif -#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR - , adapter_nr -#endif - ); + as102_dev->name, THIS_MODULE, + dev, adapter_nr); if (ret < 0) { - err("%s: dvb_register_adapter() failed (errno = %d)", - __func__, ret); - goto failed; + dev_err(dev, "%s: dvb_register_adapter() failed: %d\n", + __func__, ret); + return ret; } as102_dev->dvb_dmx.priv = as102_dev; @@ -235,22 +220,22 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) ret = dvb_dmx_init(&as102_dev->dvb_dmx); if (ret < 0) { - err("%s: dvb_dmx_init() failed (errno = %d)", __func__, ret); - goto failed; + dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret); + goto edmxinit; } ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap); if (ret < 0) { - err("%s: dvb_dmxdev_init() failed (errno = %d)", __func__, - ret); - goto failed; + dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n", + __func__, ret); + goto edmxdinit; } ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); if (ret < 0) { - err("%s: as102_dvb_register_frontend() failed (errno = %d)", + dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d", __func__, ret); - goto failed; + goto efereg; } /* init bus mutex for token locking */ @@ -259,7 +244,6 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) /* init start / stop stream mutex */ mutex_init(&as102_dev->sem); -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) /* * try to load as102 firmware. If firmware upload failed, we'll be * able to upload it later. @@ -267,18 +251,21 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) if (fw_upload) try_then_request_module(as102_fw_upload(&as102_dev->bus_adap), "firmware_class"); -#endif -failed: - LEAVE(); - /* FIXME: free dvb_XXX */ + pr_info("Registered device %s", as102_dev->name); + return 0; + +efereg: + dvb_dmxdev_release(&as102_dev->dvb_dmxdev); +edmxdinit: + dvb_dmx_release(&as102_dev->dvb_dmx); +edmxinit: + dvb_unregister_adapter(&as102_dev->dvb_adap); return ret; } void as102_dvb_unregister(struct as102_dev_t *as102_dev) { - ENTER(); - /* unregister as102 frontend */ as102_dvb_unregister_fe(&as102_dev->dvb_fe); @@ -289,28 +276,18 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev) /* unregister dvb adapter */ dvb_unregister_adapter(&as102_dev->dvb_adap); - LEAVE(); + pr_info("Unregistered device %s", as102_dev->name); } static int __init as102_driver_init(void) { - int ret = 0; - - ENTER(); + int ret; /* register this driver with the low level subsystem */ -#if defined(CONFIG_AS102_USB) ret = usb_register(&as102_usb_driver); if (ret) err("usb_register failed (ret = %d)", ret); -#endif -#if defined(CONFIG_AS102_SPI) - ret = spi_register_driver(&as102_spi_driver); - if (ret) - printk(KERN_ERR "spi_register failed (ret = %d)", ret); -#endif - LEAVE(); return ret; } @@ -327,15 +304,8 @@ module_init(as102_driver_init); */ static void __exit as102_driver_exit(void) { - ENTER(); /* deregister this driver with the low level bus subsystem */ -#if defined(CONFIG_AS102_USB) usb_deregister(&as102_usb_driver); -#endif -#if defined(CONFIG_AS102_SPI) - spi_unregister_driver(&as102_spi_driver); -#endif - LEAVE(); } /* @@ -347,5 +317,3 @@ module_exit(as102_driver_exit); MODULE_DESCRIPTION(DRIVER_FULL_NAME); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>"); - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h index fd33f5a12dcc..957f0ed0d81a 100644 --- a/drivers/staging/media/as102/as102_drv.h +++ b/drivers/staging/media/as102/as102_drv.h @@ -17,38 +17,30 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(CONFIG_AS102_USB) #include <linux/usb.h> -extern struct usb_driver as102_usb_driver; -#endif - -#if defined(CONFIG_AS102_SPI) -#include <linux/platform_device.h> -#include <linux/spi/spi.h> -#include <linux/cdev.h> - -extern struct spi_driver as102_spi_driver; -#endif - -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dmxdev.h" +#include <dvb_demux.h> +#include <dvb_frontend.h> +#include <dmxdev.h> +#include "as10x_cmd.h" +#include "as102_usb_drv.h" #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" #define DRIVER_NAME "as10x_usb" extern int as102_debug; #define debug as102_debug +extern struct usb_driver as102_usb_driver; +extern int elna_enable; #define dprintk(debug, args...) \ do { if (debug) { \ - printk(KERN_DEBUG "%s: ",__FUNCTION__); \ + pr_debug("%s: ", __func__); \ printk(args); \ } } while (0) #ifdef TRACE -#define ENTER() printk(">> enter %s\n", __FUNCTION__) -#define LEAVE() printk("<< leave %s\n", __FUNCTION__) +#define ENTER() pr_debug(">> enter %s\n", __func__) +#define LEAVE() pr_debug("<< leave %s\n", __func__) #else #define ENTER() #define LEAVE() @@ -59,39 +51,14 @@ extern int as102_debug; #define AS102_USB_BUF_SIZE 512 #define MAX_STREAM_URB 32 -#include "as10x_cmd.h" - -#if defined(CONFIG_AS102_USB) -#include "as102_usb_drv.h" -#endif - -#if defined(CONFIG_AS102_SPI) -#include "as10x_spi_drv.h" -#endif - - -struct as102_bus_adapter_t { -#if defined(CONFIG_AS102_USB) +struct as10x_bus_adapter_t { struct usb_device *usb_dev; -#elif defined(CONFIG_AS102_SPI) - struct spi_device *spi_dev; - struct cdev cdev; /* spidev raw device */ - - struct timer_list timer; - struct completion xfer_done; -#endif /* bus token lock */ struct mutex lock; /* low level interface for bus adapter */ union as10x_bus_token_t { -#if defined(CONFIG_AS102_USB) /* usb token */ struct as10x_usb_token_cmd_t usb; -#endif -#if defined(CONFIG_AS102_SPI) - /* spi token */ - struct as10x_spi_token_cmd_t spi; -#endif } token; /* token cmd xfer id */ @@ -106,7 +73,7 @@ struct as102_bus_adapter_t { struct as102_dev_t { const char *name; - struct as102_bus_adapter_t bus_adap; + struct as10x_bus_adapter_t bus_adap; struct list_head device_entry; struct kref kref; unsigned long minor; @@ -138,5 +105,3 @@ void as102_dvb_unregister(struct as102_dev_t *dev); int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); int as102_dvb_unregister_fe(struct dvb_frontend *dev); - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c index 3550f905367e..bdc5a38cddf7 100644 --- a/drivers/staging/media/as102/as102_fe.c +++ b/drivers/staging/media/as102/as102_fe.c @@ -23,17 +23,15 @@ #include "as10x_types.h" #include "as10x_cmd.h" -extern int elna_enable; - -static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, +static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst, struct as10x_tps *src); static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, - struct dvb_frontend_parameters *src); + struct dtv_frontend_properties *src); -static int as102_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int as102_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int ret = 0; struct as102_dev_t *dev; struct as10x_tune_args tune_args = { 0 }; @@ -47,7 +45,7 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe, if (mutex_lock_interruptible(&dev->bus_adap.lock)) return -EBUSY; - as102_fe_copy_tune_parameters(&tune_args, params); + as102_fe_copy_tune_parameters(&tune_args, p); /* send abilis command: SET_TUNE */ ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); @@ -60,8 +58,9 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe, return (ret < 0) ? -EINVAL : 0; } -static int as102_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) { +static int as102_fe_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int ret = 0; struct as102_dev_t *dev; struct as10x_tps tps = { 0 }; @@ -280,9 +279,9 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) } static struct dvb_frontend_ops as102_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Unknown AS102 device", - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, @@ -346,38 +345,36 @@ int as102_dvb_register_fe(struct as102_dev_t *as102_dev, return errno; } -static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, +static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps, struct as10x_tps *as10x_tps) { - struct dvb_ofdm_parameters *fe_tps = &dst->u.ofdm; - /* extract consteallation */ - switch (as10x_tps->constellation) { + switch (as10x_tps->modulation) { case CONST_QPSK: - fe_tps->constellation = QPSK; + fe_tps->modulation = QPSK; break; case CONST_QAM16: - fe_tps->constellation = QAM_16; + fe_tps->modulation = QAM_16; break; case CONST_QAM64: - fe_tps->constellation = QAM_64; + fe_tps->modulation = QAM_64; break; } /* extract hierarchy */ switch (as10x_tps->hierarchy) { case HIER_NONE: - fe_tps->hierarchy_information = HIERARCHY_NONE; + fe_tps->hierarchy = HIERARCHY_NONE; break; case HIER_ALPHA_1: - fe_tps->hierarchy_information = HIERARCHY_1; + fe_tps->hierarchy = HIERARCHY_1; break; case HIER_ALPHA_2: - fe_tps->hierarchy_information = HIERARCHY_2; + fe_tps->hierarchy = HIERARCHY_2; break; case HIER_ALPHA_4: - fe_tps->hierarchy_information = HIERARCHY_4; + fe_tps->hierarchy = HIERARCHY_4; break; } @@ -475,7 +472,7 @@ static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) } static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *params) { /* set frequency */ @@ -484,21 +481,21 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, /* fix interleaving_mode */ tune_args->interleaving_mode = INTLV_NATIVE; - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: + switch (params->bandwidth_hz) { + case 8000000: tune_args->bandwidth = BW_8_MHZ; break; - case BANDWIDTH_7_MHZ: + case 7000000: tune_args->bandwidth = BW_7_MHZ; break; - case BANDWIDTH_6_MHZ: + case 6000000: tune_args->bandwidth = BW_6_MHZ; break; default: tune_args->bandwidth = BW_8_MHZ; } - switch (params->u.ofdm.guard_interval) { + switch (params->guard_interval) { case GUARD_INTERVAL_1_32: tune_args->guard_interval = GUARD_INT_1_32; break; @@ -517,22 +514,22 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, break; } - switch (params->u.ofdm.constellation) { + switch (params->modulation) { case QPSK: - tune_args->constellation = CONST_QPSK; + tune_args->modulation = CONST_QPSK; break; case QAM_16: - tune_args->constellation = CONST_QAM16; + tune_args->modulation = CONST_QAM16; break; case QAM_64: - tune_args->constellation = CONST_QAM64; + tune_args->modulation = CONST_QAM64; break; default: - tune_args->constellation = CONST_UNKNOWN; + tune_args->modulation = CONST_UNKNOWN; break; } - switch (params->u.ofdm.transmission_mode) { + switch (params->transmission_mode) { case TRANSMISSION_MODE_2K: tune_args->transmission_mode = TRANS_MODE_2K; break; @@ -543,7 +540,7 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, tune_args->transmission_mode = TRANS_MODE_UNKNOWN; } - switch (params->u.ofdm.hierarchy_information) { + switch (params->hierarchy) { case HIERARCHY_NONE: tune_args->hierarchy = HIER_NONE; break; @@ -571,19 +568,19 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, * if HP/LP are both set to FEC_NONE, HP will be selected. */ if ((tune_args->hierarchy != HIER_NONE) && - ((params->u.ofdm.code_rate_LP == FEC_NONE) || - (params->u.ofdm.code_rate_HP == FEC_NONE))) { + ((params->code_rate_LP == FEC_NONE) || + (params->code_rate_HP == FEC_NONE))) { - if (params->u.ofdm.code_rate_LP == FEC_NONE) { + if (params->code_rate_LP == FEC_NONE) { tune_args->hier_select = HIER_HIGH_PRIORITY; tune_args->code_rate = - as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); + as102_fe_get_code_rate(params->code_rate_HP); } - if (params->u.ofdm.code_rate_HP == FEC_NONE) { + if (params->code_rate_HP == FEC_NONE) { tune_args->hier_select = HIER_LOW_PRIORITY; tune_args->code_rate = - as102_fe_get_code_rate(params->u.ofdm.code_rate_LP); + as102_fe_get_code_rate(params->code_rate_LP); } dprintk(debug, "\thierarchy: 0x%02x " @@ -596,8 +593,6 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, tune_args->code_rate); } else { tune_args->code_rate = - as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); + as102_fe_get_code_rate(params->code_rate_HP); } } - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c index c019df933cc9..43ebc43e6b9a 100644 --- a/drivers/staging/media/as102/as102_fw.c +++ b/drivers/staging/media/as102/as102_fw.c @@ -26,7 +26,6 @@ #include "as102_drv.h" #include "as102_fw.h" -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) char as102_st_fw1[] = "as102_data1_st.hex"; char as102_st_fw2[] = "as102_data2_st.hex"; char as102_dt_fw1[] = "as102_data1_dt.hex"; @@ -59,7 +58,7 @@ static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, unsigned char *src, dst; if (*fw_data++ != ':') { - printk(KERN_ERR "invalid firmware file\n"); + pr_err("invalid firmware file\n"); return -EFAULT; } @@ -102,7 +101,7 @@ static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, return (count * 2) + 2; } -static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap, +static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, unsigned char *cmd, const struct firmware *firmware) { @@ -163,19 +162,14 @@ error: return (errno == 0) ? total_read_bytes : errno; } -int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) +int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap) { int errno = -EFAULT; const struct firmware *firmware; unsigned char *cmd_buf = NULL; char *fw1, *fw2; - -#if defined(CONFIG_AS102_USB) struct usb_device *dev = bus_adap->usb_dev; -#endif -#if defined(CONFIG_AS102_SPI) - struct spi_device *dev = bus_adap->spi_dev; -#endif + ENTER(); /* select fw file to upload */ @@ -187,7 +181,6 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) fw2 = as102_st_fw2; } -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) /* allocate buffer to store firmware upload command and data */ cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL); if (cmd_buf == NULL) { @@ -198,21 +191,21 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) /* request kernel to locate firmware file: part1 */ errno = request_firmware(&firmware, fw1, &dev->dev); if (errno < 0) { - printk(KERN_ERR "%s: unable to locate firmware file: %s\n", - DRIVER_NAME, fw1); + pr_err("%s: unable to locate firmware file: %s\n", + DRIVER_NAME, fw1); goto error; } /* initiate firmware upload */ errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); if (errno < 0) { - printk(KERN_ERR "%s: error during firmware upload part1\n", - DRIVER_NAME); + pr_err("%s: error during firmware upload part1\n", + DRIVER_NAME); goto error; } - printk(KERN_INFO "%s: fimrware: %s loaded with success\n", - DRIVER_NAME, fw1); + pr_info("%s: firmware: %s loaded with success\n", + DRIVER_NAME, fw1); release_firmware(firmware); /* wait for boot to complete */ @@ -221,31 +214,28 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) /* request kernel to locate firmware file: part2 */ errno = request_firmware(&firmware, fw2, &dev->dev); if (errno < 0) { - printk(KERN_ERR "%s: unable to locate firmware file: %s\n", - DRIVER_NAME, fw2); + pr_err("%s: unable to locate firmware file: %s\n", + DRIVER_NAME, fw2); goto error; } /* initiate firmware upload */ errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); if (errno < 0) { - printk(KERN_ERR "%s: error during firmware upload part2\n", - DRIVER_NAME); + pr_err("%s: error during firmware upload part2\n", + DRIVER_NAME); goto error; } - printk(KERN_INFO "%s: fimrware: %s loaded with success\n", - DRIVER_NAME, fw2); + pr_info("%s: firmware: %s loaded with success\n", + DRIVER_NAME, fw2); error: /* free data buffer */ kfree(cmd_buf); /* release firmware if needed */ if (firmware != NULL) release_firmware(firmware); -#endif + LEAVE(); return errno; } -#endif - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/staging/media/as102/as102_fw.h index 27e5347e2e19..bd21f0554392 100644 --- a/drivers/staging/media/as102/as102_fw.h +++ b/drivers/staging/media/as102/as102_fw.h @@ -20,11 +20,10 @@ extern int dual_tuner; -#pragma pack(1) struct as10x_raw_fw_pkt { unsigned char address[4]; unsigned char data[MAX_FW_PKT_SIZE - 6]; -}; +} __packed; struct as10x_fw_pkt_t { union { @@ -32,11 +31,8 @@ struct as10x_fw_pkt_t { unsigned char length[2]; } u; struct as10x_raw_fw_pkt raw; -}; -#pragma pack() +} __packed; #ifdef __KERNEL__ -int as102_fw_upload(struct as102_bus_adapter_t *bus_adap); +int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap); #endif - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index 264be2dbd2a4..d775be0173ea 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -42,30 +42,32 @@ static struct usb_device_id as102_usb_id_table[] = { { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) }, + { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) }, { } /* Terminating entry */ }; /* Note that this table must always have the same number of entries as the as102_usb_id_table struct */ -static const char *as102_device_names[] = { +static const char * const as102_device_names[] = { AS102_REFERENCE_DESIGN, AS102_PCTV_74E, AS102_ELGATO_EYETV_DTT_NAME, AS102_NBOX_DVBT_DONGLE_NAME, + AS102_SKY_IT_DIGITAL_KEY_NAME, NULL /* Terminating entry */ }; struct usb_driver as102_usb_driver = { - .name = DRIVER_FULL_NAME, - .probe = as102_usb_probe, - .disconnect = as102_usb_disconnect, - .id_table = as102_usb_id_table + .name = DRIVER_FULL_NAME, + .probe = as102_usb_probe, + .disconnect = as102_usb_disconnect, + .id_table = as102_usb_id_table }; static const struct file_operations as102_dev_fops = { - .owner = THIS_MODULE, - .open = as102_open, - .release = as102_release, + .owner = THIS_MODULE, + .open = as102_open, + .release = as102_release, }; static struct usb_class_driver as102_usb_class_driver = { @@ -74,7 +76,7 @@ static struct usb_class_driver as102_usb_class_driver = { .minor_base = AS102_DEVICE_MAJOR, }; -static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap, +static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, unsigned char *send_buf, int send_buf_len, unsigned char *recv_buf, int recv_buf_len) { @@ -131,7 +133,7 @@ static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap, return ret; } -static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap, +static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, unsigned char *send_buf, int send_buf_len, int swap32) @@ -154,7 +156,7 @@ static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap, return ret ? ret : actual_len; } -static int as102_read_ep2(struct as102_bus_adapter_t *bus_adap, +static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, unsigned char *recv_buf, int recv_buf_len) { int ret = 0, actual_len; @@ -337,7 +339,7 @@ static void as102_usb_disconnect(struct usb_interface *intf) /* decrement usage counter */ kref_put(&as102_dev->kref, as102_usb_release); - printk(KERN_INFO "%s: device has been disconnected\n", DRIVER_NAME); + pr_info("%s: device has been disconnected\n", DRIVER_NAME); LEAVE(); } @@ -351,19 +353,19 @@ static int as102_usb_probe(struct usb_interface *intf, ENTER(); - as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); - if (as102_dev == NULL) { - err("%s: kzalloc failed", __func__); - return -ENOMEM; - } - /* This should never actually happen */ if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) != (sizeof(as102_device_names) / sizeof(const char *))) { - printk(KERN_ERR "Device names table invalid size"); + pr_err("Device names table invalid size"); return -EINVAL; } + as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); + if (as102_dev == NULL) { + err("%s: kzalloc failed", __func__); + return -ENOMEM; + } + /* Assign the user-friendly device name */ for (i = 0; i < (sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)); i++) { @@ -399,7 +401,7 @@ static int as102_usb_probe(struct usb_interface *intf, goto failed; } - printk(KERN_INFO "%s: device has been detected\n", DRIVER_NAME); + pr_info("%s: device has been detected\n", DRIVER_NAME); /* request buffer allocation for streaming */ ret = as102_alloc_usb_stream_buffer(as102_dev); @@ -432,8 +434,8 @@ static int as102_open(struct inode *inode, struct file *file) /* fetch device from usb interface */ intf = usb_find_interface(&as102_usb_driver, minor); if (intf == NULL) { - printk(KERN_ERR "%s: can't find device for minor %d\n", - __func__, minor); + pr_err("%s: can't find device for minor %d\n", + __func__, minor); ret = -ENODEV; goto exit; } @@ -474,5 +476,3 @@ static int as102_release(struct inode *inode, struct file *file) } MODULE_DEVICE_TABLE(usb, as102_usb_id_table); - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h index fb1fc41dcd79..fc2884ab02a2 100644 --- a/drivers/staging/media/as102/as102_usb_drv.h +++ b/drivers/staging/media/as102/as102_usb_drv.h @@ -47,6 +47,11 @@ #define NBOX_DVBT_DONGLE_USB_VID 0x0b89 #define NBOX_DVBT_DONGLE_USB_PID 0x0007 +/* Sky Italia: Digital Key (green led) */ +#define AS102_SKY_IT_DIGITAL_KEY_NAME "Sky IT Digital Key (green led)" +#define SKY_IT_DIGITAL_KEY_USB_VID 0x2137 +#define SKY_IT_DIGITAL_KEY_USB_PID 0x0001 + void as102_urb_stream_irq(struct urb *urb); struct as10x_usb_token_cmd_t { @@ -56,4 +61,3 @@ struct as10x_usb_token_cmd_t { struct as10x_cmd_t r; }; #endif -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c index 0dcba8065780..262bb94ad27e 100644 --- a/drivers/staging/media/as102/as10x_cmd.c +++ b/drivers/staging/media/as102/as10x_cmd.c @@ -25,35 +25,35 @@ /** * as10x_cmd_turn_on - send turn on command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * * Return 0 when no error, < 0 in case of error. */ -int as10x_cmd_turn_on(as10x_handle_t *phandle) +int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.turn_on.req)); /* fill command */ pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, - sizeof(pcmd->body.turn_on.req) + - HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.turn_on.rsp) + - HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, + sizeof(pcmd->body.turn_on.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.turn_on.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -71,31 +71,31 @@ out: /** * as10x_cmd_turn_off - send turn off command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_turn_off(as10x_handle_t *phandle) +int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.turn_off.req)); /* fill command */ pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd( - phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd( + adap, (uint8_t *) pcmd, sizeof(pcmd->body.turn_off.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE); @@ -116,23 +116,24 @@ out: /** * as10x_cmd_set_tune - send set tune command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @ptune: tune parameters * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) +int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, + struct as10x_tune_args *ptune) { int error; struct as10x_cmd_t *preq, *prsp; ENTER(); - preq = phandle->cmd; - prsp = phandle->rsp; + preq = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(preq, (++phandle->cmd_xid), + as10x_cmd_build(preq, (++adap->cmd_xid), sizeof(preq->body.set_tune.req)); /* fill command */ @@ -140,7 +141,7 @@ int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; preq->body.set_tune.req.args.hier_select = ptune->hier_select; - preq->body.set_tune.req.args.constellation = ptune->constellation; + preq->body.set_tune.req.args.modulation = ptune->modulation; preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; preq->body.set_tune.req.args.interleaving_mode = ptune->interleaving_mode; @@ -150,14 +151,14 @@ int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) ptune->transmission_mode; /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) preq, - sizeof(preq->body.set_tune.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.set_tune.rsp) - + HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) preq, + sizeof(preq->body.set_tune.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.set_tune.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -175,12 +176,12 @@ out: /** * as10x_cmd_get_tune_status - send get tune status command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @pstatus: pointer to updated status structure of the current tune * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_tune_status(as10x_handle_t *phandle, +int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, struct as10x_tune_status *pstatus) { int error; @@ -188,11 +189,11 @@ int as10x_cmd_get_tune_status(as10x_handle_t *phandle, ENTER(); - preq = phandle->cmd; - prsp = phandle->rsp; + preq = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(preq, (++phandle->cmd_xid), + as10x_cmd_build(preq, (++adap->cmd_xid), sizeof(preq->body.get_tune_status.req)); /* fill command */ @@ -200,9 +201,9 @@ int as10x_cmd_get_tune_status(as10x_handle_t *phandle, cpu_to_le16(CONTROL_PROC_GETTUNESTAT); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd( - phandle, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd( + adap, (uint8_t *) preq, sizeof(preq->body.get_tune_status.req) + HEADER_SIZE, (uint8_t *) prsp, @@ -232,24 +233,24 @@ out: } /** - * send get TPS command to AS10x - * @phandle: pointer to AS10x handle + * as10x_cmd_get_tps - send get TPS command to AS10x + * @adap: pointer to AS10x handle * @ptps: pointer to TPS parameters structure * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) +int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.get_tps.req)); /* fill command */ @@ -257,14 +258,14 @@ int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) cpu_to_le16(CONTROL_PROC_GETTPS); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.get_tps.req) + - HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.get_tps.rsp) + - HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_tps.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_tps.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -278,7 +279,7 @@ int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) goto out; /* Response OK -> get response data */ - ptps->constellation = prsp->body.get_tps.rsp.tps.constellation; + ptps->modulation = prsp->body.get_tps.rsp.tps.modulation; ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; @@ -296,12 +297,12 @@ out: /** * as10x_cmd_get_demod_stats - send get demod stats command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @pdemod_stats: pointer to demod stats parameters structure * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, +int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, struct as10x_demod_stats *pdemod_stats) { int error; @@ -309,11 +310,11 @@ int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.get_demod_stats.req)); /* fill command */ @@ -321,8 +322,8 @@ int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.get_demod_stats.req) + HEADER_SIZE, @@ -360,13 +361,13 @@ out: /** * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @is_ready: pointer to value indicating when impulse * response data is ready * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, +int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, uint8_t *is_ready) { int error; @@ -374,11 +375,11 @@ int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.get_impulse_rsp.req)); /* fill command */ @@ -386,8 +387,8 @@ int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.get_impulse_rsp.req) + HEADER_SIZE, diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/staging/media/as102/as10x_cmd.h index 01a716380e0a..4ea249e7adab 100644 --- a/drivers/staging/media/as102/as10x_cmd.h +++ b/drivers/staging/media/as102/as10x_cmd.h @@ -28,459 +28,456 @@ /*********************************/ /* MACRO DEFINITIONS */ /*********************************/ -#define AS10X_CMD_ERROR -1 +#define AS10X_CMD_ERROR -1 -#define SERVICE_PROG_ID 0x0002 -#define SERVICE_PROG_VERSION 0x0001 +#define SERVICE_PROG_ID 0x0002 +#define SERVICE_PROG_VERSION 0x0001 -#define HIER_NONE 0x00 -#define HIER_LOW_PRIORITY 0x01 +#define HIER_NONE 0x00 +#define HIER_LOW_PRIORITY 0x01 #define HEADER_SIZE (sizeof(struct as10x_cmd_header_t)) /* context request types */ -#define GET_CONTEXT_DATA 1 -#define SET_CONTEXT_DATA 2 +#define GET_CONTEXT_DATA 1 +#define SET_CONTEXT_DATA 2 /* ODSP suspend modes */ -#define CFG_MODE_ODSP_RESUME 0 -#define CFG_MODE_ODSP_SUSPEND 1 +#define CFG_MODE_ODSP_RESUME 0 +#define CFG_MODE_ODSP_SUSPEND 1 /* Dump memory size */ -#define DUMP_BLOCK_SIZE_MAX 0x20 +#define DUMP_BLOCK_SIZE_MAX 0x20 /*********************************/ /* TYPE DEFINITION */ /*********************************/ -typedef enum { - CONTROL_PROC_TURNON = 0x0001, - CONTROL_PROC_TURNON_RSP = 0x0100, - CONTROL_PROC_SET_REGISTER = 0x0002, - CONTROL_PROC_SET_REGISTER_RSP = 0x0200, - CONTROL_PROC_GET_REGISTER = 0x0003, - CONTROL_PROC_GET_REGISTER_RSP = 0x0300, - CONTROL_PROC_SETTUNE = 0x000A, - CONTROL_PROC_SETTUNE_RSP = 0x0A00, - CONTROL_PROC_GETTUNESTAT = 0x000B, - CONTROL_PROC_GETTUNESTAT_RSP = 0x0B00, - CONTROL_PROC_GETTPS = 0x000D, - CONTROL_PROC_GETTPS_RSP = 0x0D00, - CONTROL_PROC_SETFILTER = 0x000E, - CONTROL_PROC_SETFILTER_RSP = 0x0E00, - CONTROL_PROC_REMOVEFILTER = 0x000F, - CONTROL_PROC_REMOVEFILTER_RSP = 0x0F00, - CONTROL_PROC_GET_IMPULSE_RESP = 0x0012, - CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200, - CONTROL_PROC_START_STREAMING = 0x0013, - CONTROL_PROC_START_STREAMING_RSP = 0x1300, - CONTROL_PROC_STOP_STREAMING = 0x0014, - CONTROL_PROC_STOP_STREAMING_RSP = 0x1400, - CONTROL_PROC_GET_DEMOD_STATS = 0x0015, - CONTROL_PROC_GET_DEMOD_STATS_RSP = 0x1500, - CONTROL_PROC_ELNA_CHANGE_MODE = 0x0016, - CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600, - CONTROL_PROC_ODSP_CHANGE_MODE = 0x0017, - CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700, - CONTROL_PROC_AGC_CHANGE_MODE = 0x0018, - CONTROL_PROC_AGC_CHANGE_MODE_RSP = 0x1800, - - CONTROL_PROC_CONTEXT = 0x00FC, - CONTROL_PROC_CONTEXT_RSP = 0xFC00, - CONTROL_PROC_DUMP_MEMORY = 0x00FD, - CONTROL_PROC_DUMP_MEMORY_RSP = 0xFD00, - CONTROL_PROC_DUMPLOG_MEMORY = 0x00FE, - CONTROL_PROC_DUMPLOG_MEMORY_RSP = 0xFE00, - CONTROL_PROC_TURNOFF = 0x00FF, - CONTROL_PROC_TURNOFF_RSP = 0xFF00 -} control_proc; - - -#pragma pack(1) -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} TURN_ON; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t err; - } rsp; -} TURN_OFF; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* tune params */ - struct as10x_tune_args args; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } rsp; -} SET_TUNE; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* tune status */ - struct as10x_tune_status sts; - } rsp; -} GET_TUNE_STATUS; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* tps details */ - struct as10x_tps tps; - } rsp; -} GET_TPS; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } rsp; -} COMMON; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* PID to filter */ - uint16_t pid; - /* stream type (MPE, PSI/SI or PES )*/ - uint8_t stream_type; - /* PID index in filter table */ - uint8_t idx; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* Filter id */ - uint8_t filter_id; - } rsp; -} ADD_PID_FILTER; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* PID to remove */ - uint16_t pid; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } rsp; -} DEL_PID_FILTER; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} START_STREAMING; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} STOP_STREAMING; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* demod stats */ - struct as10x_demod_stats stats; - } rsp; -} GET_DEMOD_STATS; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* impulse response ready */ - uint8_t is_ready; - } rsp; -} GET_IMPULSE_RESP; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* value to write (for set context)*/ - struct as10x_register_value reg_val; - /* context tag */ - uint16_t tag; - /* context request type */ - uint16_t type; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* value read (for get context) */ - struct as10x_register_value reg_val; - /* context request type */ - uint16_t type; - /* error */ - uint8_t error; - } rsp; -} FW_CONTEXT; - -typedef union { - /* request */ - struct { - /* response identifier */ - uint16_t proc_id; - /* register description */ - struct as10x_register_addr reg_addr; - /* register content */ - struct as10x_register_value reg_val; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} SET_REGISTER; - -typedef union { - /* request */ - struct { - /* response identifier */ - uint16_t proc_id; - /* register description */ - struct as10x_register_addr reg_addr; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* register content */ - struct as10x_register_value reg_val; - } rsp; -} GET_REGISTER; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* mode */ - uint8_t mode; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} CFG_CHANGE_MODE; +enum control_proc { + CONTROL_PROC_TURNON = 0x0001, + CONTROL_PROC_TURNON_RSP = 0x0100, + CONTROL_PROC_SET_REGISTER = 0x0002, + CONTROL_PROC_SET_REGISTER_RSP = 0x0200, + CONTROL_PROC_GET_REGISTER = 0x0003, + CONTROL_PROC_GET_REGISTER_RSP = 0x0300, + CONTROL_PROC_SETTUNE = 0x000A, + CONTROL_PROC_SETTUNE_RSP = 0x0A00, + CONTROL_PROC_GETTUNESTAT = 0x000B, + CONTROL_PROC_GETTUNESTAT_RSP = 0x0B00, + CONTROL_PROC_GETTPS = 0x000D, + CONTROL_PROC_GETTPS_RSP = 0x0D00, + CONTROL_PROC_SETFILTER = 0x000E, + CONTROL_PROC_SETFILTER_RSP = 0x0E00, + CONTROL_PROC_REMOVEFILTER = 0x000F, + CONTROL_PROC_REMOVEFILTER_RSP = 0x0F00, + CONTROL_PROC_GET_IMPULSE_RESP = 0x0012, + CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200, + CONTROL_PROC_START_STREAMING = 0x0013, + CONTROL_PROC_START_STREAMING_RSP = 0x1300, + CONTROL_PROC_STOP_STREAMING = 0x0014, + CONTROL_PROC_STOP_STREAMING_RSP = 0x1400, + CONTROL_PROC_GET_DEMOD_STATS = 0x0015, + CONTROL_PROC_GET_DEMOD_STATS_RSP = 0x1500, + CONTROL_PROC_ELNA_CHANGE_MODE = 0x0016, + CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600, + CONTROL_PROC_ODSP_CHANGE_MODE = 0x0017, + CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700, + CONTROL_PROC_AGC_CHANGE_MODE = 0x0018, + CONTROL_PROC_AGC_CHANGE_MODE_RSP = 0x1800, + + CONTROL_PROC_CONTEXT = 0x00FC, + CONTROL_PROC_CONTEXT_RSP = 0xFC00, + CONTROL_PROC_DUMP_MEMORY = 0x00FD, + CONTROL_PROC_DUMP_MEMORY_RSP = 0xFD00, + CONTROL_PROC_DUMPLOG_MEMORY = 0x00FE, + CONTROL_PROC_DUMPLOG_MEMORY_RSP = 0xFE00, + CONTROL_PROC_TURNOFF = 0x00FF, + CONTROL_PROC_TURNOFF_RSP = 0xFF00 +}; + +union as10x_turn_on { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_turn_off { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t err; + } rsp; +} __packed; + +union as10x_set_tune { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* tune params */ + struct as10x_tune_args args; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_get_tune_status { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* tune status */ + struct as10x_tune_status sts; + } rsp; +} __packed; + +union as10x_get_tps { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* tps details */ + struct as10x_tps tps; + } rsp; +} __packed; + +union as10x_common { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_add_pid_filter { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* PID to filter */ + uint16_t pid; + /* stream type (MPE, PSI/SI or PES )*/ + uint8_t stream_type; + /* PID index in filter table */ + uint8_t idx; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* Filter id */ + uint8_t filter_id; + } rsp; +} __packed; + +union as10x_del_pid_filter { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* PID to remove */ + uint16_t pid; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_start_streaming { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_stop_streaming { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_get_demod_stats { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* demod stats */ + struct as10x_demod_stats stats; + } rsp; +} __packed; + +union as10x_get_impulse_resp { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* impulse response ready */ + uint8_t is_ready; + } rsp; +} __packed; + +union as10x_fw_context { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* value to write (for set context)*/ + struct as10x_register_value reg_val; + /* context tag */ + uint16_t tag; + /* context request type */ + uint16_t type; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* value read (for get context) */ + struct as10x_register_value reg_val; + /* context request type */ + uint16_t type; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_set_register { + /* request */ + struct { + /* response identifier */ + uint16_t proc_id; + /* register description */ + struct as10x_register_addr reg_addr; + /* register content */ + struct as10x_register_value reg_val; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_get_register { + /* request */ + struct { + /* response identifier */ + uint16_t proc_id; + /* register description */ + struct as10x_register_addr reg_addr; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* register content */ + struct as10x_register_value reg_val; + } rsp; +} __packed; + +union as10x_cfg_change_mode { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* mode */ + uint8_t mode; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; struct as10x_cmd_header_t { - uint16_t req_id; - uint16_t prog; - uint16_t version; - uint16_t data_len; -}; + uint16_t req_id; + uint16_t prog; + uint16_t version; + uint16_t data_len; +} __packed; #define DUMP_BLOCK_SIZE 16 -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* dump memory type request */ - uint8_t dump_req; - /* register description */ - struct as10x_register_addr reg_addr; - /* nb blocks to read */ - uint16_t num_blocks; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* dump response */ - uint8_t dump_rsp; - /* data */ - union { - uint8_t data8[DUMP_BLOCK_SIZE]; - uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; - uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; - } u; - } rsp; -} DUMP_MEMORY; - -typedef union { - struct { - /* request identifier */ - uint16_t proc_id; - /* dump memory type request */ - uint8_t dump_req; - } req; - struct { - /* request identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* dump response */ - uint8_t dump_rsp; - /* dump data */ - uint8_t data[DUMP_BLOCK_SIZE]; - } rsp; -} DUMPLOG_MEMORY; - -typedef union { - /* request */ - struct { - uint16_t proc_id; - uint8_t data[64 - sizeof(struct as10x_cmd_header_t) -2 /* proc_id */]; - } req; - /* response */ - struct { - uint16_t proc_id; - uint8_t error; - uint8_t data[64 - sizeof(struct as10x_cmd_header_t) /* header */ - - 2 /* proc_id */ - 1 /* rc */]; - } rsp; -} RAW_DATA; + +union as10x_dump_memory { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* dump memory type request */ + uint8_t dump_req; + /* register description */ + struct as10x_register_addr reg_addr; + /* nb blocks to read */ + uint16_t num_blocks; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* dump response */ + uint8_t dump_rsp; + /* data */ + union { + uint8_t data8[DUMP_BLOCK_SIZE]; + uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; + uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; + } u; + } rsp; +} __packed; + +union as10x_dumplog_memory { + struct { + /* request identifier */ + uint16_t proc_id; + /* dump memory type request */ + uint8_t dump_req; + } req; + struct { + /* request identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* dump response */ + uint8_t dump_rsp; + /* dump data */ + uint8_t data[DUMP_BLOCK_SIZE]; + } rsp; +} __packed; + +union as10x_raw_data { + /* request */ + struct { + uint16_t proc_id; + uint8_t data[64 - sizeof(struct as10x_cmd_header_t) + - 2 /* proc_id */]; + } req; + /* response */ + struct { + uint16_t proc_id; + uint8_t error; + uint8_t data[64 - sizeof(struct as10x_cmd_header_t) + - 2 /* proc_id */ - 1 /* rc */]; + } rsp; +} __packed; struct as10x_cmd_t { - /* header */ - struct as10x_cmd_header_t header; - /* body */ - union { - TURN_ON turn_on; - TURN_OFF turn_off; - SET_TUNE set_tune; - GET_TUNE_STATUS get_tune_status; - GET_TPS get_tps; - COMMON common; - ADD_PID_FILTER add_pid_filter; - DEL_PID_FILTER del_pid_filter; - START_STREAMING start_streaming; - STOP_STREAMING stop_streaming; - GET_DEMOD_STATS get_demod_stats; - GET_IMPULSE_RESP get_impulse_rsp; - FW_CONTEXT context; - SET_REGISTER set_register; - GET_REGISTER get_register; - CFG_CHANGE_MODE cfg_change_mode; - DUMP_MEMORY dump_memory; - DUMPLOG_MEMORY dumplog_memory; - RAW_DATA raw_data; - } body; -}; + struct as10x_cmd_header_t header; + union { + union as10x_turn_on turn_on; + union as10x_turn_off turn_off; + union as10x_set_tune set_tune; + union as10x_get_tune_status get_tune_status; + union as10x_get_tps get_tps; + union as10x_common common; + union as10x_add_pid_filter add_pid_filter; + union as10x_del_pid_filter del_pid_filter; + union as10x_start_streaming start_streaming; + union as10x_stop_streaming stop_streaming; + union as10x_get_demod_stats get_demod_stats; + union as10x_get_impulse_resp get_impulse_rsp; + union as10x_fw_context context; + union as10x_set_register set_register; + union as10x_get_register get_register; + union as10x_cfg_change_mode cfg_change_mode; + union as10x_dump_memory dump_memory; + union as10x_dumplog_memory dumplog_memory; + union as10x_raw_data raw_data; + } body; +} __packed; struct as10x_token_cmd_t { - /* token cmd */ - struct as10x_cmd_t c; - /* token response */ - struct as10x_cmd_t r; -}; -#pragma pack() + /* token cmd */ + struct as10x_cmd_t c; + /* token response */ + struct as10x_cmd_t r; +} __packed; /**************************/ @@ -491,50 +488,42 @@ void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id, uint16_t cmd_len); int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id); -#ifdef __cplusplus -extern "C" { -#endif - /* as10x cmd */ -int as10x_cmd_turn_on(as10x_handle_t *phandle); -int as10x_cmd_turn_off(as10x_handle_t *phandle); +int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap); +int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap); -int as10x_cmd_set_tune(as10x_handle_t *phandle, +int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, struct as10x_tune_args *ptune); -int as10x_cmd_get_tune_status(as10x_handle_t *phandle, +int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, struct as10x_tune_status *pstatus); -int as10x_cmd_get_tps(as10x_handle_t *phandle, +int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps); -int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, +int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, struct as10x_demod_stats *pdemod_stats); -int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, +int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, uint8_t *is_ready); /* as10x cmd stream */ -int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, +int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap, struct as10x_ts_filter *filter); -int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, +int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap, uint16_t pid_value); -int as10x_cmd_start_streaming(as10x_handle_t *phandle); -int as10x_cmd_stop_streaming(as10x_handle_t *phandle); +int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap); +int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap); /* as10x cmd cfg */ -int as10x_cmd_set_context(as10x_handle_t *phandle, +int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag, uint32_t value); -int as10x_cmd_get_context(as10x_handle_t *phandle, +int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag, uint32_t *pvalue); -int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode); +int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode); int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id); -#ifdef __cplusplus -} -#endif #endif -/* EOF - vim: set textwidth=80 ts=3 sw=3 sts=3 et: */ diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c index ec6f69fcf399..d2a4bce89623 100644 --- a/drivers/staging/media/as102/as10x_cmd_cfg.c +++ b/drivers/staging/media/as102/as10x_cmd_cfg.c @@ -28,13 +28,13 @@ /** * as10x_cmd_get_context - Send get context command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @tag: context tag * @pvalue: pointer where to store context value read * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, +int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag, uint32_t *pvalue) { int error; @@ -42,11 +42,11 @@ int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.context.req)); /* fill command */ @@ -55,14 +55,14 @@ int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.context.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.context.rsp) - + HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -87,13 +87,13 @@ out: /** * as10x_cmd_set_context - send set context command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @tag: context tag * @value: value to set in context * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, +int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag, uint32_t value) { int error; @@ -101,11 +101,11 @@ int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.context.req)); /* fill command */ @@ -116,14 +116,14 @@ int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.context.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.context.rsp) - + HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -142,7 +142,7 @@ out: /** * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @mode: mode selected: * - ON : 0x0 => eLNA always ON * - OFF : 0x1 => eLNA always OFF @@ -151,18 +151,18 @@ out: * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode) +int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.cfg_change_mode.req)); /* fill command */ @@ -171,8 +171,8 @@ int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode) pcmd->body.cfg_change_mode.req.mode = mode; /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.cfg_change_mode.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.cfg_change_mode.rsp) diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c index 045c70683193..6d000f60fb0e 100644 --- a/drivers/staging/media/as102/as10x_cmd_stream.c +++ b/drivers/staging/media/as102/as10x_cmd_stream.c @@ -23,12 +23,12 @@ /** * as10x_cmd_add_PID_filter - send add filter command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @filter: TSFilter filter for DVB-T * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, +int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap, struct as10x_ts_filter *filter) { int error; @@ -36,11 +36,11 @@ int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.add_pid_filter.req)); /* fill command */ @@ -55,8 +55,8 @@ int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, pcmd->body.add_pid_filter.req.idx = 0xFF; /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.add_pid_filter.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.add_pid_filter.rsp) @@ -83,12 +83,12 @@ out: /** * as10x_cmd_del_PID_filter - Send delete filter command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapte * @pid_value: PID to delete * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, +int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap, uint16_t pid_value) { int error; @@ -96,11 +96,11 @@ int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.del_pid_filter.req)); /* fill command */ @@ -109,8 +109,8 @@ int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.del_pid_filter.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.del_pid_filter.rsp) @@ -132,22 +132,22 @@ out: /** * as10x_cmd_start_streaming - Send start streaming command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_start_streaming(as10x_handle_t *phandle) +int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.start_streaming.req)); /* fill command */ @@ -155,8 +155,8 @@ int as10x_cmd_start_streaming(as10x_handle_t *phandle) cpu_to_le16(CONTROL_PROC_START_STREAMING); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.start_streaming.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.start_streaming.rsp) @@ -178,22 +178,22 @@ out: /** * as10x_cmd_stop_streaming - Send stop streaming command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_stop_streaming(as10x_handle_t *phandle) +int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap) { int8_t error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.stop_streaming.req)); /* fill command */ @@ -201,8 +201,8 @@ int as10x_cmd_stop_streaming(as10x_handle_t *phandle) cpu_to_le16(CONTROL_PROC_STOP_STREAMING); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.stop_streaming.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.stop_streaming.rsp) diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/staging/media/as102/as10x_handle.h index 4f01a76e9829..62b9795ee424 100644 --- a/drivers/staging/media/as102/as10x_handle.h +++ b/drivers/staging/media/as102/as10x_handle.h @@ -17,41 +17,37 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __KERNEL__ -struct as102_bus_adapter_t; +struct as10x_bus_adapter_t; struct as102_dev_t; -#define as10x_handle_t struct as102_bus_adapter_t #include "as10x_cmd.h" /* values for "mode" field */ -#define REGMODE8 8 -#define REGMODE16 16 -#define REGMODE32 32 +#define REGMODE8 8 +#define REGMODE16 16 +#define REGMODE32 32 struct as102_priv_ops_t { - int (*upload_fw_pkt) (struct as102_bus_adapter_t *bus_adap, + int (*upload_fw_pkt) (struct as10x_bus_adapter_t *bus_adap, unsigned char *buf, int buflen, int swap32); - int (*send_cmd) (struct as102_bus_adapter_t *bus_adap, + int (*send_cmd) (struct as10x_bus_adapter_t *bus_adap, unsigned char *buf, int buflen); - int (*xfer_cmd) (struct as102_bus_adapter_t *bus_adap, + int (*xfer_cmd) (struct as10x_bus_adapter_t *bus_adap, unsigned char *send_buf, int send_buf_len, unsigned char *recv_buf, int recv_buf_len); -/* - int (*pid_filter) (struct as102_bus_adapter_t *bus_adap, - int index, u16 pid, int onoff); -*/ + int (*start_stream) (struct as102_dev_t *dev); void (*stop_stream) (struct as102_dev_t *dev); - int (*reset_target) (struct as102_bus_adapter_t *bus_adap); + int (*reset_target) (struct as10x_bus_adapter_t *bus_adap); - int (*read_write)(struct as102_bus_adapter_t *bus_adap, uint8_t mode, + int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode, uint32_t rd_addr, uint16_t rd_len, uint32_t wr_addr, uint16_t wr_len); - int (*as102_read_ep2) (struct as102_bus_adapter_t *bus_adap, + int (*as102_read_ep2) (struct as10x_bus_adapter_t *bus_adap, unsigned char *recv_buf, int recv_buf_len); }; diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/staging/media/as102/as10x_types.h index 3dedb3c1420a..fde8140ae88b 100644 --- a/drivers/staging/media/as102/as10x_types.h +++ b/drivers/staging/media/as102/as10x_types.h @@ -26,173 +26,169 @@ /*********************************/ /* bandwidth constant values */ -#define BW_5_MHZ 0x00 -#define BW_6_MHZ 0x01 -#define BW_7_MHZ 0x02 -#define BW_8_MHZ 0x03 +#define BW_5_MHZ 0x00 +#define BW_6_MHZ 0x01 +#define BW_7_MHZ 0x02 +#define BW_8_MHZ 0x03 /* hierarchy priority selection values */ -#define HIER_NO_PRIORITY 0x00 -#define HIER_LOW_PRIORITY 0x01 -#define HIER_HIGH_PRIORITY 0x02 +#define HIER_NO_PRIORITY 0x00 +#define HIER_LOW_PRIORITY 0x01 +#define HIER_HIGH_PRIORITY 0x02 /* constellation available values */ -#define CONST_QPSK 0x00 -#define CONST_QAM16 0x01 -#define CONST_QAM64 0x02 -#define CONST_UNKNOWN 0xFF +#define CONST_QPSK 0x00 +#define CONST_QAM16 0x01 +#define CONST_QAM64 0x02 +#define CONST_UNKNOWN 0xFF /* hierarchy available values */ -#define HIER_NONE 0x00 -#define HIER_ALPHA_1 0x01 -#define HIER_ALPHA_2 0x02 -#define HIER_ALPHA_4 0x03 -#define HIER_UNKNOWN 0xFF +#define HIER_NONE 0x00 +#define HIER_ALPHA_1 0x01 +#define HIER_ALPHA_2 0x02 +#define HIER_ALPHA_4 0x03 +#define HIER_UNKNOWN 0xFF /* interleaving available values */ -#define INTLV_NATIVE 0x00 -#define INTLV_IN_DEPTH 0x01 -#define INTLV_UNKNOWN 0xFF +#define INTLV_NATIVE 0x00 +#define INTLV_IN_DEPTH 0x01 +#define INTLV_UNKNOWN 0xFF /* code rate available values */ -#define CODE_RATE_1_2 0x00 -#define CODE_RATE_2_3 0x01 -#define CODE_RATE_3_4 0x02 -#define CODE_RATE_5_6 0x03 -#define CODE_RATE_7_8 0x04 -#define CODE_RATE_UNKNOWN 0xFF +#define CODE_RATE_1_2 0x00 +#define CODE_RATE_2_3 0x01 +#define CODE_RATE_3_4 0x02 +#define CODE_RATE_5_6 0x03 +#define CODE_RATE_7_8 0x04 +#define CODE_RATE_UNKNOWN 0xFF /* guard interval available values */ -#define GUARD_INT_1_32 0x00 -#define GUARD_INT_1_16 0x01 -#define GUARD_INT_1_8 0x02 -#define GUARD_INT_1_4 0x03 -#define GUARD_UNKNOWN 0xFF +#define GUARD_INT_1_32 0x00 +#define GUARD_INT_1_16 0x01 +#define GUARD_INT_1_8 0x02 +#define GUARD_INT_1_4 0x03 +#define GUARD_UNKNOWN 0xFF /* transmission mode available values */ -#define TRANS_MODE_2K 0x00 -#define TRANS_MODE_8K 0x01 -#define TRANS_MODE_4K 0x02 -#define TRANS_MODE_UNKNOWN 0xFF +#define TRANS_MODE_2K 0x00 +#define TRANS_MODE_8K 0x01 +#define TRANS_MODE_4K 0x02 +#define TRANS_MODE_UNKNOWN 0xFF /* DVBH signalling available values */ -#define TIMESLICING_PRESENT 0x01 -#define MPE_FEC_PRESENT 0x02 +#define TIMESLICING_PRESENT 0x01 +#define MPE_FEC_PRESENT 0x02 /* tune state available */ -#define TUNE_STATUS_NOT_TUNED 0x00 -#define TUNE_STATUS_IDLE 0x01 -#define TUNE_STATUS_LOCKING 0x02 -#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 -#define TUNE_STATUS_STREAM_DETECTED 0x04 -#define TUNE_STATUS_STREAM_TUNED 0x05 -#define TUNE_STATUS_ERROR 0xFF +#define TUNE_STATUS_NOT_TUNED 0x00 +#define TUNE_STATUS_IDLE 0x01 +#define TUNE_STATUS_LOCKING 0x02 +#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 +#define TUNE_STATUS_STREAM_DETECTED 0x04 +#define TUNE_STATUS_STREAM_TUNED 0x05 +#define TUNE_STATUS_ERROR 0xFF /* available TS FID filter types */ -#define TS_PID_TYPE_TS 0 -#define TS_PID_TYPE_PSI_SI 1 -#define TS_PID_TYPE_MPE 2 +#define TS_PID_TYPE_TS 0 +#define TS_PID_TYPE_PSI_SI 1 +#define TS_PID_TYPE_MPE 2 /* number of echos available */ -#define MAX_ECHOS 15 +#define MAX_ECHOS 15 /* Context types */ -#define CONTEXT_LNA 1010 -#define CONTEXT_ELNA_HYSTERESIS 4003 -#define CONTEXT_ELNA_GAIN 4004 -#define CONTEXT_MER_THRESHOLD 5005 -#define CONTEXT_MER_OFFSET 5006 -#define CONTEXT_IR_STATE 7000 -#define CONTEXT_TSOUT_MSB_FIRST 7004 -#define CONTEXT_TSOUT_FALLING_EDGE 7005 +#define CONTEXT_LNA 1010 +#define CONTEXT_ELNA_HYSTERESIS 4003 +#define CONTEXT_ELNA_GAIN 4004 +#define CONTEXT_MER_THRESHOLD 5005 +#define CONTEXT_MER_OFFSET 5006 +#define CONTEXT_IR_STATE 7000 +#define CONTEXT_TSOUT_MSB_FIRST 7004 +#define CONTEXT_TSOUT_FALLING_EDGE 7005 /* Configuration modes */ -#define CFG_MODE_ON 0 -#define CFG_MODE_OFF 1 -#define CFG_MODE_AUTO 2 +#define CFG_MODE_ON 0 +#define CFG_MODE_OFF 1 +#define CFG_MODE_AUTO 2 -#pragma pack(1) struct as10x_tps { - uint8_t constellation; - uint8_t hierarchy; - uint8_t interleaving_mode; - uint8_t code_rate_HP; - uint8_t code_rate_LP; - uint8_t guard_interval; - uint8_t transmission_mode; - uint8_t DVBH_mask_HP; - uint8_t DVBH_mask_LP; - uint16_t cell_ID; -}; + uint8_t modulation; + uint8_t hierarchy; + uint8_t interleaving_mode; + uint8_t code_rate_HP; + uint8_t code_rate_LP; + uint8_t guard_interval; + uint8_t transmission_mode; + uint8_t DVBH_mask_HP; + uint8_t DVBH_mask_LP; + uint16_t cell_ID; +} __packed; struct as10x_tune_args { - /* frequency */ - uint32_t freq; - /* bandwidth */ - uint8_t bandwidth; - /* hierarchy selection */ - uint8_t hier_select; - /* constellation */ - uint8_t constellation; - /* hierarchy */ - uint8_t hierarchy; - /* interleaving mode */ - uint8_t interleaving_mode; - /* code rate */ - uint8_t code_rate; - /* guard interval */ - uint8_t guard_interval; - /* transmission mode */ - uint8_t transmission_mode; -}; + /* frequency */ + uint32_t freq; + /* bandwidth */ + uint8_t bandwidth; + /* hierarchy selection */ + uint8_t hier_select; + /* constellation */ + uint8_t modulation; + /* hierarchy */ + uint8_t hierarchy; + /* interleaving mode */ + uint8_t interleaving_mode; + /* code rate */ + uint8_t code_rate; + /* guard interval */ + uint8_t guard_interval; + /* transmission mode */ + uint8_t transmission_mode; +} __packed; struct as10x_tune_status { - /* tune status */ - uint8_t tune_state; - /* signal strength */ - int16_t signal_strength; - /* packet error rate 10^-4 */ - uint16_t PER; - /* bit error rate 10^-4 */ - uint16_t BER; -}; + /* tune status */ + uint8_t tune_state; + /* signal strength */ + int16_t signal_strength; + /* packet error rate 10^-4 */ + uint16_t PER; + /* bit error rate 10^-4 */ + uint16_t BER; +} __packed; struct as10x_demod_stats { - /* frame counter */ - uint32_t frame_count; - /* Bad frame counter */ - uint32_t bad_frame_count; - /* Number of wrong bytes fixed by Reed-Solomon */ - uint32_t bytes_fixed_by_rs; - /* Averaged MER */ - uint16_t mer; - /* statistics calculation state indicator (started or not) */ - uint8_t has_started; -}; + /* frame counter */ + uint32_t frame_count; + /* Bad frame counter */ + uint32_t bad_frame_count; + /* Number of wrong bytes fixed by Reed-Solomon */ + uint32_t bytes_fixed_by_rs; + /* Averaged MER */ + uint16_t mer; + /* statistics calculation state indicator (started or not) */ + uint8_t has_started; +} __packed; struct as10x_ts_filter { - uint16_t pid; /** valid PID value 0x00 : 0x2000 */ - uint8_t type; /** Red TS_PID_TYPE_<N> values */ - uint8_t idx; /** index in filtering table */ -}; + uint16_t pid; /* valid PID value 0x00 : 0x2000 */ + uint8_t type; /* Red TS_PID_TYPE_<N> values */ + uint8_t idx; /* index in filtering table */ +} __packed; struct as10x_register_value { - uint8_t mode; - union { - uint8_t value8; /* 8 bit value */ - uint16_t value16; /* 16 bit value */ - uint32_t value32; /* 32 bit value */ - }u; -}; - -#pragma pack() + uint8_t mode; + union { + uint8_t value8; /* 8 bit value */ + uint16_t value16; /* 16 bit value */ + uint32_t value32; /* 32 bit value */ + } u; +} __packed; struct as10x_register_addr { - /* register addr */ - uint32_t addr; - /* register mode access */ - uint8_t mode; + /* register addr */ + uint32_t addr; + /* register mode access */ + uint8_t mode; }; - #endif diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index 04e93c49f03a..280c84ec4cc2 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -218,9 +218,10 @@ dt3155_start_acq(struct dt3155_priv *pd) * driver-specific callbacks (vb2_ops) */ static int -dt3155_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], - void *alloc_ctxs[]) +dt3155_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) + { struct dt3155_priv *pd = vb2_get_drv_priv(q); void *ret; @@ -262,12 +263,6 @@ dt3155_buf_prepare(struct vb2_buffer *vb) } static int -dt3155_start_streaming(struct vb2_queue *q) -{ - return 0; -} - -static int dt3155_stop_streaming(struct vb2_queue *q) { struct dt3155_priv *pd = vb2_get_drv_priv(q); @@ -308,7 +303,6 @@ const struct vb2_ops q_ops = { .wait_prepare = dt3155_wait_prepare, .wait_finish = dt3155_wait_finish, .buf_prepare = dt3155_buf_prepare, - .start_streaming = dt3155_start_streaming, .stop_streaming = dt3155_stop_streaming, .buf_queue = dt3155_buf_queue, }; @@ -914,9 +908,10 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_req_region; pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0)); - if (!pd->regs) + if (!pd->regs) { err = -ENOMEM; goto err_pci_iomap; + } err = dt3155_init_board(pdev); if (err) goto err_init_board; diff --git a/drivers/staging/media/easycap/easycap.h b/drivers/staging/media/easycap/easycap.h index 7b256a948c27..a007e7442be8 100644 --- a/drivers/staging/media/easycap/easycap.h +++ b/drivers/staging/media/easycap/easycap.h @@ -98,7 +98,6 @@ #define EASYCAP_DRIVER_VERSION "0.9.01" #define EASYCAP_DRIVER_DESCRIPTION "easycapdc60" -#define USB_SKEL_MINOR_BASE 192 #define DONGLE_MANY 8 #define INPUT_MANY 6 /*---------------------------------------------------------------------------*/ @@ -324,8 +323,6 @@ struct easycap { int lost[INPUT_MANY]; int merit[180]; - long long int dnbydt; - int video_interface; int video_altsetting_on; int video_altsetting_off; @@ -353,7 +350,6 @@ struct easycap { u8 *pcache; int video_mt; int audio_mt; - long long audio_bytes; u32 isequence; int vma_many; @@ -450,9 +446,6 @@ struct easycap { * SOUND PROPERTIES */ /*---------------------------------------------------------------------------*/ - - int audio_buffer_many; - int allocation_audio_urb; int allocation_audio_page; int allocation_audio_struct; @@ -469,72 +462,53 @@ struct easycap { * VIDEO FUNCTION PROTOTYPES */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +int easycap_newinput(struct easycap *, int); +void easycap_testcard(struct easycap *, int); +int easycap_isdongle(struct easycap *); + long easycap_unlocked_ioctl(struct file *, unsigned int, unsigned long); -int easycap_dqbuf(struct easycap *, int); -int submit_video_urbs(struct easycap *); -int kill_video_urbs(struct easycap *); -int field2frame(struct easycap *); -int redaub(struct easycap *, void *, void *, - int, int, u8, u8, bool); -void easycap_testcard(struct easycap *, int); -int fillin_formats(void); -int newinput(struct easycap *, int); -int adjust_standard(struct easycap *, v4l2_std_id); -int adjust_format(struct easycap *, u32, u32, u32, - int, bool); -int adjust_brightness(struct easycap *, int); -int adjust_contrast(struct easycap *, int); -int adjust_saturation(struct easycap *, int); -int adjust_hue(struct easycap *, int); -int adjust_volume(struct easycap *, int); + +int easycap_video_dqbuf(struct easycap *, int); +int easycap_video_submit_urbs(struct easycap *); +int easycap_video_kill_urbs(struct easycap *); +int easycap_video_fillin_formats(void); + +int adjust_standard(struct easycap *, v4l2_std_id); +int adjust_format(struct easycap *, u32, u32, u32, int, bool); +int adjust_brightness(struct easycap *, int); +int adjust_contrast(struct easycap *, int); +int adjust_saturation(struct easycap *, int); +int adjust_hue(struct easycap *, int); /*---------------------------------------------------------------------------*/ /* * AUDIO FUNCTION PROTOTYPES */ /*---------------------------------------------------------------------------*/ -int easycap_alsa_probe(struct easycap *); -void easycap_alsa_complete(struct urb *); - -int easycap_sound_setup(struct easycap *); -int submit_audio_urbs(struct easycap *); -int kill_audio_urbs(struct easycap *); -void easyoss_testtone(struct easycap *, int); -int audio_setup(struct easycap *); +int easycap_alsa_probe(struct easycap *); +int easycap_audio_kill_urbs(struct easycap *); +void easycap_alsa_complete(struct urb *); /*---------------------------------------------------------------------------*/ /* * LOW-LEVEL FUNCTION PROTOTYPES */ /*---------------------------------------------------------------------------*/ -int audio_gainget(struct usb_device *); -int audio_gainset(struct usb_device *, s8); +int easycap_audio_gainset(struct usb_device *, s8); +int easycap_audio_setup(struct easycap *); -int set_interface(struct usb_device *, u16); -int wakeup_device(struct usb_device *); -int confirm_resolution(struct usb_device *); -int confirm_stream(struct usb_device *); +int easycap_wakeup_device(struct usb_device *); -int setup_stk(struct usb_device *, bool); -int setup_saa(struct usb_device *, bool); -int setup_vt(struct usb_device *); -int check_stk(struct usb_device *, bool); -int check_saa(struct usb_device *, bool); -int ready_saa(struct usb_device *); -int merit_saa(struct usb_device *); -int check_vt(struct usb_device *); -int select_input(struct usb_device *, int, int); -int set_resolution(struct usb_device *, - u16, u16, u16, u16); +int setup_stk(struct usb_device *, bool); +int setup_saa(struct usb_device *, bool); +int ready_saa(struct usb_device *); +int merit_saa(struct usb_device *); +int check_vt(struct usb_device *); +int select_input(struct usb_device *, int, int); +int set_resolution(struct usb_device *, u16, u16, u16, u16); -int read_saa(struct usb_device *, u16); -int read_stk(struct usb_device *, u32); -int write_saa(struct usb_device *, u16, u16); -int write_000(struct usb_device *, u16, u16); -int start_100(struct usb_device *); -int stop_100(struct usb_device *); -int write_300(struct usb_device *); -int read_vt(struct usb_device *, u16); -int write_vt(struct usb_device *, u16, u16); -int isdongle(struct easycap *); +int read_saa(struct usb_device *, u16); +int write_saa(struct usb_device *, u16, u16); +int start_100(struct usb_device *); +int stop_100(struct usb_device *); /*---------------------------------------------------------------------------*/ @@ -588,7 +562,6 @@ extern bool easycap_readback; extern const struct easycap_standard easycap_standard[]; extern struct easycap_format easycap_format[]; extern struct v4l2_queryctrl easycap_control[]; -extern struct usb_driver easycap_usb_driver; extern struct easycap_dongle easycapdc60_dongle[]; #endif /* !__EASYCAP_H__ */ diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c index c99addfb6242..9413b37490c2 100644 --- a/drivers/staging/media/easycap/easycap_ioctl.c +++ b/drivers/staging/media/easycap/easycap_ioctl.c @@ -25,7 +25,6 @@ */ /*****************************************************************************/ -#include <linux/version.h> #include "easycap.h" /*--------------------------------------------------------------------------*/ @@ -125,7 +124,7 @@ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) } if (peasycap->video_isoc_streaming) { resubmit = true; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); } else resubmit = false; /*--------------------------------------------------------------------------*/ @@ -331,7 +330,7 @@ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } if (resubmit) - submit_video_urbs(peasycap); + easycap_video_submit_urbs(peasycap); return 0; } /*****************************************************************************/ @@ -558,7 +557,7 @@ int adjust_format(struct easycap *peasycap, peasycap->bytesperpixel * peasycap->width * peasycap->height; if (peasycap->video_isoc_streaming) { resubmit = true; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); } else resubmit = false; /*---------------------------------------------------------------------------*/ @@ -622,7 +621,7 @@ int adjust_format(struct easycap *peasycap, } /*---------------------------------------------------------------------------*/ if (resubmit) - submit_video_urbs(peasycap); + easycap_video_submit_urbs(peasycap); return peasycap_best_format - easycap_format; } @@ -667,16 +666,15 @@ int adjust_brightness(struct easycap *peasycap, int value) peasycap->inputset[peasycap->input].brightness_ok = 1; } else JOM(8, "%i=peasycap->input\n", peasycap->input); + mood = 0x00FF & (unsigned int)peasycap->brightness; - if (!write_saa(peasycap->pusb_device, 0x0A, mood)) { - SAM("adjusting brightness to 0x%02X\n", mood); - return 0; - } else { + if (write_saa(peasycap->pusb_device, 0x0A, mood)) { SAM("WARNING: failed to adjust brightness " "to 0x%02X\n", mood); return -ENOENT; } - break; + SAM("adjusting brightness to 0x%02X\n", mood); + return 0; } i1++; } @@ -726,15 +724,13 @@ int adjust_contrast(struct easycap *peasycap, int value) JOM(8, "%i=peasycap->input\n", peasycap->input); mood = 0x00FF & (unsigned int) (peasycap->contrast - 128); - if (!write_saa(peasycap->pusb_device, 0x0B, mood)) { - SAM("adjusting contrast to 0x%02X\n", mood); - return 0; - } else { + if (write_saa(peasycap->pusb_device, 0x0B, mood)) { SAM("WARNING: failed to adjust contrast to " "0x%02X\n", mood); return -ENOENT; } - break; + SAM("adjusting contrast to 0x%02X\n", mood); + return 0; } i1++; } @@ -784,14 +780,13 @@ int adjust_saturation(struct easycap *peasycap, int value) } else JOM(8, "%i=peasycap->input\n", peasycap->input); mood = 0x00FF & (unsigned int) (peasycap->saturation - 128); - if (!write_saa(peasycap->pusb_device, 0x0C, mood)) { - SAM("adjusting saturation to 0x%02X\n", mood); - return 0; - } else { + if (write_saa(peasycap->pusb_device, 0x0C, mood)) { SAM("WARNING: failed to adjust saturation to " "0x%02X\n", mood); return -ENOENT; } + SAM("adjusting saturation to 0x%02X\n", mood); + return 0; break; } i1++; @@ -839,13 +834,12 @@ int adjust_hue(struct easycap *peasycap, int value) JOM(8, "%i=peasycap->input\n", peasycap->input); i2 = peasycap->hue - 128; mood = 0x00FF & ((int) i2); - if (!write_saa(peasycap->pusb_device, 0x0D, mood)) { - SAM("adjusting hue to 0x%02X\n", mood); - return 0; - } else { + if (write_saa(peasycap->pusb_device, 0x0D, mood)) { SAM("WARNING: failed to adjust hue to 0x%02X\n", mood); return -ENOENT; } + SAM("adjusting hue to 0x%02X\n", mood); + return 0; break; } i1++; @@ -854,7 +848,7 @@ int adjust_hue(struct easycap *peasycap, int value) return -ENOENT; } /*****************************************************************************/ -int adjust_volume(struct easycap *peasycap, int value) +static int adjust_volume(struct easycap *peasycap, int value) { s8 mood; int i1; @@ -885,15 +879,13 @@ int adjust_volume(struct easycap *peasycap, int value) mood = (16 > peasycap->volume) ? 16 : ((31 < peasycap->volume) ? 31 : (s8) peasycap->volume); - if (!audio_gainset(peasycap->pusb_device, mood)) { - SAM("adjusting volume to 0x%02X\n", mood); - return 0; - } else { + if (!easycap_audio_gainset(peasycap->pusb_device, mood)) { SAM("WARNING: failed to adjust volume to " "0x%2X\n", mood); return -ENOENT; } - break; + SAM("adjusting volume to 0x%02X\n", mood); + return 0; } i1++; } @@ -971,7 +963,7 @@ long easycap_unlocked_ioctl(struct file *file, SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } - kd = isdongle(peasycap); + kd = easycap_isdongle(peasycap); if (0 <= kd && DONGLE_MANY > kd) { if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) { SAY("ERROR: cannot lock " @@ -986,7 +978,7 @@ long easycap_unlocked_ioctl(struct file *file, * IF NECESSARY, BAIL OUT. */ /*---------------------------------------------------------------------------*/ - if (kd != isdongle(peasycap)) + if (kd != easycap_isdongle(peasycap)) return -ERESTARTSYS; if (!file) { SAY("ERROR: file is NULL\n"); @@ -1226,7 +1218,7 @@ long easycap_unlocked_ioctl(struct file *file, return -EINVAL; } - rc = newinput(peasycap, (int)index); + rc = easycap_newinput(peasycap, (int)index); if (0 == rc) { JOM(8, "newinput(.,%i) OK\n", (int)index); } else { @@ -2209,7 +2201,7 @@ long easycap_unlocked_ioctl(struct file *file, if (!peasycap->polled) { do { - rcdq = easycap_dqbuf(peasycap, 0); + rcdq = easycap_video_dqbuf(peasycap, 0); if (-EIO == rcdq) { JOM(8, "returning -EIO because " "dqbuf() returned -EIO\n"); @@ -2313,7 +2305,7 @@ long easycap_unlocked_ioctl(struct file *file, mutex_unlock(&easycapdc60_dongle[kd].mutex_video); return -EFAULT; } - submit_video_urbs(peasycap); + easycap_video_submit_urbs(peasycap); peasycap->video_idle = 0; peasycap->audio_idle = 0; peasycap->video_eof = 0; diff --git a/drivers/staging/media/easycap/easycap_low.c b/drivers/staging/media/easycap/easycap_low.c index 0385735ac6df..0380babed22c 100644 --- a/drivers/staging/media/easycap/easycap_low.c +++ b/drivers/staging/media/easycap/easycap_low.c @@ -40,6 +40,7 @@ #include "easycap.h" + #define GET(X, Y, Z) do { \ int __rc; \ *(Z) = (u16)0; \ @@ -59,9 +60,9 @@ /*--------------------------------------------------------------------------*/ static const struct stk1160config { - int reg; - int set; -} stk1160configPAL[256] = { + u16 reg; + u16 set; +} stk1160configPAL[] = { {0x000, 0x0098}, {0x002, 0x0093}, @@ -103,7 +104,7 @@ static const struct stk1160config { {0xFFF, 0xFFFF} }; /*--------------------------------------------------------------------------*/ -static const struct stk1160config stk1160configNTSC[256] = { +static const struct stk1160config stk1160configNTSC[] = { {0x000, 0x0098}, {0x002, 0x0093}, @@ -146,9 +147,9 @@ static const struct stk1160config stk1160configNTSC[256] = { }; /*--------------------------------------------------------------------------*/ static const struct saa7113config { - int reg; - int set; -} saa7113configPAL[256] = { + u8 reg; + u8 set; +} saa7113configPAL[] = { {0x01, 0x08}, {0x02, 0x80}, {0x03, 0x33}, @@ -202,7 +203,7 @@ static const struct saa7113config { {0xFF, 0xFF} }; /*--------------------------------------------------------------------------*/ -static const struct saa7113config saa7113configNTSC[256] = { +static const struct saa7113config saa7113configNTSC[] = { {0x01, 0x08}, {0x02, 0x80}, {0x03, 0x33}, @@ -355,101 +356,6 @@ static int wait_i2c(struct usb_device *p) } /****************************************************************************/ -int confirm_resolution(struct usb_device *p) -{ - u8 get0, get1, get2, get3, get4, get5, get6, get7; - - if (!p) - return -ENODEV; - GET(p, 0x0110, &get0); - GET(p, 0x0111, &get1); - GET(p, 0x0112, &get2); - GET(p, 0x0113, &get3); - GET(p, 0x0114, &get4); - GET(p, 0x0115, &get5); - GET(p, 0x0116, &get6); - GET(p, 0x0117, &get7); - JOT(8, "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X\n", - get0, get1, get2, get3, get4, get5, get6, get7); - JOT(8, "....cf PAL_720x526: " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X\n", - 0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001); - JOT(8, "....cf PAL_704x526: " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X\n", - 0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001); - JOT(8, "....cf VGA_640x480: " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X\n", - 0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001); - return 0; -} -/****************************************************************************/ -int confirm_stream(struct usb_device *p) -{ - u16 get2; - u8 igot; - - if (!p) - return -ENODEV; - GET(p, 0x0100, &igot); get2 = 0x80 & igot; - if (0x80 == get2) - JOT(8, "confirm_stream: OK\n"); - else - JOT(8, "confirm_stream: STUCK\n"); - return 0; -} -/****************************************************************************/ -int setup_stk(struct usb_device *p, bool ntsc) -{ - int i; - const struct stk1160config *cfg; - if (!p) - return -ENODEV; - cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL; - for (i = 0; cfg[i].reg != 0xFFF; i++) - SET(p, cfg[i].reg, cfg[i].set); - - write_300(p); - - return 0; -} -/****************************************************************************/ -int setup_saa(struct usb_device *p, bool ntsc) -{ - int i, ir; - const struct saa7113config *cfg; - if (!p) - return -ENODEV; - cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL; - for (i = 0; cfg[i].reg != 0xFF; i++) - ir = write_saa(p, cfg[i].reg, cfg[i].set); - return 0; -} -/****************************************************************************/ -int write_000(struct usb_device *p, u16 set2, u16 set0) -{ - u8 igot0, igot2; - - if (!p) - return -ENODEV; - GET(p, 0x0002, &igot2); - GET(p, 0x0000, &igot0); - SET(p, 0x0002, set2); - SET(p, 0x0000, set0); - return 0; -} -/****************************************************************************/ int write_saa(struct usb_device *p, u16 reg0, u16 set0) { if (!p) @@ -470,8 +376,7 @@ int write_saa(struct usb_device *p, u16 reg0, u16 set0) * REGISTER 504: TARGET ADDRESS ON VT1612A */ /*--------------------------------------------------------------------------*/ -int -write_vt(struct usb_device *p, u16 reg0, u16 set0) +static int write_vt(struct usb_device *p, u16 reg0, u16 set0) { u8 igot; u16 got502, got503; @@ -508,7 +413,7 @@ write_vt(struct usb_device *p, u16 reg0, u16 set0) * REGISTER 504: TARGET ADDRESS ON VT1612A */ /*--------------------------------------------------------------------------*/ -int read_vt(struct usb_device *p, u16 reg0) +static int read_vt(struct usb_device *p, u16 reg0) { u8 igot; u16 got502, got503; @@ -532,7 +437,7 @@ int read_vt(struct usb_device *p, u16 reg0) * THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO. */ /*--------------------------------------------------------------------------*/ -int write_300(struct usb_device *p) +static int write_300(struct usb_device *p) { if (!p) return -ENODEV; @@ -545,32 +450,36 @@ int write_300(struct usb_device *p) return 0; } /****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * NOTE: THE FOLLOWING IS NOT CHECKED: - * REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL. - */ -/*--------------------------------------------------------------------------*/ -int check_saa(struct usb_device *p, bool ntsc) +/****************************************************************************/ +int setup_stk(struct usb_device *p, bool ntsc) { - int i, ir, rc = 0; - struct saa7113config const *cfg; + int i; + const struct stk1160config *cfg; if (!p) return -ENODEV; + cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL; + for (i = 0; cfg[i].reg != 0xFFF; i++) + SET(p, cfg[i].reg, cfg[i].set); + + write_300(p); - cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL; + return 0; +} +/****************************************************************************/ +int setup_saa(struct usb_device *p, bool ntsc) +{ + int i, rc; + const struct saa7113config *cfg; + if (!p) + return -ENODEV; + cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL; for (i = 0; cfg[i].reg != 0xFF; i++) { - if (0x0F == cfg[i].reg) - continue; - ir = read_saa(p, cfg[i].reg); - if (ir != cfg[i].set) { - SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", - cfg[i].reg, ir, cfg[i].set); - rc--; - } + rc = write_saa(p, cfg[i].reg, cfg[i].set); + if (rc) + dev_err(&p->dev, + "Failed to set SAA register %d", cfg[i].reg); } - - return (rc < -8) ? rc : 0; + return 0; } /****************************************************************************/ int merit_saa(struct usb_device *p) @@ -609,60 +518,22 @@ int ready_saa(struct usb_device *p) msleep(marktime); j++; } + if (max == j) return -1; - else { - if (0x20 & rc) { - rate = 2; - JOT(8, "hardware detects 60 Hz\n"); - } else { - rate = 0; - JOT(8, "hardware detects 50 Hz\n"); - } - if (0x80 & rc) - JOT(8, "hardware detects interlacing\n"); - else { - rate++; - JOT(8, "hardware detects no interlacing\n"); - } - } - return 0; -} -/****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * NOTE: THE FOLLOWING ARE NOT CHECKED: - * REGISTERS 0x000, 0x002: FUNCTIONALITY IS NOT KNOWN - * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config....[.].set) - */ -/*--------------------------------------------------------------------------*/ -int check_stk(struct usb_device *p, bool ntsc) -{ - int i, ir; - const struct stk1160config *cfg; - - if (!p) - return -ENODEV; - cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL; - - for (i = 0; 0xFFF != cfg[i].reg; i++) { - if (0x000 == cfg[i].reg || 0x002 == cfg[i].reg) - continue; - - ir = read_stk(p, cfg[i].reg); - if (0x100 == cfg[i].reg) { - if ((ir != (0xFF & cfg[i].set)) && - (ir != (0x80 | (0xFF & cfg[i].set))) && - (0xFFFF != cfg[i].set)) { - SAY("STK reg[0x%03X]=0x%02X expected 0x%02X\n", - cfg[i].reg, ir, cfg[i].set); - } - continue; - } - if ((ir != (0xFF & cfg[i].set)) && (0xFFFF != cfg[i].set)) - SAY("STK register 0x%03X has 0x%02X,expected 0x%02X\n", - cfg[i].reg, ir, cfg[i].set); + if (0x20 & rc) { + rate = 2; + JOT(8, "hardware detects 60 Hz\n"); + } else { + rate = 0; + JOT(8, "hardware detects 50 Hz\n"); + } + if (0x80 & rc) + JOT(8, "hardware detects interlacing\n"); + else { + rate++; + JOT(8, "hardware detects no interlacing\n"); } return 0; } @@ -682,7 +553,7 @@ int read_saa(struct usb_device *p, u16 reg0) return igot; } /****************************************************************************/ -int read_stk(struct usb_device *p, u32 reg0) +static int read_stk(struct usb_device *p, u32 reg0) { u8 igot; @@ -692,27 +563,7 @@ int read_stk(struct usb_device *p, u32 reg0) GET(p, reg0, &igot); return igot; } -/****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * HARDWARE USERSPACE INPUT NUMBER PHYSICAL INPUT DRIVER input VALUE - * - * CVBS+S-VIDEO 0 or 1 CVBS 1 - * FOUR-CVBS 0 or 1 CVBS1 1 - * FOUR-CVBS 2 CVBS2 2 - * FOUR-CVBS 3 CVBS3 3 - * FOUR-CVBS 4 CVBS4 4 - * CVBS+S-VIDEO 5 S-VIDEO 5 - * - * WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED: - * - * mode 7 => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED) - * mode 9 => USE AUTOMATIC GAIN CONTROL (DEFAULT) - * -*/ -/*---------------------------------------------------------------------------*/ -int -select_input(struct usb_device *p, int input, int mode) +int select_input(struct usb_device *p, int input, int mode) { int ir; @@ -877,10 +728,11 @@ int stop_100(struct usb_device *p) /****************************************************************************/ /****************************************************************************/ /*****************************************************************************/ -int wakeup_device(struct usb_device *pusb_device) +int easycap_wakeup_device(struct usb_device *pusb_device) { if (!pusb_device) return -ENODEV; + return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), USB_REQ_SET_FEATURE, USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, @@ -888,8 +740,7 @@ int wakeup_device(struct usb_device *pusb_device) 0, NULL, 0, 50000); } /*****************************************************************************/ -int -audio_setup(struct easycap *peasycap) +int easycap_audio_setup(struct easycap *peasycap) { struct usb_device *pusb_device; u8 buffer[1]; @@ -970,7 +821,7 @@ audio_setup(struct easycap *peasycap) * SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN. */ /*---------------------------------------------------------------------------*/ - if (0 != audio_gainset(pusb_device, peasycap->gain)) + if (easycap_audio_gainset(pusb_device, peasycap->gain)) SAY("ERROR: audio_gainset() failed\n"); check_vt(pusb_device); return 0; @@ -1047,7 +898,7 @@ int check_vt(struct usb_device *pusb_device) * 31 12.0 22.5 34.5 */ /*---------------------------------------------------------------------------*/ -int audio_gainset(struct usb_device *pusb_device, s8 loud) +int easycap_audio_gainset(struct usb_device *pusb_device, s8 loud) { int igot; u8 tmp; @@ -1115,15 +966,3 @@ int audio_gainset(struct usb_device *pusb_device, s8 loud) return 0; } /*****************************************************************************/ -int audio_gainget(struct usb_device *pusb_device) -{ - int igot; - - if (!pusb_device) - return -ENODEV; - igot = read_vt(pusb_device, 0x001C); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x1C\n"); - return igot; -} -/*****************************************************************************/ diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c index a45c0b507067..8ff5f38ea196 100644 --- a/drivers/staging/media/easycap/easycap_main.c +++ b/drivers/staging/media/easycap/easycap_main.c @@ -66,6 +66,10 @@ struct easycap_dongle easycapdc60_dongle[DONGLE_MANY]; static struct mutex mutex_dongle; static void easycap_complete(struct urb *purb); static int reset(struct easycap *peasycap); +static int field2frame(struct easycap *peasycap); +static int redaub(struct easycap *peasycap, + void *pad, void *pex, int much, int more, + u8 mask, u8 margin, bool isuy); const char *strerror(int err) { @@ -109,23 +113,13 @@ const char *strerror(int err) #undef ERRNOSTR } -/*---------------------------------------------------------------------------*/ -/* - * PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE - * - * NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY - * CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253. - * THIS IS THE CASE FOR OpenSUSE. - */ -/*---------------------------------------------------------------------------*/ -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /****************************************************************************/ /*---------------------------------------------------------------------------*/ /* * THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap */ /*---------------------------------------------------------------------------*/ -int isdongle(struct easycap *peasycap) +int easycap_isdongle(struct easycap *peasycap) { int k; if (!peasycap) @@ -161,14 +155,13 @@ static int easycap_open(struct inode *inode, struct file *file) if (!peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; - } else { - JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device); } + + JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device); + file->private_data = peasycap; - rc = wakeup_device(peasycap->pusb_device); - if (0 == rc) - JOM(8, "wakeup_device() OK\n"); - else { + rc = easycap_wakeup_device(peasycap->pusb_device); + if (rc) { SAM("ERROR: wakeup_device() rc = %i\n", rc); if (-ENODEV == rc) SAM("ERROR: wakeup_device() returned -ENODEV\n"); @@ -176,6 +169,7 @@ static int easycap_open(struct inode *inode, struct file *file) SAM("ERROR: wakeup_device() rc = %i\n", rc); return rc; } + JOM(8, "wakeup_device() OK\n"); peasycap->input = 0; rc = reset(peasycap); if (rc) { @@ -303,7 +297,7 @@ static int reset(struct easycap *peasycap) peasycap->saturation = -8192; peasycap->hue = -8192; - rc = newinput(peasycap, input); + rc = easycap_newinput(peasycap, input); if (rc) { SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input); @@ -364,8 +358,7 @@ static int reset(struct easycap *peasycap) * SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE. */ /*---------------------------------------------------------------------------*/ -int -newinput(struct easycap *peasycap, int input) +int easycap_newinput(struct easycap *peasycap, int input) { int rc, k, m, mood, off; int inputnow, video_idlenow, audio_idlenow; @@ -397,7 +390,7 @@ newinput(struct easycap *peasycap, int input) peasycap->audio_idle = 1; if (peasycap->video_isoc_streaming) { resubmit = true; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); } else { resubmit = false; } @@ -532,7 +525,7 @@ newinput(struct easycap *peasycap, int input) return -EFAULT; } if (resubmit) - submit_video_urbs(peasycap); + easycap_video_submit_urbs(peasycap); peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1; peasycap->video_idle = video_idlenow; @@ -542,7 +535,7 @@ newinput(struct easycap *peasycap, int input) return 0; } /*****************************************************************************/ -int submit_video_urbs(struct easycap *peasycap) +int easycap_video_submit_urbs(struct easycap *peasycap) { struct data_urb *pdata_urb; struct urb *purb; @@ -616,43 +609,53 @@ int submit_video_urbs(struct easycap *peasycap) peasycap->video_eof = 1; } - if (isbad) { - JOM(4, "attempting cleanup instead of submitting\n"); - list_for_each(plist_head, (peasycap->purb_video_head)) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb) { - purb = pdata_urb->purb; - if (purb) - usb_kill_urb(purb); - } - } - peasycap->video_isoc_streaming = 0; - } else { + if (isbad) + easycap_video_kill_urbs(peasycap); + else peasycap->video_isoc_streaming = 1; - JOM(4, "submitted %i video urbs\n", m); - } } else { JOM(4, "already streaming video urbs\n"); } return 0; } /*****************************************************************************/ -int kill_video_urbs(struct easycap *peasycap) +int easycap_audio_kill_urbs(struct easycap *peasycap) { int m; struct list_head *plist_head; struct data_urb *pdata_urb; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); + if (!peasycap->audio_isoc_streaming) + return 0; + + if (!peasycap->purb_audio_head) { + SAM("ERROR: peasycap->purb_audio_head is NULL\n"); return -EFAULT; } - if (!peasycap->video_isoc_streaming) { - JOM(8, "%i=video_isoc_streaming, no video urbs killed\n", - peasycap->video_isoc_streaming); - return 0; + + peasycap->audio_isoc_streaming = 0; + m = 0; + list_for_each(plist_head, peasycap->purb_audio_head) { + pdata_urb = list_entry(plist_head, struct data_urb, list_head); + if (pdata_urb && pdata_urb->purb) { + usb_kill_urb(pdata_urb->purb); + m++; + } } + + JOM(4, "%i audio urbs killed\n", m); + + return 0; +} +int easycap_video_kill_urbs(struct easycap *peasycap) +{ + int m; + struct list_head *plist_head; + struct data_urb *pdata_urb; + + if (!peasycap->video_isoc_streaming) + return 0; + if (!peasycap->purb_video_head) { SAM("ERROR: peasycap->purb_video_head is NULL\n"); return -EFAULT; @@ -690,8 +693,8 @@ static int videodev_release(struct video_device *pvideo_device) SAY("ending unsuccessfully\n"); return -EFAULT; } - if (0 != kill_video_urbs(peasycap)) { - SAM("ERROR: kill_video_urbs() failed\n"); + if (easycap_video_kill_urbs(peasycap)) { + SAM("ERROR: easycap_video_kill_urbs() failed\n"); return -EFAULT; } JOM(4, "ending successfully\n"); @@ -727,27 +730,22 @@ static void easycap_delete(struct kref *pkref) SAM("ERROR: peasycap is NULL: cannot perform deletions\n"); return; } - kd = isdongle(peasycap); + kd = easycap_isdongle(peasycap); /*---------------------------------------------------------------------------*/ /* * FREE VIDEO. */ /*---------------------------------------------------------------------------*/ if (peasycap->purb_video_head) { - JOM(4, "freeing video urbs\n"); m = 0; - list_for_each(plist_head, (peasycap->purb_video_head)) { + list_for_each(plist_head, peasycap->purb_video_head) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (!pdata_urb) { - JOM(4, "ERROR: pdata_urb is NULL\n"); - } else { - if (pdata_urb->purb) { - usb_free_urb(pdata_urb->purb); - pdata_urb->purb = NULL; - peasycap->allocation_video_urb -= 1; - m++; - } + if (pdata_urb && pdata_urb->purb) { + usb_free_urb(pdata_urb->purb); + pdata_urb->purb = NULL; + peasycap->allocation_video_urb--; + m++; } } @@ -763,7 +761,6 @@ static void easycap_delete(struct kref *pkref) peasycap->allocation_video_struct -= sizeof(struct data_urb); kfree(pdata_urb); - pdata_urb = NULL; m++; } } @@ -828,15 +825,11 @@ static void easycap_delete(struct kref *pkref) list_for_each(plist_head, (peasycap->purb_audio_head)) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (!pdata_urb) - JOM(4, "ERROR: pdata_urb is NULL\n"); - else { - if (pdata_urb->purb) { - usb_free_urb(pdata_urb->purb); - pdata_urb->purb = NULL; - peasycap->allocation_audio_urb -= 1; - m++; - } + if (pdata_urb && pdata_urb->purb) { + usb_free_urb(pdata_urb->purb); + pdata_urb->purb = NULL; + peasycap->allocation_audio_urb--; + m++; } } JOM(4, "%i audio urbs freed\n", m); @@ -851,7 +844,6 @@ static void easycap_delete(struct kref *pkref) peasycap->allocation_audio_struct -= sizeof(struct data_urb); kfree(pdata_urb); - pdata_urb = NULL; m++; } } @@ -940,7 +932,7 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait) return -EFAULT; } /*---------------------------------------------------------------------------*/ - kd = isdongle(peasycap); + kd = easycap_isdongle(peasycap); if (0 <= kd && DONGLE_MANY > kd) { if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) { SAY("ERROR: cannot down dongle[%i].mutex_video\n", kd); @@ -952,7 +944,7 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait) * peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. * IF NECESSARY, BAIL OUT. */ - if (kd != isdongle(peasycap)) { + if (kd != easycap_isdongle(peasycap)) { mutex_unlock(&easycapdc60_dongle[kd].mutex_video); return -ERESTARTSYS; } @@ -980,21 +972,21 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait) */ return -ERESTARTSYS; /*---------------------------------------------------------------------------*/ - rc = easycap_dqbuf(peasycap, 0); + rc = easycap_video_dqbuf(peasycap, 0); peasycap->polled = 1; mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - if (0 == rc) - return POLLIN | POLLRDNORM; - else + if (rc) return POLLERR; - } + + return POLLIN | POLLRDNORM; +} /*****************************************************************************/ /*---------------------------------------------------------------------------*/ /* * IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING. */ /*---------------------------------------------------------------------------*/ -int easycap_dqbuf(struct easycap *peasycap, int mode) +int easycap_video_dqbuf(struct easycap *peasycap, int mode) { int input, ifield, miss, rc; @@ -1080,7 +1072,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) JOM(8, " ... failed returning -EIO\n"); peasycap->video_eof = 1; peasycap->audio_eof = 1; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); return -EIO; } peasycap->status = 0; @@ -1090,7 +1082,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) #endif /*PERSEVERE*/ peasycap->video_eof = 1; peasycap->audio_eof = 1; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); JOM(8, "returning -EIO\n"); return -EIO; } @@ -1143,7 +1135,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) JOM(8, " ... failed returning -EIO\n"); peasycap->video_eof = 1; peasycap->audio_eof = 1; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); return -EIO; } peasycap->status = 0; @@ -1153,7 +1145,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) #endif /*PERSEVERE*/ peasycap->video_eof = 1; peasycap->audio_eof = 1; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); JOM(8, "returning -EIO\n"); return -EIO; } @@ -1207,12 +1199,9 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) * WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH * odd==false IS TRANSFERRED TO THE FRAME BUFFER. * - * THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM - * CHOOSES THE OPTION V4L2_FIELD_INTERLACED. */ /*---------------------------------------------------------------------------*/ -int -field2frame(struct easycap *peasycap) +static int field2frame(struct easycap *peasycap) { void *pex, *pad; @@ -1221,7 +1210,7 @@ field2frame(struct easycap *peasycap) int rc, bytesperpixel, multiplier; int much, more, over, rump, caches, input; u8 mask, margin; - bool odd, isuy, decimatepixel, offerfields, badinput; + bool odd, isuy, decimatepixel, badinput; if (!peasycap) { SAY("ERROR: peasycap is NULL\n"); @@ -1237,8 +1226,6 @@ field2frame(struct easycap *peasycap) peasycap->field_buffer[peasycap->field_read][0].input, peasycap->field_read, peasycap->frame_fill); JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel); - if (peasycap->offerfields) - JOM(8, "===== offerfields\n"); /*---------------------------------------------------------------------------*/ /* @@ -1260,7 +1247,6 @@ field2frame(struct easycap *peasycap) #endif /*EASYCAP_TESTCARD*/ /*---------------------------------------------------------------------------*/ - offerfields = peasycap->offerfields; bytesperpixel = peasycap->bytesperpixel; decimatepixel = peasycap->decimatepixel; @@ -1601,9 +1587,9 @@ field2frame(struct easycap *peasycap) * REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE. BEWARE. */ /*---------------------------------------------------------------------------*/ -int -redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more, - u8 mask, u8 margin, bool isuy) +static int redaub(struct easycap *peasycap, + void *pad, void *pex, int much, int more, + u8 mask, u8 margin, bool isuy) { static s32 ay[256], bu[256], rv[256], gu[256], gv[256]; u8 *pcache; @@ -2855,20 +2841,7 @@ static void easycap_complete(struct urb *purb) } return; } -static const struct file_operations easycap_fops = { - .owner = THIS_MODULE, - .open = easycap_open, - .unlocked_ioctl = easycap_unlocked_ioctl, - .poll = easycap_poll, - .mmap = easycap_mmap, - .llseek = no_llseek, -}; -static const struct usb_class_driver easycap_class = { - .name = "usb/easycap%d", - .fops = &easycap_fops, - .minor_base = USB_SKEL_MINOR_BASE, -}; -/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ + static const struct v4l2_file_operations v4l2_fops = { .owner = THIS_MODULE, .open = easycap_open_noinode, @@ -2917,6 +2890,7 @@ static int easycap_usb_probe(struct usb_interface *intf, SAY("ERROR: usb_host_interface not found\n"); return -EFAULT; } + interface = &alt->desc; if (!interface) { SAY("ERROR: intf_descriptor is NULL\n"); @@ -2976,44 +2950,31 @@ static int easycap_usb_probe(struct usb_interface *intf, if (mutex_lock_interruptible(&mutex_dongle)) { SAY("ERROR: cannot down mutex_dongle\n"); return -ERESTARTSYS; - } else { -/*---------------------------------------------------------------------------*/ - /* - * FOR INTERFACES 1 AND 2 THE POINTER peasycap WILL NEED TO - * TO BE THE SAME AS THAT ALLOCATED NOW FOR INTERFACE 0. - * - * NORMALLY ndong WILL NOT HAVE CHANGED SINCE INTERFACE 0 WAS - * PROBED, BUT THIS MAY NOT BE THE CASE IF, FOR EXAMPLE, TWO - * EASYCAPs ARE PLUGGED IN SIMULTANEOUSLY. - */ -/*---------------------------------------------------------------------------*/ - for (ndong = 0; ndong < DONGLE_MANY; ndong++) { - if ((!easycapdc60_dongle[ndong].peasycap) && - (!mutex_is_locked(&easycapdc60_dongle - [ndong].mutex_video)) && - (!mutex_is_locked(&easycapdc60_dongle - [ndong].mutex_audio))) { - easycapdc60_dongle[ndong].peasycap = peasycap; - peasycap->isdongle = ndong; - JOM(8, "intf[%i]: peasycap-->easycap" - "_dongle[%i].peasycap\n", - bInterfaceNumber, ndong); - break; - } - } - if (DONGLE_MANY <= ndong) { - SAM("ERROR: too many dongles\n"); - mutex_unlock(&mutex_dongle); - return -ENOMEM; + } + + for (ndong = 0; ndong < DONGLE_MANY; ndong++) { + if ((!easycapdc60_dongle[ndong].peasycap) && + (!mutex_is_locked(&easycapdc60_dongle + [ndong].mutex_video)) && + (!mutex_is_locked(&easycapdc60_dongle + [ndong].mutex_audio))) { + easycapdc60_dongle[ndong].peasycap = peasycap; + peasycap->isdongle = ndong; + JOM(8, "intf[%i]: peasycap-->easycap" + "_dongle[%i].peasycap\n", + bInterfaceNumber, ndong); + break; } + } + + if (DONGLE_MANY <= ndong) { + SAM("ERROR: too many dongles\n"); mutex_unlock(&mutex_dongle); + return -ENOMEM; } + mutex_unlock(&mutex_dongle); + peasycap->allocation_video_struct = sizeof(struct easycap); - peasycap->allocation_video_page = 0; - peasycap->allocation_video_urb = 0; - peasycap->allocation_audio_struct = 0; - peasycap->allocation_audio_page = 0; - peasycap->allocation_audio_urb = 0; /*---------------------------------------------------------------------------*/ /* @@ -3023,7 +2984,6 @@ static int easycap_usb_probe(struct usb_interface *intf, peasycap->pusb_device = usbdev; peasycap->pusb_interface = intf; - peasycap->ilk = 0; peasycap->microphone = false; peasycap->video_interface = -1; @@ -3042,38 +3002,21 @@ static int easycap_usb_probe(struct usb_interface *intf, peasycap->frame_buffer_many = FRAME_BUFFER_MANY; - for (k = 0; k < INPUT_MANY; k++) - peasycap->lost[k] = 0; - peasycap->skip = 0; - peasycap->skipped = 0; - peasycap->offerfields = 0; /*---------------------------------------------------------------------------*/ /* * DYNAMICALLY FILL IN THE AVAILABLE FORMATS ... */ /*---------------------------------------------------------------------------*/ - rc = fillin_formats(); + rc = easycap_video_fillin_formats(); if (0 > rc) { SAM("ERROR: fillin_formats() rc = %i\n", rc); return -EFAULT; } JOM(4, "%i formats available\n", rc); -/*---------------------------------------------------------------------------*/ -/* - * ... AND POPULATE easycap.inputset[] -*/ -/*---------------------------------------------------------------------------*/ - /* FIXME: maybe we just use memset 0 */ + + /* ... AND POPULATE easycap.inputset[] */ + inputset = peasycap->inputset; - for (k = 0; k < INPUT_MANY; k++) { - inputset[k].input_ok = 0; - inputset[k].standard_offset_ok = 0; - inputset[k].format_offset_ok = 0; - inputset[k].brightness_ok = 0; - inputset[k].contrast_ok = 0; - inputset[k].saturation_ok = 0; - inputset[k].hue_ok = 0; - } fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN; m = 0; @@ -3390,11 +3333,10 @@ static int easycap_usb_probe(struct usb_interface *intf, if (!isokalt) { SAM("ERROR: no viable video_altsetting_on\n"); return -ENOENT; - } else { - peasycap->video_altsetting_on = okalt[isokalt - 1]; - JOM(4, "%i=video_altsetting_on <====\n", - peasycap->video_altsetting_on); } + peasycap->video_altsetting_on = okalt[isokalt - 1]; + JOM(4, "%i=video_altsetting_on <====\n", + peasycap->video_altsetting_on); /*---------------------------------------------------------------------------*/ /* * DECIDE THE VIDEO STREAMING PARAMETERS @@ -3480,8 +3422,9 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: Could not allocate frame " "buffer %i page %i\n", k, m); return -ENOMEM; - } else - peasycap->allocation_video_page += 1; + } + + peasycap->allocation_video_page += 1; peasycap->frame_buffer[k][m].pgo = pbuf; } peasycap->frame_buffer[k][m].pto = @@ -3510,11 +3453,11 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: Could not allocate field" " buffer %i page %i\n", k, m); return -ENOMEM; - } - else - peasycap->allocation_video_page += 1; - peasycap->field_buffer[k][m].pgo = pbuf; } + + peasycap->allocation_video_page += 1; + peasycap->field_buffer[k][m].pgo = pbuf; + } peasycap->field_buffer[k][m].pto = peasycap->field_buffer[k][m].pgo; } @@ -3538,9 +3481,9 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: Could not allocate isoc video buffer " "%i\n", k); return -ENOMEM; - } else - peasycap->allocation_video_page += - BIT(VIDEO_ISOC_ORDER); + } + peasycap->allocation_video_page += + BIT(VIDEO_ISOC_ORDER); peasycap->video_isoc_buffer[k].pgo = pbuf; peasycap->video_isoc_buffer[k].pto = @@ -3569,15 +3512,17 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: usb_alloc_urb returned NULL for buffer " "%i\n", k); return -ENOMEM; - } else - peasycap->allocation_video_urb += 1; + } + + peasycap->allocation_video_urb += 1; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL); if (!pdata_urb) { SAM("ERROR: Could not allocate struct data_urb.\n"); return -ENOMEM; - } else - peasycap->allocation_video_struct += + } + + peasycap->allocation_video_struct += sizeof(struct data_urb); pdata_urb->purb = purb; @@ -3694,13 +3639,12 @@ static int easycap_usb_probe(struct usb_interface *intf, err("Not able to register with videodev"); videodev_release(&(peasycap->video_device)); return -ENODEV; - } else { - (peasycap->registered_video)++; - SAM("registered with videodev: %i=minor\n", - peasycap->video_device.minor); - peasycap->minor = peasycap->video_device.minor; } -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ + + peasycap->registered_video++; + SAM("registered with videodev: %i=minor\n", + peasycap->video_device.minor); + peasycap->minor = peasycap->video_device.minor; break; } @@ -3734,11 +3678,10 @@ static int easycap_usb_probe(struct usb_interface *intf, if (!isokalt) { SAM("ERROR: no viable audio_altsetting_on\n"); return -ENOENT; - } else { - peasycap->audio_altsetting_on = okalt[isokalt - 1]; - JOM(4, "%i=audio_altsetting_on <====\n", - peasycap->audio_altsetting_on); } + peasycap->audio_altsetting_on = okalt[isokalt - 1]; + JOM(4, "%i=audio_altsetting_on <====\n", + peasycap->audio_altsetting_on); peasycap->audio_endpointnumber = okepn[isokalt - 1]; JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber); @@ -3847,8 +3790,8 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: Could not allocate isoc audio buffer " "%i\n", k); return -ENOMEM; - } else - peasycap->allocation_audio_page += + } + peasycap->allocation_audio_page += BIT(AUDIO_ISOC_ORDER); peasycap->audio_isoc_buffer[k].pgo = pbuf; @@ -3996,12 +3939,9 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface) { struct usb_host_interface *pusb_host_interface; struct usb_interface_descriptor *pusb_interface_descriptor; - u8 bInterfaceNumber; struct easycap *peasycap; - - struct list_head *plist_head; - struct data_urb *pdata_urb; - int minor, m, kd; + int minor, kd; + u8 bInterfaceNumber; JOT(4, "\n"); @@ -4036,45 +3976,14 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface) peasycap->audio_eof = 1; wake_up_interruptible(&(peasycap->wq_video)); wake_up_interruptible(&(peasycap->wq_audio)); -/*---------------------------------------------------------------------------*/ + switch (bInterfaceNumber) { - case 0: { - if (peasycap->purb_video_head) { - JOM(4, "killing video urbs\n"); - m = 0; - list_for_each(plist_head, peasycap->purb_video_head) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb) { - if (pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } - } - } - JOM(4, "%i video urbs killed\n", m); - } + case 0: + easycap_video_kill_urbs(peasycap); break; - } -/*---------------------------------------------------------------------------*/ - case 2: { - if (peasycap->purb_audio_head) { - JOM(4, "killing audio urbs\n"); - m = 0; - list_for_each(plist_head, peasycap->purb_audio_head) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb) { - if (pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } - } - } - JOM(4, "%i audio urbs killed\n", m); - } + case 2: + easycap_audio_kill_urbs(peasycap); break; - } default: break; } @@ -4087,7 +3996,7 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface) * AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE. */ /*--------------------------------------------------------------------------*/ - kd = isdongle(peasycap); + kd = easycap_isdongle(peasycap); switch (bInterfaceNumber) { case 0: { if (0 <= kd && DONGLE_MANY > kd) { @@ -4212,7 +4121,7 @@ static struct usb_device_id easycap_usb_device_id_table[] = { }; MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table); -struct usb_driver easycap_usb_driver = { +static struct usb_driver easycap_usb_driver = { .name = "easycap", .id_table = easycap_usb_device_id_table, .probe = easycap_usb_probe, diff --git a/drivers/staging/media/easycap/easycap_settings.c b/drivers/staging/media/easycap/easycap_settings.c index 70f59b13c34d..3f5f5b3e5a35 100644 --- a/drivers/staging/media/easycap/easycap_settings.c +++ b/drivers/staging/media/easycap/easycap_settings.c @@ -313,7 +313,7 @@ const struct easycap_standard easycap_standard[] = { struct easycap_format easycap_format[1 + SETTINGS_MANY]; -int fillin_formats(void) +int easycap_video_fillin_formats(void) { const char *name1, *name2, *name3, *name4; struct v4l2_format *fmt; diff --git a/drivers/staging/media/easycap/easycap_sound.c b/drivers/staging/media/easycap/easycap_sound.c index b22bb39b5f69..8c8bcae8ded8 100644 --- a/drivers/staging/media/easycap/easycap_sound.c +++ b/drivers/staging/media/easycap/easycap_sound.c @@ -56,6 +56,141 @@ static const struct snd_pcm_hardware alsa_hardware = { }; +/*---------------------------------------------------------------------------*/ +/* + * SUBMIT ALL AUDIO URBS. + */ +/*---------------------------------------------------------------------------*/ +static int easycap_audio_submit_urbs(struct easycap *peasycap) +{ + struct data_urb *pdata_urb; + struct urb *purb; + struct list_head *plist_head; + int j, isbad, nospc, m, rc; + int isbuf; + + if (!peasycap->purb_audio_head) { + SAM("ERROR: peasycap->urb_audio_head uninitialized\n"); + return -EFAULT; + } + if (!peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + return -EFAULT; + } + + if (peasycap->audio_isoc_streaming) { + JOM(4, "already streaming audio urbs\n"); + return 0; + } + + JOM(4, "initial submission of all audio urbs\n"); + rc = usb_set_interface(peasycap->pusb_device, + peasycap->audio_interface, + peasycap->audio_altsetting_on); + JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", + peasycap->audio_interface, + peasycap->audio_altsetting_on, rc); + + isbad = 0; + nospc = 0; + m = 0; + list_for_each(plist_head, peasycap->purb_audio_head) { + pdata_urb = list_entry(plist_head, struct data_urb, list_head); + if (pdata_urb && pdata_urb->purb) { + purb = pdata_urb->purb; + isbuf = pdata_urb->isbuf; + + purb->interval = 1; + purb->dev = peasycap->pusb_device; + purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, + peasycap->audio_endpointnumber); + purb->transfer_flags = URB_ISO_ASAP; + purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo; + purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size; + purb->complete = easycap_alsa_complete; + purb->context = peasycap; + purb->start_frame = 0; + purb->number_of_packets = peasycap->audio_isoc_framesperdesc; + for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) { + purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize; + purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize; + } + + rc = usb_submit_urb(purb, GFP_KERNEL); + if (rc) { + isbad++; + SAM("ERROR: usb_submit_urb() failed" + " for urb with rc: -%s: %d\n", + strerror(rc), rc); + } else { + m++; + } + } else { + isbad++; + } + } + if (nospc) { + SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc); + SAM("..... possibly inadequate USB bandwidth\n"); + peasycap->audio_eof = 1; + } + + if (isbad) + easycap_audio_kill_urbs(peasycap); + else + peasycap->audio_isoc_streaming = m; + + return 0; +} +/*---------------------------------------------------------------------------*/ +/* + * COMMON AUDIO INITIALIZATION + */ +/*---------------------------------------------------------------------------*/ +static int easycap_sound_setup(struct easycap *peasycap) +{ + int rc; + + JOM(4, "starting initialization\n"); + + if (!peasycap) { + SAY("ERROR: peasycap is NULL.\n"); + return -EFAULT; + } + if (!peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + return -ENODEV; + } + JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device); + + rc = easycap_audio_setup(peasycap); + JOM(8, "audio_setup() returned %i\n", rc); + + if (!peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device has become NULL\n"); + return -ENODEV; + } +/*---------------------------------------------------------------------------*/ + if (!peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device has become NULL\n"); + return -ENODEV; + } + rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, + peasycap->audio_altsetting_on); + JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, + peasycap->audio_altsetting_on, rc); + + rc = easycap_wakeup_device(peasycap->pusb_device); + JOM(8, "wakeup_device() returned %i\n", rc); + + peasycap->audio_eof = 0; + peasycap->audio_idle = 0; + + easycap_audio_submit_urbs(peasycap); + + JOM(4, "finished initialization\n"); + return 0; +} /*****************************************************************************/ /*---------------------------------------------------------------------------*/ /* @@ -64,8 +199,7 @@ static const struct snd_pcm_hardware alsa_hardware = { * IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO. */ /*---------------------------------------------------------------------------*/ -void -easycap_alsa_complete(struct urb *purb) +void easycap_alsa_complete(struct urb *purb) { struct easycap *peasycap; struct snd_pcm_substream *pss; @@ -458,7 +592,6 @@ static int easycap_alsa_ack(struct snd_pcm_substream *pss) static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd) { struct easycap *peasycap; - int retval; JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START, SNDRV_PCM_TRIGGER_STOP); @@ -481,7 +614,7 @@ static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd) break; } default: - retval = -EINVAL; + return -EINVAL; } return 0; } @@ -615,202 +748,3 @@ int easycap_alsa_probe(struct easycap *peasycap) return 0; } -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * COMMON AUDIO INITIALIZATION - */ -/*---------------------------------------------------------------------------*/ -int -easycap_sound_setup(struct easycap *peasycap) -{ - int rc; - - JOM(4, "starting initialization\n"); - - if (!peasycap) { - SAY("ERROR: peasycap is NULL.\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -ENODEV; - } - JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device); - - rc = audio_setup(peasycap); - JOM(8, "audio_setup() returned %i\n", rc); - - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -ENODEV; - } -/*---------------------------------------------------------------------------*/ - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -ENODEV; - } - rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, - peasycap->audio_altsetting_on); - JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, - peasycap->audio_altsetting_on, rc); - - rc = wakeup_device(peasycap->pusb_device); - JOM(8, "wakeup_device() returned %i\n", rc); - - peasycap->audio_eof = 0; - peasycap->audio_idle = 0; - - submit_audio_urbs(peasycap); - - JOM(4, "finished initialization\n"); - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * SUBMIT ALL AUDIO URBS. - */ -/*---------------------------------------------------------------------------*/ -int -submit_audio_urbs(struct easycap *peasycap) -{ - struct data_urb *pdata_urb; - struct urb *purb; - struct list_head *plist_head; - int j, isbad, nospc, m, rc; - int isbuf; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->purb_audio_head) { - SAM("ERROR: peasycap->urb_audio_head uninitialized\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - - if (peasycap->audio_isoc_streaming) { - JOM(4, "already streaming audio urbs\n"); - return 0; - } - - JOM(4, "initial submission of all audio urbs\n"); - rc = usb_set_interface(peasycap->pusb_device, - peasycap->audio_interface, - peasycap->audio_altsetting_on); - JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", - peasycap->audio_interface, - peasycap->audio_altsetting_on, rc); - - isbad = 0; - nospc = 0; - m = 0; - list_for_each(plist_head, peasycap->purb_audio_head) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - purb = pdata_urb->purb; - isbuf = pdata_urb->isbuf; - - purb->interval = 1; - purb->dev = peasycap->pusb_device; - purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, - peasycap->audio_endpointnumber); - purb->transfer_flags = URB_ISO_ASAP; - purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo; - purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size; - purb->complete = easycap_alsa_complete; - purb->context = peasycap; - purb->start_frame = 0; - purb->number_of_packets = peasycap->audio_isoc_framesperdesc; - for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) { - purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize; - purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize; - } - - rc = usb_submit_urb(purb, GFP_KERNEL); - if (rc) { - isbad++; - SAM("ERROR: usb_submit_urb() failed" - " for urb with rc: -%s: %d\n", - strerror(rc), rc); - } else { - m++; - } - } else { - isbad++; - } - } - if (nospc) { - SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc); - SAM("..... possibly inadequate USB bandwidth\n"); - peasycap->audio_eof = 1; - } - if (isbad) { - JOM(4, "attempting cleanup instead of submitting\n"); - list_for_each(plist_head, (peasycap->purb_audio_head)) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) - usb_kill_urb(pdata_urb->purb); - } - peasycap->audio_isoc_streaming = 0; - } else { - peasycap->audio_isoc_streaming = m; - JOM(4, "submitted %i audio urbs\n", m); - } - - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * KILL ALL AUDIO URBS. - */ -/*---------------------------------------------------------------------------*/ -int -kill_audio_urbs(struct easycap *peasycap) -{ - int m; - struct list_head *plist_head; - struct data_urb *pdata_urb; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - - if (!peasycap->audio_isoc_streaming) { - JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n", - peasycap->audio_isoc_streaming); - return 0; - } - - if (!peasycap->purb_audio_head) { - SAM("ERROR: peasycap->purb_audio_head is NULL\n"); - return -EFAULT; - } - - peasycap->audio_isoc_streaming = 0; - JOM(4, "killing audio urbs\n"); - m = 0; - list_for_each(plist_head, (peasycap->purb_audio_head)) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } - } - JOM(4, "%i audio urbs killed\n", m); - - return 0; -} -/*****************************************************************************/ diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index b7175fe1b15f..70e006b50f29 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -1054,7 +1054,13 @@ static int go7007_usb_probe(struct usb_interface *intf, else go->hpi_ops = &go7007_usb_onboard_hpi_ops; go->hpi_context = usb; - usb_fill_int_urb(usb->intr_urb, usb->usbdev, + if (go->board_id == GO7007_BOARDID_SENSORAY_2250) + usb_fill_bulk_urb(usb->intr_urb, usb->usbdev, + usb_rcvbulkpipe(usb->usbdev, 4), + usb->intr_urb->transfer_buffer, 2*sizeof(u16), + go7007_usb_readinterrupt_complete, go); + else + usb_fill_int_urb(usb->intr_urb, usb->usbdev, usb_rcvintpipe(usb->usbdev, 4), usb->intr_urb->transfer_buffer, 2*sizeof(u16), go7007_usb_readinterrupt_complete, go, 8); diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c index deac938d8505..d071c838ac2a 100644 --- a/drivers/staging/media/go7007/snd-go7007.c +++ b/drivers/staging/media/go7007/snd-go7007.c @@ -38,7 +38,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; module_param_array(index, int, NULL, 0444); module_param_array(id, charp, NULL, 0444); diff --git a/drivers/staging/media/lirc/lirc_bt829.c b/drivers/staging/media/lirc/lirc_bt829.c index c5a0d27a02dc..4d20e9f74118 100644 --- a/drivers/staging/media/lirc/lirc_bt829.c +++ b/drivers/staging/media/lirc/lirc_bt829.c @@ -53,7 +53,7 @@ static unsigned char do_get_bits(void); #define DRIVER_NAME "lirc_bt829" -static int debug; +static bool debug; #define dprintk(fmt, args...) \ do { \ if (debug) \ diff --git a/drivers/staging/media/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c index 6cd4cd67a1dd..7a2501776679 100644 --- a/drivers/staging/media/lirc/lirc_igorplugusb.c +++ b/drivers/staging/media/lirc/lirc_igorplugusb.c @@ -62,9 +62,9 @@ /* debugging support */ #ifdef CONFIG_USB_DEBUG -static int debug = 1; +static bool debug = 1; #else -static int debug; +static bool debug; #endif #define dprintk(fmt, args...) \ diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c index f68218012f23..5f7f8cd3a661 100644 --- a/drivers/staging/media/lirc/lirc_imon.c +++ b/drivers/staging/media/lirc/lirc_imon.c @@ -63,7 +63,7 @@ static int display_open(struct inode *inode, struct file *file); static int display_close(struct inode *inode, struct file *file); /* VFD write operation */ -static ssize_t vfd_write(struct file *file, const char *buf, +static ssize_t vfd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos); /* LIRC driver function prototypes */ @@ -369,7 +369,7 @@ static int send_packet(struct imon_context *context) * than 32 bytes are provided spaces will be appended to * generate a full screen. */ -static ssize_t vfd_write(struct file *file, const char *buf, +static ssize_t vfd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos) { int i; diff --git a/drivers/staging/media/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c index 792aac0a8e7b..dd2bca7b56fa 100644 --- a/drivers/staging/media/lirc/lirc_parallel.c +++ b/drivers/staging/media/lirc/lirc_parallel.c @@ -63,8 +63,8 @@ /*** Global Variables ***/ -static int debug; -static int check_pselecd; +static bool debug; +static bool check_pselecd; unsigned int irq = LIRC_IRQ; unsigned int io = LIRC_PORT; @@ -752,4 +752,4 @@ module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging messages"); module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); +MODULE_PARM_DESC(check_pselecd, "Check for printer (default: 0)"); diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index 8a060a8a7224..8dd8897ad860 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -107,13 +107,13 @@ struct lirc_serial { static int type; static int io; static int irq; -static int iommap; +static bool iommap; static int ioshift; -static int softcarrier = 1; -static int share_irq; -static int debug; +static bool softcarrier = 1; +static bool share_irq; +static bool debug; static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ -static int txsense; /* 0 = active high, 1 = active low */ +static bool txsense; /* 0 = active high, 1 = active low */ #define dprintk(fmt, args...) \ do { \ @@ -773,7 +773,7 @@ static int hardware_init_port(void) /* we fail, there's nothing here */ printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test " "failed, cannot continue\n"); - return -EINVAL; + return -ENODEV; } @@ -836,25 +836,22 @@ static int hardware_init_port(void) return 0; } -static int init_port(void) +static int __devinit lirc_serial_probe(struct platform_device *dev) { int i, nlow, nhigh, result; result = request_irq(irq, irq_handler, (share_irq ? IRQF_SHARED : 0), LIRC_DRIVER_NAME, (void *)&hardware); - - switch (result) { - case -EBUSY: - printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); - return -EBUSY; - case -EINVAL: - printk(KERN_ERR LIRC_DRIVER_NAME - ": Bad irq number or handler\n"); - return -EINVAL; - default: - break; - }; + if (result < 0) { + if (result == -EBUSY) + printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", + irq); + else if (result == -EINVAL) + printk(KERN_ERR LIRC_DRIVER_NAME + ": Bad irq number or handler\n"); + return result; + } /* Reserve io region. */ /* @@ -875,11 +872,13 @@ static int init_port(void) ": or compile the serial port driver as module and\n"); printk(KERN_WARNING LIRC_DRIVER_NAME ": make sure this module is loaded first\n"); - return -EBUSY; + result = -EBUSY; + goto exit_free_irq; } - if (hardware_init_port() < 0) - return -EINVAL; + result = hardware_init_port(); + if (result < 0) + goto exit_release_region; /* Initialize pulse/space widths */ init_timing_params(duty_cycle, freq); @@ -911,6 +910,28 @@ static int init_port(void) dprintk("Interrupt %d, port %04x obtained\n", irq, io); return 0; + +exit_release_region: + if (iommap != 0) + release_mem_region(iommap, 8 << ioshift); + else + release_region(io, 8); +exit_free_irq: + free_irq(irq, (void *)&hardware); + + return result; +} + +static int __devexit lirc_serial_remove(struct platform_device *dev) +{ + free_irq(irq, (void *)&hardware); + + if (iommap != 0) + release_mem_region(iommap, 8 << ioshift); + else + release_region(io, 8); + + return 0; } static int set_use_inc(void *data) @@ -955,7 +976,7 @@ static ssize_t lirc_write(struct file *file, const char *buf, int *wbuf; if (!(hardware[type].features & LIRC_CAN_SEND_PULSE)) - return -EBADF; + return -EPERM; count = n / sizeof(int); if (n % sizeof(int) || count % 2 == 0) @@ -1006,11 +1027,11 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) return result; /* only LIRC_MODE_PULSE supported */ if (value != LIRC_MODE_PULSE) - return -ENOSYS; + return -EINVAL; break; case LIRC_GET_LENGTH: - return -ENOSYS; + return -ENOIOCTLCMD; break; case LIRC_SET_SEND_DUTY_CYCLE: @@ -1076,16 +1097,6 @@ static struct lirc_driver driver = { static struct platform_device *lirc_serial_dev; -static int __devinit lirc_serial_probe(struct platform_device *dev) -{ - return 0; -} - -static int __devexit lirc_serial_remove(struct platform_device *dev) -{ - return 0; -} - static int lirc_serial_suspend(struct platform_device *dev, pm_message_t state) { @@ -1111,11 +1122,11 @@ static void lirc_serial_exit(void); static int lirc_serial_resume(struct platform_device *dev) { unsigned long flags; + int result; - if (hardware_init_port() < 0) { - lirc_serial_exit(); - return -EINVAL; - } + result = hardware_init_port(); + if (result < 0) + return result; spin_lock_irqsave(&hardware[type].lock, flags); /* Enable Interrupt */ @@ -1148,7 +1159,7 @@ static int __init lirc_serial_init(void) /* Init read buffer. */ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); if (result < 0) - return -ENOMEM; + return result; result = platform_driver_register(&lirc_serial_driver); if (result) { @@ -1188,10 +1199,6 @@ static int __init lirc_serial_init_module(void) { int result; - result = lirc_serial_init(); - if (result) - return result; - switch (type) { case LIRC_HOMEBREW: case LIRC_IRDEO: @@ -1211,8 +1218,7 @@ static int __init lirc_serial_init_module(void) break; #endif default: - result = -EINVAL; - goto exit_serial_exit; + return -EINVAL; } if (!softcarrier) { switch (type) { @@ -1228,37 +1234,26 @@ static int __init lirc_serial_init_module(void) } } - result = init_port(); - if (result < 0) - goto exit_serial_exit; + result = lirc_serial_init(); + if (result) + return result; + driver.features = hardware[type].features; driver.dev = &lirc_serial_dev->dev; driver.minor = lirc_register_driver(&driver); if (driver.minor < 0) { printk(KERN_ERR LIRC_DRIVER_NAME ": register_chrdev failed!\n"); - result = -EIO; - goto exit_release; + lirc_serial_exit(); + return driver.minor; } return 0; -exit_release: - release_region(io, 8); -exit_serial_exit: - lirc_serial_exit(); - return result; } static void __exit lirc_serial_exit_module(void) { - lirc_serial_exit(); - - free_irq(irq, (void *)&hardware); - - if (iommap != 0) - release_mem_region(iommap, 8 << ioshift); - else - release_region(io, 8); lirc_unregister_driver(driver.minor); + lirc_serial_exit(); dprintk("cleaned up module\n"); } diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c index 6903d3992eca..c94382b917ac 100644 --- a/drivers/staging/media/lirc/lirc_sir.c +++ b/drivers/staging/media/lirc/lirc_sir.c @@ -173,7 +173,7 @@ static DEFINE_SPINLOCK(hardware_lock); static int rx_buf[RBUF_LEN]; static unsigned int rx_tail, rx_head; -static int debug; +static bool debug; #define dprintk(fmt, args...) \ do { \ if (debug) \ diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 0302d82a12f7..76ea4a8f2c75 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -155,8 +155,8 @@ static struct mutex tx_data_lock; #define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args) /* module parameters */ -static int debug; /* debug output */ -static int tx_only; /* only handle the IR Tx function */ +static bool debug; /* debug output */ +static bool tx_only; /* only handle the IR Tx function */ static int minor = -1; /* minor number */ #define dprintk(fmt, args...) \ diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile index 72816cf16704..337e38c3a0f0 100644 --- a/drivers/staging/media/solo6x10/Makefile +++ b/drivers/staging/media/solo6x10/Makefile @@ -1,3 +1,3 @@ solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o -obj-$(CONFIG_SOLO6X10) := solo6x10.o +obj-$(CONFIG_SOLO6X10) += solo6x10.o diff --git a/drivers/staging/media/solo6x10/jpeg.h b/drivers/staging/media/solo6x10/solo6x10-jpeg.h index 50defec318cc..50defec318cc 100644 --- a/drivers/staging/media/solo6x10/jpeg.h +++ b/drivers/staging/media/solo6x10/solo6x10-jpeg.h diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index bee7280bbed9..f8f0da952288 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -26,7 +26,7 @@ #include <media/videobuf-dma-sg.h> #include "solo6x10.h" #include "tw28.h" -#include "jpeg.h" +#include "solo6x10-jpeg.h" #define MIN_VID_BUFFERS 4 #define FRAME_BUF_SIZE (128 * 1024) diff --git a/drivers/staging/octeon/Makefile b/drivers/staging/octeon/Makefile index fc850bac88c1..9012dee0c348 100644 --- a/drivers/staging/octeon/Makefile +++ b/drivers/staging/octeon/Makefile @@ -20,9 +20,4 @@ octeon-ethernet-y += ethernet-sgmii.o octeon-ethernet-y += ethernet-spi.o octeon-ethernet-y += ethernet-tx.o octeon-ethernet-y += ethernet-xaui.o -octeon-ethernet-y += cvmx-pko.o cvmx-spi.o cvmx-cmd-queue.o \ - cvmx-helper-board.o cvmx-helper.o cvmx-helper-xaui.o \ - cvmx-helper-rgmii.o cvmx-helper-sgmii.o cvmx-helper-npi.o \ - cvmx-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \ - cvmx-interrupt-decodes.o cvmx-interrupt-rsl.o diff --git a/drivers/staging/octeon/cvmx-packet.h b/drivers/staging/octeon/cvmx-packet.h deleted file mode 100644 index 62ffe78a8c81..000000000000 --- a/drivers/staging/octeon/cvmx-packet.h +++ /dev/null @@ -1,65 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * - * Packet buffer defines. - */ - -#ifndef __CVMX_PACKET_H__ -#define __CVMX_PACKET_H__ - -/** - * This structure defines a buffer pointer on Octeon - */ -union cvmx_buf_ptr { - void *ptr; - uint64_t u64; - struct { - /* - * if set, invert the "free" pick of the overall - * packet. HW always sets this bit to 0 on inbound - * packet - */ - uint64_t i:1; - /* - * Indicates the amount to back up to get to the - * buffer start in cache lines. In most cases this is - * less than one complete cache line, so the value is - * zero. - */ - uint64_t back:4; - /* The pool that the buffer came from / goes to */ - uint64_t pool:3; - /* The size of the segment pointed to by addr (in bytes) */ - uint64_t size:16; - /* Pointer to the first byte of the data, NOT buffer */ - uint64_t addr:40; - } s; -}; - -#endif /* __CVMX_PACKET_H__ */ diff --git a/drivers/staging/octeon/cvmx-smix-defs.h b/drivers/staging/octeon/cvmx-smix-defs.h deleted file mode 100644 index 9ae45fcbe3e3..000000000000 --- a/drivers/staging/octeon/cvmx-smix-defs.h +++ /dev/null @@ -1,178 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, Version 2, as - * published by the Free Software Foundation. - * - * This file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_SMIX_DEFS_H__ -#define __CVMX_SMIX_DEFS_H__ - -#define CVMX_SMIX_CLK(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001818ull + (((offset) & 1) * 256)) -#define CVMX_SMIX_CMD(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001800ull + (((offset) & 1) * 256)) -#define CVMX_SMIX_EN(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001820ull + (((offset) & 1) * 256)) -#define CVMX_SMIX_RD_DAT(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001810ull + (((offset) & 1) * 256)) -#define CVMX_SMIX_WR_DAT(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001808ull + (((offset) & 1) * 256)) - -union cvmx_smix_clk { - uint64_t u64; - struct cvmx_smix_clk_s { - uint64_t reserved_25_63:39; - uint64_t mode:1; - uint64_t reserved_21_23:3; - uint64_t sample_hi:5; - uint64_t sample_mode:1; - uint64_t reserved_14_14:1; - uint64_t clk_idle:1; - uint64_t preamble:1; - uint64_t sample:4; - uint64_t phase:8; - } s; - struct cvmx_smix_clk_cn30xx { - uint64_t reserved_21_63:43; - uint64_t sample_hi:5; - uint64_t reserved_14_15:2; - uint64_t clk_idle:1; - uint64_t preamble:1; - uint64_t sample:4; - uint64_t phase:8; - } cn30xx; - struct cvmx_smix_clk_cn30xx cn31xx; - struct cvmx_smix_clk_cn30xx cn38xx; - struct cvmx_smix_clk_cn30xx cn38xxp2; - struct cvmx_smix_clk_cn50xx { - uint64_t reserved_25_63:39; - uint64_t mode:1; - uint64_t reserved_21_23:3; - uint64_t sample_hi:5; - uint64_t reserved_14_15:2; - uint64_t clk_idle:1; - uint64_t preamble:1; - uint64_t sample:4; - uint64_t phase:8; - } cn50xx; - struct cvmx_smix_clk_s cn52xx; - struct cvmx_smix_clk_cn50xx cn52xxp1; - struct cvmx_smix_clk_s cn56xx; - struct cvmx_smix_clk_cn50xx cn56xxp1; - struct cvmx_smix_clk_cn30xx cn58xx; - struct cvmx_smix_clk_cn30xx cn58xxp1; -}; - -union cvmx_smix_cmd { - uint64_t u64; - struct cvmx_smix_cmd_s { - uint64_t reserved_18_63:46; - uint64_t phy_op:2; - uint64_t reserved_13_15:3; - uint64_t phy_adr:5; - uint64_t reserved_5_7:3; - uint64_t reg_adr:5; - } s; - struct cvmx_smix_cmd_cn30xx { - uint64_t reserved_17_63:47; - uint64_t phy_op:1; - uint64_t reserved_13_15:3; - uint64_t phy_adr:5; - uint64_t reserved_5_7:3; - uint64_t reg_adr:5; - } cn30xx; - struct cvmx_smix_cmd_cn30xx cn31xx; - struct cvmx_smix_cmd_cn30xx cn38xx; - struct cvmx_smix_cmd_cn30xx cn38xxp2; - struct cvmx_smix_cmd_s cn50xx; - struct cvmx_smix_cmd_s cn52xx; - struct cvmx_smix_cmd_s cn52xxp1; - struct cvmx_smix_cmd_s cn56xx; - struct cvmx_smix_cmd_s cn56xxp1; - struct cvmx_smix_cmd_cn30xx cn58xx; - struct cvmx_smix_cmd_cn30xx cn58xxp1; -}; - -union cvmx_smix_en { - uint64_t u64; - struct cvmx_smix_en_s { - uint64_t reserved_1_63:63; - uint64_t en:1; - } s; - struct cvmx_smix_en_s cn30xx; - struct cvmx_smix_en_s cn31xx; - struct cvmx_smix_en_s cn38xx; - struct cvmx_smix_en_s cn38xxp2; - struct cvmx_smix_en_s cn50xx; - struct cvmx_smix_en_s cn52xx; - struct cvmx_smix_en_s cn52xxp1; - struct cvmx_smix_en_s cn56xx; - struct cvmx_smix_en_s cn56xxp1; - struct cvmx_smix_en_s cn58xx; - struct cvmx_smix_en_s cn58xxp1; -}; - -union cvmx_smix_rd_dat { - uint64_t u64; - struct cvmx_smix_rd_dat_s { - uint64_t reserved_18_63:46; - uint64_t pending:1; - uint64_t val:1; - uint64_t dat:16; - } s; - struct cvmx_smix_rd_dat_s cn30xx; - struct cvmx_smix_rd_dat_s cn31xx; - struct cvmx_smix_rd_dat_s cn38xx; - struct cvmx_smix_rd_dat_s cn38xxp2; - struct cvmx_smix_rd_dat_s cn50xx; - struct cvmx_smix_rd_dat_s cn52xx; - struct cvmx_smix_rd_dat_s cn52xxp1; - struct cvmx_smix_rd_dat_s cn56xx; - struct cvmx_smix_rd_dat_s cn56xxp1; - struct cvmx_smix_rd_dat_s cn58xx; - struct cvmx_smix_rd_dat_s cn58xxp1; -}; - -union cvmx_smix_wr_dat { - uint64_t u64; - struct cvmx_smix_wr_dat_s { - uint64_t reserved_18_63:46; - uint64_t pending:1; - uint64_t val:1; - uint64_t dat:16; - } s; - struct cvmx_smix_wr_dat_s cn30xx; - struct cvmx_smix_wr_dat_s cn31xx; - struct cvmx_smix_wr_dat_s cn38xx; - struct cvmx_smix_wr_dat_s cn38xxp2; - struct cvmx_smix_wr_dat_s cn50xx; - struct cvmx_smix_wr_dat_s cn52xx; - struct cvmx_smix_wr_dat_s cn52xxp1; - struct cvmx_smix_wr_dat_s cn56xx; - struct cvmx_smix_wr_dat_s cn56xxp1; - struct cvmx_smix_wr_dat_s cn58xx; - struct cvmx_smix_wr_dat_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h index 6a2cd50a17df..bdaec8d2ca0c 100644 --- a/drivers/staging/octeon/ethernet-defines.h +++ b/drivers/staging/octeon/ethernet-defines.h @@ -59,7 +59,7 @@ #ifndef __ETHERNET_DEFINES_H__ #define __ETHERNET_DEFINES_H__ -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> #define OCTEON_ETHERNET_VERSION "1.9" diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c index f18e3e140413..63800ba71d06 100644 --- a/drivers/staging/octeon/ethernet-mdio.c +++ b/drivers/staging/octeon/ethernet-mdio.c @@ -38,9 +38,9 @@ #include "ethernet-mdio.h" #include "ethernet-util.h" -#include "cvmx-helper-board.h" +#include <asm/octeon/cvmx-helper-board.h> -#include "cvmx-smix-defs.h" +#include <asm/octeon/cvmx-smix-defs.h> static void cvm_oct_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c index 635bb86cdcff..78b6cb743769 100644 --- a/drivers/staging/octeon/ethernet-mem.c +++ b/drivers/staging/octeon/ethernet-mem.c @@ -32,7 +32,7 @@ #include "ethernet-defines.h" -#include "cvmx-fpa.h" +#include <asm/octeon/cvmx-fpa.h> /** * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c index c3d73f8431ae..d8f5f694ec35 100644 --- a/drivers/staging/octeon/ethernet-rgmii.c +++ b/drivers/staging/octeon/ethernet-rgmii.c @@ -37,11 +37,11 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-helper.h> #include <asm/octeon/cvmx-ipd-defs.h> #include <asm/octeon/cvmx-npi-defs.h> -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> DEFINE_SPINLOCK(global_register_lock); diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 8b307b428791..400df8cbee53 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -52,14 +52,14 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-helper.h" -#include "cvmx-wqe.h" -#include "cvmx-fau.h" -#include "cvmx-pow.h" -#include "cvmx-pip.h" -#include "cvmx-scratch.h" - -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-wqe.h> +#include <asm/octeon/cvmx-fau.h> +#include <asm/octeon/cvmx-pow.h> +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-scratch.h> + +#include <asm/octeon/cvmx-gmxx-defs.h> struct cvm_napi_wrapper { struct napi_struct napi; diff --git a/drivers/staging/octeon/ethernet-rx.h b/drivers/staging/octeon/ethernet-rx.h index a0743b85d54e..9240c85ce241 100644 --- a/drivers/staging/octeon/ethernet-rx.h +++ b/drivers/staging/octeon/ethernet-rx.h @@ -24,7 +24,7 @@ * This file may also be available under a different license from Cavium. * Contact Cavium Networks for more information *********************************************************************/ -#include "cvmx-fau.h" +#include <asm/octeon/cvmx-fau.h> void cvm_oct_poll_controller(struct net_device *dev); void cvm_oct_rx_initialize(void); diff --git a/drivers/staging/octeon/ethernet-sgmii.c b/drivers/staging/octeon/ethernet-sgmii.c index 5e148b512c97..d3e82430eba6 100644 --- a/drivers/staging/octeon/ethernet-sgmii.c +++ b/drivers/staging/octeon/ethernet-sgmii.c @@ -35,9 +35,9 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> int cvm_oct_sgmii_open(struct net_device *dev) { diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c index d0e2d514968a..af8d62818f13 100644 --- a/drivers/staging/octeon/ethernet-spi.c +++ b/drivers/staging/octeon/ethernet-spi.c @@ -35,11 +35,11 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-spi.h" +#include <asm/octeon/cvmx-spi.h> #include <asm/octeon/cvmx-npi-defs.h> -#include "cvmx-spxx-defs.h" -#include "cvmx-stxx-defs.h" +#include <asm/octeon/cvmx-spxx-defs.h> +#include <asm/octeon/cvmx-stxx-defs.h> static int number_spi_ports; static int need_retrain[2] = { 0, 0 }; diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 2542c3743904..56d74dc2fbd5 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -47,13 +47,13 @@ #include "ethernet-tx.h" #include "ethernet-util.h" -#include "cvmx-wqe.h" -#include "cvmx-fau.h" -#include "cvmx-pip.h" -#include "cvmx-pko.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-wqe.h> +#include <asm/octeon/cvmx-fau.h> +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> #define CVM_OCT_SKB_CB(skb) ((u64 *)((skb)->cb)) diff --git a/drivers/staging/octeon/ethernet-xaui.c b/drivers/staging/octeon/ethernet-xaui.c index 861a4b3fe857..419f8c34ecdf 100644 --- a/drivers/staging/octeon/ethernet-xaui.c +++ b/drivers/staging/octeon/ethernet-xaui.c @@ -35,9 +35,9 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> int cvm_oct_xaui_open(struct net_device *dev) { diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 076f86675ce6..9112cd882154 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -44,14 +44,14 @@ #include "ethernet-mdio.h" #include "ethernet-util.h" -#include "cvmx-pip.h" -#include "cvmx-pko.h" -#include "cvmx-fau.h" -#include "cvmx-ipd.h" -#include "cvmx-helper.h" - -#include "cvmx-gmxx-defs.h" -#include "cvmx-smix-defs.h" +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-fau.h> +#include <asm/octeon/cvmx-ipd.h> +#include <asm/octeon/cvmx-helper.h> + +#include <asm/octeon/cvmx-gmxx-defs.h> +#include <asm/octeon/cvmx-smix-defs.h> #if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) \ && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c index 02fafecd4773..897a3a99c794 100644 --- a/drivers/staging/quatech_usb2/quatech_usb2.c +++ b/drivers/staging/quatech_usb2/quatech_usb2.c @@ -16,7 +16,7 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +static bool debug; /* Version Information */ #define DRIVER_VERSION "v2.00" diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index c44e41af2880..1c5780f1571b 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -16,7 +16,7 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +static bool debug; /* Version Information */ #define DRIVER_VERSION "v2.14" diff --git a/drivers/staging/speakup/speakup.h b/drivers/staging/speakup/speakup.h index 412b87947f66..e66579e6147a 100644 --- a/drivers/staging/speakup/speakup.h +++ b/drivers/staging/speakup/speakup.h @@ -116,7 +116,7 @@ extern int bleep_time, bell_pos; extern int spell_delay, key_echo; extern short punc_mask; extern short pitch_shift, synth_flags; -extern int quiet_boot; +extern bool quiet_boot; extern char *synth_name; extern struct bleep unprocessed_sound; diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index c241074a4b5e..2222d6919ef5 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c @@ -22,7 +22,7 @@ static struct spk_synth *synths[MAXSYNTHS]; struct spk_synth *synth; char pitch_buff[32] = ""; static int module_status; -int quiet_boot; +bool quiet_boot; struct speakup_info_t speakup_info = { .spinlock = __SPIN_LOCK_UNLOCKED(speakup_info.spinlock), diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 08a449b4abf9..f50582169b24 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -41,7 +41,7 @@ static void __exit tsi148_exit(void); /* Module parameter */ -static int err_chk; +static bool err_chk; static int geoid; static const char driver_name[] = "vme_tsi148"; diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 8599545cdf9e..ac44af165b27 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -27,8 +27,7 @@ #include <scsi/scsi_device.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_tmr.h> -#include <target/target_core_transport.h> +#include <target/target_core_fabric.h> #include "iscsi_target_core.h" #include "iscsi_target_parameters.h" @@ -284,8 +283,8 @@ static struct iscsi_np *iscsit_get_np( sock_in6 = (struct sockaddr_in6 *)sockaddr; sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr; - if (!memcmp((void *)&sock_in6->sin6_addr.in6_u, - (void *)&sock_in6_e->sin6_addr.in6_u, + if (!memcmp(&sock_in6->sin6_addr.in6_u, + &sock_in6_e->sin6_addr.in6_u, sizeof(struct in6_addr))) ip_match = 1; @@ -1225,7 +1224,7 @@ static void iscsit_do_crypto_hash_buf( crypto_hash_init(hash); - sg_init_one(&sg, (u8 *)buf, payload_length); + sg_init_one(&sg, buf, payload_length); crypto_hash_update(hash, &sg, payload_length); if (padding) { @@ -1603,7 +1602,7 @@ static int iscsit_handle_nop_out( /* * Attach ping data to struct iscsi_cmd->buf_ptr. */ - cmd->buf_ptr = (void *)ping_data; + cmd->buf_ptr = ping_data; cmd->buf_ptr_size = payload_length; pr_debug("Got %u bytes of NOPOUT ping" @@ -3197,7 +3196,7 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) end_of_buf = 1; goto eob; } - memcpy((void *)payload + payload_len, buf, len); + memcpy(payload + payload_len, buf, len); payload_len += len; spin_lock(&tiqn->tiqn_tpg_lock); @@ -3229,7 +3228,7 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) end_of_buf = 1; goto eob; } - memcpy((void *)payload + payload_len, buf, len); + memcpy(payload + payload_len, buf, len); payload_len += len; } spin_unlock(&tpg->tpg_np_lock); @@ -3486,7 +3485,7 @@ int iscsi_target_tx_thread(void *arg) struct iscsi_conn *conn; struct iscsi_queue_req *qr = NULL; struct se_cmd *se_cmd; - struct iscsi_thread_set *ts = (struct iscsi_thread_set *)arg; + struct iscsi_thread_set *ts = arg; /* * Allow ourselves to be interrupted by SIGINT so that a * connection recovery / failure event can be triggered externally. @@ -3775,7 +3774,7 @@ int iscsi_target_rx_thread(void *arg) u8 buffer[ISCSI_HDR_LEN], opcode; u32 checksum = 0, digest = 0; struct iscsi_conn *conn = NULL; - struct iscsi_thread_set *ts = (struct iscsi_thread_set *)arg; + struct iscsi_thread_set *ts = arg; struct kvec iov; /* * Allow ourselves to be interrupted by SIGINT so that a diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 1cd6ce373b83..db0cf7c8adde 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -82,7 +82,7 @@ static void chap_gen_challenge( unsigned int *c_len) { unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1]; - struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol; + struct iscsi_chap *chap = conn->auth_protocol; memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1); @@ -120,7 +120,7 @@ static struct iscsi_chap *chap_server_open( if (!conn->auth_protocol) return NULL; - chap = (struct iscsi_chap *) conn->auth_protocol; + chap = conn->auth_protocol; /* * We only support MD5 MDA presently. */ @@ -165,14 +165,15 @@ static int chap_server_compute_md5( unsigned int *nr_out_len) { char *endptr; - unsigned char id, digest[MD5_SIGNATURE_SIZE]; + unsigned long id; + unsigned char digest[MD5_SIGNATURE_SIZE]; unsigned char type, response[MD5_SIGNATURE_SIZE * 2 + 2]; unsigned char identifier[10], *challenge = NULL; unsigned char *challenge_binhex = NULL; unsigned char client_digest[MD5_SIGNATURE_SIZE]; unsigned char server_digest[MD5_SIGNATURE_SIZE]; unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH]; - struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol; + struct iscsi_chap *chap = conn->auth_protocol; struct crypto_hash *tfm; struct hash_desc desc; struct scatterlist sg; @@ -246,7 +247,7 @@ static int chap_server_compute_md5( goto out; } - sg_init_one(&sg, (void *)&chap->id, 1); + sg_init_one(&sg, &chap->id, 1); ret = crypto_hash_update(&desc, &sg, 1); if (ret < 0) { pr_err("crypto_hash_update() failed for id\n"); @@ -254,7 +255,7 @@ static int chap_server_compute_md5( goto out; } - sg_init_one(&sg, (void *)&auth->password, strlen(auth->password)); + sg_init_one(&sg, &auth->password, strlen(auth->password)); ret = crypto_hash_update(&desc, &sg, strlen(auth->password)); if (ret < 0) { pr_err("crypto_hash_update() failed for password\n"); @@ -262,7 +263,7 @@ static int chap_server_compute_md5( goto out; } - sg_init_one(&sg, (void *)chap->challenge, CHAP_CHALLENGE_LENGTH); + sg_init_one(&sg, chap->challenge, CHAP_CHALLENGE_LENGTH); ret = crypto_hash_update(&desc, &sg, CHAP_CHALLENGE_LENGTH); if (ret < 0) { pr_err("crypto_hash_update() failed for challenge\n"); @@ -305,14 +306,17 @@ static int chap_server_compute_md5( } if (type == HEX) - id = (unsigned char)simple_strtoul((char *)&identifier[2], - &endptr, 0); + id = simple_strtoul(&identifier[2], &endptr, 0); else - id = (unsigned char)simple_strtoul(identifier, &endptr, 0); + id = simple_strtoul(identifier, &endptr, 0); + if (id > 255) { + pr_err("chap identifier: %lu greater than 255\n", id); + goto out; + } /* * RFC 1994 says Identifier is no more than octet (8 bits). */ - pr_debug("[server] Got CHAP_I=%d\n", id); + pr_debug("[server] Got CHAP_I=%lu\n", id); /* * Get CHAP_C. */ @@ -351,7 +355,7 @@ static int chap_server_compute_md5( goto out; } - sg_init_one(&sg, (void *)&id, 1); + sg_init_one(&sg, &id, 1); ret = crypto_hash_update(&desc, &sg, 1); if (ret < 0) { pr_err("crypto_hash_update() failed for id\n"); @@ -359,7 +363,7 @@ static int chap_server_compute_md5( goto out; } - sg_init_one(&sg, (void *)auth->password_mutual, + sg_init_one(&sg, auth->password_mutual, strlen(auth->password_mutual)); ret = crypto_hash_update(&desc, &sg, strlen(auth->password_mutual)); if (ret < 0) { @@ -371,7 +375,7 @@ static int chap_server_compute_md5( /* * Convert received challenge to binary hex. */ - sg_init_one(&sg, (void *)challenge_binhex, challenge_len); + sg_init_one(&sg, challenge_binhex, challenge_len); ret = crypto_hash_update(&desc, &sg, challenge_len); if (ret < 0) { pr_err("crypto_hash_update() failed for ma challenge\n"); @@ -414,7 +418,7 @@ static int chap_got_response( char *nr_out_ptr, unsigned int *nr_out_len) { - struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol; + struct iscsi_chap *chap = conn->auth_protocol; switch (chap->digest_type) { case CHAP_DIGEST_MD5: @@ -437,7 +441,7 @@ u32 chap_main_loop( int *in_len, int *out_len) { - struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol; + struct iscsi_chap *chap = conn->auth_protocol; if (!chap) { chap = chap_server_open(conn, auth, in_text, out_text, out_len); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index db327845e46b..3468caab47a2 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -22,12 +22,8 @@ #include <linux/configfs.h> #include <linux/export.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_fabric_configfs.h> -#include <target/target_core_fabric_lib.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> #include <target/target_core_configfs.h> #include <target/configfs_macros.h> @@ -56,8 +52,7 @@ struct iscsi_portal_group *lio_get_tpg_from_tpg_item( { struct se_portal_group *se_tpg = container_of(to_config_group(item), struct se_portal_group, tpg_group); - struct iscsi_portal_group *tpg = - (struct iscsi_portal_group *)se_tpg->se_tpg_fabric_ptr; + struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; int ret; if (!tpg) { @@ -1225,7 +1220,7 @@ struct se_portal_group *lio_target_tiqn_addtpg( ret = core_tpg_register( &lio_target_fabric_configfs->tf_ops, - wwn, &tpg->tpg_se_tpg, (void *)tpg, + wwn, &tpg->tpg_se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) return NULL; diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c index a19fa5eea88e..f63ea35bc4ae 100644 --- a/drivers/target/iscsi/iscsi_target_device.c +++ b/drivers/target/iscsi/iscsi_target_device.c @@ -21,8 +21,7 @@ #include <scsi/scsi_device.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> +#include <target/target_core_fabric.h> #include "iscsi_target_core.h" #include "iscsi_target_device.h" diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index b7ffc3cd40cc..478451167b62 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -21,7 +21,7 @@ #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> +#include <target/target_core_fabric.h> #include "iscsi_target_core.h" #include "iscsi_target_seq_pdu_list.h" diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 101b1beb3bca..255c0d67e898 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -21,7 +21,7 @@ #include <linux/list.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> +#include <target/target_core_fabric.h> #include "iscsi_target_core.h" #include "iscsi_target_seq_pdu_list.h" diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 0b8404c30125..1af1f21af21f 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -21,7 +21,7 @@ #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> +#include <target/target_core_fabric.h> #include "iscsi_target_core.h" #include "iscsi_target_datain_values.h" diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index d734bdec24f9..373b0cc6abd8 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -23,7 +23,7 @@ #include <linux/crypto.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> +#include <target/target_core_fabric.h> #include "iscsi_target_core.h" #include "iscsi_target_tq.h" @@ -143,7 +143,7 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn) list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list, sess_list) { - sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess_p = se_sess->fabric_sess_ptr; spin_lock(&sess_p->conn_lock); if (atomic_read(&sess_p->session_fall_back_to_erl0) || atomic_read(&sess_p->session_logout) || @@ -151,9 +151,9 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn) spin_unlock(&sess_p->conn_lock); continue; } - if (!memcmp((void *)sess_p->isid, (void *)conn->sess->isid, 6) && - (!strcmp((void *)sess_p->sess_ops->InitiatorName, - (void *)initiatorname_param->value) && + if (!memcmp(sess_p->isid, conn->sess->isid, 6) && + (!strcmp(sess_p->sess_ops->InitiatorName, + initiatorname_param->value) && (sess_p->sess_ops->SessionType == sessiontype))) { atomic_set(&sess_p->session_reinstatement, 1); spin_unlock(&sess_p->conn_lock); @@ -229,7 +229,7 @@ static int iscsi_login_zero_tsih_s1( iscsi_login_set_conn_values(sess, conn, pdu->cid); sess->init_task_tag = pdu->itt; - memcpy((void *)&sess->isid, (void *)pdu->isid, 6); + memcpy(&sess->isid, pdu->isid, 6); sess->exp_cmd_sn = pdu->cmdsn; INIT_LIST_HEAD(&sess->sess_conn_list); INIT_LIST_HEAD(&sess->sess_ooo_cmdsn_list); @@ -440,8 +440,7 @@ static int iscsi_login_non_zero_tsih_s2( atomic_read(&sess_p->session_logout) || (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) continue; - if (!memcmp((const void *)sess_p->isid, - (const void *)pdu->isid, 6) && + if (!memcmp(sess_p->isid, pdu->isid, 6) && (sess_p->tsih == pdu->tsih)) { iscsit_inc_session_usage_count(sess_p); iscsit_stop_time2retain_timer(sess_p); @@ -654,7 +653,7 @@ static int iscsi_post_login_handler( spin_lock_bh(&se_tpg->session_lock); __transport_register_session(&sess->tpg->tpg_se_tpg, - se_sess->se_node_acl, se_sess, (void *)sess); + se_sess->se_node_acl, se_sess, sess); pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n"); sess->session_state = TARG_SESS_STATE_LOGGED_IN; @@ -811,7 +810,7 @@ int iscsi_target_setup_login_socket( * Setup the np->np_sockaddr from the passed sockaddr setup * in iscsi_target_configfs.c code.. */ - memcpy((void *)&np->np_sockaddr, (void *)sockaddr, + memcpy(&np->np_sockaddr, sockaddr, sizeof(struct __kernel_sockaddr_storage)); if (sockaddr->ss_family == AF_INET6) @@ -821,6 +820,7 @@ int iscsi_target_setup_login_socket( /* * Set SO_REUSEADDR, and disable Nagel Algorithm with TCP_NODELAY. */ + /* FIXME: Someone please explain why this is endian-safe */ opt = 1; if (np->np_network_transport == ISCSI_TCP) { ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, @@ -832,6 +832,7 @@ int iscsi_target_setup_login_socket( } } + /* FIXME: Someone please explain why this is endian-safe */ ret = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); if (ret < 0) { @@ -1206,7 +1207,7 @@ out: int iscsi_target_login_thread(void *arg) { - struct iscsi_np *np = (struct iscsi_np *)arg; + struct iscsi_np *np = arg; int ret; allow_signal(SIGINT); diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 98936cb7c294..e89fa7457254 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -21,7 +21,7 @@ #include <linux/ctype.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_tpg.h> +#include <target/target_core_fabric.h> #include "iscsi_target_core.h" #include "iscsi_target_parameters.h" @@ -732,7 +732,7 @@ static void iscsi_initiatorname_tolower( u32 iqn_size = strlen(param_buf), i; for (i = 0; i < iqn_size; i++) { - c = (char *)¶m_buf[i]; + c = ¶m_buf[i]; if (!isupper(*c)) continue; diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.c b/drivers/target/iscsi/iscsi_target_nodeattrib.c index aeafbe0cd7d1..b3c699c4fe8c 100644 --- a/drivers/target/iscsi/iscsi_target_nodeattrib.c +++ b/drivers/target/iscsi/iscsi_target_nodeattrib.c @@ -19,7 +19,6 @@ ******************************************************************************/ #include <target/target_core_base.h> -#include <target/target_core_transport.h> #include "iscsi_target_core.h" #include "iscsi_target_device.h" @@ -135,7 +134,7 @@ extern int iscsit_na_nopin_timeout( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; spin_lock(&sess->conn_lock); list_for_each_entry(conn, &sess->sess_conn_list, diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index f1db83077e0a..421d6947dc64 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -23,7 +23,6 @@ #include <linux/export.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> #include <target/configfs_macros.h> #include "iscsi_target_core.h" @@ -746,7 +745,7 @@ static ssize_t iscsi_stat_sess_show_attr_node( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; if (sess) ret = snprintf(page, PAGE_SIZE, "%u\n", sess->sess_ops->SessionType ? 0 : ISCSI_NODE_INDEX); @@ -770,7 +769,7 @@ static ssize_t iscsi_stat_sess_show_attr_indx( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; if (sess) ret = snprintf(page, PAGE_SIZE, "%u\n", sess->session_index); @@ -794,7 +793,7 @@ static ssize_t iscsi_stat_sess_show_attr_cmd_pdus( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; if (sess) ret = snprintf(page, PAGE_SIZE, "%u\n", sess->cmd_pdus); } @@ -817,7 +816,7 @@ static ssize_t iscsi_stat_sess_show_attr_rsp_pdus( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; if (sess) ret = snprintf(page, PAGE_SIZE, "%u\n", sess->rsp_pdus); } @@ -840,7 +839,7 @@ static ssize_t iscsi_stat_sess_show_attr_txdata_octs( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; if (sess) ret = snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)sess->tx_data_octets); @@ -864,7 +863,7 @@ static ssize_t iscsi_stat_sess_show_attr_rxdata_octs( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; if (sess) ret = snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)sess->rx_data_octets); @@ -888,7 +887,7 @@ static ssize_t iscsi_stat_sess_show_attr_conn_digest_errors( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; if (sess) ret = snprintf(page, PAGE_SIZE, "%u\n", sess->conn_digest_errors); @@ -912,7 +911,7 @@ static ssize_t iscsi_stat_sess_show_attr_conn_timeout_errors( spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; + sess = se_sess->fabric_sess_ptr; if (sess) ret = snprintf(page, PAGE_SIZE, "%u\n", sess->conn_timeout_errors); diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index 490207eacde9..255ed35da815 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -21,7 +21,7 @@ #include <asm/unaligned.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> +#include <target/target_core_fabric.h> #include "iscsi_target_core.h" #include "iscsi_target_seq_pdu_list.h" diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index d4cf2cd25c44..879d8d0fa3fe 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -19,10 +19,8 @@ ******************************************************************************/ #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include <target/target_core_tpg.h> #include "iscsi_target_core.h" #include "iscsi_target_erl0.h" @@ -72,7 +70,7 @@ int iscsit_load_discovery_tpg(void) ret = core_tpg_register( &lio_target_fabric_configfs->tf_ops, - NULL, &tpg->tpg_se_tpg, (void *)tpg, + NULL, &tpg->tpg_se_tpg, tpg, TRANSPORT_TPG_TYPE_DISCOVERY); if (ret < 0) { kfree(tpg); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 02348f727bd4..a05ca1c4f01c 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -22,9 +22,7 @@ #include <scsi/scsi_tcq.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_tmr.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> #include "iscsi_target_core.h" @@ -289,7 +287,7 @@ struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr( } se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, - (void *)cmd->tmr_req, tcm_function, + cmd->tmr_req, tcm_function, GFP_KERNEL); if (!se_cmd->se_tmr_req) goto out; @@ -1066,7 +1064,7 @@ static void iscsit_handle_nopin_response_timeout(unsigned long data) if (tiqn) { spin_lock_bh(&tiqn->sess_err_stats.lock); strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, - (void *)conn->sess->sess_ops->InitiatorName); + conn->sess->sess_ops->InitiatorName); tiqn->sess_err_stats.last_sess_failure_type = ISCSI_SESS_ERR_CXN_TIMEOUT; tiqn->sess_err_stats.cxn_timeout_errors++; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 81d5832fbbd5..c47ff7f59e57 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -33,14 +33,9 @@ #include <scsi/scsi_cmnd.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_fabric_configfs.h> -#include <target/target_core_fabric_lib.h> #include <target/target_core_configfs.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> -#include <target/target_core_tmr.h> #include "tcm_loop.h" @@ -421,11 +416,11 @@ static struct scsi_host_template tcm_loop_driver_template = { .queuecommand = tcm_loop_queuecommand, .change_queue_depth = tcm_loop_change_queue_depth, .eh_device_reset_handler = tcm_loop_device_reset, - .can_queue = TL_SCSI_CAN_QUEUE, + .can_queue = 1024, .this_id = -1, - .sg_tablesize = TL_SCSI_SG_TABLESIZE, - .cmd_per_lun = TL_SCSI_CMD_PER_LUN, - .max_sectors = TL_SCSI_MAX_SECTORS, + .sg_tablesize = 256, + .cmd_per_lun = 1024, + .max_sectors = 0xFFFF, .use_clustering = DISABLE_CLUSTERING, .slave_alloc = tcm_loop_slave_alloc, .slave_configure = tcm_loop_slave_configure, @@ -564,8 +559,7 @@ static char *tcm_loop_get_fabric_name(void) static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) { - struct tcm_loop_tpg *tl_tpg = - (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; /* * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba() @@ -592,8 +586,7 @@ static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) { - struct tcm_loop_tpg *tl_tpg = - (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; /* * Return the passed NAA identifier for the SAS Target Port */ @@ -602,8 +595,7 @@ static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg) { - struct tcm_loop_tpg *tl_tpg = - (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; /* * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83 * to represent the SCSI Target Port. @@ -623,8 +615,7 @@ static u32 tcm_loop_get_pr_transport_id( int *format_code, unsigned char *buf) { - struct tcm_loop_tpg *tl_tpg = - (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; switch (tl_hba->tl_proto_id) { @@ -653,8 +644,7 @@ static u32 tcm_loop_get_pr_transport_id_len( struct t10_pr_registration *pr_reg, int *format_code) { - struct tcm_loop_tpg *tl_tpg = - (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; switch (tl_hba->tl_proto_id) { @@ -687,8 +677,7 @@ static char *tcm_loop_parse_pr_out_transport_id( u32 *out_tid_len, char **port_nexus_ptr) { - struct tcm_loop_tpg *tl_tpg = - (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_tpg *tl_tpg = se_tpg->se_tpg_fabric_ptr; struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; switch (tl_hba->tl_proto_id) { diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 6b76c7a22bb0..15a036441471 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -1,16 +1,7 @@ #define TCM_LOOP_VERSION "v2.1-rc1" #define TL_WWN_ADDR_LEN 256 #define TL_TPGS_PER_HBA 32 -/* - * Defaults for struct scsi_host_template tcm_loop_driver_template - * - * We use large can_queue and cmd_per_lun here and let TCM enforce - * the underlying se_device_t->queue_depth. - */ -#define TL_SCSI_CAN_QUEUE 1024 -#define TL_SCSI_CMD_PER_LUN 1024 -#define TL_SCSI_MAX_SECTORS 1024 -#define TL_SCSI_SG_TABLESIZE 256 + /* * Used in tcm_loop_driver_probe() for struct Scsi_Host->max_cmd_len */ diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 1dcbef499d6a..1b1edd14f4bf 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -32,13 +32,12 @@ #include <scsi/scsi_cmnd.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> +#include "target_core_internal.h" #include "target_core_alua.h" -#include "target_core_hba.h" #include "target_core_ua.h" static int core_alua_check_transition(int state, int *primary); diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 831468b3163d..2f2235edefff 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -29,10 +29,11 @@ #include <scsi/scsi.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> + +#include "target_core_internal.h" #include "target_core_ua.h" -#include "target_core_cdb.h" static void target_fill_alua_data(struct se_port *port, unsigned char *buf) @@ -94,6 +95,18 @@ target_emulate_inquiry_std(struct se_cmd *cmd) buf[2] = dev->transport->get_device_rev(dev); /* + * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2 + * + * SPC4 says: + * A RESPONSE DATA FORMAT field set to 2h indicates that the + * standard INQUIRY data is in the format defined in this + * standard. Response data format values less than 2h are + * obsolete. Response data format values greater than 2h are + * reserved. + */ + buf[3] = 2; + + /* * Enable SCCS and TPGS fields for Emulated ALUA */ if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) @@ -115,11 +128,9 @@ target_emulate_inquiry_std(struct se_cmd *cmd) goto out; } - snprintf((unsigned char *)&buf[8], 8, "LIO-ORG"); - snprintf((unsigned char *)&buf[16], 16, "%s", - &dev->se_sub_dev->t10_wwn.model[0]); - snprintf((unsigned char *)&buf[32], 4, "%s", - &dev->se_sub_dev->t10_wwn.revision[0]); + snprintf(&buf[8], 8, "LIO-ORG"); + snprintf(&buf[16], 16, "%s", dev->se_sub_dev->t10_wwn.model); + snprintf(&buf[32], 4, "%s", dev->se_sub_dev->t10_wwn.revision); buf[4] = 31; /* Set additional length to 31 */ out: @@ -138,8 +149,7 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) SDF_EMULATED_VPD_UNIT_SERIAL) { u32 unit_serial_len; - unit_serial_len = - strlen(&dev->se_sub_dev->t10_wwn.unit_serial[0]); + unit_serial_len = strlen(dev->se_sub_dev->t10_wwn.unit_serial); unit_serial_len++; /* For NULL Terminator */ if (((len + 4) + unit_serial_len) > cmd->data_length) { @@ -148,8 +158,8 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) buf[3] = (len & 0xff); return 0; } - len += sprintf((unsigned char *)&buf[4], "%s", - &dev->se_sub_dev->t10_wwn.unit_serial[0]); + len += sprintf(&buf[4], "%s", + dev->se_sub_dev->t10_wwn.unit_serial); len++; /* Extra Byte for NULL Terminator */ buf[3] = len; } @@ -279,14 +289,13 @@ check_t10_vend_desc: len += (prod_len + unit_serial_len); goto check_port; } - id_len += sprintf((unsigned char *)&buf[off+12], - "%s:%s", prod, + id_len += sprintf(&buf[off+12], "%s:%s", prod, &dev->se_sub_dev->t10_wwn.unit_serial[0]); } buf[off] = 0x2; /* ASCII */ buf[off+1] = 0x1; /* T10 Vendor ID */ buf[off+2] = 0x0; - memcpy((unsigned char *)&buf[off+4], "LIO-ORG", 8); + memcpy(&buf[off+4], "LIO-ORG", 8); /* Extra Byte for NULL Terminator */ id_len++; /* Identifier Length */ diff --git a/drivers/target/target_core_cdb.h b/drivers/target/target_core_cdb.h deleted file mode 100644 index ad6b1e393001..000000000000 --- a/drivers/target/target_core_cdb.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef TARGET_CORE_CDB_H -#define TARGET_CORE_CDB_H - -int target_emulate_inquiry(struct se_task *task); -int target_emulate_readcapacity(struct se_task *task); -int target_emulate_readcapacity_16(struct se_task *task); -int target_emulate_modesense(struct se_task *task); -int target_emulate_request_sense(struct se_task *task); -int target_emulate_unmap(struct se_task *task); -int target_emulate_write_same(struct se_task *task); -int target_emulate_synchronize_cache(struct se_task *task); -int target_emulate_noop(struct se_task *task); - -#endif /* TARGET_CORE_CDB_H */ diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 93d4f6a1b798..0955bb8979fb 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -39,18 +39,16 @@ #include <linux/spinlock.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> #include <target/target_core_fabric_configfs.h> #include <target/target_core_configfs.h> #include <target/configfs_macros.h> +#include "target_core_internal.h" #include "target_core_alua.h" -#include "target_core_hba.h" #include "target_core_pr.h" #include "target_core_rd.h" -#include "target_core_stat.h" extern struct t10_alua_lu_gp *default_lu_gp; @@ -1452,7 +1450,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( return -ENOMEM; orig = opts; - while ((ptr = strsep(&opts, ",")) != NULL) { + while ((ptr = strsep(&opts, ",\n")) != NULL) { if (!*ptr) continue; @@ -1631,7 +1629,7 @@ static struct config_item_type target_core_dev_pr_cit = { static ssize_t target_core_show_dev_info(void *p, char *page) { - struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *se_dev = p; struct se_hba *hba = se_dev->se_dev_hba; struct se_subsystem_api *t = hba->transport; int bl = 0; @@ -1659,7 +1657,7 @@ static ssize_t target_core_store_dev_control( const char *page, size_t count) { - struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *se_dev = p; struct se_hba *hba = se_dev->se_dev_hba; struct se_subsystem_api *t = hba->transport; @@ -1682,7 +1680,7 @@ static struct target_core_configfs_attribute target_core_attr_dev_control = { static ssize_t target_core_show_dev_alias(void *p, char *page) { - struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *se_dev = p; if (!(se_dev->su_dev_flags & SDF_USING_ALIAS)) return 0; @@ -1695,7 +1693,7 @@ static ssize_t target_core_store_dev_alias( const char *page, size_t count) { - struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *se_dev = p; struct se_hba *hba = se_dev->se_dev_hba; ssize_t read_bytes; @@ -1710,6 +1708,9 @@ static ssize_t target_core_store_dev_alias( read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN, "%s", page); + if (se_dev->se_dev_alias[read_bytes - 1] == '\n') + se_dev->se_dev_alias[read_bytes - 1] = '\0'; + pr_debug("Target_Core_ConfigFS: %s/%s set alias: %s\n", config_item_name(&hba->hba_group.cg_item), config_item_name(&se_dev->se_dev_group.cg_item), @@ -1728,7 +1729,7 @@ static struct target_core_configfs_attribute target_core_attr_dev_alias = { static ssize_t target_core_show_dev_udev_path(void *p, char *page) { - struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *se_dev = p; if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) return 0; @@ -1741,7 +1742,7 @@ static ssize_t target_core_store_dev_udev_path( const char *page, size_t count) { - struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *se_dev = p; struct se_hba *hba = se_dev->se_dev_hba; ssize_t read_bytes; @@ -1756,6 +1757,9 @@ static ssize_t target_core_store_dev_udev_path( read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN, "%s", page); + if (se_dev->se_dev_udev_path[read_bytes - 1] == '\n') + se_dev->se_dev_udev_path[read_bytes - 1] = '\0'; + pr_debug("Target_Core_ConfigFS: %s/%s set udev_path: %s\n", config_item_name(&hba->hba_group.cg_item), config_item_name(&se_dev->se_dev_group.cg_item), @@ -1777,7 +1781,7 @@ static ssize_t target_core_store_dev_enable( const char *page, size_t count) { - struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *se_dev = p; struct se_device *dev; struct se_hba *hba = se_dev->se_dev_hba; struct se_subsystem_api *t = hba->transport; @@ -1822,7 +1826,7 @@ static struct target_core_configfs_attribute target_core_attr_dev_enable = { static ssize_t target_core_show_alua_lu_gp(void *p, char *page) { struct se_device *dev; - struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *su_dev = p; struct config_item *lu_ci; struct t10_alua_lu_gp *lu_gp; struct t10_alua_lu_gp_member *lu_gp_mem; @@ -1860,7 +1864,7 @@ static ssize_t target_core_store_alua_lu_gp( size_t count) { struct se_device *dev; - struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p; + struct se_subsystem_dev *su_dev = p; struct se_hba *hba = su_dev->se_dev_hba; struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL; struct t10_alua_lu_gp_member *lu_gp_mem; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 9b8639425472..0c5992f0d946 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -42,13 +42,11 @@ #include <scsi/scsi_device.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> +#include "target_core_internal.h" #include "target_core_alua.h" -#include "target_core_hba.h" #include "target_core_pr.h" #include "target_core_ua.h" @@ -1134,8 +1132,6 @@ int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag) */ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) { - u32 orig_queue_depth = dev->queue_depth; - if (atomic_read(&dev->dev_export_obj.obj_access_count)) { pr_err("dev[%p]: Unable to change SE Device TCQ while" " dev_export_obj: %d count exists\n", dev, @@ -1169,11 +1165,6 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) } dev->se_sub_dev->se_dev_attrib.queue_depth = dev->queue_depth = queue_depth; - if (queue_depth > orig_queue_depth) - atomic_add(queue_depth - orig_queue_depth, &dev->depth_left); - else if (queue_depth < orig_queue_depth) - atomic_sub(orig_queue_depth - queue_depth, &dev->depth_left); - pr_debug("dev[%p]: SE Device TCQ Depth changed to: %u\n", dev, queue_depth); return 0; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 09b6f8729f91..4f77cce22646 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -36,18 +36,14 @@ #include <linux/configfs.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_fabric_configfs.h> #include <target/target_core_configfs.h> #include <target/configfs_macros.h> +#include "target_core_internal.h" #include "target_core_alua.h" -#include "target_core_hba.h" #include "target_core_pr.h" -#include "target_core_stat.h" #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index ec4249be617e..283a36e464e6 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -34,13 +34,10 @@ #include <scsi/scsi_cmnd.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_lib.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include "target_core_hba.h" +#include "target_core_internal.h" #include "target_core_pr.h" /* @@ -402,7 +399,7 @@ char *iscsi_parse_pr_out_transport_id( add_len = ((buf[2] >> 8) & 0xff); add_len |= (buf[3] & 0xff); - tid_len = strlen((char *)&buf[4]); + tid_len = strlen(&buf[4]); tid_len += 4; /* Add four bytes for iSCSI Transport ID header */ tid_len += 1; /* Add one byte for NULL terminator */ padding = ((-tid_len) & 3); @@ -423,11 +420,11 @@ char *iscsi_parse_pr_out_transport_id( * format. */ if (format_code == 0x40) { - p = strstr((char *)&buf[4], ",i,0x"); + p = strstr(&buf[4], ",i,0x"); if (!p) { pr_err("Unable to locate \",i,0x\" seperator" " for Initiator port identifier: %s\n", - (char *)&buf[4]); + &buf[4]); return NULL; } *p = '\0'; /* Terminate iSCSI Name */ diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index b4864fba4ef0..7ed58e2df791 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -37,8 +37,7 @@ #include <scsi/scsi_host.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> +#include <target/target_core_backend.h> #include "target_core_file.h" @@ -86,7 +85,7 @@ static void fd_detach_hba(struct se_hba *hba) static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name) { struct fd_dev *fd_dev; - struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr; + struct fd_host *fd_host = hba->hba_ptr; fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL); if (!fd_dev) { @@ -114,8 +113,8 @@ static struct se_device *fd_create_virtdevice( struct se_device *dev; struct se_dev_limits dev_limits; struct queue_limits *limits; - struct fd_dev *fd_dev = (struct fd_dev *) p; - struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr; + struct fd_dev *fd_dev = p; + struct fd_host *fd_host = hba->hba_ptr; mm_segment_t old_fs; struct file *file; struct inode *inode = NULL; @@ -240,7 +239,7 @@ fail: */ static void fd_free_device(void *p) { - struct fd_dev *fd_dev = (struct fd_dev *) p; + struct fd_dev *fd_dev = p; if (fd_dev->fd_file) { filp_close(fd_dev->fd_file, NULL); @@ -498,7 +497,7 @@ static ssize_t fd_set_configfs_dev_params( orig = opts; - while ((ptr = strsep(&opts, ",")) != NULL) { + while ((ptr = strsep(&opts, ",\n")) != NULL) { if (!*ptr) continue; @@ -559,7 +558,7 @@ out: static ssize_t fd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev) { - struct fd_dev *fd_dev = (struct fd_dev *) se_dev->se_dev_su_ptr; + struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) { pr_err("Missing fd_dev_name=\n"); diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index c68019d6c406..3dd1bd4b6f71 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -37,11 +37,10 @@ #include <net/tcp.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> -#include <target/target_core_transport.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> -#include "target_core_hba.h" +#include "target_core_internal.h" static LIST_HEAD(subsystem_list); static DEFINE_MUTEX(subsystem_mutex); diff --git a/drivers/target/target_core_hba.h b/drivers/target/target_core_hba.h deleted file mode 100644 index bb0fea5f730c..000000000000 --- a/drivers/target/target_core_hba.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef TARGET_CORE_HBA_H -#define TARGET_CORE_HBA_H - -extern struct se_hba *core_alloc_hba(const char *, u32, u32); -extern int core_delete_hba(struct se_hba *); - -#endif /* TARGET_CORE_HBA_H */ diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 4aa992204438..cc8e6b58ef20 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -42,8 +42,7 @@ #include <scsi/scsi_host.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> +#include <target/target_core_backend.h> #include "target_core_iblock.h" @@ -391,7 +390,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, orig = opts; - while ((ptr = strsep(&opts, ",")) != NULL) { + while ((ptr = strsep(&opts, ",\n")) != NULL) { if (!*ptr) continue; @@ -465,7 +464,7 @@ static ssize_t iblock_show_configfs_dev_params( if (bd) { bl += sprintf(b + bl, "Major: %d Minor: %d %s\n", MAJOR(bd->bd_dev), MINOR(bd->bd_dev), (!bd->bd_contains) ? - "" : (bd->bd_holder == (struct iblock_dev *)ibd) ? + "" : (bd->bd_holder == ibd) ? "CLAIMED: IBLOCK" : "CLAIMED: OS"); } else { bl += sprintf(b + bl, "Major: 0 Minor: 0\n"); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h new file mode 100644 index 000000000000..26f135e94f6e --- /dev/null +++ b/drivers/target/target_core_internal.h @@ -0,0 +1,123 @@ +#ifndef TARGET_CORE_INTERNAL_H +#define TARGET_CORE_INTERNAL_H + +/* target_core_alua.c */ +extern struct t10_alua_lu_gp *default_lu_gp; + +/* target_core_cdb.c */ +int target_emulate_inquiry(struct se_task *task); +int target_emulate_readcapacity(struct se_task *task); +int target_emulate_readcapacity_16(struct se_task *task); +int target_emulate_modesense(struct se_task *task); +int target_emulate_request_sense(struct se_task *task); +int target_emulate_unmap(struct se_task *task); +int target_emulate_write_same(struct se_task *task); +int target_emulate_synchronize_cache(struct se_task *task); +int target_emulate_noop(struct se_task *task); + +/* target_core_device.c */ +struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); +int core_free_device_list_for_node(struct se_node_acl *, + struct se_portal_group *); +void core_dec_lacl_count(struct se_node_acl *, struct se_cmd *); +void core_update_device_list_access(u32, u32, struct se_node_acl *); +int core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *, + u32, u32, struct se_node_acl *, struct se_portal_group *, int); +void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); +int core_dev_export(struct se_device *, struct se_portal_group *, + struct se_lun *); +void core_dev_unexport(struct se_device *, struct se_portal_group *, + struct se_lun *); +int target_report_luns(struct se_task *); +void se_release_device_for_hba(struct se_device *); +void se_release_vpd_for_dev(struct se_device *); +int se_free_virtual_device(struct se_device *, struct se_hba *); +int se_dev_check_online(struct se_device *); +int se_dev_check_shutdown(struct se_device *); +void se_dev_set_default_attribs(struct se_device *, struct se_dev_limits *); +int se_dev_set_task_timeout(struct se_device *, u32); +int se_dev_set_max_unmap_lba_count(struct se_device *, u32); +int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32); +int se_dev_set_unmap_granularity(struct se_device *, u32); +int se_dev_set_unmap_granularity_alignment(struct se_device *, u32); +int se_dev_set_emulate_dpo(struct se_device *, int); +int se_dev_set_emulate_fua_write(struct se_device *, int); +int se_dev_set_emulate_fua_read(struct se_device *, int); +int se_dev_set_emulate_write_cache(struct se_device *, int); +int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int); +int se_dev_set_emulate_tas(struct se_device *, int); +int se_dev_set_emulate_tpu(struct se_device *, int); +int se_dev_set_emulate_tpws(struct se_device *, int); +int se_dev_set_enforce_pr_isids(struct se_device *, int); +int se_dev_set_is_nonrot(struct se_device *, int); +int se_dev_set_emulate_rest_reord(struct se_device *dev, int); +int se_dev_set_queue_depth(struct se_device *, u32); +int se_dev_set_max_sectors(struct se_device *, u32); +int se_dev_set_optimal_sectors(struct se_device *, u32); +int se_dev_set_block_size(struct se_device *, u32); +struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *, + struct se_device *, u32); +int core_dev_del_lun(struct se_portal_group *, u32); +struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); +struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, + u32, char *, int *); +int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, + struct se_lun_acl *, u32, u32); +int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, + struct se_lun *, struct se_lun_acl *); +void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, + struct se_lun_acl *lacl); +int core_dev_setup_virtual_lun0(void); +void core_dev_release_virtual_lun0(void); + +/* target_core_hba.c */ +struct se_hba *core_alloc_hba(const char *, u32, u32); +int core_delete_hba(struct se_hba *); + +/* target_core_tmr.c */ +int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *, + struct list_head *, struct se_cmd *); + +/* target_core_tpg.c */ +extern struct se_device *g_lun0_dev; + +struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, + const char *); +struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, + unsigned char *); +void core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *); +void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *); +struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32); +int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, + u32, void *); +struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32, int *); +int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *); + +/* target_core_transport.c */ +extern struct kmem_cache *se_tmr_req_cache; + +int init_se_kmem_caches(void); +void release_se_kmem_caches(void); +u32 scsi_get_new_index(scsi_index_t); +void transport_subsystem_check_init(void); +void transport_cmd_finish_abort(struct se_cmd *, int); +void __transport_remove_task_from_execute_queue(struct se_task *, + struct se_device *); +unsigned char *transport_dump_cmd_direction(struct se_cmd *); +void transport_dump_dev_state(struct se_device *, char *, int *); +void transport_dump_dev_info(struct se_device *, struct se_lun *, + unsigned long long, char *, int *); +void transport_dump_vpd_proto_id(struct t10_vpd *, unsigned char *, int); +int transport_dump_vpd_assoc(struct t10_vpd *, unsigned char *, int); +int transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int); +int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); +bool target_stop_task(struct se_task *task, unsigned long *flags); +int transport_clear_lun_from_sessions(struct se_lun *); +void transport_send_task_abort(struct se_cmd *); + +/* target_core_stat.c */ +void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); +void target_stat_setup_port_default_groups(struct se_lun *); +void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); + +#endif /* TARGET_CORE_INTERNAL_H */ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 95dee7074aeb..429ad7291664 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -33,14 +33,11 @@ #include <asm/unaligned.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_tmr.h> -#include <target/target_core_tpg.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include "target_core_hba.h" +#include "target_core_internal.h" #include "target_core_pr.h" #include "target_core_ua.h" @@ -2984,21 +2981,6 @@ static void core_scsi3_release_preempt_and_abort( } } -int core_scsi3_check_cdb_abort_and_preempt( - struct list_head *preempt_and_abort_list, - struct se_cmd *cmd) -{ - struct t10_pr_registration *pr_reg, *pr_reg_tmp; - - list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list, - pr_reg_abort_list) { - if (pr_reg->pr_res_key == cmd->pr_res_key) - return 0; - } - - return 1; -} - static int core_scsi3_pro_preempt( struct se_cmd *cmd, int type, diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index b97f6940dd05..7a233feb7e99 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -60,8 +60,6 @@ extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *, struct se_node_acl *); extern void core_scsi3_free_all_registrations(struct se_device *); extern unsigned char *core_scsi3_pr_dump_type(int); -extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *, - struct se_cmd *); extern int target_scsi3_emulate_pr_in(struct se_task *task); extern int target_scsi3_emulate_pr_out(struct se_task *task); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 8b15e56b0384..d35467d42e12 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -44,8 +44,7 @@ #include <scsi/scsi_tcq.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> +#include <target/target_core_backend.h> #include "target_core_pscsi.h" @@ -105,7 +104,7 @@ static void pscsi_detach_hba(struct se_hba *hba) static int pscsi_pmode_enable_hba(struct se_hba *hba, unsigned long mode_flag) { - struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr; + struct pscsi_hba_virt *phv = hba->hba_ptr; struct Scsi_Host *sh = phv->phv_lld_host; /* * Release the struct Scsi_Host @@ -351,7 +350,6 @@ static struct se_device *pscsi_add_device_to_list( * scsi_device_put() and the pdv->pdv_sd cleared. */ pdv->pdv_sd = sd; - dev = transport_add_device_to_core_hba(hba, &pscsi_template, se_dev, dev_flags, pdv, &dev_limits, NULL, NULL); @@ -406,7 +404,7 @@ static struct se_device *pscsi_create_type_disk( __releases(sh->host_lock) { struct se_device *dev; - struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; + struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; struct Scsi_Host *sh = sd->host; struct block_device *bd; u32 dev_flags = 0; @@ -454,7 +452,7 @@ static struct se_device *pscsi_create_type_rom( __releases(sh->host_lock) { struct se_device *dev; - struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; + struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; struct Scsi_Host *sh = sd->host; u32 dev_flags = 0; @@ -489,7 +487,7 @@ static struct se_device *pscsi_create_type_other( __releases(sh->host_lock) { struct se_device *dev; - struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; + struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr; struct Scsi_Host *sh = sd->host; u32 dev_flags = 0; @@ -510,10 +508,10 @@ static struct se_device *pscsi_create_virtdevice( struct se_subsystem_dev *se_dev, void *p) { - struct pscsi_dev_virt *pdv = (struct pscsi_dev_virt *)p; + struct pscsi_dev_virt *pdv = p; struct se_device *dev; struct scsi_device *sd; - struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr; + struct pscsi_hba_virt *phv = hba->hba_ptr; struct Scsi_Host *sh = phv->phv_lld_host; int legacy_mode_enable = 0; @@ -818,7 +816,7 @@ static ssize_t pscsi_set_configfs_dev_params(struct se_hba *hba, orig = opts; - while ((ptr = strsep(&opts, ",")) != NULL) { + while ((ptr = strsep(&opts, ",\n")) != NULL) { if (!*ptr) continue; @@ -1144,7 +1142,7 @@ static unsigned char *pscsi_get_sense_buffer(struct se_task *task) { struct pscsi_plugin_task *pt = PSCSI_TASK(task); - return (unsigned char *)&pt->pscsi_sense[0]; + return pt->pscsi_sense; } /* pscsi_get_device_rev(): diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 02e51faa2f4e..8b68f7b82631 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -37,9 +37,7 @@ #include <scsi/scsi_host.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> #include "target_core_rd.h" @@ -474,7 +472,7 @@ static ssize_t rd_set_configfs_dev_params( orig = opts; - while ((ptr = strsep(&opts, ",")) != NULL) { + while ((ptr = strsep(&opts, ",\n")) != NULL) { if (!*ptr) continue; diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 874152aed94a..f8c2d2cc3431 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -43,12 +43,12 @@ #include <scsi/scsi_host.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> #include <target/configfs_macros.h> -#include "target_core_hba.h" +#include "target_core_internal.h" #ifndef INITIAL_JIFFIES #define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) @@ -1755,8 +1755,7 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident( /* scsiAttIntrPortName+scsiAttIntrPortIdentifier */ memset(buf, 0, 64); if (tpg->se_tpg_tfo->sess_get_initiator_sid != NULL) - tpg->se_tpg_tfo->sess_get_initiator_sid(se_sess, - (unsigned char *)&buf[0], 64); + tpg->se_tpg_tfo->sess_get_initiator_sid(se_sess, buf, 64); ret = snprintf(page, PAGE_SIZE, "%s+i+%s\n", nacl->initiatorname, buf); spin_unlock_irq(&nacl->nacl_sess_lock); diff --git a/drivers/target/target_core_stat.h b/drivers/target/target_core_stat.h deleted file mode 100644 index 86c252f9ea47..000000000000 --- a/drivers/target/target_core_stat.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef TARGET_CORE_STAT_H -#define TARGET_CORE_STAT_H - -extern void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); -extern void target_stat_setup_port_default_groups(struct se_lun *); -extern void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); - -#endif /*** TARGET_CORE_STAT_H ***/ diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 684522805a1f..dcb0618c9388 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -32,12 +32,11 @@ #include <scsi/scsi_cmnd.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_tmr.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> +#include "target_core_internal.h" #include "target_core_alua.h" #include "target_core_pr.h" @@ -101,6 +100,21 @@ static void core_tmr_handle_tas_abort( transport_cmd_finish_abort(cmd, 0); } +static int target_check_cdb_and_preempt(struct list_head *list, + struct se_cmd *cmd) +{ + struct t10_pr_registration *reg; + + if (!list) + return 0; + list_for_each_entry(reg, list, pr_reg_abort_list) { + if (reg->pr_res_key == cmd->pr_res_key) + return 0; + } + + return 1; +} + static void core_tmr_drain_tmr_list( struct se_device *dev, struct se_tmr_req *tmr, @@ -132,9 +146,7 @@ static void core_tmr_drain_tmr_list( * parameter (eg: for PROUT PREEMPT_AND_ABORT service action * skip non regisration key matching TMRs. */ - if (preempt_and_abort_list && - (core_scsi3_check_cdb_abort_and_preempt( - preempt_and_abort_list, cmd) != 0)) + if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd)) continue; spin_lock(&cmd->t_state_lock); @@ -211,9 +223,7 @@ static void core_tmr_drain_task_list( * For PREEMPT_AND_ABORT usage, only process commands * with a matching reservation key. */ - if (preempt_and_abort_list && - (core_scsi3_check_cdb_abort_and_preempt( - preempt_and_abort_list, cmd) != 0)) + if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd)) continue; /* * Not aborting PROUT PREEMPT_AND_ABORT CDB.. @@ -222,7 +232,7 @@ static void core_tmr_drain_task_list( continue; list_move_tail(&task->t_state_list, &drain_task_list); - atomic_set(&task->task_state_active, 0); + task->t_state_active = false; /* * Remove from task execute list before processing drain_task_list */ @@ -321,9 +331,7 @@ static void core_tmr_drain_cmd_list( * For PREEMPT_AND_ABORT usage, only process commands * with a matching reservation key. */ - if (preempt_and_abort_list && - (core_scsi3_check_cdb_abort_and_preempt( - preempt_and_abort_list, cmd) != 0)) + if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd)) continue; /* * Not aborting PROUT PREEMPT_AND_ABORT CDB.. diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 8ddd133025b9..b7668029bb31 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -39,13 +39,10 @@ #include <scsi/scsi_cmnd.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> -#include "target_core_hba.h" -#include "target_core_stat.h" +#include "target_core_internal.h" extern struct se_device *g_lun0_dev; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0257658e2e3e..d3ddd1361949 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -45,16 +45,12 @@ #include <scsi/scsi_tcq.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_tmr.h> -#include <target/target_core_tpg.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_backend.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> +#include "target_core_internal.h" #include "target_core_alua.h" -#include "target_core_cdb.h" -#include "target_core_hba.h" #include "target_core_pr.h" #include "target_core_ua.h" @@ -72,7 +68,7 @@ struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; static int transport_generic_write_pending(struct se_cmd *); static int transport_processing_thread(void *param); -static int __transport_execute_tasks(struct se_device *dev); +static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *); static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); @@ -212,14 +208,13 @@ u32 scsi_get_new_index(scsi_index_t type) return new_index; } -void transport_init_queue_obj(struct se_queue_obj *qobj) +static void transport_init_queue_obj(struct se_queue_obj *qobj) { atomic_set(&qobj->queue_cnt, 0); INIT_LIST_HEAD(&qobj->qobj_list); init_waitqueue_head(&qobj->thread_wq); spin_lock_init(&qobj->cmd_queue_lock); } -EXPORT_SYMBOL(transport_init_queue_obj); void transport_subsystem_check_init(void) { @@ -426,18 +421,18 @@ static void transport_all_task_dev_remove_state(struct se_cmd *cmd) if (task->task_flags & TF_ACTIVE) continue; - if (!atomic_read(&task->task_state_active)) - continue; - spin_lock_irqsave(&dev->execute_task_lock, flags); - list_del(&task->t_state_list); - pr_debug("Removed ITT: 0x%08x dev: %p task[%p]\n", - cmd->se_tfo->get_task_tag(cmd), dev, task); - spin_unlock_irqrestore(&dev->execute_task_lock, flags); + if (task->t_state_active) { + pr_debug("Removed ITT: 0x%08x dev: %p task[%p]\n", + cmd->se_tfo->get_task_tag(cmd), dev, task); - atomic_set(&task->task_state_active, 0); - atomic_dec(&cmd->t_task_cdbs_ex_left); + list_del(&task->t_state_list); + atomic_dec(&cmd->t_task_cdbs_ex_left); + task->t_state_active = false; + } + spin_unlock_irqrestore(&dev->execute_task_lock, flags); } + } /* transport_cmd_check_stop(): @@ -696,12 +691,6 @@ void transport_complete_task(struct se_task *task, int success) struct se_cmd *cmd = task->task_se_cmd; struct se_device *dev = cmd->se_dev; unsigned long flags; -#if 0 - pr_debug("task: %p CDB: 0x%02x obj_ptr: %p\n", task, - cmd->t_task_cdb[0], dev); -#endif - if (dev) - atomic_inc(&dev->depth_left); spin_lock_irqsave(&cmd->t_state_lock, flags); task->task_flags &= ~TF_ACTIVE; @@ -714,7 +703,7 @@ void transport_complete_task(struct se_task *task, int success) if (dev && dev->transport->transport_complete) { if (dev->transport->transport_complete(task) != 0) { cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE; - task->task_sense = 1; + task->task_flags |= TF_HAS_SENSE; success = 1; } } @@ -743,13 +732,7 @@ void transport_complete_task(struct se_task *task, int success) } if (cmd->t_tasks_failed) { - if (!task->task_error_status) { - task->task_error_status = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - cmd->scsi_sense_reason = - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } - + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; INIT_WORK(&cmd->work, target_complete_failure_work); } else { atomic_set(&cmd->t_transport_complete, 1); @@ -824,7 +807,7 @@ static void __transport_add_task_to_execute_queue( head_of_queue = transport_add_task_check_sam_attr(task, task_prev, dev); atomic_inc(&dev->execute_tasks); - if (atomic_read(&task->task_state_active)) + if (task->t_state_active) return; /* * Determine if this task needs to go to HEAD_OF_QUEUE for the @@ -838,7 +821,7 @@ static void __transport_add_task_to_execute_queue( else list_add_tail(&task->t_state_list, &dev->state_task_list); - atomic_set(&task->task_state_active, 1); + task->t_state_active = true; pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n", task->task_se_cmd->se_tfo->get_task_tag(task->task_se_cmd), @@ -853,29 +836,26 @@ static void transport_add_tasks_to_state_queue(struct se_cmd *cmd) spin_lock_irqsave(&cmd->t_state_lock, flags); list_for_each_entry(task, &cmd->t_task_list, t_list) { - if (atomic_read(&task->task_state_active)) - continue; - spin_lock(&dev->execute_task_lock); - list_add_tail(&task->t_state_list, &dev->state_task_list); - atomic_set(&task->task_state_active, 1); - - pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n", - task->task_se_cmd->se_tfo->get_task_tag( - task->task_se_cmd), task, dev); - + if (!task->t_state_active) { + list_add_tail(&task->t_state_list, + &dev->state_task_list); + task->t_state_active = true; + + pr_debug("Added ITT: 0x%08x task[%p] to dev: %p\n", + task->task_se_cmd->se_tfo->get_task_tag( + task->task_se_cmd), task, dev); + } spin_unlock(&dev->execute_task_lock); } spin_unlock_irqrestore(&cmd->t_state_lock, flags); } -static void transport_add_tasks_from_cmd(struct se_cmd *cmd) +static void __transport_add_tasks_from_cmd(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_task *task, *task_prev = NULL; - unsigned long flags; - spin_lock_irqsave(&dev->execute_task_lock, flags); list_for_each_entry(task, &cmd->t_task_list, t_list) { if (!list_empty(&task->t_execute_list)) continue; @@ -886,6 +866,15 @@ static void transport_add_tasks_from_cmd(struct se_cmd *cmd) __transport_add_task_to_execute_queue(task, task_prev, dev); task_prev = task; } +} + +static void transport_add_tasks_from_cmd(struct se_cmd *cmd) +{ + unsigned long flags; + struct se_device *dev = cmd->se_dev; + + spin_lock_irqsave(&dev->execute_task_lock, flags); + __transport_add_tasks_from_cmd(cmd); spin_unlock_irqrestore(&dev->execute_task_lock, flags); } @@ -896,7 +885,7 @@ void __transport_remove_task_from_execute_queue(struct se_task *task, atomic_dec(&dev->execute_tasks); } -void transport_remove_task_from_execute_queue( +static void transport_remove_task_from_execute_queue( struct se_task *task, struct se_device *dev) { @@ -983,9 +972,8 @@ void transport_dump_dev_state( break; } - *bl += sprintf(b + *bl, " Execute/Left/Max Queue Depth: %d/%d/%d", - atomic_read(&dev->execute_tasks), atomic_read(&dev->depth_left), - dev->queue_depth); + *bl += sprintf(b + *bl, " Execute/Max Queue Depth: %d/%d", + atomic_read(&dev->execute_tasks), dev->queue_depth); *bl += sprintf(b + *bl, " SectorSize: %u MaxSectors: %u\n", dev->se_sub_dev->se_dev_attrib.block_size, dev->se_sub_dev->se_dev_attrib.max_sectors); *bl += sprintf(b + *bl, " "); @@ -1340,9 +1328,6 @@ struct se_device *transport_add_device_to_core_hba( spin_lock_init(&dev->se_port_lock); spin_lock_init(&dev->se_tmr_lock); spin_lock_init(&dev->qf_cmd_lock); - - dev->queue_depth = dev_limits->queue_depth; - atomic_set(&dev->depth_left, dev->queue_depth); atomic_set(&dev->dev_ordered_id, 0); se_dev_set_default_attribs(dev, dev_limits); @@ -1654,6 +1639,80 @@ int transport_handle_cdb_direct( } EXPORT_SYMBOL(transport_handle_cdb_direct); +/** + * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd + * + * @se_cmd: command descriptor to submit + * @se_sess: associated se_sess for endpoint + * @cdb: pointer to SCSI CDB + * @sense: pointer to SCSI sense buffer + * @unpacked_lun: unpacked LUN to reference for struct se_lun + * @data_length: fabric expected data transfer length + * @task_addr: SAM task attribute + * @data_dir: DMA data direction + * @flags: flags for command submission from target_sc_flags_tables + * + * This may only be called from process context, and also currently + * assumes internal allocation of fabric payload buffer by target-core. + **/ +int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, + unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, + u32 data_length, int task_attr, int data_dir, int flags) +{ + struct se_portal_group *se_tpg; + int rc; + + se_tpg = se_sess->se_tpg; + BUG_ON(!se_tpg); + BUG_ON(se_cmd->se_tfo || se_cmd->se_sess); + BUG_ON(in_interrupt()); + /* + * Initialize se_cmd for target operation. From this point + * exceptions are handled by sending exception status via + * target_core_fabric_ops->queue_status() callback + */ + transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, + data_length, data_dir, task_attr, sense); + /* + * Obtain struct se_cmd->cmd_kref reference and add new cmd to + * se_sess->sess_cmd_list. A second kref_get here is necessary + * for fabrics using TARGET_SCF_ACK_KREF that expect a second + * kref_put() to happen during fabric packet acknowledgement. + */ + target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + /* + * Signal bidirectional data payloads to target-core + */ + if (flags & TARGET_SCF_BIDI_OP) + se_cmd->se_cmd_flags |= SCF_BIDI; + /* + * Locate se_lun pointer and attach it to struct se_cmd + */ + if (transport_lookup_cmd_lun(se_cmd, unpacked_lun) < 0) + goto out_check_cond; + /* + * Sanitize CDBs via transport_generic_cmd_sequencer() and + * allocate the necessary tasks to complete the received CDB+data + */ + rc = transport_generic_allocate_tasks(se_cmd, cdb); + if (rc != 0) + goto out_check_cond; + /* + * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend + * for immediate execution of READs, otherwise wait for + * transport_generic_handle_data() to be called for WRITEs + * when fabric has filled the incoming buffer. + */ + transport_handle_cdb_direct(se_cmd); + return 0; + +out_check_cond: + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + return 0; +} +EXPORT_SYMBOL(target_submit_cmd); + /* * Used by fabric module frontends defining a TFO->new_cmd_map() caller * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to @@ -1920,18 +1979,6 @@ static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd) spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); } -static inline int transport_tcq_window_closed(struct se_device *dev) -{ - if (dev->dev_tcq_window_closed++ < - PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD) { - msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT); - } else - msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG); - - wake_up_interruptible(&dev->dev_queue_obj.thread_wq); - return 0; -} - /* * Called from Fabric Module context from transport_execute_tasks() * @@ -2014,13 +2061,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd) static int transport_execute_tasks(struct se_cmd *cmd) { int add_tasks; - - if (se_dev_check_online(cmd->se_dev) != 0) { - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - transport_generic_request_failure(cmd); - return 0; - } - + struct se_device *se_dev = cmd->se_dev; /* * Call transport_cmd_check_stop() to see if a fabric exception * has occurred that prevents execution. @@ -2034,19 +2075,16 @@ static int transport_execute_tasks(struct se_cmd *cmd) if (!add_tasks) goto execute_tasks; /* - * This calls transport_add_tasks_from_cmd() to handle - * HEAD_OF_QUEUE ordering for SAM Task Attribute emulation - * (if enabled) in __transport_add_task_to_execute_queue() and - * transport_add_task_check_sam_attr(). + * __transport_execute_tasks() -> __transport_add_tasks_from_cmd() + * adds associated se_tasks while holding dev->execute_task_lock + * before I/O dispath to avoid a double spinlock access. */ - transport_add_tasks_from_cmd(cmd); + __transport_execute_tasks(se_dev, cmd); + return 0; } - /* - * Kick the execution queue for the cmd associated struct se_device - * storage object. - */ + execute_tasks: - __transport_execute_tasks(cmd->se_dev); + __transport_execute_tasks(se_dev, NULL); return 0; } @@ -2056,24 +2094,18 @@ execute_tasks: * * Called from transport_processing_thread() */ -static int __transport_execute_tasks(struct se_device *dev) +static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *new_cmd) { int error; struct se_cmd *cmd = NULL; struct se_task *task = NULL; unsigned long flags; - /* - * Check if there is enough room in the device and HBA queue to send - * struct se_tasks to the selected transport. - */ check_depth: - if (!atomic_read(&dev->depth_left)) - return transport_tcq_window_closed(dev); - - dev->dev_tcq_window_closed = 0; - spin_lock_irq(&dev->execute_task_lock); + if (new_cmd != NULL) + __transport_add_tasks_from_cmd(new_cmd); + if (list_empty(&dev->execute_task_list)) { spin_unlock_irq(&dev->execute_task_lock); return 0; @@ -2083,10 +2115,7 @@ check_depth: __transport_remove_task_from_execute_queue(task, dev); spin_unlock_irq(&dev->execute_task_lock); - atomic_dec(&dev->depth_left); - cmd = task->task_se_cmd; - spin_lock_irqsave(&cmd->t_state_lock, flags); task->task_flags |= (TF_ACTIVE | TF_SENT); atomic_inc(&cmd->t_task_cdbs_sent); @@ -2107,10 +2136,10 @@ check_depth: spin_unlock_irqrestore(&cmd->t_state_lock, flags); atomic_set(&cmd->t_transport_sent, 0); transport_stop_tasks_for_cmd(cmd); - atomic_inc(&dev->depth_left); transport_generic_request_failure(cmd); } + new_cmd = NULL; goto check_depth; return 0; @@ -2351,7 +2380,7 @@ static int transport_get_sense_data(struct se_cmd *cmd) list_for_each_entry_safe(task, task_tmp, &cmd->t_task_list, t_list) { - if (!task->task_sense) + if (!(task->task_flags & TF_HAS_SENSE)) continue; if (!dev->transport->get_sense_buffer) { @@ -3346,6 +3375,32 @@ static inline void transport_free_pages(struct se_cmd *cmd) } /** + * transport_release_cmd - free a command + * @cmd: command to free + * + * This routine unconditionally frees a command, and reference counting + * or list removal must be done in the caller. + */ +static void transport_release_cmd(struct se_cmd *cmd) +{ + BUG_ON(!cmd->se_tfo); + + if (cmd->se_tmr_req) + core_tmr_release_req(cmd->se_tmr_req); + if (cmd->t_task_cdb != cmd->__t_task_cdb) + kfree(cmd->t_task_cdb); + /* + * If this cmd has been setup with target_get_sess_cmd(), drop + * the kref and call ->release_cmd() in kref callback. + */ + if (cmd->check_release != 0) { + target_put_sess_cmd(cmd->se_sess, cmd); + return; + } + cmd->se_tfo->release_cmd(cmd); +} + +/** * transport_put_cmd - release a reference to a command * @cmd: command to release * @@ -3870,33 +3925,6 @@ queue_full: return 0; } -/** - * transport_release_cmd - free a command - * @cmd: command to free - * - * This routine unconditionally frees a command, and reference counting - * or list removal must be done in the caller. - */ -void transport_release_cmd(struct se_cmd *cmd) -{ - BUG_ON(!cmd->se_tfo); - - if (cmd->se_tmr_req) - core_tmr_release_req(cmd->se_tmr_req); - if (cmd->t_task_cdb != cmd->__t_task_cdb) - kfree(cmd->t_task_cdb); - /* - * Check if target_wait_for_sess_cmds() is expecting to - * release se_cmd directly here.. - */ - if (cmd->check_release != 0 && cmd->se_tfo->check_release_cmd) - if (cmd->se_tfo->check_release_cmd(cmd) != 0) - return; - - cmd->se_tfo->release_cmd(cmd); -} -EXPORT_SYMBOL(transport_release_cmd); - void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { @@ -3923,11 +3951,22 @@ EXPORT_SYMBOL(transport_generic_free_cmd); /* target_get_sess_cmd - Add command to active ->sess_cmd_list * @se_sess: session to reference * @se_cmd: command descriptor to add + * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, + bool ack_kref) { unsigned long flags; + kref_init(&se_cmd->cmd_kref); + /* + * Add a second kref if the fabric caller is expecting to handle + * fabric acknowledgement that requires two target_put_sess_cmd() + * invocations before se_cmd descriptor release. + */ + if (ack_kref == true) + kref_get(&se_cmd->cmd_kref); + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); se_cmd->check_release = 1; @@ -3935,30 +3974,36 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) } EXPORT_SYMBOL(target_get_sess_cmd); -/* target_put_sess_cmd - Check for active I/O shutdown or list delete - * @se_sess: session to reference - * @se_cmd: command descriptor to drop - */ -int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +static void target_release_cmd_kref(struct kref *kref) { + struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); + struct se_session *se_sess = se_cmd->se_sess; unsigned long flags; spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (list_empty(&se_cmd->se_cmd_list)) { spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); WARN_ON(1); - return 0; + return; } - if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); complete(&se_cmd->cmd_wait_comp); - return 1; + return; } list_del(&se_cmd->se_cmd_list); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - return 0; + se_cmd->se_tfo->release_cmd(se_cmd); +} + +/* target_put_sess_cmd - Check for active I/O shutdown via kref_put + * @se_sess: session to reference + * @se_cmd: command descriptor to drop + */ +int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +{ + return kref_put(&se_cmd->cmd_kref, target_release_cmd_kref); } EXPORT_SYMBOL(target_put_sess_cmd); @@ -4174,7 +4219,7 @@ check_cond: static int transport_clear_lun_thread(void *p) { - struct se_lun *lun = (struct se_lun *)p; + struct se_lun *lun = p; __transport_clear_lun_from_sessions(lun); complete(&lun->lun_shutdown_comp); @@ -4353,6 +4398,7 @@ int transport_send_check_condition_and_sense( case TCM_NON_EXISTENT_LUN: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* LOGICAL UNIT NOT SUPPORTED */ @@ -4362,6 +4408,7 @@ int transport_send_check_condition_and_sense( case TCM_SECTOR_COUNT_TOO_MANY: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID COMMAND OPERATION CODE */ @@ -4370,6 +4417,7 @@ int transport_send_check_condition_and_sense( case TCM_UNKNOWN_MODE_PAGE: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN CDB */ @@ -4378,6 +4426,7 @@ int transport_send_check_condition_and_sense( case TCM_CHECK_CONDITION_ABORT_CMD: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* BUS DEVICE RESET FUNCTION OCCURRED */ @@ -4387,6 +4436,7 @@ int transport_send_check_condition_and_sense( case TCM_INCORRECT_AMOUNT_OF_DATA: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* WRITE ERROR */ @@ -4397,6 +4447,7 @@ int transport_send_check_condition_and_sense( case TCM_INVALID_CDB_FIELD: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* INVALID FIELD IN CDB */ @@ -4405,6 +4456,7 @@ int transport_send_check_condition_and_sense( case TCM_INVALID_PARAMETER_LIST: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* INVALID FIELD IN PARAMETER LIST */ @@ -4413,6 +4465,7 @@ int transport_send_check_condition_and_sense( case TCM_UNEXPECTED_UNSOLICITED_DATA: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* WRITE ERROR */ @@ -4423,6 +4476,7 @@ int transport_send_check_condition_and_sense( case TCM_SERVICE_CRC_ERROR: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* PROTOCOL SERVICE CRC ERROR */ @@ -4433,6 +4487,7 @@ int transport_send_check_condition_and_sense( case TCM_SNACK_REJECTED: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* READ ERROR */ @@ -4443,6 +4498,7 @@ int transport_send_check_condition_and_sense( case TCM_WRITE_PROTECTED: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* DATA PROTECT */ buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT; /* WRITE PROTECTED */ @@ -4451,6 +4507,7 @@ int transport_send_check_condition_and_sense( case TCM_CHECK_CONDITION_UNIT_ATTENTION: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* UNIT ATTENTION */ buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); @@ -4460,6 +4517,7 @@ int transport_send_check_condition_and_sense( case TCM_CHECK_CONDITION_NOT_READY: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* Not Ready */ buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY; transport_get_sense_codes(cmd, &asc, &ascq); @@ -4470,6 +4528,7 @@ int transport_send_check_condition_and_sense( default: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* LOGICAL UNIT COMMUNICATION FAILURE */ @@ -4545,11 +4604,7 @@ void transport_send_task_abort(struct se_cmd *cmd) cmd->se_tfo->queue_status(cmd); } -/* transport_generic_do_tmr(): - * - * - */ -int transport_generic_do_tmr(struct se_cmd *cmd) +static int transport_generic_do_tmr(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct se_tmr_req *tmr = cmd->se_tmr_req; @@ -4597,7 +4652,7 @@ static int transport_processing_thread(void *param) { int ret; struct se_cmd *cmd; - struct se_device *dev = (struct se_device *) param; + struct se_device *dev = param; while (!kthread_should_stop()) { ret = wait_event_interruptible(dev->dev_queue_obj.thread_wq, @@ -4607,8 +4662,6 @@ static int transport_processing_thread(void *param) goto out; get_cmd: - __transport_execute_tasks(dev); - cmd = transport_get_cmd_from_queue(&dev->dev_queue_obj); if (!cmd) continue; diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 50a480db7a66..3e12f6bcfa10 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -30,13 +30,11 @@ #include <scsi/scsi_cmnd.h> #include <target/target_core_base.h> -#include <target/target_core_device.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> +#include "target_core_internal.h" #include "target_core_alua.h" -#include "target_core_hba.h" #include "target_core_pr.h" #include "target_core_ua.h" diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 71fc9cea5dc9..addc18f727ea 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -39,12 +39,8 @@ #include <scsi/fc_encode.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> -#include <target/target_core_tmr.h> #include <target/configfs_macros.h> #include "tcm_fc.h" @@ -367,6 +363,11 @@ static void ft_send_tm(struct ft_cmd *cmd) struct ft_sess *sess; u8 tm_func; + transport_init_se_cmd(&cmd->se_cmd, &ft_configfs->tf_ops, + cmd->sess->se_sess, 0, DMA_NONE, 0, + &cmd->ft_sense_buffer[0]); + target_get_sess_cmd(cmd->sess->se_sess, &cmd->se_cmd, false); + fcp = fc_frame_payload_get(cmd->req_frame, sizeof(*fcp)); switch (fcp->fc_tm_flags) { @@ -420,7 +421,6 @@ static void ft_send_tm(struct ft_cmd *cmd) sess = cmd->sess; transport_send_check_condition_and_sense(&cmd->se_cmd, cmd->se_cmd.scsi_sense_reason, 0); - transport_generic_free_cmd(&cmd->se_cmd, 0); ft_sess_put(sess); return; } @@ -536,7 +536,6 @@ static void ft_send_work(struct work_struct *work) { struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); - struct se_cmd *se_cmd; struct fcp_cmnd *fcp; int data_dir = 0; u32 data_len; @@ -591,15 +590,6 @@ static void ft_send_work(struct work_struct *work) data_len = ntohl(fcp->fc_dl); cmd->cdb = fcp->fc_cdb; } - - se_cmd = &cmd->se_cmd; - /* - * Initialize struct se_cmd descriptor from target_core_mod - * infrastructure - */ - transport_init_se_cmd(se_cmd, &ft_configfs->tf_ops, cmd->sess->se_sess, - data_len, data_dir, task_attr, - &cmd->ft_sense_buffer[0]); /* * Check for FCP task management flags */ @@ -607,39 +597,20 @@ static void ft_send_work(struct work_struct *work) ft_send_tm(cmd); return; } - fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); - cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun); - ret = transport_lookup_cmd_lun(&cmd->se_cmd, cmd->lun); + /* + * Use a single se_cmd->cmd_kref as we expect to release se_cmd + * directly from ft_check_stop_free callback in response path. + */ + ret = target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, cmd->cdb, + &cmd->ft_sense_buffer[0], cmd->lun, data_len, + task_attr, data_dir, 0); + pr_debug("r_ctl %x alloc target_submit_cmd %d\n", fh->fh_r_ctl, ret); if (ret < 0) { ft_dump_cmd(cmd, __func__); - transport_send_check_condition_and_sense(&cmd->se_cmd, - cmd->se_cmd.scsi_sense_reason, 0); - return; - } - - ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb); - - pr_debug("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret); - ft_dump_cmd(cmd, __func__); - - if (ret == -ENOMEM) { - transport_send_check_condition_and_sense(se_cmd, - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); - transport_generic_free_cmd(se_cmd, 0); - return; - } - if (ret == -EINVAL) { - if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) - ft_queue_status(se_cmd); - else - transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); - transport_generic_free_cmd(se_cmd, 0); return; } - transport_handle_cdb_direct(se_cmd); return; err: diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 9402b7387cac..73852fbc857b 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -41,12 +41,8 @@ #include <scsi/libfc.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> +#include <target/target_core_fabric.h> #include <target/target_core_fabric_configfs.h> -#include <target/target_core_fabric_lib.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> #include <target/target_core_configfs.h> #include <target/configfs_macros.h> diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index 1369b1cb103d..d8cabc21036d 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -48,10 +48,7 @@ #include <scsi/fc_encode.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> #include <target/configfs_macros.h> diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 326921385aff..4c0507cf808c 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -40,10 +40,7 @@ #include <scsi/libfc.h> #include <target/target_core_base.h> -#include <target/target_core_transport.h> -#include <target/target_core_fabric_ops.h> -#include <target/target_core_device.h> -#include <target/target_core_tpg.h> +#include <target/target_core_fabric.h> #include <target/target_core_configfs.h> #include <target/configfs_macros.h> diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 6a1241c7f841..de88aa5566e5 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -118,7 +118,7 @@ static unsigned long board2; static unsigned long board3; static unsigned long board4; static unsigned long controller; -static int support_low_speed; +static bool support_low_speed; static unsigned long modem1; static unsigned long modem2; static unsigned long modem3; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index f32a2ea70100..aca2386c5ef1 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1605,4 +1605,27 @@ config SERIAL_XILINX_PS_UART_CONSOLE help Enable a Xilinx PS UART port to be the system console. +config SERIAL_AR933X + bool "AR933X serial port support" + depends on SOC_AR933X + select SERIAL_CORE + help + If you have an Atheros AR933X SOC based board and want to use the + built-in UART of the SoC, say Y to this option. + +config SERIAL_AR933X_CONSOLE + bool "Console on AR933X serial port" + depends on SERIAL_AR933X=y + select SERIAL_CORE_CONSOLE + help + Enable a built-in UART port of the AR933X to be the system console. + +config SERIAL_AR933X_NR_UARTS + int "Maximum number of AR933X serial ports" + depends on SERIAL_AR933X + default "2" + help + Set this to the number of serial ports you want the driver + to support. + endmenu diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 07e0494c6830..f5b01f2ce525 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -91,3 +91,4 @@ obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o +obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 6958594f2fc0..9ae024025ff3 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -268,7 +268,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) struct dma_slave_config tx_conf = { .dst_addr = uap->port.mapbase + UART01x_DR, .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, - .direction = DMA_TO_DEVICE, + .direction = DMA_MEM_TO_DEV, .dst_maxburst = uap->fifosize >> 1, }; struct dma_chan *chan; @@ -301,7 +301,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap) struct dma_slave_config rx_conf = { .src_addr = uap->port.mapbase + UART01x_DR, .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, - .direction = DMA_FROM_DEVICE, + .direction = DMA_DEV_TO_MEM, .src_maxburst = uap->fifosize >> 1, }; @@ -480,7 +480,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) return -EBUSY; } - desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE, + desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE); @@ -676,7 +676,7 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; dma_dev = rxchan->device; desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1, - DMA_FROM_DEVICE, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); /* * If the DMA engine is busy and cannot prepare a diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c new file mode 100644 index 000000000000..e4f60e2b87f3 --- /dev/null +++ b/drivers/tty/serial/ar933x_uart.c @@ -0,0 +1,688 @@ +/* + * Atheros AR933X SoC built-in UART driver + * + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * 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 <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/irq.h> + +#include <asm/mach-ath79/ar933x_uart.h> +#include <asm/mach-ath79/ar933x_uart_platform.h> + +#define DRIVER_NAME "ar933x-uart" + +#define AR933X_DUMMY_STATUS_RD 0x01 + +static struct uart_driver ar933x_uart_driver; + +struct ar933x_uart_port { + struct uart_port port; + unsigned int ier; /* shadow Interrupt Enable Register */ +}; + +static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, + int offset) +{ + return readl(up->port.membase + offset); +} + +static inline void ar933x_uart_write(struct ar933x_uart_port *up, + int offset, unsigned int value) +{ + writel(value, up->port.membase + offset); +} + +static inline void ar933x_uart_rmw(struct ar933x_uart_port *up, + unsigned int offset, + unsigned int mask, + unsigned int val) +{ + unsigned int t; + + t = ar933x_uart_read(up, offset); + t &= ~mask; + t |= val; + ar933x_uart_write(up, offset, t); +} + +static inline void ar933x_uart_rmw_set(struct ar933x_uart_port *up, + unsigned int offset, + unsigned int val) +{ + ar933x_uart_rmw(up, offset, 0, val); +} + +static inline void ar933x_uart_rmw_clear(struct ar933x_uart_port *up, + unsigned int offset, + unsigned int val) +{ + ar933x_uart_rmw(up, offset, val, 0); +} + +static inline void ar933x_uart_start_tx_interrupt(struct ar933x_uart_port *up) +{ + up->ier |= AR933X_UART_INT_TX_EMPTY; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up) +{ + up->ier &= ~AR933X_UART_INT_TX_EMPTY; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) +{ + unsigned int rdata; + + rdata = ch & AR933X_UART_DATA_TX_RX_MASK; + rdata |= AR933X_UART_DATA_TX_CSR; + ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata); +} + +static unsigned int ar933x_uart_tx_empty(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + unsigned long flags; + unsigned int rdata; + + spin_lock_irqsave(&up->port.lock, flags); + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); + spin_unlock_irqrestore(&up->port.lock, flags); + + return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT; +} + +static unsigned int ar933x_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR; +} + +static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void ar933x_uart_start_tx(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + ar933x_uart_start_tx_interrupt(up); +} + +static void ar933x_uart_stop_tx(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + ar933x_uart_stop_tx_interrupt(up); +} + +static void ar933x_uart_stop_rx(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + up->ier &= ~AR933X_UART_INT_RX_VALID; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); + else + ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void ar933x_uart_enable_ms(struct uart_port *port) +{ +} + +static void ar933x_uart_set_termios(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + unsigned int cs; + unsigned long flags; + unsigned int baud, scale; + + /* Only CS8 is supported */ + new->c_cflag &= ~CSIZE; + new->c_cflag |= CS8; + + /* Only one stop bit is supported */ + new->c_cflag &= ~CSTOPB; + + cs = 0; + if (new->c_cflag & PARENB) { + if (!(new->c_cflag & PARODD)) + cs |= AR933X_UART_CS_PARITY_EVEN; + else + cs |= AR933X_UART_CS_PARITY_ODD; + } else { + cs |= AR933X_UART_CS_PARITY_NONE; + } + + /* Mark/space parity is not supported */ + new->c_cflag &= ~CMSPAR; + + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + scale = (port->uartclk / (16 * baud)) - 1; + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* Update the per-port timeout. */ + uart_update_timeout(port, new->c_cflag, baud); + + up->port.ignore_status_mask = 0; + + /* ignore all characters if CREAD is not set */ + if ((new->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD; + + ar933x_uart_write(up, AR933X_UART_CLOCK_REG, + scale << AR933X_UART_CLOCK_SCALE_S | 8192); + + /* setup configuration register */ + ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs); + + /* enable host interrupt */ + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_HOST_INT_EN); + + spin_unlock_irqrestore(&up->port.lock, flags); + + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); +} + +static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) +{ + struct tty_struct *tty; + int max_count = 256; + + tty = tty_port_tty_get(&up->port.state->port); + do { + unsigned int rdata; + unsigned char ch; + + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); + if ((rdata & AR933X_UART_DATA_RX_CSR) == 0) + break; + + /* remove the character from the FIFO */ + ar933x_uart_write(up, AR933X_UART_DATA_REG, + AR933X_UART_DATA_RX_CSR); + + if (!tty) { + /* discard the data if no tty available */ + continue; + } + + up->port.icount.rx++; + ch = rdata & AR933X_UART_DATA_TX_RX_MASK; + + if (uart_handle_sysrq_char(&up->port, ch)) + continue; + + if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } while (max_count-- > 0); + + if (tty) { + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } +} + +static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (uart_tx_stopped(&up->port)) + return; + + count = up->port.fifosize; + do { + unsigned int rdata; + + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); + if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) + break; + + if (up->port.x_char) { + ar933x_uart_putc(up, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + continue; + } + + if (uart_circ_empty(xmit)) + break; + + ar933x_uart_putc(up, xmit->buf[xmit->tail]); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (!uart_circ_empty(xmit)) + ar933x_uart_start_tx_interrupt(up); +} + +static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) +{ + struct ar933x_uart_port *up = dev_id; + unsigned int status; + + status = ar933x_uart_read(up, AR933X_UART_CS_REG); + if ((status & AR933X_UART_CS_HOST_INT) == 0) + return IRQ_NONE; + + spin_lock(&up->port.lock); + + status = ar933x_uart_read(up, AR933X_UART_INT_REG); + status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG); + + if (status & AR933X_UART_INT_RX_VALID) { + ar933x_uart_write(up, AR933X_UART_INT_REG, + AR933X_UART_INT_RX_VALID); + ar933x_uart_rx_chars(up); + } + + if (status & AR933X_UART_INT_TX_EMPTY) { + ar933x_uart_write(up, AR933X_UART_INT_REG, + AR933X_UART_INT_TX_EMPTY); + ar933x_uart_stop_tx_interrupt(up); + ar933x_uart_tx_chars(up); + } + + spin_unlock(&up->port.lock); + + return IRQ_HANDLED; +} + +static int ar933x_uart_startup(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + unsigned long flags; + int ret; + + ret = request_irq(up->port.irq, ar933x_uart_interrupt, + up->port.irqflags, dev_name(up->port.dev), up); + if (ret) + return ret; + + spin_lock_irqsave(&up->port.lock, flags); + + /* Enable HOST interrupts */ + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_HOST_INT_EN); + + /* Enable RX interrupts */ + up->ier = AR933X_UART_INT_RX_VALID; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); + + spin_unlock_irqrestore(&up->port.lock, flags); + + return 0; +} + +static void ar933x_uart_shutdown(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + /* Disable all interrupts */ + up->ier = 0; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); + + /* Disable break condition */ + ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); + + free_irq(up->port.irq, up); +} + +static const char *ar933x_uart_type(struct uart_port *port) +{ + return (port->type == PORT_AR933X) ? "AR933X UART" : NULL; +} + +static void ar933x_uart_release_port(struct uart_port *port) +{ + /* Nothing to release ... */ +} + +static int ar933x_uart_request_port(struct uart_port *port) +{ + /* UARTs always present */ + return 0; +} + +static void ar933x_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_AR933X; +} + +static int ar933x_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && + ser->type != PORT_AR933X) + return -EINVAL; + + if (ser->irq < 0 || ser->irq >= NR_IRQS) + return -EINVAL; + + if (ser->baud_base < 28800) + return -EINVAL; + + return 0; +} + +static struct uart_ops ar933x_uart_ops = { + .tx_empty = ar933x_uart_tx_empty, + .set_mctrl = ar933x_uart_set_mctrl, + .get_mctrl = ar933x_uart_get_mctrl, + .stop_tx = ar933x_uart_stop_tx, + .start_tx = ar933x_uart_start_tx, + .stop_rx = ar933x_uart_stop_rx, + .enable_ms = ar933x_uart_enable_ms, + .break_ctl = ar933x_uart_break_ctl, + .startup = ar933x_uart_startup, + .shutdown = ar933x_uart_shutdown, + .set_termios = ar933x_uart_set_termios, + .type = ar933x_uart_type, + .release_port = ar933x_uart_release_port, + .request_port = ar933x_uart_request_port, + .config_port = ar933x_uart_config_port, + .verify_port = ar933x_uart_verify_port, +}; + +#ifdef CONFIG_SERIAL_AR933X_CONSOLE + +static struct ar933x_uart_port * +ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; + +static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up) +{ + unsigned int status; + unsigned int timeout = 60000; + + /* Wait up to 60ms for the character(s) to be sent. */ + do { + status = ar933x_uart_read(up, AR933X_UART_DATA_REG); + if (--timeout == 0) + break; + udelay(1); + } while ((status & AR933X_UART_DATA_TX_CSR) == 0); +} + +static void ar933x_uart_console_putchar(struct uart_port *port, int ch) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + ar933x_uart_wait_xmitr(up); + ar933x_uart_putc(up, ch); +} + +static void ar933x_uart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct ar933x_uart_port *up = ar933x_console_ports[co->index]; + unsigned long flags; + unsigned int int_en; + int locked = 1; + + local_irq_save(flags); + + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&up->port.lock); + else + spin_lock(&up->port.lock); + + /* + * First save the IER then disable the interrupts + */ + int_en = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0); + + uart_console_write(&up->port, s, count, ar933x_uart_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + ar933x_uart_wait_xmitr(up); + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, int_en); + + ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); + + if (locked) + spin_unlock(&up->port.lock); + + local_irq_restore(flags); +} + +static int ar933x_uart_console_setup(struct console *co, char *options) +{ + struct ar933x_uart_port *up; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= CONFIG_SERIAL_AR933X_NR_UARTS) + return -EINVAL; + + up = ar933x_console_ports[co->index]; + if (!up) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&up->port, co, baud, parity, bits, flow); +} + +static struct console ar933x_uart_console = { + .name = "ttyATH", + .write = ar933x_uart_console_write, + .device = uart_console_device, + .setup = ar933x_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &ar933x_uart_driver, +}; + +static void ar933x_uart_add_console_port(struct ar933x_uart_port *up) +{ + ar933x_console_ports[up->port.line] = up; +} + +#define AR933X_SERIAL_CONSOLE (&ar933x_uart_console) + +#else + +static inline void ar933x_uart_add_console_port(struct ar933x_uart_port *up) {} + +#define AR933X_SERIAL_CONSOLE NULL + +#endif /* CONFIG_SERIAL_AR933X_CONSOLE */ + +static struct uart_driver ar933x_uart_driver = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = "ttyATH", + .nr = CONFIG_SERIAL_AR933X_NR_UARTS, + .cons = AR933X_SERIAL_CONSOLE, +}; + +static int __devinit ar933x_uart_probe(struct platform_device *pdev) +{ + struct ar933x_uart_platform_data *pdata; + struct ar933x_uart_port *up; + struct uart_port *port; + struct resource *mem_res; + struct resource *irq_res; + int id; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -EINVAL; + + id = pdev->id; + if (id == -1) + id = 0; + + if (id > CONFIG_SERIAL_AR933X_NR_UARTS) + return -EINVAL; + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_res) { + dev_err(&pdev->dev, "no MEM resource\n"); + return -EINVAL; + } + + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq_res) { + dev_err(&pdev->dev, "no IRQ resource\n"); + return -EINVAL; + } + + up = kzalloc(sizeof(struct ar933x_uart_port), GFP_KERNEL); + if (!up) + return -ENOMEM; + + port = &up->port; + port->mapbase = mem_res->start; + + port->membase = ioremap(mem_res->start, AR933X_UART_REGS_SIZE); + if (!port->membase) { + ret = -ENOMEM; + goto err_free_up; + } + + port->line = id; + port->irq = irq_res->start; + port->dev = &pdev->dev; + port->type = PORT_AR933X; + port->iotype = UPIO_MEM32; + port->uartclk = pdata->uartclk; + + port->regshift = 2; + port->fifosize = AR933X_UART_FIFO_SIZE; + port->ops = &ar933x_uart_ops; + + ar933x_uart_add_console_port(up); + + ret = uart_add_one_port(&ar933x_uart_driver, &up->port); + if (ret) + goto err_unmap; + + platform_set_drvdata(pdev, up); + return 0; + +err_unmap: + iounmap(up->port.membase); +err_free_up: + kfree(up); + return ret; +} + +static int __devexit ar933x_uart_remove(struct platform_device *pdev) +{ + struct ar933x_uart_port *up; + + up = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + + if (up) { + uart_remove_one_port(&ar933x_uart_driver, &up->port); + iounmap(up->port.membase); + kfree(up); + } + + return 0; +} + +static struct platform_driver ar933x_uart_platform_driver = { + .probe = ar933x_uart_probe, + .remove = __devexit_p(ar933x_uart_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init ar933x_uart_init(void) +{ + int ret; + + ar933x_uart_driver.nr = CONFIG_SERIAL_AR933X_NR_UARTS; + ret = uart_register_driver(&ar933x_uart_driver); + if (ret) + goto err_out; + + ret = platform_driver_register(&ar933x_uart_platform_driver); + if (ret) + goto err_unregister_uart_driver; + + return 0; + +err_unregister_uart_driver: + uart_unregister_driver(&ar933x_uart_driver); +err_out: + return ret; +} + +static void __exit ar933x_uart_exit(void) +{ + platform_driver_unregister(&ar933x_uart_platform_driver); + uart_unregister_driver(&ar933x_uart_driver); +} + +module_init(ar933x_uart_init); +module_exit(ar933x_uart_exit); + +MODULE_DESCRIPTION("Atheros AR933X UART driver"); +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index de0f613ed6f5..17ae65762d1a 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -764,7 +764,7 @@ static int dma_handle_rx(struct eg20t_port *priv) sg_dma_address(sg) = priv->rx_buf_dma; desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx, - sg, 1, DMA_FROM_DEVICE, + sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) @@ -923,7 +923,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) } desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx, - priv->sg_tx_p, nent, DMA_TO_DEVICE, + priv->sg_tx_p, nent, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n", diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 9e62349b3d9f..75085795528e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1339,7 +1339,7 @@ static void sci_submit_rx(struct sci_port *s) struct dma_async_tx_descriptor *desc; desc = chan->device->device_prep_slave_sg(chan, - sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT); + sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); if (desc) { s->desc_rx[i] = desc; @@ -1454,7 +1454,7 @@ static void work_fn_tx(struct work_struct *work) BUG_ON(!sg_dma_len(sg)); desc = chan->device->device_prep_slave_sg(chan, - sg, s->sg_len_tx, DMA_TO_DEVICE, + sg, s->sg_len_tx, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { /* switch to PIO */ diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index e67fb20490d2..ff8017f87914 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -850,7 +850,7 @@ static int mgsl_device_count; * .text section address and breakpoint on module load. * This is useful for use with gdb and add-symbol-file command. */ -static int break_on_load; +static bool break_on_load; /* * Driver major number, defaults to zero to get auto diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 0f6b796c95c5..a7efe538df00 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -456,7 +456,7 @@ static int synclinkmp_device_count = 0; * .text section address and breakpoint on module load. * This is useful for use with gdb and add-symbol-file command. */ -static int break_on_load = 0; +static bool break_on_load = 0; /* * Driver major number, defaults to zero to get auto diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index b42092e1f164..98dd9e49b684 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -73,9 +73,9 @@ static const char speedtch_driver_name[] = "speedtch"; #define DEFAULT_SW_BUFFERING 0 static unsigned int altsetting = 0; /* zero means: use the default */ -static int dl_512_first = DEFAULT_DL_512_FIRST; -static int enable_isoc = DEFAULT_ENABLE_ISOC; -static int sw_buffering = DEFAULT_SW_BUFFERING; +static bool dl_512_first = DEFAULT_DL_512_FIRST; +static bool enable_isoc = DEFAULT_ENABLE_ISOC; +static bool sw_buffering = DEFAULT_SW_BUFFERING; #define DEFAULT_B_MAX_DSL 8128 #define DEFAULT_MODEM_MODE 11 diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 00f171a7a8a0..01ea5d7421d4 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -542,7 +542,7 @@ static int modem_index; static unsigned int debug; static unsigned int altsetting[NB_MODEM] = { [0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF}; -static int sync_wait[NB_MODEM]; +static bool sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; static int annex[NB_MODEM]; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3af5e2dd1d82..8df4b76465ac 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -93,7 +93,7 @@ struct async { u8 bulk_status; }; -static int usbfs_snoop; +static bool usbfs_snoop; module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 79d339e2e700..a0613d8f9be7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -102,7 +102,7 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; /* cycle leds on hubs that aren't blinking for attention */ -static int blinkenlights = 0; +static bool blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); @@ -131,12 +131,12 @@ MODULE_PARM_DESC(initial_descriptor_timeout, * otherwise the new scheme is used. If that fails and "use_both_schemes" * is set, then the driver will make another attempt, using the other scheme. */ -static int old_scheme_first = 0; +static bool old_scheme_first = 0; module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(old_scheme_first, "start with the old device initialization scheme"); -static int use_both_schemes = 1; +static bool use_both_schemes = 1; module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " @@ -2026,7 +2026,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define SET_ADDRESS_TRIES 2 #define GET_DESCRIPTOR_TRIES 2 #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) -#define USE_NEW_SCHEME(i) ((i) / 2 == old_scheme_first) +#define USE_NEW_SCHEME(i) ((i) / 2 == (int)old_scheme_first) #define HUB_ROOT_RESET_TIME 50 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 1382c90d0834..8ca9f994a280 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -47,7 +47,7 @@ const char *usbcore_name = "usbcore"; -static int nousb; /* Disable USB when built into kernel image */ +static bool nousb; /* Disable USB when built into kernel image */ #ifdef CONFIG_USB_SUSPEND static int usb_autosuspend_delay = 2; /* Default delay value, diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index e9a2c5c44454..c16ff55a74e8 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -152,15 +152,15 @@ static const char *ep_string[] = { }; /* DMA usage flag */ -static int use_dma = 1; +static bool use_dma = 1; /* packet per buffer dma */ -static int use_dma_ppb = 1; +static bool use_dma_ppb = 1; /* with per descr. update */ -static int use_dma_ppb_du; +static bool use_dma_ppb_du; /* buffer fill mode */ static int use_dma_bufferfill_mode; /* full speed only mode */ -static int use_fullspeed; +static bool use_fullspeed; /* tx buffer size for high speed */ static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 0cd764d59351..a28f6ffcd0f3 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -250,9 +250,9 @@ static struct usb_configuration rndis_config_driver = { /*-------------------------------------------------------------------------*/ #ifdef CONFIG_USB_ETH_EEM -static int use_eem = 1; +static bool use_eem = 1; #else -static int use_eem; +static bool use_eem; #endif module_param(use_eem, bool, 0); MODULE_PARM_DESC(use_eem, "use CDC EEM mode"); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index e0f30fc70e45..47766f0e7caa 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -303,16 +303,16 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[FSG_MAX_LUNS]; char *serial; - int ro[FSG_MAX_LUNS]; - int nofua[FSG_MAX_LUNS]; + bool ro[FSG_MAX_LUNS]; + bool nofua[FSG_MAX_LUNS]; unsigned int num_filenames; unsigned int num_ros; unsigned int num_nofuas; unsigned int nluns; - int removable; - int can_stall; - int cdrom; + bool removable; + bool can_stall; + bool cdrom; char *transport_parm; char *protocol_parm; diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 4c81d540bc26..7322d293213e 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -69,7 +69,7 @@ static const char * const ep_name[] = { * * If use_dma is disabled, pio will be used instead. */ -static int use_dma = 0; +static bool use_dma = 0; module_param(use_dma, bool, 0644); /* diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index cf1f36454d08..cdedd1336745 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -90,8 +90,8 @@ static const char *const ep_name [] = { * Some gadget drivers work better with the dma support here than others. * These two parameters let you use PIO or more aggressive DMA. */ -static int use_dma = 1; -static int use_dma_chaining = 0; +static bool use_dma = 1; +static bool use_dma_chaining = 0; /* "modprobe net2280 use_dma=n" etc */ module_param (use_dma, bool, S_IRUGO); @@ -112,7 +112,7 @@ module_param (fifo_mode, ushort, 0644); * USB suspend requests will be ignored. This is acceptable for * self-powered devices */ -static int enable_suspend = 0; +static bool enable_suspend = 0; /* "modprobe net2280 enable_suspend=1" etc */ module_param (enable_suspend, bool, S_IRUGO); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 7db5bbe6251b..576cd8578b45 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -98,7 +98,7 @@ module_param (fifo_mode, uint, 0); MODULE_PARM_DESC (fifo_mode, "endpoint configuration"); #ifdef USE_DMA -static unsigned use_dma = 1; +static bool use_dma = 1; /* "modprobe omap_udc use_dma=y", or else as a kernel * boot parameter "omap_udc:use_dma=y" diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index dd2313cce1d3..a3fcaae4bc2a 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -359,7 +359,7 @@ struct pch_udc_dev { static const char ep0_string[] = "ep0in"; static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */ struct pch_udc_dev *pch_udc; /* pointer to device object */ -static int speed_fs; +static bool speed_fs; module_param_named(speed_fs, speed_fs, bool, S_IRUGO); MODULE_PARM_DESC(speed_fs, "true for Full speed operation"); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ed1b816e58d8..ad9e5b2df642 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -123,11 +123,11 @@ MODULE_AUTHOR("Al Borchers"); MODULE_AUTHOR("David Brownell"); MODULE_LICENSE("GPL"); -static int use_acm = true; +static bool use_acm = true; module_param(use_acm, bool, 0); MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes"); -static int use_obex = false; +static bool use_obex = false; module_param(use_obex, bool, 0); MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no"); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 20697cc132d1..31d34832907e 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -81,7 +81,7 @@ module_param(buflen, uint, 0); * work better with hosts where config changes are problematic or * controllers (like original superh) that only support one config. */ -static int loopdefault = 0; +static bool loopdefault = 0; module_param(loopdefault, bool, S_IRUGO|S_IWUSR); /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 4c0c9734251d..91413cac97be 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -219,7 +219,7 @@ config USB_CNS3XXX_EHCI config USB_EHCI_ATH79 bool "EHCI support for AR7XXX/AR9XXX SoCs" - depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X) + depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X) select USB_EHCI_ROOT_HUB_TT default y ---help--- diff --git a/drivers/usb/host/alchemy-common.c b/drivers/usb/host/alchemy-common.c index b4192c964d0d..936af8359fb2 100644 --- a/drivers/usb/host/alchemy-common.c +++ b/drivers/usb/host/alchemy-common.c @@ -52,9 +52,263 @@ USBCFG_EBE | USBCFG_EME | USBCFG_OBE | \ USBCFG_OME) +/* Au1300 USB config registers */ +#define USB_DWC_CTRL1 0x00 +#define USB_DWC_CTRL2 0x04 +#define USB_VBUS_TIMER 0x10 +#define USB_SBUS_CTRL 0x14 +#define USB_MSR_ERR 0x18 +#define USB_DWC_CTRL3 0x1C +#define USB_DWC_CTRL4 0x20 +#define USB_OTG_STATUS 0x28 +#define USB_DWC_CTRL5 0x2C +#define USB_DWC_CTRL6 0x30 +#define USB_DWC_CTRL7 0x34 +#define USB_PHY_STATUS 0xC0 +#define USB_INT_STATUS 0xC4 +#define USB_INT_ENABLE 0xC8 + +#define USB_DWC_CTRL1_OTGD 0x04 /* set to DISable OTG */ +#define USB_DWC_CTRL1_HSTRS 0x02 /* set to ENable EHCI */ +#define USB_DWC_CTRL1_DCRS 0x01 /* set to ENable UDC */ + +#define USB_DWC_CTRL2_PHY1RS 0x04 /* set to enable PHY1 */ +#define USB_DWC_CTRL2_PHY0RS 0x02 /* set to enable PHY0 */ +#define USB_DWC_CTRL2_PHYRS 0x01 /* set to enable PHY */ + +#define USB_DWC_CTRL3_OHCI1_CKEN (1 << 19) +#define USB_DWC_CTRL3_OHCI0_CKEN (1 << 18) +#define USB_DWC_CTRL3_EHCI0_CKEN (1 << 17) +#define USB_DWC_CTRL3_OTG0_CKEN (1 << 16) + +#define USB_SBUS_CTRL_SBCA 0x04 /* coherent access */ + +#define USB_INTEN_FORCE 0x20 +#define USB_INTEN_PHY 0x10 +#define USB_INTEN_UDC 0x08 +#define USB_INTEN_EHCI 0x04 +#define USB_INTEN_OHCI1 0x02 +#define USB_INTEN_OHCI0 0x01 static DEFINE_SPINLOCK(alchemy_usb_lock); +static inline void __au1300_usb_phyctl(void __iomem *base, int enable) +{ + unsigned long r, s; + + r = __raw_readl(base + USB_DWC_CTRL2); + s = __raw_readl(base + USB_DWC_CTRL3); + + s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN | + USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN; + + if (enable) { + /* simply enable all PHYs */ + r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | + USB_DWC_CTRL2_PHYRS; + __raw_writel(r, base + USB_DWC_CTRL2); + wmb(); + } else if (!s) { + /* no USB block active, do disable all PHYs */ + r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | + USB_DWC_CTRL2_PHYRS); + __raw_writel(r, base + USB_DWC_CTRL2); + wmb(); + } +} + +static inline void __au1300_ohci_control(void __iomem *base, int enable, int id) +{ + unsigned long r; + + if (enable) { + __raw_writel(1, base + USB_DWC_CTRL7); /* start OHCI clock */ + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); /* enable OHCI block */ + r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN + : USB_DWC_CTRL3_OHCI1_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); /* power up the PHYs */ + + r = __raw_readl(base + USB_INT_ENABLE); + r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + /* reset the OHCI start clock bit */ + __raw_writel(0, base + USB_DWC_CTRL7); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1); + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN + : USB_DWC_CTRL3_OHCI1_CKEN); + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_ehci_control(void __iomem *base, int enable) +{ + unsigned long r; + + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL3); + r |= USB_DWC_CTRL3_EHCI0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_HSTRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + + r = __raw_readl(base + USB_INT_ENABLE); + r |= USB_INTEN_EHCI; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~USB_INTEN_EHCI; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_HSTRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~USB_DWC_CTRL3_EHCI0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_udc_control(void __iomem *base, int enable) +{ + unsigned long r; + + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_DCRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + + r = __raw_readl(base + USB_INT_ENABLE); + r |= USB_INTEN_UDC; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~USB_INTEN_UDC; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_DCRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_otg_control(void __iomem *base, int enable) +{ + unsigned long r; + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL3); + r |= USB_DWC_CTRL3_OTG0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_OTGD; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + } else { + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_OTGD; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~USB_DWC_CTRL3_OTG0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline int au1300_usb_control(int block, int enable) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + int ret = 0; + + switch (block) { + case ALCHEMY_USB_OHCI0: + __au1300_ohci_control(base, enable, 0); + break; + case ALCHEMY_USB_OHCI1: + __au1300_ohci_control(base, enable, 1); + break; + case ALCHEMY_USB_EHCI0: + __au1300_ehci_control(base, enable); + break; + case ALCHEMY_USB_UDC0: + __au1300_udc_control(base, enable); + break; + case ALCHEMY_USB_OTG0: + __au1300_otg_control(base, enable); + break; + default: + ret = -ENODEV; + } + return ret; +} + +static inline void au1300_usb_init(void) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + + /* set some sane defaults. Note: we don't fiddle with DWC_CTRL4 + * here at all: Port 2 routing (EHCI or UDC) must be set either + * by boot firmware or platform init code; I can't autodetect + * a sane setting. + */ + __raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */ + wmb(); + __raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */ + wmb(); + __raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */ + wmb(); + __raw_writel(~0, base + USB_INT_STATUS); /* clear int status */ + wmb(); + /* set coherent access bit */ + __raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL); + wmb(); +} static inline void __au1200_ohci_control(void __iomem *base, int enable) { @@ -233,6 +487,9 @@ int alchemy_usb_control(int block, int enable) case ALCHEMY_CPU_AU1200: ret = au1200_usb_control(block, enable); break; + case ALCHEMY_CPU_AU1300: + ret = au1300_usb_control(block, enable); + break; default: ret = -ENODEV; } @@ -281,6 +538,20 @@ static void au1200_usb_pm(int susp) } } +static void au1300_usb_pm(int susp) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + /* remember Port2 routing */ + if (susp) { + alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4); + } else { + au1300_usb_init(); + __raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4); + wmb(); + } +} + static void alchemy_usb_pm(int susp) { switch (alchemy_get_cputype()) { @@ -295,6 +566,9 @@ static void alchemy_usb_pm(int susp) case ALCHEMY_CPU_AU1200: au1200_usb_pm(susp); break; + case ALCHEMY_CPU_AU1300: + au1300_usb_pm(susp); + break; } } @@ -328,6 +602,9 @@ static int __init alchemy_usb_init(void) case ALCHEMY_CPU_AU1200: au1200_usb_init(); break; + case ALCHEMY_CPU_AU1300: + au1300_usb_init(); + break; } register_syscore_ops(&alchemy_usb_pm_ops); diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c index afb6743cf094..f1424f9bc363 100644 --- a/drivers/usb/host/ehci-ath79.c +++ b/drivers/usb/host/ehci-ath79.c @@ -33,6 +33,10 @@ static const struct platform_device_id ehci_ath79_id_table[] = { .driver_data = EHCI_ATH79_IP_V2, }, { + .name = "ar933x-ehci", + .driver_data = EHCI_ATH79_IP_V2, + }, + { /* terminating entry */ }, }; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e311a511529b..a007a9fe0f87 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -112,7 +112,7 @@ module_param (park, uint, S_IRUGO); MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets"); /* for flakey hardware, ignore overcurrent indicators */ -static int ignore_oc = 0; +static bool ignore_oc = 0; module_param (ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index 32793ce3d9e9..9c2cc4633894 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -183,7 +183,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op) } irq = irq_of_parse_and_map(dn, 0); - if (irq == NO_IRQ) { + if (!irq) { printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); rv = -EBUSY; goto err_irq; diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 40d886adff53..4ea63b2cac42 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -89,7 +89,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) { - int ret; + int ret, unit; struct usb_hcd *hcd; if (usb_disabled()) @@ -120,7 +120,9 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) goto err2; } - if (alchemy_usb_control(ALCHEMY_USB_OHCI0, 1)) { + unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? + ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; + if (alchemy_usb_control(unit, 1)) { printk(KERN_INFO "%s: controller init failed!\n", pdev->name); ret = -ENODEV; goto err3; @@ -135,7 +137,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) return ret; } - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); + alchemy_usb_control(unit, 0); err3: iounmap(hcd->regs); err2: @@ -148,9 +150,12 @@ err1: static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + int unit; + unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? + ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; usb_remove_hcd(hcd); - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); + alchemy_usb_control(unit, 0); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 5f5a63241436..34b9edd86651 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -115,13 +115,13 @@ static inline void sb800_prefetch(struct ohci_hcd *ohci, int on) /* Some boards misreport power switching/overcurrent */ -static int distrust_firmware = 1; +static bool distrust_firmware = 1; module_param (distrust_firmware, bool, 0); MODULE_PARM_DESC (distrust_firmware, "true to distrust firmware power/overcurrent setup"); /* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */ -static int no_handshake = 0; +static bool no_handshake = 0; module_param (no_handshake, bool, 0); MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 6f62de5c6e35..015c7c62ed49 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -233,7 +233,7 @@ module_param(park, uint, S_IRUGO); MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets"); /* For flakey hardware, ignore overcurrent indicators */ -static int ignore_oc; +static bool ignore_oc; module_param(ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC(ignore_oc, "ignore bogus hardware overcurrent indications"); diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 533d12cca371..16dd6a6abf00 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -74,7 +74,7 @@ MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) INT_MODULE_PARM(testing, 0); /* Some boards misreport power switching/overcurrent*/ -static int distrust_firmware = 1; +static bool distrust_firmware = 1; module_param(distrust_firmware, bool, 0); MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" "t setup"); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index c8ae199cfbb8..6b5eb1017e2c 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -59,7 +59,7 @@ #define DRIVER_DESC "USB Universal Host Controller Interface driver" /* for flakey hardware, ignore overcurrent indicators */ -static int ignore_oc; +static bool ignore_oc; module_param(ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications"); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 2dbe600fbc11..a4a3c7cd4a11 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -53,7 +53,7 @@ MODULE_AUTHOR("Tony Olech"); MODULE_DESCRIPTION("FTDI ELAN driver"); MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -static int distrust_firmware = 1; +static bool distrust_firmware = 1; module_param(distrust_firmware, bool, 0); MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" "t setup"); diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 2453a39b4794..4fd0dc835ae5 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -62,7 +62,7 @@ MODULE_LICENSE("GPL"); /* Module parameters */ static DEFINE_MUTEX(iowarrior_mutex); -static int debug = 0; +static bool debug = 0; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "debug=1 enables debugging messages"); diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 53be7aef6308..66bc376005d2 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -750,7 +750,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) * So this module parameter lets the heuristic be disabled. When using * gadgetfs, the heuristic will probably need to be disabled. */ -static int cppi_rx_rndis = 1; +static bool cppi_rx_rndis = 1; module_param(cppi_rx_rndis, bool, 0); MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic"); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index f6ff7923048b..56cf0243979e 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1586,7 +1586,7 @@ irqreturn_t musb_interrupt(struct musb *musb) EXPORT_SYMBOL_GPL(musb_interrupt); #ifndef CONFIG_MUSB_PIO_ONLY -static int __initdata use_dma = 1; +static bool __initdata use_dma = 1; /* "modprobe ... use_dma=0" etc */ module_param(use_dma, bool, 0); diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index a163632877af..97cb45916c43 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -84,7 +84,7 @@ static bool ux500_configure_channel(struct dma_channel *channel, struct musb_hw_ep *hw_ep = ux500_channel->hw_ep; struct dma_chan *dma_chan = ux500_channel->dma_chan; struct dma_async_tx_descriptor *dma_desc; - enum dma_data_direction direction; + enum dma_transfer_direction direction; struct scatterlist sg; struct dma_slave_config slave_conf; enum dma_slave_buswidth addr_width; @@ -104,7 +104,7 @@ static bool ux500_configure_channel(struct dma_channel *channel, sg_dma_address(&sg) = dma_addr; sg_dma_len(&sg) = len; - direction = ux500_channel->is_tx ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + direction = ux500_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; addr_width = (len & 0x3) ? DMA_SLAVE_BUSWIDTH_1_BYTE : DMA_SLAVE_BUSWIDTH_4_BYTES; diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 07ccea9ada40..74fe6e62e0f7 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -30,7 +30,7 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #define AB8500_MAIN_WD_CTRL_REG 0x01 #define AB8500_USB_LINE_STAT_REG 0x80 diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index b51fcd80d244..72339bd6fcab 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -772,10 +772,10 @@ static void usbhsf_dma_prepare_tasklet(unsigned long data) struct dma_async_tx_descriptor *desc; struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); struct device *dev = usbhs_priv_to_dev(priv); - enum dma_data_direction dir; + enum dma_transfer_direction dir; dma_cookie_t cookie; - dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; sg_init_table(&sg, 1); sg_set_page(&sg, virt_to_page(pkt->dma), diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index b43d07df4c44..123bf9155339 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -52,7 +52,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; /* Vendor and Product ID */ #define AIRCABLE_VID 0x16CA diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 18e875b92e00..69328dcfd91a 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -37,7 +37,7 @@ #include <linux/mutex.h> #include <linux/spinlock.h> -static int debug; +static bool debug; /* * Version information */ diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index f9f29b289f2f..29ffeb6279c7 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -37,7 +37,7 @@ #include <linux/usb/serial.h> #include "belkin_sa.h" -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 0e77511060c0..5e53cc59e652 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -70,7 +70,7 @@ #define CH341_NBREAK_BITS_REG2 0x40 -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x4348, 0x5523) }, diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index adfe660ed008..fba1147ed916 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -49,7 +49,7 @@ static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_startup(struct usb_serial *); static void cp210x_dtr_rts(struct usb_serial_port *p, int on); -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 98bf83349838..6bc3802a581a 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -43,7 +43,7 @@ #define CYBERJACK_LOCAL_BUF_SIZE 32 -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 07680d6b792b..3bdeafa29c24 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -46,10 +46,10 @@ #include "cypress_m8.h" -static int debug; -static int stats; +static bool debug; +static bool stats; static int interval; -static int unstable_bauds; +static bool unstable_bauds; /* * Version Information diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 6d26a77d0f2a..b23bebd721a1 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -251,7 +251,7 @@ static int digi_read_oob_callback(struct urb *urb); /* Statics */ -static int debug; +static bool debug; static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 504b5585ea45..aced6817bf95 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -28,7 +28,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c290df97108e..01b6404df395 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -55,7 +55,7 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB FTDI Serial Converters Driver" -static int debug; +static bool debug; static __u16 vendor = FTDI_VID; static __u16 product; diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index e21ce9ddfc63..5d4b099dcf8b 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -16,7 +16,7 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1404, 0xcddc) }, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index bf12565f8e87..21343378c322 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -42,7 +42,7 @@ static int initial_mode = 1; /* debug flag */ -static int debug; +static bool debug; #define GARMIN_VENDOR_ID 0x091E diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index abd2ee2b2f99..0497575e4799 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -191,7 +191,7 @@ static const struct divisor_table_entry divisor_table[] = { }; /* local variables */ -static int debug; +static bool debug; static atomic_t CmdUrbs; /* Number of outstanding Command Write Urbs */ diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index e44d375edaad..65bf06aa591a 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -210,10 +210,10 @@ static unsigned char OperationalMajorVersion; static unsigned char OperationalMinorVersion; static unsigned short OperationalBuildNumber; -static int debug; +static bool debug; static int closing_wait = EDGE_CLOSING_WAIT; -static int ignore_cpu_rev; +static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 36f5cbe90485..06053a920dd8 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -34,7 +34,7 @@ #define DRIVER_DESC "USB PocketPC PDA driver" static __u16 product, vendor; -static int debug; +static bool debug; static int connect_retries = KP_RETRIES; static int initial_wait; diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 5170799d6e94..6f9356f3f99e 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -147,7 +147,7 @@ static struct usb_driver usb_ipw_driver = { .no_dynamic_id = 1, }; -static int debug; +static bool debug; static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) { diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 0c537da0d3cd..84a396e83671 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -45,7 +45,7 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB IR Dongle driver" -static int debug; +static bool debug; /* if overridden by the user, then use their value for the size of the read and * write urbs */ diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 64d0ffd4440b..3077a4436976 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -34,9 +34,9 @@ #ifdef CONFIG_USB_SERIAL_DEBUG -static int debug = 1; +static bool debug = 1; #else -static int debug; +static bool debug; #endif /* @@ -65,7 +65,7 @@ static int clockmode = 1; static int cdmode = 1; static int iuu_cardin; static int iuu_cardout; -static int xmas; +static bool xmas; static int vcc_default = 5; static void read_rxcmd_callback(struct urb *urb); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index bc8dc203e818..4cc36c761801 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -45,7 +45,7 @@ #include <linux/usb/serial.h> #include "keyspan.h" -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index a40615674a68..7c62a7048302 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -31,7 +31,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; /* make a simple define to handle if we are compiling keyspan_pda or xircom support */ #if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 19373cb7c5bf..fc064e1442ca 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -49,7 +49,7 @@ #include <linux/usb/serial.h> #include "kl5kusb105.h" -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index a975bb80303f..27fa9c8a77b0 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -45,7 +45,7 @@ #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" -static int debug; +static bool debug; /* * Function prototypes diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 19d112f51b97..4554ee49e635 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -71,7 +71,7 @@ struct moschip_port { struct urb *write_urb_pool[NUM_URBS]; }; -static int debug; +static bool debug; static struct usb_serial_driver moschip7720_2port_driver; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 55cfd6265b98..03b5e249e95e 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -263,7 +263,7 @@ struct moschip_port { }; -static int debug; +static bool debug; /* * mos7840_set_reg_sync diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 1f00f243c26c..b28f1db0195f 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -21,7 +21,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 45a8c55881d3..8b8d58a2ac12 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -23,7 +23,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 691f57a9d712..262ded9e076b 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -32,7 +32,7 @@ * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */ #define DRIVER_DESC "Opticon USB barcode to serial driver (1D)" -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x065a, 0x0009) }, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index c96b6b6509fb..420d9857394a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1234,7 +1234,7 @@ static struct usb_serial_driver option_1port_device = { #endif }; -static int debug; +static bool debug; /* per port private data */ diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 2161d1c3c089..e287fd32682c 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -74,7 +74,7 @@ static struct usb_driver oti6858_driver = { .no_dynamic_id = 1, }; -static int debug; +static bool debug; /* requests */ #define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 329295615d06..3d8cda57ce7a 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -36,7 +36,7 @@ */ #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" -static int debug; +static bool debug; #define PL2303_CLOSING_WAIT (30*HZ) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index aa9367f5b421..1d5deee3be52 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -22,7 +22,7 @@ #define DRIVER_AUTHOR "Qualcomm Inc" #define DRIVER_DESC "Qualcomm USB Serial driver" -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { {USB_DEVICE(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index a36e2313eed0..d074b3740dcb 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -81,9 +81,9 @@ #define CONFIG_USB_SERIAL_SAFE_PADDED 0 #endif -static int debug; -static int safe = 1; -static int padded = CONFIG_USB_SERIAL_SAFE_PADDED; +static bool debug; +static bool safe = 1; +static bool padded = CONFIG_USB_SERIAL_SAFE_PADDED; #define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>" diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index f2485429172f..fdae0a4407cb 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -46,8 +46,8 @@ allocations > PAGE_SIZE and the number of packets in a page is an integer 512 is the largest possible packet on EHCI */ -static int debug; -static int nmea; +static bool debug; +static bool nmea; /* Used in interface blacklisting */ struct sierra_iface_info { diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 180ea6c7911c..d7f5eee18f00 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -33,7 +33,7 @@ #define DRIVER_VERSION "v0.10" #define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" -static int debug; +static bool debug; #define SPCP8x5_007_VID 0x04FC #define SPCP8x5_007_PID 0x0201 diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 87362e48796e..7697858d8858 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -46,7 +46,7 @@ #define FULLPWRBIT 0x00000080 #define NEXT_BOARD_POWER_BIT 0x00000004 -static int debug; +static bool debug; /* Version Information */ #define DRIVER_VERSION "v0.1" diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index c70cc012d03f..50651cf4fc61 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -20,7 +20,7 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x05e0, 0x0600) }, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 4af21f46096e..8468eb769a29 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -150,7 +150,7 @@ static int ti_download_firmware(struct ti_device *tdev); /* Data */ /* module parameters */ -static int debug; +static bool debug; static int closing_wait = TI_DEFAULT_CLOSING_WAIT; static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT]; static unsigned int vendor_3410_count; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index ce6c1a65a544..611b206591cb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -61,7 +61,7 @@ static struct usb_driver usb_serial_driver = { drivers depend on it. */ -static int debug; +static bool debug; /* initially all NULL */ static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; static DEFINE_MUTEX(table_lock); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index d555ca9567b8..c88657dd31c8 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -37,7 +37,7 @@ #include <linux/serial.h> #include "usb-wwan.h" -static int debug; +static bool debug; void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) { diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 1c11959a7d58..210e4b10dc11 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -52,7 +52,7 @@ static int palm_os_4_probe(struct usb_serial *serial, const struct usb_device_id *id); /* Parameters that may be passed into the module. */ -static int debug; +static bool debug; static __u16 vendor; static __u16 product; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 11af903cb09f..7e0acf5c8e38 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -36,7 +36,7 @@ #include <linux/ihex.h> #include "whiteheat.h" /* WhiteHEAT specific commands */ -static int debug; +static bool debug; #ifndef CMSPAR #define CMSPAR 0 diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d83e967e4e15..6ca0c407c144 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1763,16 +1763,16 @@ config FB_AU1100 au1100fb:panel=<name>. config FB_AU1200 - bool "Au1200 LCD Driver" + bool "Au1200/Au1300 LCD Driver" depends on (FB = y) && MIPS_ALCHEMY select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS help - This is the framebuffer driver for the AMD Au1200 SOC. It can drive - various panels and CRTs by passing in kernel cmd line option - au1200fb:panel=<name>. + This is the framebuffer driver for the Au1200/Au1300 SOCs. + It can drive various panels and CRTs by passing in kernel cmd line + option au1200fb:panel=<name>. config FB_VT8500 bool "VT8500 LCD Driver" @@ -2413,7 +2413,6 @@ source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" source "drivers/video/backlight/Kconfig" -source "drivers/video/display/Kconfig" if VT source "drivers/video/console/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9b9d8fff7732..142606814d98 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -13,7 +13,7 @@ fb-objs := $(fb-y) obj-$(CONFIG_VT) += console/ obj-$(CONFIG_LOGO) += logo/ -obj-y += backlight/ display/ +obj-y += backlight/ obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 5ea6596dd824..f23cae094f1b 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -152,10 +152,10 @@ - hsstrt: Start of horizontal synchronization pulse - hsstop: End of horizontal synchronization pulse - - htotal: Last value on the line (i.e. line length = htotal+1) + - htotal: Last value on the line (i.e. line length = htotal + 1) - vsstrt: Start of vertical synchronization pulse - vsstop: End of vertical synchronization pulse - - vtotal: Last line value (i.e. number of lines = vtotal+1) + - vtotal: Last line value (i.e. number of lines = vtotal + 1) - hcenter: Start of vertical retrace for interlace You can specify the blanking timings independently. Currently I just set @@ -184,7 +184,7 @@ clock): - diwstrt_h: Horizontal start of the visible window - - diwstop_h: Horizontal stop+1(*) of the visible window + - diwstop_h: Horizontal stop + 1(*) of the visible window - diwstrt_v: Vertical start of the visible window - diwstop_v: Vertical stop of the visible window - ddfstrt: Horizontal start of display DMA @@ -193,7 +193,7 @@ Sprite positioning: - - sprstrt_h: Horizontal start-4 of sprite + - sprstrt_h: Horizontal start - 4 of sprite - sprstrt_v: Vertical start of sprite (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. @@ -212,21 +212,21 @@ display parameters. Here's what I found out: - ddfstrt and ddfstop are best aligned to 64 pixels. - - the chipset needs 64+4 horizontal pixels after the DMA start before the - first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to - display the first pixel on the line too. Increase diwstrt_h for virtual - screen panning. + - the chipset needs 64 + 4 horizontal pixels after the DMA start before + the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want + to display the first pixel on the line too. Increase diwstrt_h for + virtual screen panning. - the display DMA always fetches 64 pixels at a time (fmode = 3). - - ddfstop is ddfstrt+#pixels-64. - - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1 - more than htotal. + - ddfstop is ddfstrt+#pixels - 64. + - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can + be 1 more than htotal. - hscroll simply adds a delay to the display output. Smooth horizontal - panning needs an extra 64 pixels on the left to prefetch the pixels that - `fall off' on the left. + panning needs an extra 64 pixels on the left to prefetch the pixels that + `fall off' on the left. - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane - DMA, so it's best to make the DMA start as late as possible. + DMA, so it's best to make the DMA start as late as possible. - you really don't want to make ddfstrt < 128, since this will steal DMA - cycles from the other DMA channels (audio, floppy and Chip RAM refresh). + cycles from the other DMA channels (audio, floppy and Chip RAM refresh). - I make diwstop_h and diwstop_v as large as possible. General dependencies @@ -234,8 +234,8 @@ - all values are SHRES pixel (35ns) - table 1:fetchstart table 2:prefetch table 3:fetchsize - ------------------ ---------------- ----------------- + table 1:fetchstart table 2:prefetch table 3:fetchsize + ------------------ ---------------- ----------------- Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES -------------#------+-----+------#------+-----+------#------+-----+------ Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 @@ -245,21 +245,21 @@ - chipset needs 4 pixels before the first pixel is output - ddfstrt must be aligned to fetchstart (table 1) - chipset needs also prefetch (table 2) to get first pixel data, so - ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch + ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch - for horizontal panning decrease diwstrt_h - the length of a fetchline must be aligned to fetchsize (table 3) - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit - moved to optimize use of dma (useful for OCS/ECS overscan displays) - - ddfstop is ddfstrt+ddfsize-fetchsize + moved to optimize use of dma (useful for OCS/ECS overscan displays) + - ddfstop is ddfstrt + ddfsize - fetchsize - If C= didn't change anything for AGA, then at following positions the - dma bus is already used: - ddfstrt < 48 -> memory refresh - < 96 -> disk dma - < 160 -> audio dma - < 192 -> sprite 0 dma - < 416 -> sprite dma (32 per sprite) + dma bus is already used: + ddfstrt < 48 -> memory refresh + < 96 -> disk dma + < 160 -> audio dma + < 192 -> sprite 0 dma + < 416 -> sprite dma (32 per sprite) - in accordance with the hardware reference manual a hardware stop is at - 192, but AGA (ECS?) can go below this. + 192, but AGA (ECS?) can go below this. DMA priorities -------------- @@ -269,7 +269,7 @@ the hardware cursor: - if you want to start display DMA too early, you lose the ability to - do smooth horizontal panning (xpanstep 1 -> 64). + do smooth horizontal panning (xpanstep 1 -> 64). - if you want to go even further, you lose the hardware cursor too. IMHO a hardware cursor is more important for X than horizontal scrolling, @@ -286,8 +286,8 @@ Standard VGA timings -------------------- - xres yres left right upper lower hsync vsync - ---- ---- ---- ----- ----- ----- ----- ----- + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- 80x25 720 400 27 45 35 12 108 2 80x30 720 480 27 45 30 9 108 2 @@ -297,8 +297,8 @@ As a comparison, graphics/monitor.h suggests the following: - xres yres left right upper lower hsync vsync - ---- ---- ---- ----- ----- ----- ----- ----- + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- VGA 640 480 52 112 24 19 112 - 2 + VGA70 640 400 52 112 27 21 112 - 2 - @@ -309,10 +309,10 @@ VSYNC HSYNC Vertical size Vertical total ----- ----- ------------- -------------- - + + Reserved Reserved - + - 400 414 - - + 350 362 - - - 480 496 + + + Reserved Reserved + + - 400 414 + - + 350 362 + - - 480 496 Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 @@ -326,33 +326,34 @@ ----------- - a scanline is 64 µs long, of which 52.48 µs are visible. This is about - 736 visible 70 ns pixels per line. + 736 visible 70 ns pixels per line. - we have 625 scanlines, of which 575 are visible (interlaced); after - rounding this becomes 576. + rounding this becomes 576. RETMA -> NTSC ------------- - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about - 736 visible 70 ns pixels per line. + 736 visible 70 ns pixels per line. - we have 525 scanlines, of which 485 are visible (interlaced); after - rounding this becomes 484. + rounding this becomes 484. Thus if you want a PAL compatible display, you have to do the following: - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast - timings are to be used. - - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an - interlaced, 312 for a non-interlaced and 156 for a doublescanned - display. - - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES, - 908 for a HIRES and 454 for a LORES display. + timings are to be used. + - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an + interlaced, 312 for a non-interlaced and 156 for a doublescanned + display. + - make sure left_margin + xres + right_margin + hsync_len = 1816 for a + SHRES, 908 for a HIRES and 454 for a LORES display. - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), - left_margin+2*hsync_len must be greater or equal. + left_margin + 2 * hsync_len must be greater or equal. - the upper visible part begins at 48 (interlaced; non-interlaced:24, - doublescanned:12), upper_margin+2*vsync_len must be greater or equal. + doublescanned:12), upper_margin + 2 * vsync_len must be greater or + equal. - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync - of 4 scanlines + of 4 scanlines The settings for a NTSC compatible display are straightforward. @@ -361,7 +362,7 @@ anything about horizontal/vertical synchronization nor refresh rates. - -- Geert -- + -- Geert -- *******************************************************************************/ @@ -540,45 +541,45 @@ static u_short maxfmode, chipset; * Various macros */ -#define up2(v) (((v)+1) & -2) +#define up2(v) (((v) + 1) & -2) #define down2(v) ((v) & -2) #define div2(v) ((v)>>1) #define mod2(v) ((v) & 1) -#define up4(v) (((v)+3) & -4) +#define up4(v) (((v) + 3) & -4) #define down4(v) ((v) & -4) -#define mul4(v) ((v)<<2) +#define mul4(v) ((v) << 2) #define div4(v) ((v)>>2) #define mod4(v) ((v) & 3) -#define up8(v) (((v)+7) & -8) +#define up8(v) (((v) + 7) & -8) #define down8(v) ((v) & -8) #define div8(v) ((v)>>3) #define mod8(v) ((v) & 7) -#define up16(v) (((v)+15) & -16) +#define up16(v) (((v) + 15) & -16) #define down16(v) ((v) & -16) #define div16(v) ((v)>>4) #define mod16(v) ((v) & 15) -#define up32(v) (((v)+31) & -32) +#define up32(v) (((v) + 31) & -32) #define down32(v) ((v) & -32) #define div32(v) ((v)>>5) #define mod32(v) ((v) & 31) -#define up64(v) (((v)+63) & -64) +#define up64(v) (((v) + 63) & -64) #define down64(v) ((v) & -64) #define div64(v) ((v)>>6) #define mod64(v) ((v) & 63) -#define upx(x,v) (((v)+(x)-1) & -(x)) -#define downx(x,v) ((v) & -(x)) -#define modx(x,v) ((v) & ((x)-1)) +#define upx(x, v) (((v) + (x) - 1) & -(x)) +#define downx(x, v) ((v) & -(x)) +#define modx(x, v) ((v) & ((x) - 1)) /* if x1 is not a constant, this macro won't make real sense :-) */ #ifdef __mc68000__ #define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ - "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;}) + "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;}) #else /* We know a bit about the numbers, so we can do it this way */ #define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ @@ -607,7 +608,7 @@ static u_short maxfmode, chipset; #define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ #define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ -#define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */ +#define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */ #define DUMMYSPRITEMEMSIZE (8) static u_long spritememory; @@ -634,9 +635,9 @@ static u_long min_fstrt = 192; * Copper Instructions */ -#define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val)) -#define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val)) -#define CWAIT(x, y) (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe) +#define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val)) +#define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val)) +#define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe) #define CEND (0xfffffffe) @@ -709,7 +710,7 @@ static u_short *lofsprite, *shfsprite, *dummysprite; * Current Video Mode */ -static struct amifb_par { +struct amifb_par { /* General Values */ @@ -772,15 +773,6 @@ static struct amifb_par { /* Additional AGA Hardware Registers */ u_short fmode; /* vmode */ -} currentpar; - - -static struct fb_info fb_info = { - .fix = { - .id = "Amiga ", - .visual = FB_VISUAL_PSEUDOCOLOR, - .accel = FB_ACCEL_AMIGABLITT - } }; @@ -820,116 +812,123 @@ static u_short is_lace = 0; /* Screen is laced */ static struct fb_videomode ami_modedb[] __initdata = { - /* - * AmigaOS Video Modes - * - * If you change these, make sure to update DEFMODE_* as well! - */ - - { - /* 640x200, 15 kHz, 60 Hz (NTSC) */ - "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, - FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ - "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, - FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x256, 15 kHz, 50 Hz (PAL) */ - "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, - FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ - "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, - FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x480, 29 kHz, 57 Hz */ - "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x960, 29 kHz, 57 Hz interlaced */ - "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x200, 15 kHz, 72 Hz */ - "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 15 kHz, 72 Hz interlaced */ - "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 29 kHz, 68 Hz */ - "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x800, 29 kHz, 68 Hz interlaced */ - "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 800x300, 23 kHz, 70 Hz */ - "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 800x600, 23 kHz, 70 Hz interlaced */ - "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x200, 27 kHz, 57 Hz doublescan */ - "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, - 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP - }, { - /* 640x400, 27 kHz, 57 Hz */ - "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x800, 27 kHz, 57 Hz interlaced */ - "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x256, 27 kHz, 47 Hz doublescan */ - "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, - 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP - }, { - /* 640x512, 27 kHz, 47 Hz */ - "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x1024, 27 kHz, 47 Hz interlaced */ - "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, - - /* - * VGA Video Modes - */ - - { - /* 640x480, 31 kHz, 60 Hz (VGA) */ - "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 31 kHz, 70 Hz (VGA) */ - "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, - FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, + /* + * AmigaOS Video Modes + * + * If you change these, make sure to update DEFMODE_* as well! + */ + + { + /* 640x200, 15 kHz, 60 Hz (NTSC) */ + "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ + "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x256, 15 kHz, 50 Hz (PAL) */ + "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ + "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x480, 29 kHz, 57 Hz */ + "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x960, 29 kHz, 57 Hz interlaced */ + "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, + 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 15 kHz, 72 Hz */ + "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 15 kHz, 72 Hz interlaced */ + "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, + 10, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 29 kHz, 68 Hz */ + "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x800, 29 kHz, 68 Hz interlaced */ + "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, + 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 800x300, 23 kHz, 70 Hz */ + "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 800x600, 23 kHz, 70 Hz interlaced */ + "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 27 kHz, 57 Hz doublescan */ + "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* 640x400, 27 kHz, 57 Hz */ + "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x800, 27 kHz, 57 Hz interlaced */ + "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x256, 27 kHz, 47 Hz doublescan */ + "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* 640x512, 27 kHz, 47 Hz */ + "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x1024, 27 kHz, 47 Hz interlaced */ + "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, + + /* + * VGA Video Modes + */ + + { + /* 640x480, 31 kHz, 60 Hz (VGA) */ + "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 31 kHz, 70 Hz (VGA) */ + "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, + FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, + FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, #if 0 - /* - * A2024 video modes - * These modes don't work yet because there's no A2024 driver. - */ - - { - /* 1024x800, 10 Hz */ - "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 1024x800, 15 Hz */ - "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - } + /* + * A2024 video modes + * These modes don't work yet because there's no A2024 driver. + */ + + { + /* 1024x800, 10 Hz */ + "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 1024x800, 15 Hz */ + "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + } #endif }; @@ -953,6 +952,11 @@ 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) */ +static u16 amifb_vfmin __initdata; /* monitor vfreq lower limit (Hz) */ +static u16 amifb_vfmax __initdata; /* monitor vfreq upper limit (Hz) */ + /* * Macros for the conversion from real world values to hardware register @@ -992,19 +996,20 @@ static int amifb_inverse = 0; /* bplcon1 (smooth scrolling) */ #define hscroll2hw(hscroll) \ - (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \ - ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f)) + (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \ + ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \ + ((hscroll)>>2 & 0x000f)) /* diwstrt/diwstop/diwhigh (visible display window) */ #define diwstrt2hw(diwstrt_h, diwstrt_v) \ - (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) + (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) #define diwstop2hw(diwstop_h, diwstop_v) \ - (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) + (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) #define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ - (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \ + (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \ ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ - ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) + ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) /* ddfstrt/ddfstop (display DMA) */ @@ -1015,38 +1020,39 @@ static int amifb_inverse = 0; #define hsstrt2hw(hsstrt) (div8(hsstrt)) #define hsstop2hw(hsstop) (div8(hsstop)) -#define htotal2hw(htotal) (div8(htotal)-1) +#define htotal2hw(htotal) (div8(htotal) - 1) #define vsstrt2hw(vsstrt) (div2(vsstrt)) #define vsstop2hw(vsstop) (div2(vsstop)) -#define vtotal2hw(vtotal) (div2(vtotal)-1) +#define vtotal2hw(vtotal) (div2(vtotal) - 1) #define hcenter2hw(htotal) (div8(htotal)) /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ -#define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) -#define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) +#define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) +#define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) #define vbstrt2hw(vbstrt) (div2(vbstrt)) #define vbstop2hw(vbstop) (div2(vbstop)) /* colour */ #define rgb2hw8_high(red, green, blue) \ - (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) + (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) #define rgb2hw8_low(red, green, blue) \ - (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f)) + (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f)) #define rgb2hw4(red, green, blue) \ - (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) + (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) #define rgb2hw2(red, green, blue) \ - (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4)) + (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4)) /* sprpos/sprctl (sprite positioning) */ #define spr2hw_pos(start_v, start_h) \ - (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff)) + (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff)) #define spr2hw_ctl(start_v, start_h, stop_v) \ - (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \ - ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \ - ((start_h)>>2&0x0001)) + (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \ + ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \ + ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \ + ((start_h)>>2 & 0x0001)) /* get current vertical position of beam */ #define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) @@ -1055,7 +1061,7 @@ static int amifb_inverse = 0; * Copper Initialisation List */ -#define COPINITSIZE (sizeof(copins)*40) +#define COPINITSIZE (sizeof(copins) * 40) enum { cip_bplcon0 @@ -1066,7 +1072,7 @@ enum { * Don't change the order, build_copper()/rebuild_copper() rely on this */ -#define COPLISTSIZE (sizeof(copins)*64) +#define COPLISTSIZE (sizeof(copins) * 64) enum { cop_wait, cop_bplcon0, @@ -1108,82 +1114,1199 @@ static u_short sprfetchmode[3] = { }; +/* --------------------------- Hardware routines --------------------------- */ + /* - * Interface used by the world + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. */ -int amifb_setup(char*); +static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, + const struct fb_info *info) +{ + u_short clk_shift, line_shift; + u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; + u_int htotal, vtotal; -static int amifb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info); -static int amifb_set_par(struct fb_info *info); -static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info); -static int amifb_blank(int blank, struct fb_info *info); -static int amifb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info); -static void amifb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect); -static void amifb_copyarea(struct fb_info *info, - const struct fb_copyarea *region); -static void amifb_imageblit(struct fb_info *info, - const struct fb_image *image); -static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); + /* + * Find a matching Pixel Clock + */ + for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) + if (var->pixclock <= pixclock[clk_shift]) + break; + if (clk_shift > TAG_LORES) { + DPRINTK("pixclock too high\n"); + return -EINVAL; + } + par->clk_shift = clk_shift; /* - * Interface to the low level console driver + * Check the Geometry Values */ -static void amifb_deinit(struct platform_device *pdev); + if ((par->xres = var->xres) < 64) + par->xres = 64; + if ((par->yres = var->yres) < 64) + par->yres = 64; + if ((par->vxres = var->xres_virtual) < par->xres) + par->vxres = par->xres; + if ((par->vyres = var->yres_virtual) < par->yres) + par->vyres = par->yres; + + par->bpp = var->bits_per_pixel; + if (!var->nonstd) { + if (par->bpp < 1) + par->bpp = 1; + if (par->bpp > maxdepth[clk_shift]) { + if (round_down_bpp && maxdepth[clk_shift]) + par->bpp = maxdepth[clk_shift]; + else { + DPRINTK("invalid bpp\n"); + return -EINVAL; + } + } + } else if (var->nonstd == FB_NONSTD_HAM) { + if (par->bpp < 6) + par->bpp = 6; + if (par->bpp != 6) { + if (par->bpp < 8) + par->bpp = 8; + if (par->bpp != 8 || !IS_AGA) { + DPRINTK("invalid bpp for ham mode\n"); + return -EINVAL; + } + } + } else { + DPRINTK("unknown nonstd mode\n"); + return -EINVAL; + } /* - * Internal routines + * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing + * checks failed and smooth scrolling is not possible */ -static int flash_cursor(void); -static irqreturn_t amifb_interrupt(int irq, void *dev_id); -static u_long chipalloc(u_long size); -static void chipfree(void); + par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + line_shift = 0; + break; + case FB_VMODE_NONINTERLACED: + line_shift = 1; + break; + case FB_VMODE_DOUBLE: + if (!IS_AGA) { + DPRINTK("double mode only possible with aga\n"); + return -EINVAL; + } + line_shift = 2; + break; + default: + DPRINTK("unknown video mode\n"); + return -EINVAL; + break; + } + par->line_shift = line_shift; /* - * Hardware routines + * Vertical and Horizontal Timings */ -static int ami_decode_var(struct fb_var_screeninfo *var, - struct amifb_par *par); -static int ami_encode_var(struct fb_var_screeninfo *var, - struct amifb_par *par); -static void ami_pan_var(struct fb_var_screeninfo *var); -static int ami_update_par(void); -static void ami_update_display(void); -static void ami_init_display(void); -static void ami_do_blank(void); -static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix); -static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data); -static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data); -static int ami_get_cursorstate(struct fb_cursorstate *state); -static int ami_set_cursorstate(struct fb_cursorstate *state); -static void ami_set_sprite(void); -static void ami_init_copper(void); -static void ami_reinit_copper(void); -static void ami_build_copper(void); -static void ami_rebuild_copper(void); + xres_n = par->xres << clk_shift; + yres_n = par->yres << line_shift; + par->htotal = down8((var->left_margin + par->xres + var->right_margin + + var->hsync_len) << clk_shift); + par->vtotal = + down2(((var->upper_margin + par->yres + var->lower_margin + + var->vsync_len) << line_shift) + 1); + if (IS_AGA) + par->bplcon3 = sprpixmode[clk_shift]; + else + par->bplcon3 = 0; + if (var->sync & FB_SYNC_BROADCAST) { + par->diwstop_h = par->htotal - + ((var->right_margin - var->hsync_len) << clk_shift); + if (IS_AGA) + par->diwstop_h += mod4(var->hsync_len); + else + par->diwstop_h = down4(par->diwstop_h); + + par->diwstrt_h = par->diwstop_h - xres_n; + par->diwstop_v = par->vtotal - + ((var->lower_margin - var->vsync_len) << line_shift); + par->diwstrt_v = par->diwstop_v - yres_n; + if (par->diwstop_h >= par->htotal + 8) { + DPRINTK("invalid diwstop_h\n"); + return -EINVAL; + } + if (par->diwstop_v > par->vtotal) { + DPRINTK("invalid diwstop_v\n"); + return -EINVAL; + } + + if (!IS_OCS) { + /* Initialize sync with some reasonable values for pwrsave */ + par->hsstrt = 160; + par->hsstop = 320; + par->vsstrt = 30; + par->vsstop = 34; + } else { + par->hsstrt = 0; + par->hsstop = 0; + par->vsstrt = 0; + par->vsstop = 0; + } + if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) { + /* PAL video mode */ + if (par->htotal != PAL_HTOTAL) { + DPRINTK("htotal invalid for pal\n"); + return -EINVAL; + } + if (par->diwstrt_h < PAL_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for pal\n"); + return -EINVAL; + } + if (par->diwstrt_v < PAL_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for pal\n"); + return -EINVAL; + } + htotal = PAL_HTOTAL>>clk_shift; + vtotal = PAL_VTOTAL>>1; + if (!IS_OCS) { + par->beamcon0 = BMC0_PAL; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = BMC0_PAL; + par->hsstop = 1; + } else if (amiga_vblank != 50) { + DPRINTK("pal not supported by this chipset\n"); + return -EINVAL; + } + } else { + /* NTSC video mode + * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK + * and NTSC activated, so than better let diwstop_h <= 1812 + */ + if (par->htotal != NTSC_HTOTAL) { + DPRINTK("htotal invalid for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_h < NTSC_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_v < NTSC_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for ntsc\n"); + return -EINVAL; + } + htotal = NTSC_HTOTAL>>clk_shift; + vtotal = NTSC_VTOTAL>>1; + if (!IS_OCS) { + par->beamcon0 = 0; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = 0; + par->hsstop = 1; + } else if (amiga_vblank != 60) { + DPRINTK("ntsc not supported by this chipset\n"); + return -EINVAL; + } + } + if (IS_OCS) { + if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || + par->diwstrt_v >= 512 || par->diwstop_v < 256) { + DPRINTK("invalid position for display on ocs\n"); + return -EINVAL; + } + } + } else if (!IS_OCS) { + /* Programmable video mode */ + par->hsstrt = var->right_margin << clk_shift; + par->hsstop = (var->right_margin + var->hsync_len) << clk_shift; + par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); + if (!IS_AGA) + par->diwstop_h = down4(par->diwstop_h) - 16; + par->diwstrt_h = par->diwstop_h - xres_n; + par->hbstop = par->diwstrt_h + 4; + par->hbstrt = par->diwstop_h + 4; + if (par->hbstrt >= par->htotal + 8) + par->hbstrt -= par->htotal; + par->hcenter = par->hsstrt + (par->htotal >> 1); + par->vsstrt = var->lower_margin << line_shift; + par->vsstop = (var->lower_margin + var->vsync_len) << line_shift; + par->diwstop_v = par->vtotal; + if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + par->diwstop_v -= 2; + par->diwstrt_v = par->diwstop_v - yres_n; + par->vbstop = par->diwstrt_v - 2; + par->vbstrt = par->diwstop_v - 2; + if (par->vtotal > 2048) { + DPRINTK("vtotal too high\n"); + return -EINVAL; + } + if (par->htotal > 2048) { + DPRINTK("htotal too high\n"); + return -EINVAL; + } + par->bplcon3 |= BPC3_EXTBLKEN; + par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | + BMC0_PAL | BMC0_VARCSYEN; + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->beamcon0 |= BMC0_HSYTRUE; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->beamcon0 |= BMC0_VSYTRUE; + if (var->sync & FB_SYNC_COMP_HIGH_ACT) + par->beamcon0 |= BMC0_CSYTRUE; + htotal = par->htotal>>clk_shift; + vtotal = par->vtotal>>1; + } else { + DPRINTK("only broadcast modes possible for ocs\n"); + return -EINVAL; + } + + /* + * Checking the DMA timing + */ + + fconst = 16 << maxfmode << clk_shift; + + /* + * smallest window start value without turn off other dma cycles + * than sprite1-7, unless you change min_fstrt + */ + + + fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64); + fstrt = downx(fconst, par->diwstrt_h - 4) - fsize; + if (fstrt < min_fstrt) { + DPRINTK("fetch start too low\n"); + return -EINVAL; + } + + /* + * smallest window start value where smooth scrolling is possible + */ + + fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) - + fsize; + if (fstrt < min_fstrt) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + maxfetchstop = down16(par->htotal - 80); + + fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst; + fsize = upx(fconst, xres_n + + modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4))); + if (fstrt + fsize > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = upx(fconst, xres_n); + if (fstrt + fsize > maxfetchstop) { + DPRINTK("fetch stop too high\n"); + return -EINVAL; + } + + if (maxfmode + clk_shift <= 1) { + fsize = up64(xres_n + fconst - 1); + if (min_fstrt + fsize - 64 > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = up64(xres_n); + if (min_fstrt + fsize - 64 > maxfetchstop) { + DPRINTK("fetch size too high\n"); + return -EINVAL; + } + + fsize -= 64; + } else + fsize -= fconst; + + /* + * Check if there is enough time to update the bitplane pointers for ywrap + */ + + if (par->htotal - fsize - 64 < par->bpp * 64) + par->vmode &= ~FB_VMODE_YWRAP; + + /* + * Bitplane calculations and check the Memory Requirements + */ + + if (amifb_ilbm) { + par->next_plane = div8(upx(16 << maxfmode, par->vxres)); + par->next_line = par->bpp * par->next_plane; + if (par->next_line * par->vyres > info->fix.smem_len) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } else { + par->next_line = div8(upx(16 << maxfmode, par->vxres)); + par->next_plane = par->vyres * par->next_line; + if (par->next_plane * par->bpp > info->fix.smem_len) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } + + /* + * Hardware Register Values + */ + + par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; + if (!IS_OCS) + par->bplcon0 |= BPC0_ECSENA; + if (par->bpp == 8) + par->bplcon0 |= BPC0_BPU3; + else + par->bplcon0 |= par->bpp << 12; + if (var->nonstd == FB_NONSTD_HAM) + par->bplcon0 |= BPC0_HAM; + if (var->sync & FB_SYNC_EXT) + par->bplcon0 |= BPC0_ERSY; + + if (IS_AGA) + par->fmode = bplfetchmode[maxfmode]; + + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + par->bplcon0 |= BPC0_LACE; + break; + case FB_VMODE_DOUBLE: + if (IS_AGA) + par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; + break; + } + + if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->xoffset || par->yoffset < 0 || + par->yoffset >= par->vyres) + par->xoffset = par->yoffset = 0; + } else { + if (par->xoffset < 0 || + par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) || + par->yoffset < 0 || par->yoffset > par->vyres - par->yres) + par->xoffset = par->yoffset = 0; + } + } else + par->xoffset = par->yoffset = 0; + + par->crsr.crsr_x = par->crsr.crsr_y = 0; + par->crsr.spot_x = par->crsr.spot_y = 0; + par->crsr.height = par->crsr.width = 0; + + return 0; +} + + /* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static void ami_encode_var(struct fb_var_screeninfo *var, + struct amifb_par *par) +{ + u_short clk_shift, line_shift; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + + clk_shift = par->clk_shift; + line_shift = par->line_shift; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->vxres; + var->yres_virtual = par->vyres; + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red.offset = 0; + var->red.msb_right = 0; + var->red.length = par->bpp; + if (par->bplcon0 & BPC0_HAM) + var->red.length -= 2; + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + + if (par->bplcon0 & BPC0_HAM) + var->nonstd = FB_NONSTD_HAM; + else + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + + var->pixclock = pixclock[clk_shift]; + + if (IS_AGA && par->fmode & FMODE_BSCAN2) + var->vmode = FB_VMODE_DOUBLE; + else if (par->bplcon0 & BPC0_LACE) + var->vmode = FB_VMODE_INTERLACED; + else + var->vmode = FB_VMODE_NONINTERLACED; + + if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { + var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift; + var->right_margin = par->hsstrt>>clk_shift; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift; + var->lower_margin = par->vsstrt>>line_shift; + var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; + var->sync = 0; + if (par->beamcon0 & BMC0_HSYTRUE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (par->beamcon0 & BMC0_VSYTRUE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (par->beamcon0 & BMC0_CSYTRUE) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + } else { + var->sync = FB_SYNC_BROADCAST; + var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); + var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = 4>>line_shift; + var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; + var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - + var->lower_margin - var->vsync_len; + } + + if (par->bplcon0 & BPC0_ERSY) + var->sync |= FB_SYNC_EXT; + if (par->vmode & FB_VMODE_YWRAP) + var->vmode |= FB_VMODE_YWRAP; +} + + + /* + * Update hardware + */ + +static void ami_update_par(struct fb_info *info) +{ + struct amifb_par *par = info->par; + short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; + + clk_shift = par->clk_shift; + + if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) + par->xoffset = upx(16 << maxfmode, par->xoffset); + + fconst = 16 << maxfmode << clk_shift; + vshift = modx(16 << maxfmode, par->xoffset); + fstrt = par->diwstrt_h - (vshift << clk_shift) - 4; + fsize = (par->xres + vshift) << clk_shift; + shift = modx(fconst, fstrt); + move = downx(2 << maxfmode, div8(par->xoffset)); + if (maxfmode + clk_shift > 1) { + fstrt = downx(fconst, fstrt) - 64; + fsize = upx(fconst, fsize); + fstop = fstrt + fsize - fconst; + } else { + mod = fstrt = downx(fconst, fstrt) - fconst; + fstop = fstrt + upx(fconst, fsize) - 64; + fsize = up64(fsize); + fstrt = fstop - fsize + 64; + if (fstrt < min_fstrt) { + fstop += min_fstrt - fstrt; + fstrt = min_fstrt; + } + move = move - div8((mod - fstrt)>>clk_shift); + } + mod = par->next_line - div8(fsize>>clk_shift); + par->ddfstrt = fstrt; + par->ddfstop = fstop; + par->bplcon1 = hscroll2hw(shift); + par->bpl2mod = mod; + if (par->bplcon0 & BPC0_LACE) + par->bpl2mod += par->next_line; + if (IS_AGA && (par->fmode & FMODE_BSCAN2)) + par->bpl1mod = -div8(fsize>>clk_shift); + else + par->bpl1mod = par->bpl2mod; + + if (par->yoffset) { + par->bplpt0 = info->fix.smem_start + + par->next_line * par->yoffset + move; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->yoffset > par->vyres - par->yres) { + par->bplpt0wrap = info->fix.smem_start + move; + if (par->bplcon0 & BPC0_LACE && + mod2(par->diwstrt_v + par->vyres - + par->yoffset)) + par->bplpt0wrap += par->next_line; + } + } + } else + par->bplpt0 = info->fix.smem_start + move; + + if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) + par->bplpt0 += par->next_line; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + * in `var'. + */ + +static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct amifb_par *par = info->par; + + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + par->vmode |= FB_VMODE_YWRAP; + else + par->vmode &= ~FB_VMODE_YWRAP; + + do_vmode_pan = 0; + ami_update_par(info); + do_vmode_pan = 1; +} + + +static void ami_update_display(const struct amifb_par *par) +{ + custom.bplcon1 = par->bplcon1; + custom.bpl1mod = par->bpl1mod; + custom.bpl2mod = par->bpl2mod; + custom.ddfstrt = ddfstrt2hw(par->ddfstrt); + custom.ddfstop = ddfstop2hw(par->ddfstop); +} + + /* + * Change the video mode (called by VBlank interrupt) + */ + +static void ami_init_display(const struct amifb_par *par) +{ + int i; + + custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; + custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; + if (!IS_OCS) { + custom.bplcon3 = par->bplcon3; + if (IS_AGA) + custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; + if (par->beamcon0 & BMC0_VARBEAMEN) { + custom.htotal = htotal2hw(par->htotal); + custom.hbstrt = hbstrt2hw(par->hbstrt); + custom.hbstop = hbstop2hw(par->hbstop); + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.hcenter = hcenter2hw(par->hcenter); + custom.vtotal = vtotal2hw(par->vtotal); + custom.vbstrt = vbstrt2hw(par->vbstrt); + custom.vbstop = vbstop2hw(par->vbstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + } + } + if (!IS_OCS || par->hsstop) + custom.beamcon0 = par->beamcon0; + if (IS_AGA) + custom.fmode = par->fmode; + + /* + * The minimum period for audio depends on htotal + */ + + amiga_audio_min_period = div16(par->htotal); + + is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; +#if 1 + if (is_lace) { + i = custom.vposr >> 15; + } else { + custom.vposw = custom.vposr | 0x8000; + i = 1; + } +#else + i = 1; + custom.vposw = custom.vposr | 0x8000; +#endif + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); +} + + /* + * (Un)Blank the screen (called by VBlank interrupt) + */ + +static void ami_do_blank(const struct amifb_par *par) +{ +#if defined(CONFIG_FB_AMIGA_AGA) + u_short bplcon3 = par->bplcon3; +#endif + u_char red, green, blue; + + if (do_blank > 0) { + custom.dmacon = DMAF_RASTER | DMAF_SPRITE; + red = green = blue = 0; + if (!IS_OCS && do_blank > 1) { + switch (do_blank) { + case FB_BLANK_VSYNC_SUSPEND: + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vtotal + 4); + custom.vsstop = vsstop2hw(par->vtotal + 4); + break; + case FB_BLANK_HSYNC_SUSPEND: + custom.hsstrt = hsstrt2hw(par->htotal + 16); + custom.hsstop = hsstop2hw(par->htotal + 16); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstrt2hw(par->vsstop); + break; + case FB_BLANK_POWERDOWN: + custom.hsstrt = hsstrt2hw(par->htotal + 16); + custom.hsstop = hsstop2hw(par->htotal + 16); + custom.vsstrt = vsstrt2hw(par->vtotal + 4); + custom.vsstop = vsstop2hw(par->vtotal + 4); + break; + } + if (!(par->beamcon0 & BMC0_VARBEAMEN)) { + custom.htotal = htotal2hw(par->htotal); + custom.vtotal = vtotal2hw(par->vtotal); + custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; + } + } + } else { + custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; + red = red0; + green = green0; + blue = blue0; + if (!IS_OCS) { + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + custom.beamcon0 = par->beamcon0; + } + } +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + custom.bplcon3 = bplcon3; + custom.color[0] = rgb2hw8_high(red, green, blue); + custom.bplcon3 = bplcon3 | BPC3_LOCT; + custom.color[0] = rgb2hw8_low(red, green, blue); + custom.bplcon3 = bplcon3; + } else +#endif +#if defined(CONFIG_FB_AMIGA_ECS) + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + for (i = 12; i >= 0; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<= 2; color >>= 2; + for (i = 3; i >= 0; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + } else +#endif + custom.color[0] = rgb2hw4(red, green, blue); + is_blanked = do_blank > 0 ? do_blank : 0; +} + +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, + const struct amifb_par *par) +{ + fix->crsr_width = fix->crsr_xsize = par->crsr.width; + fix->crsr_height = fix->crsr_ysize = par->crsr.height; + fix->crsr_color1 = 17; + fix->crsr_color2 = 18; + return 0; +} + +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, + u_char __user *data, + const struct amifb_par *par) +{ + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + register u_char color; + short height, width, bits, words; + int size, alloc; + + size = par->crsr.height * par->crsr.width; + alloc = var->height * var->width; + var->height = par->crsr.height; + var->width = par->crsr.width; + var->xspot = par->crsr.spot_x; + var->yspot = par->crsr.spot_y; + if (size > var->height * var->width) + return -ENAMETOOLONG; + if (!access_ok(VERIFY_WRITE, data, size)) + return -EFAULT; + delta = 1 << par->crsr.fmode; + lspr = lofsprite + (delta << 1); + if (par->bplcon0 & BPC0_LACE) + sspr = shfsprite + (delta << 1); + else + sspr = NULL; + for (height = (short)var->height - 1; height >= 0; height--) { + bits = 0; words = delta; datawords = 0; + for (width = (short)var->width - 1; width >= 0; width--) { + if (bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" + : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); +#else + datawords = (*(lspr + delta) << 16) | (*lspr++); +#endif + } + --bits; +#ifdef __mc68000__ + asm volatile ( + "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " + "swap %1 ; lslw #1,%1 ; roxlb #1,%0" + : "=d" (color), "=d" (datawords) : "1" (datawords)); +#else + color = (((datawords >> 30) & 2) + | ((datawords >> 15) & 1)); + datawords <<= 1; +#endif + put_user(color, data++); + } + if (bits > 0) { + --words; ++lspr; + } + while (--words >= 0) + ++lspr; +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + return 0; +} + +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, + u_char __user *data, struct amifb_par *par) +{ + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + u_short fmode; + short height, width, bits, words; + + if (!var->width) + return -EINVAL; + else if (var->width <= 16) + fmode = TAG_FMODE_1; + else if (var->width <= 32) + fmode = TAG_FMODE_2; + else if (var->width <= 64) + fmode = TAG_FMODE_4; + else + return -EINVAL; + if (fmode > maxfmode) + return -EINVAL; + if (!var->height) + return -EINVAL; + if (!access_ok(VERIFY_READ, data, var->width * var->height)) + return -EFAULT; + delta = 1 << fmode; + lofsprite = shfsprite = (u_short *)spritememory; + lspr = lofsprite + (delta << 1); + if (par->bplcon0 & BPC0_LACE) { + if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height + 4) << fmode << 2); + shfsprite += ((var->height + 5)&-2) << fmode; + sspr = shfsprite + (delta << 1); + } else { + if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height + 2) << fmode << 2); + sspr = NULL; + } + for (height = (short)var->height - 1; height >= 0; height--) { + bits = 16; words = delta; datawords = 0; + for (width = (short)var->width - 1; width >= 0; width--) { + unsigned long tdata = 0; + get_user(tdata, data); + data++; +#ifdef __mc68000__ + asm volatile ( + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" + : "=d" (datawords) + : "0" (datawords), "d" (tdata)); +#else + datawords = ((datawords << 1) & 0xfffefffe); + datawords |= tdata & 1; + datawords |= (tdata & 2) << (16 - 1); +#endif + if (--bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); +#else + *(lspr + delta) = (u_short) (datawords >> 16); + *lspr++ = (u_short) (datawords & 0xffff); +#endif + } + } + if (bits < 16) { + --words; +#ifdef __mc68000__ + asm volatile ( + "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " + "swap %2 ; lslw %4,%2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); +#else + *(lspr + delta) = (u_short) (datawords >> (16 + bits)); + *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); +#endif + } + while (--words >= 0) { +#ifdef __mc68000__ + asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); +#else + *(lspr + delta) = 0; + *lspr++ = 0; +#endif + } +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + par->crsr.height = var->height; + par->crsr.width = var->width; + par->crsr.spot_x = var->xspot; + par->crsr.spot_y = var->yspot; + par->crsr.fmode = fmode; + if (IS_AGA) { + par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); + par->fmode |= sprfetchmode[fmode]; + custom.fmode = par->fmode; + } + return 0; +} + +static int ami_get_cursorstate(struct fb_cursorstate *state, + const struct amifb_par *par) +{ + state->xoffset = par->crsr.crsr_x; + state->yoffset = par->crsr.crsr_y; + state->mode = cursormode; + return 0; +} + +static int ami_set_cursorstate(struct fb_cursorstate *state, + struct amifb_par *par) +{ + par->crsr.crsr_x = state->xoffset; + par->crsr.crsr_y = state->yoffset; + if ((cursormode = state->mode) == FB_CURSOR_OFF) + cursorstate = -1; + do_cursor = 1; + return 0; +} + +static void ami_set_sprite(const struct amifb_par *par) +{ + copins *copl, *cops; + u_short hs, vs, ve; + u_long pl, ps, pt; + short mx, my; + + cops = copdisplay.list[currentcop][0]; + copl = copdisplay.list[currentcop][1]; + ps = pl = ZTWO_PADDR(dummysprite); + mx = par->crsr.crsr_x - par->crsr.spot_x; + my = par->crsr.crsr_y - par->crsr.spot_y; + if (!(par->vmode & FB_VMODE_YWRAP)) { + mx -= par->xoffset; + my -= par->yoffset; + } + if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && + mx > -(short)par->crsr.width && mx < par->xres && + my > -(short)par->crsr.height && my < par->yres) { + pl = ZTWO_PADDR(lofsprite); + hs = par->diwstrt_h + (mx << par->clk_shift) - 4; + vs = par->diwstrt_v + (my << par->line_shift); + ve = vs + (par->crsr.height << par->line_shift); + if (par->bplcon0 & BPC0_LACE) { + ps = ZTWO_PADDR(shfsprite); + lofsprite[0] = spr2hw_pos(vs, hs); + shfsprite[0] = spr2hw_pos(vs + 1, hs); + if (mod2(vs)) { + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); + shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1); + pt = pl; pl = ps; ps = pt; + } else { + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1); + shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve); + } + } else { + lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); + } + } + copl[cop_spr0ptrh].w[1] = highw(pl); + copl[cop_spr0ptrl].w[1] = loww(pl); + if (par->bplcon0 & BPC0_LACE) { + cops[cop_spr0ptrh].w[1] = highw(ps); + cops[cop_spr0ptrl].w[1] = loww(ps); + } +} + + + /* + * Initialise the Copper Initialisation List + */ + +static void __init ami_init_copper(void) +{ + copins *cop = copdisplay.init; + u_long p; + int i; + + if (!IS_OCS) { + (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); + (cop++)->l = CMOVE(0x0181, diwstrt); + (cop++)->l = CMOVE(0x0281, diwstop); + (cop++)->l = CMOVE(0x0000, diwhigh); + } else + (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); + p = ZTWO_PADDR(dummysprite); + for (i = 0; i < 8; i++) { + (cop++)->l = CMOVE(0, spr[i].pos); + (cop++)->l = CMOVE(highw(p), sprpt[i]); + (cop++)->l = CMOVE2(loww(p), sprpt[i]); + } + + (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); + copdisplay.wait = cop; + (cop++)->l = CEND; + (cop++)->l = CMOVE(0, copjmp2); + cop->l = CEND; + + custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); + custom.copjmp1 = 0; +} + +static void ami_reinit_copper(const struct amifb_par *par) +{ + copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; + copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); +} + + + /* + * Rebuild the Copper List + * + * We only change the things that are not static + */ + +static void ami_rebuild_copper(const struct amifb_par *par) +{ + copins *copl, *cops; + u_short line, h_end1, h_end2; + short i; + u_long p; + + if (IS_AGA && maxfmode + par->clk_shift == 0) + h_end1 = par->diwstrt_h - 64; + else + h_end1 = par->htotal - 32; + h_end2 = par->ddfstop + 64; + + ami_set_sprite(par); + + copl = copdisplay.rebuild[1]; + p = par->bplpt0; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres - par->yres) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1; + while (line >= 512) { + (copl++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (copl++)->l = CWAIT(h_end1, line); + else + (copl++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + } + } else + p = par->bplpt0wrap; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + copl->l = CEND; + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.rebuild[0]; + p = par->bplpt0; + if (mod2(par->diwstrt_v)) + p -= par->next_line; + else + p += par->next_line; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres - par->yres + 1) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2; + while (line >= 512) { + (cops++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (cops++)->l = CWAIT(h_end1, line); + else + (cops++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + if (mod2(par->diwstrt_v + par->vyres - + par->yoffset)) + p -= par->next_line; + else + p += par->next_line; + } + } else + p = par->bplpt0wrap - par->next_line; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + cops->l = CEND; + } +} + + + /* + * Build the Copper List + */ + +static void ami_build_copper(struct fb_info *info) +{ + struct amifb_par *par = info->par; + copins *copl, *cops; + u_long p; + + currentcop = 1 - currentcop; + + copl = copdisplay.list[currentcop][1]; + + (copl++)->l = CWAIT(0, 10); + (copl++)->l = CMOVE(par->bplcon0, bplcon0); + (copl++)->l = CMOVE(0, sprpt[0]); + (copl++)->l = CMOVE2(0, sprpt[0]); + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.list[currentcop][0]; + + (cops++)->l = CWAIT(0, 10); + (cops++)->l = CMOVE(par->bplcon0, bplcon0); + (cops++)->l = CMOVE(0, sprpt[0]); + (cops++)->l = CMOVE2(0, sprpt[0]); + + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop); + (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1, + par->diwstop_h, par->diwstop_v + 1), diwhigh); + (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop); + (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + p = ZTWO_PADDR(copdisplay.list[currentcop][0]); + (copl++)->l = CMOVE(highw(p), cop2lc); + (copl++)->l = CMOVE2(loww(p), cop2lc); + p = ZTWO_PADDR(copdisplay.list[currentcop][1]); + (cops++)->l = CMOVE(highw(p), cop2lc); + (cops++)->l = CMOVE2(loww(p), cop2lc); + copdisplay.rebuild[0] = cops; + } else { + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + } + copdisplay.rebuild[1] = copl; + + ami_update_par(info); + ami_rebuild_copper(info->par); +} -static struct fb_ops amifb_ops = { - .owner = THIS_MODULE, - .fb_check_var = amifb_check_var, - .fb_set_par = amifb_set_par, - .fb_setcolreg = amifb_setcolreg, - .fb_blank = amifb_blank, - .fb_pan_display = amifb_pan_display, - .fb_fillrect = amifb_fillrect, - .fb_copyarea = amifb_copyarea, - .fb_imageblit = amifb_imageblit, - .fb_ioctl = amifb_ioctl, -}; static void __init amifb_setup_mcap(char *spec) { @@ -1216,13 +2339,13 @@ static void __init amifb_setup_mcap(char *spec) if (hmax <= 0 || hmax <= hmin) return; - fb_info.monspecs.vfmin = vmin; - fb_info.monspecs.vfmax = vmax; - fb_info.monspecs.hfmin = hmin; - fb_info.monspecs.hfmax = hmax; + amifb_hfmin = hmin; + amifb_hfmax = hmax; + amifb_vfmin = vmin; + amifb_vfmax = vmax; } -int __init amifb_setup(char *options) +static int __init amifb_setup(char *options) { char *this_opt; @@ -1238,9 +2361,9 @@ int __init amifb_setup(char *options) } else if (!strcmp(this_opt, "ilbm")) amifb_ilbm = 1; else if (!strncmp(this_opt, "monitorcap:", 11)) - amifb_setup_mcap(this_opt+11); + amifb_setup_mcap(this_opt + 11); else if (!strncmp(this_opt, "fstart:", 7)) - min_fstrt = simple_strtoul(this_opt+7, NULL, 0); + min_fstrt = simple_strtoul(this_opt + 7, NULL, 0); else mode_option = this_opt; } @@ -1259,7 +2382,8 @@ static int amifb_check_var(struct fb_var_screeninfo *var, struct amifb_par par; /* Validate wanted screen parameters */ - if ((err = ami_decode_var(var, &par))) + err = ami_decode_var(var, &par, info); + if (err) return err; /* Encode (possibly rounded) screen parameters */ @@ -1270,16 +2394,19 @@ static int amifb_check_var(struct fb_var_screeninfo *var, static int amifb_set_par(struct fb_info *info) { - struct amifb_par *par = (struct amifb_par *)info->par; + struct amifb_par *par = info->par; + int error; do_vmode_pan = 0; do_vmode_full = 0; /* Decode wanted screen parameters */ - ami_decode_var(&info->var, par); + error = ami_decode_var(&info->var, par, info); + if (error) + return error; /* Set new videomode */ - ami_build_copper(); + ami_build_copper(info); /* Set VBlank trigger */ do_vmode_full = 1; @@ -1295,20 +2422,20 @@ static int amifb_set_par(struct fb_info *info) info->fix.type = FB_TYPE_PLANES; info->fix.type_aux = 0; } - info->fix.line_length = div8(upx(16<<maxfmode, par->vxres)); + info->fix.line_length = div8(upx(16 << maxfmode, par->vxres)); if (par->vmode & FB_VMODE_YWRAP) { info->fix.ywrapstep = 1; info->fix.xpanstep = 0; info->fix.ypanstep = 0; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | - FBINFO_READS_FAST; /* override SCROLL_REDRAW */ + FBINFO_READS_FAST; /* override SCROLL_REDRAW */ } else { info->fix.ywrapstep = 0; if (par->vmode & FB_VMODE_SMOOTH_XPAN) info->fix.xpanstep = 1; else - info->fix.xpanstep = 16<<maxfmode; + info->fix.xpanstep = 16 << maxfmode; info->fix.ypanstep = 1; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; } @@ -1317,6 +2444,95 @@ static int amifb_set_par(struct fb_info *info) /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + const struct amifb_par *par = info->par; + + if (IS_AGA) { + if (regno > 255) + return 1; + } else if (par->bplcon0 & BPC0_SHRES) { + if (regno > 3) + return 1; + } else { + if (regno > 31) + return 1; + } + red >>= 8; + green >>= 8; + blue >>= 8; + if (!regno) { + red0 = red; + green0 = green; + blue0 = blue; + } + + /* + * Update the corresponding Hardware Color Register, unless it's Color + * Register 0 and the screen is blanked. + * + * VBlank is switched off to protect bplcon3 or ecs_palette[] from + * being changed by ami_do_blank() during the VBlank. + */ + + if (regno || !is_blanked) { +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + u_short bplcon3 = par->bplcon3; + VBlankOff(); + custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); + custom.color[regno & 31] = rgb2hw8_high(red, green, + blue); + custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) | + BPC3_LOCT; + custom.color[regno & 31] = rgb2hw8_low(red, green, + blue); + custom.bplcon3 = bplcon3; + VBlankOn(); + } else +#endif +#if defined(CONFIG_FB_AMIGA_ECS) + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + VBlankOff(); + for (i = regno + 12; i >= (int)regno; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<= 2; color >>= 2; + regno = down16(regno) + mul4(mod4(regno)); + for (i = regno + 3; i >= (int)regno; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + VBlankOn(); + } else +#endif + custom.color[regno] = rgb2hw4(red, green, blue); + } + return 0; +} + + + /* + * Blank the display. + */ + +static int amifb_blank(int blank, struct fb_info *info) +{ + do_blank = blank ? blank : -1; + + return 0; +} + + + /* * Pan or Wrap the Display * * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag @@ -1327,18 +2543,19 @@ static int amifb_pan_display(struct fb_var_screeninfo *var, { if (var->vmode & FB_VMODE_YWRAP) { if (var->yoffset < 0 || - var->yoffset >= info->var.yres_virtual || var->xoffset) - return -EINVAL; + var->yoffset >= info->var.yres_virtual || var->xoffset) + return -EINVAL; } else { /* * TODO: There will be problems when xpan!=1, so some columns * on the right side will never be seen */ - if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) || - var->yoffset+info->var.yres > info->var.yres_virtual) + if (var->xoffset + info->var.xres > + upx(16 << maxfmode, info->var.xres_virtual) || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; } - ami_pan_var(var); + ami_pan_var(var, info); info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) @@ -1360,10 +2577,10 @@ static int amifb_pan_display(struct fb_var_screeninfo *var, #endif - /* - * Compose two values, using a bitmask as decision value - * This is equivalent to (a & mask) | (b & ~mask) - */ + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ static inline unsigned long comp(unsigned long a, unsigned long b, unsigned long mask) @@ -1379,29 +2596,29 @@ static inline unsigned long xor(unsigned long a, unsigned long b, } - /* - * Unaligned forward bit copy using 32-bit or 64-bit memory accesses - */ + /* + * Unaligned forward bit copy using 32-bit or 64-bit memory accesses + */ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, int src_idx, u32 n) { unsigned long first, last; - int shift = dst_idx-src_idx, left, right; + int shift = dst_idx - src_idx, left, right; unsigned long d0, d1; int m; if (!n) return; - shift = dst_idx-src_idx; + shift = dst_idx - src_idx; first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); if (!shift) { // Same alignment for source and dest - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single word if (last) first &= last; @@ -1413,7 +2630,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, *dst = comp(*src, *dst, first); dst++; src++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1439,17 +2656,17 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, } else { // Different alignment for source and dest - right = shift & (BITS_PER_LONG-1); - left = -shift & (BITS_PER_LONG-1); + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single destination word if (last) first &= last; if (shift > 0) { // Single source word *dst = comp(*src >> right, *dst, first); - } else if (src_idx+n <= BITS_PER_LONG) { + } else if (src_idx + n <= BITS_PER_LONG) { // Single source word *dst = comp(*src << left, *dst, first); } else { @@ -1467,7 +2684,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, // Single source word *dst = comp(d0 >> right, *dst, first); dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } else { // 2 source words d1 = *src++; @@ -1475,7 +2692,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, first); d0 = d1; dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1519,40 +2736,40 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, } - /* - * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses - */ + /* + * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses + */ static void bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, int src_idx, u32 n) { unsigned long first, last; - int shift = dst_idx-src_idx, left, right; + int shift = dst_idx - src_idx, left, right; unsigned long d0, d1; int m; if (!n) return; - dst += (n-1)/BITS_PER_LONG; - src += (n-1)/BITS_PER_LONG; - if ((n-1) % BITS_PER_LONG) { - dst_idx += (n-1) % BITS_PER_LONG; + dst += (n - 1) / BITS_PER_LONG; + src += (n - 1) / BITS_PER_LONG; + if ((n - 1) % BITS_PER_LONG) { + dst_idx += (n - 1) % BITS_PER_LONG; dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= BITS_PER_LONG-1; - src_idx += (n-1) % BITS_PER_LONG; + dst_idx &= BITS_PER_LONG - 1; + src_idx += (n - 1) % BITS_PER_LONG; src += src_idx >> SHIFT_PER_LONG; - src_idx &= BITS_PER_LONG-1; + src_idx &= BITS_PER_LONG - 1; } - shift = dst_idx-src_idx; - first = ~0UL << (BITS_PER_LONG-1-dst_idx); - last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG))); + shift = dst_idx - src_idx; + first = ~0UL << (BITS_PER_LONG - 1 - dst_idx); + last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG))); if (!shift) { // Same alignment for source and dest - if ((unsigned long)dst_idx+1 >= n) { + if ((unsigned long)dst_idx + 1 >= n) { // Single word if (last) first &= last; @@ -1564,7 +2781,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, *dst = comp(*src, *dst, first); dst--; src--; - n -= dst_idx+1; + n -= dst_idx + 1; } // Main chunk @@ -1590,17 +2807,17 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, } else { // Different alignment for source and dest - right = shift & (BITS_PER_LONG-1); - left = -shift & (BITS_PER_LONG-1); + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); - if ((unsigned long)dst_idx+1 >= n) { + if ((unsigned long)dst_idx + 1 >= n) { // Single destination word if (last) first &= last; if (shift < 0) { // Single source word *dst = comp(*src << left, *dst, first); - } else if (1+(unsigned long)src_idx >= n) { + } else if (1 + (unsigned long)src_idx >= n) { // Single source word *dst = comp(*src >> right, *dst, first); } else { @@ -1618,7 +2835,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, // Single source word *dst = comp(d0 << left, *dst, first); dst--; - n -= dst_idx+1; + n -= dst_idx + 1; } else { // 2 source words d1 = *src--; @@ -1626,7 +2843,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, first); d0 = d1; dst--; - n -= dst_idx+1; + n -= dst_idx + 1; } // Main chunk @@ -1670,30 +2887,30 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, } - /* - * Unaligned forward inverting bit copy using 32-bit or 64-bit memory - * accesses - */ + /* + * Unaligned forward inverting bit copy using 32-bit or 64-bit memory + * accesses + */ static void bitcpy_not(unsigned long *dst, int dst_idx, const unsigned long *src, int src_idx, u32 n) { unsigned long first, last; - int shift = dst_idx-src_idx, left, right; + int shift = dst_idx - src_idx, left, right; unsigned long d0, d1; int m; if (!n) return; - shift = dst_idx-src_idx; + shift = dst_idx - src_idx; first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); if (!shift) { // Same alignment for source and dest - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single word if (last) first &= last; @@ -1705,7 +2922,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, *dst = comp(~*src, *dst, first); dst++; src++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1731,17 +2948,17 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, } else { // Different alignment for source and dest - right = shift & (BITS_PER_LONG-1); - left = -shift & (BITS_PER_LONG-1); + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single destination word if (last) first &= last; if (shift > 0) { // Single source word *dst = comp(~*src >> right, *dst, first); - } else if (src_idx+n <= BITS_PER_LONG) { + } else if (src_idx + n <= BITS_PER_LONG) { // Single source word *dst = comp(~*src << left, *dst, first); } else { @@ -1759,7 +2976,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, // Single source word *dst = comp(d0 >> right, *dst, first); dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } else { // 2 source words d1 = ~*src++; @@ -1767,7 +2984,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, first); d0 = d1; dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1811,9 +3028,9 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, } - /* - * Unaligned 32-bit pattern fill using 32/64-bit memory accesses - */ + /* + * Unaligned 32-bit pattern fill using 32/64-bit memory accesses + */ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) { @@ -1828,9 +3045,9 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) #endif first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single word if (last) first &= last; @@ -1841,7 +3058,7 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) if (first) { *dst = comp(val, *dst, first); dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1867,9 +3084,9 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) } - /* - * Unaligned 32-bit pattern xor using 32/64-bit memory accesses - */ + /* + * Unaligned 32-bit pattern xor using 32/64-bit memory accesses + */ static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) { @@ -1884,9 +3101,9 @@ static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) #endif first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single word if (last) first &= last; @@ -1897,7 +3114,7 @@ static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) if (first) { *dst = xor(val, *dst, first); dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1924,12 +3141,12 @@ static inline void fill_one_line(int bpp, unsigned long next_plane, { while (1) { dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); + dst_idx &= (BITS_PER_LONG - 1); bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); if (!--bpp) break; color >>= 1; - dst_idx += next_plane*8; + dst_idx += next_plane * 8; } } @@ -1939,12 +3156,12 @@ static inline void xor_one_line(int bpp, unsigned long next_plane, { while (color) { dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); + dst_idx &= (BITS_PER_LONG - 1); bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); if (!--bpp) break; color >>= 1; - dst_idx += next_plane*8; + dst_idx += next_plane * 8; } } @@ -1952,7 +3169,7 @@ static inline void xor_one_line(int bpp, unsigned long next_plane, static void amifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct amifb_par *par = (struct amifb_par *)info->par; + struct amifb_par *par = info->par; int dst_idx, x2, y2; unsigned long *dst; u32 width, height; @@ -1972,23 +3189,23 @@ static void amifb_fillrect(struct fb_info *info, height = y2 - rect->dy; dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; - dst_idx += rect->dy*par->next_line*8+rect->dx; + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; + dst_idx += rect->dy * par->next_line * 8 + rect->dx; while (height--) { switch (rect->rop) { - case ROP_COPY: + case ROP_COPY: fill_one_line(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, width, rect->color); break; - case ROP_XOR: + case ROP_XOR: xor_one_line(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, width, rect->color); break; } - dst_idx += par->next_line*8; + dst_idx += par->next_line * 8; } } @@ -1998,14 +3215,14 @@ static inline void copy_one_line(int bpp, unsigned long next_plane, { while (1) { dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); + dst_idx &= (BITS_PER_LONG - 1); src += src_idx >> SHIFT_PER_LONG; - src_idx &= (BITS_PER_LONG-1); + src_idx &= (BITS_PER_LONG - 1); bitcpy(dst, dst_idx, src, src_idx, n); if (!--bpp) break; - dst_idx += next_plane*8; - src_idx += next_plane*8; + dst_idx += next_plane * 8; + src_idx += next_plane * 8; } } @@ -2015,14 +3232,14 @@ static inline void copy_one_line_rev(int bpp, unsigned long next_plane, { while (1) { dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); + dst_idx &= (BITS_PER_LONG - 1); src += src_idx >> SHIFT_PER_LONG; - src_idx &= (BITS_PER_LONG-1); + src_idx &= (BITS_PER_LONG - 1); bitcpy_rev(dst, dst_idx, src, src_idx, n); if (!--bpp) break; - dst_idx += next_plane*8; - src_idx += next_plane*8; + dst_idx += next_plane * 8; + src_idx += next_plane * 8; } } @@ -2030,7 +3247,7 @@ static inline void copy_one_line_rev(int bpp, unsigned long next_plane, static void amifb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { - struct amifb_par *par = (struct amifb_par *)info->par; + struct amifb_par *par = info->par; int x2, y2; u32 dx, dy, sx, sy, width, height; unsigned long *dst, *src; @@ -2065,16 +3282,16 @@ static void amifb_copyarea(struct fb_info *info, rev_copy = 1; } dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); src = dst; - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; src_idx = dst_idx; - dst_idx += dy*par->next_line*8+dx; - src_idx += sy*par->next_line*8+sx; + dst_idx += dy * par->next_line * 8 + dx; + src_idx += sy * par->next_line * 8 + sx; if (rev_copy) { while (height--) { - dst_idx -= par->next_line*8; - src_idx -= par->next_line*8; + dst_idx -= par->next_line * 8; + src_idx -= par->next_line * 8; copy_one_line_rev(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, src, src_idx, width); @@ -2084,8 +3301,8 @@ static void amifb_copyarea(struct fb_info *info, copy_one_line(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, src, src_idx, width); - dst_idx += par->next_line*8; - src_idx += par->next_line*8; + dst_idx += par->next_line * 8; + src_idx += par->next_line * 8; } } } @@ -2095,34 +3312,35 @@ static inline void expand_one_line(int bpp, unsigned long next_plane, unsigned long *dst, int dst_idx, u32 n, const u8 *data, u32 bgcolor, u32 fgcolor) { - const unsigned long *src; - int src_idx; - - while (1) { - dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); - if ((bgcolor ^ fgcolor) & 1) { - src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1)); - src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8; - if (fgcolor & 1) - bitcpy(dst, dst_idx, src, src_idx, n); - else - bitcpy_not(dst, dst_idx, src, src_idx, n); - /* set or clear */ - } else - bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); - if (!--bpp) - break; - bgcolor >>= 1; - fgcolor >>= 1; - dst_idx += next_plane*8; - } + const unsigned long *src; + int src_idx; + + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG - 1); + if ((bgcolor ^ fgcolor) & 1) { + src = (unsigned long *) + ((unsigned long)data & ~(BYTES_PER_LONG - 1)); + src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8; + if (fgcolor & 1) + bitcpy(dst, dst_idx, src, src_idx, n); + else + bitcpy_not(dst, dst_idx, src, src_idx, n); + /* set or clear */ + } else + bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); + if (!--bpp) + break; + bgcolor >>= 1; + fgcolor >>= 1; + dst_idx += next_plane * 8; + } } static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) { - struct amifb_par *par = (struct amifb_par *)info->par; + struct amifb_par *par = info->par; int x2, y2; unsigned long *dst; int dst_idx; @@ -2145,17 +3363,17 @@ static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) if (image->depth == 1) { dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; - dst_idx += dy*par->next_line*8+dx; + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; + dst_idx += dy * par->next_line * 8 + dx; src = image->data; - pitch = (image->width+7)/8; + pitch = (image->width + 7) / 8; while (height--) { expand_one_line(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, width, src, image->bg_color, image->fg_color); - dst_idx += par->next_line*8; + dst_idx += par->next_line * 8; src += pitch; } } else { @@ -2182,45 +3400,119 @@ static int amifb_ioctl(struct fb_info *info, int i; switch (cmd) { - case FBIOGET_FCURSORINFO: - i = ami_get_fix_cursorinfo(&crsr.fix); - if (i) - return i; - return copy_to_user(argp, &crsr.fix, - sizeof(crsr.fix)) ? -EFAULT : 0; - - case FBIOGET_VCURSORINFO: - i = ami_get_var_cursorinfo(&crsr.var, - ((struct fb_var_cursorinfo __user *)arg)->data); - if (i) - return i; - return copy_to_user(argp, &crsr.var, - sizeof(crsr.var)) ? -EFAULT : 0; - - case FBIOPUT_VCURSORINFO: - if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) - return -EFAULT; - return ami_set_var_cursorinfo(&crsr.var, - ((struct fb_var_cursorinfo __user *)arg)->data); - - case FBIOGET_CURSORSTATE: - i = ami_get_cursorstate(&crsr.state); - if (i) - return i; - return copy_to_user(argp, &crsr.state, - sizeof(crsr.state)) ? -EFAULT : 0; - - case FBIOPUT_CURSORSTATE: - if (copy_from_user(&crsr.state, argp, - sizeof(crsr.state))) - return -EFAULT; - return ami_set_cursorstate(&crsr.state); + case FBIOGET_FCURSORINFO: + i = ami_get_fix_cursorinfo(&crsr.fix, info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.fix, + sizeof(crsr.fix)) ? -EFAULT : 0; + + case FBIOGET_VCURSORINFO: + i = ami_get_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo __user *)arg)->data, + info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.var, + sizeof(crsr.var)) ? -EFAULT : 0; + + case FBIOPUT_VCURSORINFO: + if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) + return -EFAULT; + return ami_set_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo __user *)arg)->data, + info->par); + + case FBIOGET_CURSORSTATE: + i = ami_get_cursorstate(&crsr.state, info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.state, + sizeof(crsr.state)) ? -EFAULT : 0; + + case FBIOPUT_CURSORSTATE: + if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) + return -EFAULT; + return ami_set_cursorstate(&crsr.state, info->par); } return -EINVAL; } /* + * Flash the cursor (called by VBlank interrupt) + */ + +static int flash_cursor(void) +{ + static int cursorcount = 1; + + if (cursormode == FB_CURSOR_FLASH) { + if (!--cursorcount) { + cursorstate = -cursorstate; + cursorcount = cursorrate; + if (!is_blanked) + return 1; + } + } + return 0; +} + + /* + * VBlank Display Interrupt + */ + +static irqreturn_t amifb_interrupt(int irq, void *dev_id) +{ + struct amifb_par *par = dev_id; + + if (do_vmode_pan || do_vmode_full) + ami_update_display(par); + + if (do_vmode_full) + ami_init_display(par); + + if (do_vmode_pan) { + flash_cursor(); + ami_rebuild_copper(par); + do_cursor = do_vmode_pan = 0; + } else if (do_cursor) { + flash_cursor(); + ami_set_sprite(par); + do_cursor = 0; + } else { + if (flash_cursor()) + ami_set_sprite(par); + } + + if (do_blank) { + ami_do_blank(par); + do_blank = 0; + } + + if (do_vmode_full) { + ami_reinit_copper(par); + do_vmode_full = 0; + } + return IRQ_HANDLED; +} + + +static struct fb_ops amifb_ops = { + .owner = THIS_MODULE, + .fb_check_var = amifb_check_var, + .fb_set_par = amifb_set_par, + .fb_setcolreg = amifb_setcolreg, + .fb_blank = amifb_blank, + .fb_pan_display = amifb_pan_display, + .fb_fillrect = amifb_fillrect, + .fb_copyarea = amifb_copyarea, + .fb_imageblit = amifb_imageblit, + .fb_ioctl = amifb_ioctl, +}; + + + /* * Allocate, Clear and Align a Block of Chip Memory */ @@ -2250,6 +3542,7 @@ static inline void chipfree(void) static int __init amifb_probe(struct platform_device *pdev) { + struct fb_info *info; int tag, i, err = 0; u_long chipptr; u_int defmode; @@ -2265,71 +3558,80 @@ static int __init amifb_probe(struct platform_device *pdev) #endif custom.dmacon = DMAF_ALL | DMAF_MASTER; + info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); + if (!info) { + dev_err(&pdev->dev, "framebuffer_alloc failed\n"); + return -ENOMEM; + } + + strcpy(info->fix.id, "Amiga "); + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.accel = FB_ACCEL_AMIGABLITT; + switch (amiga_chipset) { #ifdef CONFIG_FB_AMIGA_OCS - case CS_OCS: - strcat(fb_info.fix.id, "OCS"); + case CS_OCS: + strcat(info->fix.id, "OCS"); default_chipset: - chipset = TAG_OCS; - maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ - maxdepth[TAG_HIRES] = 4; - maxdepth[TAG_LORES] = 6; - maxfmode = TAG_FMODE_1; - defmode = amiga_vblank == 50 ? DEFMODE_PAL - : DEFMODE_NTSC; - fb_info.fix.smem_len = VIDEOMEMSIZE_OCS; - break; + chipset = TAG_OCS; + maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; + info->fix.smem_len = VIDEOMEMSIZE_OCS; + break; #endif /* CONFIG_FB_AMIGA_OCS */ #ifdef CONFIG_FB_AMIGA_ECS - case CS_ECS: - strcat(fb_info.fix.id, "ECS"); - chipset = TAG_ECS; - maxdepth[TAG_SHRES] = 2; - maxdepth[TAG_HIRES] = 4; - maxdepth[TAG_LORES] = 6; - maxfmode = TAG_FMODE_1; - if (AMIGAHW_PRESENT(AMBER_FF)) - defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL - : DEFMODE_AMBER_NTSC; - else - defmode = amiga_vblank == 50 ? DEFMODE_PAL - : DEFMODE_NTSC; - if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > - VIDEOMEMSIZE_ECS_2M) - fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M; - else - fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M; - break; + case CS_ECS: + strcat(info->fix.id, "ECS"); + chipset = TAG_ECS; + maxdepth[TAG_SHRES] = 2; + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + if (AMIGAHW_PRESENT(AMBER_FF)) + defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL + : DEFMODE_AMBER_NTSC; + else + defmode = amiga_vblank == 50 ? DEFMODE_PAL + : DEFMODE_NTSC; + if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_ECS_2M) + info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; + else + info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; + break; #endif /* CONFIG_FB_AMIGA_ECS */ #ifdef CONFIG_FB_AMIGA_AGA - case CS_AGA: - strcat(fb_info.fix.id, "AGA"); - chipset = TAG_AGA; - maxdepth[TAG_SHRES] = 8; - maxdepth[TAG_HIRES] = 8; - maxdepth[TAG_LORES] = 8; - maxfmode = TAG_FMODE_4; - defmode = DEFMODE_AGA; - if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > - VIDEOMEMSIZE_AGA_2M) - fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M; - else - fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M; - break; + case CS_AGA: + strcat(info->fix.id, "AGA"); + chipset = TAG_AGA; + maxdepth[TAG_SHRES] = 8; + maxdepth[TAG_HIRES] = 8; + maxdepth[TAG_LORES] = 8; + maxfmode = TAG_FMODE_4; + defmode = DEFMODE_AGA; + if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_AGA_2M) + info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; + else + info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; + break; #endif /* CONFIG_FB_AMIGA_AGA */ - default: + default: #ifdef CONFIG_FB_AMIGA_OCS - printk("Unknown graphics chipset, defaulting to OCS\n"); - strcat(fb_info.fix.id, "Unknown"); - goto default_chipset; + printk("Unknown graphics chipset, defaulting to OCS\n"); + strcat(info->fix.id, "Unknown"); + goto default_chipset; #else /* CONFIG_FB_AMIGA_OCS */ - err = -ENODEV; - goto amifb_error; + err = -ENODEV; + goto release; #endif /* CONFIG_FB_AMIGA_OCS */ - break; + break; } /* @@ -2356,42 +3658,44 @@ default_chipset: } } - /* - * These monitor specs are for a typical Amiga monitor (e.g. A1960) - */ - if (fb_info.monspecs.hfmin == 0) { - fb_info.monspecs.hfmin = 15000; - fb_info.monspecs.hfmax = 38000; - fb_info.monspecs.vfmin = 49; - fb_info.monspecs.vfmax = 90; + if (amifb_hfmin) { + info->monspecs.hfmin = amifb_hfmin; + info->monspecs.hfmax = amifb_hfmax; + info->monspecs.vfmin = amifb_vfmin; + info->monspecs.vfmax = amifb_vfmax; + } else { + /* + * These are for a typical Amiga monitor (e.g. A1960) + */ + info->monspecs.hfmin = 15000; + info->monspecs.hfmax = 38000; + info->monspecs.vfmin = 49; + info->monspecs.vfmax = 90; } - fb_info.fbops = &amifb_ops; - fb_info.par = ¤tpar; - fb_info.flags = FBINFO_DEFAULT; - fb_info.device = &pdev->dev; + info->fbops = &amifb_ops; + info->flags = FBINFO_DEFAULT; + info->device = &pdev->dev; - if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, + if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { err = -EINVAL; - goto amifb_error; + goto release; } fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, - &fb_info.modelist); + &info->modelist); round_down_bpp = 0; - chipptr = chipalloc(fb_info.fix.smem_len+ - SPRITEMEMSIZE+ - DUMMYSPRITEMEMSIZE+ - COPINITSIZE+ - 4*COPLISTSIZE); + chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + + DUMMYSPRITEMEMSIZE + COPINITSIZE + + 4 * COPLISTSIZE); if (!chipptr) { err = -ENOMEM; - goto amifb_error; + goto release; } - assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len); + assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); @@ -2403,1398 +3707,78 @@ default_chipset: /* * access the videomem with writethrough cache */ - fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory); - videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start, - fb_info.fix.smem_len); + info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); + videomemory = (u_long)ioremap_writethrough(info->fix.smem_start, + info->fix.smem_len); if (!videomemory) { - printk("amifb: WARNING! unable to map videomem cached writethrough\n"); - fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start); + dev_warn(&pdev->dev, + "Unable to map videomem cached writethrough\n"); + info->screen_base = (char *)ZTWO_VADDR(info->fix.smem_start); } else - fb_info.screen_base = (char *)videomemory; + info->screen_base = (char *)videomemory; memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); /* - * Enable Display DMA - */ - - custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | - DMAF_BLITTER | DMAF_SPRITE; - - /* * Make sure the Copper has something to do */ - ami_init_copper(); - if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, - "fb vertb handler", ¤tpar)) { - err = -EBUSY; - goto amifb_error; - } - - err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0); - if (err) - goto amifb_error; - - if (register_framebuffer(&fb_info) < 0) { - err = -EINVAL; - goto amifb_error; - } - - printk("fb%d: %s frame buffer device, using %dK of video memory\n", - fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10); - - return 0; - -amifb_error: - amifb_deinit(pdev); - return err; -} - -static void amifb_deinit(struct platform_device *pdev) -{ - if (fb_info.cmap.len) - fb_dealloc_cmap(&fb_info.cmap); - fb_dealloc_cmap(&fb_info.cmap); - chipfree(); - if (videomemory) - iounmap((void*)videomemory); - custom.dmacon = DMAF_ALL | DMAF_MASTER; -} - - - /* - * Blank the display. - */ - -static int amifb_blank(int blank, struct fb_info *info) -{ - do_blank = blank ? blank : -1; - - return 0; -} - - /* - * Flash the cursor (called by VBlank interrupt) - */ - -static int flash_cursor(void) -{ - static int cursorcount = 1; - - if (cursormode == FB_CURSOR_FLASH) { - if (!--cursorcount) { - cursorstate = -cursorstate; - cursorcount = cursorrate; - if (!is_blanked) - return 1; - } - } - return 0; -} - - /* - * VBlank Display Interrupt - */ - -static irqreturn_t amifb_interrupt(int irq, void *dev_id) -{ - if (do_vmode_pan || do_vmode_full) - ami_update_display(); - - if (do_vmode_full) - ami_init_display(); - - if (do_vmode_pan) { - flash_cursor(); - ami_rebuild_copper(); - do_cursor = do_vmode_pan = 0; - } else if (do_cursor) { - flash_cursor(); - ami_set_sprite(); - do_cursor = 0; - } else { - if (flash_cursor()) - ami_set_sprite(); - } - - if (do_blank) { - ami_do_blank(); - do_blank = 0; - } - - if (do_vmode_full) { - ami_reinit_copper(); - do_vmode_full = 0; - } - return IRQ_HANDLED; -} - -/* --------------------------- Hardware routines --------------------------- */ - - /* - * Get the video params out of `var'. If a value doesn't fit, round - * it up, if it's too big, return -EINVAL. - */ - -static int ami_decode_var(struct fb_var_screeninfo *var, - struct amifb_par *par) -{ - u_short clk_shift, line_shift; - u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; - u_int htotal, vtotal; - - /* - * Find a matching Pixel Clock - */ - - for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) - if (var->pixclock <= pixclock[clk_shift]) - break; - if (clk_shift > TAG_LORES) { - DPRINTK("pixclock too high\n"); - return -EINVAL; - } - par->clk_shift = clk_shift; - - /* - * Check the Geometry Values - */ - - if ((par->xres = var->xres) < 64) - par->xres = 64; - if ((par->yres = var->yres) < 64) - par->yres = 64; - if ((par->vxres = var->xres_virtual) < par->xres) - par->vxres = par->xres; - if ((par->vyres = var->yres_virtual) < par->yres) - par->vyres = par->yres; - - par->bpp = var->bits_per_pixel; - if (!var->nonstd) { - if (par->bpp < 1) - par->bpp = 1; - if (par->bpp > maxdepth[clk_shift]) { - if (round_down_bpp && maxdepth[clk_shift]) - par->bpp = maxdepth[clk_shift]; - else { - DPRINTK("invalid bpp\n"); - return -EINVAL; - } - } - } else if (var->nonstd == FB_NONSTD_HAM) { - if (par->bpp < 6) - par->bpp = 6; - if (par->bpp != 6) { - if (par->bpp < 8) - par->bpp = 8; - if (par->bpp != 8 || !IS_AGA) { - DPRINTK("invalid bpp for ham mode\n"); - return -EINVAL; - } - } - } else { - DPRINTK("unknown nonstd mode\n"); - return -EINVAL; - } - - /* - * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing - * checks failed and smooth scrolling is not possible - */ - - par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; - switch (par->vmode & FB_VMODE_MASK) { - case FB_VMODE_INTERLACED: - line_shift = 0; - break; - case FB_VMODE_NONINTERLACED: - line_shift = 1; - break; - case FB_VMODE_DOUBLE: - if (!IS_AGA) { - DPRINTK("double mode only possible with aga\n"); - return -EINVAL; - } - line_shift = 2; - break; - default: - DPRINTK("unknown video mode\n"); - return -EINVAL; - break; - } - par->line_shift = line_shift; - - /* - * Vertical and Horizontal Timings - */ - - xres_n = par->xres<<clk_shift; - yres_n = par->yres<<line_shift; - par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift); - par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1); - - if (IS_AGA) - par->bplcon3 = sprpixmode[clk_shift]; - else - par->bplcon3 = 0; - if (var->sync & FB_SYNC_BROADCAST) { - par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift); - if (IS_AGA) - par->diwstop_h += mod4(var->hsync_len); - else - par->diwstop_h = down4(par->diwstop_h); - - par->diwstrt_h = par->diwstop_h - xres_n; - par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift); - par->diwstrt_v = par->diwstop_v - yres_n; - if (par->diwstop_h >= par->htotal+8) { - DPRINTK("invalid diwstop_h\n"); - return -EINVAL; - } - if (par->diwstop_v > par->vtotal) { - DPRINTK("invalid diwstop_v\n"); - return -EINVAL; - } - - if (!IS_OCS) { - /* Initialize sync with some reasonable values for pwrsave */ - par->hsstrt = 160; - par->hsstop = 320; - par->vsstrt = 30; - par->vsstop = 34; - } else { - par->hsstrt = 0; - par->hsstop = 0; - par->vsstrt = 0; - par->vsstop = 0; - } - if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) { - /* PAL video mode */ - if (par->htotal != PAL_HTOTAL) { - DPRINTK("htotal invalid for pal\n"); - return -EINVAL; - } - if (par->diwstrt_h < PAL_DIWSTRT_H) { - DPRINTK("diwstrt_h too low for pal\n"); - return -EINVAL; - } - if (par->diwstrt_v < PAL_DIWSTRT_V) { - DPRINTK("diwstrt_v too low for pal\n"); - return -EINVAL; - } - htotal = PAL_HTOTAL>>clk_shift; - vtotal = PAL_VTOTAL>>1; - if (!IS_OCS) { - par->beamcon0 = BMC0_PAL; - par->bplcon3 |= BPC3_BRDRBLNK; - } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || - AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { - par->beamcon0 = BMC0_PAL; - par->hsstop = 1; - } else if (amiga_vblank != 50) { - DPRINTK("pal not supported by this chipset\n"); - return -EINVAL; - } - } else { - /* NTSC video mode - * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK - * and NTSC activated, so than better let diwstop_h <= 1812 - */ - if (par->htotal != NTSC_HTOTAL) { - DPRINTK("htotal invalid for ntsc\n"); - return -EINVAL; - } - if (par->diwstrt_h < NTSC_DIWSTRT_H) { - DPRINTK("diwstrt_h too low for ntsc\n"); - return -EINVAL; - } - if (par->diwstrt_v < NTSC_DIWSTRT_V) { - DPRINTK("diwstrt_v too low for ntsc\n"); - return -EINVAL; - } - htotal = NTSC_HTOTAL>>clk_shift; - vtotal = NTSC_VTOTAL>>1; - if (!IS_OCS) { - par->beamcon0 = 0; - par->bplcon3 |= BPC3_BRDRBLNK; - } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || - AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { - par->beamcon0 = 0; - par->hsstop = 1; - } else if (amiga_vblank != 60) { - DPRINTK("ntsc not supported by this chipset\n"); - return -EINVAL; - } - } - if (IS_OCS) { - if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || - par->diwstrt_v >= 512 || par->diwstop_v < 256) { - DPRINTK("invalid position for display on ocs\n"); - return -EINVAL; - } - } - } else if (!IS_OCS) { - /* Programmable video mode */ - par->hsstrt = var->right_margin<<clk_shift; - par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift; - par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); - if (!IS_AGA) - par->diwstop_h = down4(par->diwstop_h) - 16; - par->diwstrt_h = par->diwstop_h - xres_n; - par->hbstop = par->diwstrt_h + 4; - par->hbstrt = par->diwstop_h + 4; - if (par->hbstrt >= par->htotal + 8) - par->hbstrt -= par->htotal; - par->hcenter = par->hsstrt + (par->htotal >> 1); - par->vsstrt = var->lower_margin<<line_shift; - par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift; - par->diwstop_v = par->vtotal; - if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) - par->diwstop_v -= 2; - par->diwstrt_v = par->diwstop_v - yres_n; - par->vbstop = par->diwstrt_v - 2; - par->vbstrt = par->diwstop_v - 2; - if (par->vtotal > 2048) { - DPRINTK("vtotal too high\n"); - return -EINVAL; - } - if (par->htotal > 2048) { - DPRINTK("htotal too high\n"); - return -EINVAL; - } - par->bplcon3 |= BPC3_EXTBLKEN; - par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | - BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | - BMC0_PAL | BMC0_VARCSYEN; - if (var->sync & FB_SYNC_HOR_HIGH_ACT) - par->beamcon0 |= BMC0_HSYTRUE; - if (var->sync & FB_SYNC_VERT_HIGH_ACT) - par->beamcon0 |= BMC0_VSYTRUE; - if (var->sync & FB_SYNC_COMP_HIGH_ACT) - par->beamcon0 |= BMC0_CSYTRUE; - htotal = par->htotal>>clk_shift; - vtotal = par->vtotal>>1; - } else { - DPRINTK("only broadcast modes possible for ocs\n"); - return -EINVAL; - } - - /* - * Checking the DMA timing - */ - - fconst = 16<<maxfmode<<clk_shift; - - /* - * smallest window start value without turn off other dma cycles - * than sprite1-7, unless you change min_fstrt - */ - - - fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64); - fstrt = downx(fconst, par->diwstrt_h-4) - fsize; - if (fstrt < min_fstrt) { - DPRINTK("fetch start too low\n"); - return -EINVAL; - } - - /* - * smallest window start value where smooth scrolling is possible - */ - - fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize; - if (fstrt < min_fstrt) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - maxfetchstop = down16(par->htotal - 80); - - fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst; - fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4))); - if (fstrt + fsize > maxfetchstop) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - fsize = upx(fconst, xres_n); - if (fstrt + fsize > maxfetchstop) { - DPRINTK("fetch stop too high\n"); - return -EINVAL; - } - - if (maxfmode + clk_shift <= 1) { - fsize = up64(xres_n + fconst - 1); - if (min_fstrt + fsize - 64 > maxfetchstop) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - fsize = up64(xres_n); - if (min_fstrt + fsize - 64 > maxfetchstop) { - DPRINTK("fetch size too high\n"); - return -EINVAL; - } - - fsize -= 64; - } else - fsize -= fconst; - - /* - * Check if there is enough time to update the bitplane pointers for ywrap - */ - - if (par->htotal-fsize-64 < par->bpp*64) - par->vmode &= ~FB_VMODE_YWRAP; - - /* - * Bitplane calculations and check the Memory Requirements - */ - - if (amifb_ilbm) { - par->next_plane = div8(upx(16<<maxfmode, par->vxres)); - par->next_line = par->bpp*par->next_plane; - if (par->next_line * par->vyres > fb_info.fix.smem_len) { - DPRINTK("too few video mem\n"); - return -EINVAL; - } - } else { - par->next_line = div8(upx(16<<maxfmode, par->vxres)); - par->next_plane = par->vyres*par->next_line; - if (par->next_plane * par->bpp > fb_info.fix.smem_len) { - DPRINTK("too few video mem\n"); - return -EINVAL; - } - } - - /* - * Hardware Register Values - */ - - par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; - if (!IS_OCS) - par->bplcon0 |= BPC0_ECSENA; - if (par->bpp == 8) - par->bplcon0 |= BPC0_BPU3; - else - par->bplcon0 |= par->bpp<<12; - if (var->nonstd == FB_NONSTD_HAM) - par->bplcon0 |= BPC0_HAM; - if (var->sync & FB_SYNC_EXT) - par->bplcon0 |= BPC0_ERSY; - - if (IS_AGA) - par->fmode = bplfetchmode[maxfmode]; - - switch (par->vmode & FB_VMODE_MASK) { - case FB_VMODE_INTERLACED: - par->bplcon0 |= BPC0_LACE; - break; - case FB_VMODE_DOUBLE: - if (IS_AGA) - par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; - break; - } - - if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { - par->xoffset = var->xoffset; - par->yoffset = var->yoffset; - if (par->vmode & FB_VMODE_YWRAP) { - if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres) - par->xoffset = par->yoffset = 0; - } else { - if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) || - par->yoffset < 0 || par->yoffset > par->vyres-par->yres) - par->xoffset = par->yoffset = 0; - } - } else - par->xoffset = par->yoffset = 0; - - par->crsr.crsr_x = par->crsr.crsr_y = 0; - par->crsr.spot_x = par->crsr.spot_y = 0; - par->crsr.height = par->crsr.width = 0; - - return 0; -} - - /* - * Fill the `var' structure based on the values in `par' and maybe - * other values read out of the hardware. - */ - -static int ami_encode_var(struct fb_var_screeninfo *var, - struct amifb_par *par) -{ - u_short clk_shift, line_shift; - - memset(var, 0, sizeof(struct fb_var_screeninfo)); - - clk_shift = par->clk_shift; - line_shift = par->line_shift; - - var->xres = par->xres; - var->yres = par->yres; - var->xres_virtual = par->vxres; - var->yres_virtual = par->vyres; - var->xoffset = par->xoffset; - var->yoffset = par->yoffset; - - var->bits_per_pixel = par->bpp; - var->grayscale = 0; - - var->red.offset = 0; - var->red.msb_right = 0; - var->red.length = par->bpp; - if (par->bplcon0 & BPC0_HAM) - var->red.length -= 2; - var->blue = var->green = var->red; - var->transp.offset = 0; - var->transp.length = 0; - var->transp.msb_right = 0; - - if (par->bplcon0 & BPC0_HAM) - var->nonstd = FB_NONSTD_HAM; - else - var->nonstd = 0; - var->activate = 0; - - var->height = -1; - var->width = -1; - - var->pixclock = pixclock[clk_shift]; - - if (IS_AGA && par->fmode & FMODE_BSCAN2) - var->vmode = FB_VMODE_DOUBLE; - else if (par->bplcon0 & BPC0_LACE) - var->vmode = FB_VMODE_INTERLACED; - else - var->vmode = FB_VMODE_NONINTERLACED; - - if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { - var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift; - var->right_margin = par->hsstrt>>clk_shift; - var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; - var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift; - var->lower_margin = par->vsstrt>>line_shift; - var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; - var->sync = 0; - if (par->beamcon0 & BMC0_HSYTRUE) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (par->beamcon0 & BMC0_VSYTRUE) - var->sync |= FB_SYNC_VERT_HIGH_ACT; - if (par->beamcon0 & BMC0_CSYTRUE) - var->sync |= FB_SYNC_COMP_HIGH_ACT; - } else { - var->sync = FB_SYNC_BROADCAST; - var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); - var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; - var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; - var->vsync_len = 4>>line_shift; - var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; - var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - - var->lower_margin - var->vsync_len; - } - - if (par->bplcon0 & BPC0_ERSY) - var->sync |= FB_SYNC_EXT; - if (par->vmode & FB_VMODE_YWRAP) - var->vmode |= FB_VMODE_YWRAP; - - return 0; -} - - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - * in `var'. - */ - -static void ami_pan_var(struct fb_var_screeninfo *var) -{ - struct amifb_par *par = ¤tpar; - - par->xoffset = var->xoffset; - par->yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - par->vmode |= FB_VMODE_YWRAP; - else - par->vmode &= ~FB_VMODE_YWRAP; - - do_vmode_pan = 0; - ami_update_par(); - do_vmode_pan = 1; -} - - /* - * Update hardware - */ - -static int ami_update_par(void) -{ - struct amifb_par *par = ¤tpar; - short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; - - clk_shift = par->clk_shift; - - if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) - par->xoffset = upx(16<<maxfmode, par->xoffset); - - fconst = 16<<maxfmode<<clk_shift; - vshift = modx(16<<maxfmode, par->xoffset); - fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4; - fsize = (par->xres+vshift)<<clk_shift; - shift = modx(fconst, fstrt); - move = downx(2<<maxfmode, div8(par->xoffset)); - if (maxfmode + clk_shift > 1) { - fstrt = downx(fconst, fstrt) - 64; - fsize = upx(fconst, fsize); - fstop = fstrt + fsize - fconst; - } else { - mod = fstrt = downx(fconst, fstrt) - fconst; - fstop = fstrt + upx(fconst, fsize) - 64; - fsize = up64(fsize); - fstrt = fstop - fsize + 64; - if (fstrt < min_fstrt) { - fstop += min_fstrt - fstrt; - fstrt = min_fstrt; - } - move = move - div8((mod-fstrt)>>clk_shift); - } - mod = par->next_line - div8(fsize>>clk_shift); - par->ddfstrt = fstrt; - par->ddfstop = fstop; - par->bplcon1 = hscroll2hw(shift); - par->bpl2mod = mod; - if (par->bplcon0 & BPC0_LACE) - par->bpl2mod += par->next_line; - if (IS_AGA && (par->fmode & FMODE_BSCAN2)) - par->bpl1mod = -div8(fsize>>clk_shift); - else - par->bpl1mod = par->bpl2mod; - - if (par->yoffset) { - par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move; - if (par->vmode & FB_VMODE_YWRAP) { - if (par->yoffset > par->vyres-par->yres) { - par->bplpt0wrap = fb_info.fix.smem_start + move; - if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset)) - par->bplpt0wrap += par->next_line; - } - } - } else - par->bplpt0 = fb_info.fix.smem_start + move; - - if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) - par->bplpt0 += par->next_line; - - return 0; -} - - - /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (IS_AGA) { - if (regno > 255) - return 1; - } else if (currentpar.bplcon0 & BPC0_SHRES) { - if (regno > 3) - return 1; - } else { - if (regno > 31) - return 1; - } - red >>= 8; - green >>= 8; - blue >>= 8; - if (!regno) { - red0 = red; - green0 = green; - blue0 = blue; - } - - /* - * Update the corresponding Hardware Color Register, unless it's Color - * Register 0 and the screen is blanked. - * - * VBlank is switched off to protect bplcon3 or ecs_palette[] from - * being changed by ami_do_blank() during the VBlank. - */ - - if (regno || !is_blanked) { -#if defined(CONFIG_FB_AMIGA_AGA) - if (IS_AGA) { - u_short bplcon3 = currentpar.bplcon3; - VBlankOff(); - custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000); - custom.color[regno&31] = rgb2hw8_high(red, green, blue); - custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT; - custom.color[regno&31] = rgb2hw8_low(red, green, blue); - custom.bplcon3 = bplcon3; - VBlankOn(); - } else -#endif -#if defined(CONFIG_FB_AMIGA_ECS) - if (currentpar.bplcon0 & BPC0_SHRES) { - u_short color, mask; - int i; - - mask = 0x3333; - color = rgb2hw2(red, green, blue); - VBlankOff(); - for (i = regno+12; i >= (int)regno; i -= 4) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - mask <<=2; color >>= 2; - regno = down16(regno)+mul4(mod4(regno)); - for (i = regno+3; i >= (int)regno; i--) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - VBlankOn(); - } else -#endif - custom.color[regno] = rgb2hw4(red, green, blue); - } - return 0; -} - -static void ami_update_display(void) -{ - struct amifb_par *par = ¤tpar; - - custom.bplcon1 = par->bplcon1; - custom.bpl1mod = par->bpl1mod; - custom.bpl2mod = par->bpl2mod; - custom.ddfstrt = ddfstrt2hw(par->ddfstrt); - custom.ddfstop = ddfstop2hw(par->ddfstop); -} - - /* - * Change the video mode (called by VBlank interrupt) - */ - -static void ami_init_display(void) -{ - struct amifb_par *par = ¤tpar; - int i; - - custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; - custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; - if (!IS_OCS) { - custom.bplcon3 = par->bplcon3; - if (IS_AGA) - custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; - if (par->beamcon0 & BMC0_VARBEAMEN) { - custom.htotal = htotal2hw(par->htotal); - custom.hbstrt = hbstrt2hw(par->hbstrt); - custom.hbstop = hbstop2hw(par->hbstop); - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.hcenter = hcenter2hw(par->hcenter); - custom.vtotal = vtotal2hw(par->vtotal); - custom.vbstrt = vbstrt2hw(par->vbstrt); - custom.vbstop = vbstop2hw(par->vbstop); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstop2hw(par->vsstop); - } - } - if (!IS_OCS || par->hsstop) - custom.beamcon0 = par->beamcon0; - if (IS_AGA) - custom.fmode = par->fmode; - - /* - * The minimum period for audio depends on htotal - */ - - amiga_audio_min_period = div16(par->htotal); - - is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; -#if 1 - if (is_lace) { - i = custom.vposr >> 15; - } else { - custom.vposw = custom.vposr | 0x8000; - i = 1; - } -#else - i = 1; - custom.vposw = custom.vposr | 0x8000; -#endif - custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); -} - - /* - * (Un)Blank the screen (called by VBlank interrupt) + * Enable Display DMA */ + custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_BLITTER | DMAF_SPRITE; -static void ami_do_blank(void) -{ - struct amifb_par *par = ¤tpar; -#if defined(CONFIG_FB_AMIGA_AGA) - u_short bplcon3 = par->bplcon3; -#endif - u_char red, green, blue; - - if (do_blank > 0) { - custom.dmacon = DMAF_RASTER | DMAF_SPRITE; - red = green = blue = 0; - if (!IS_OCS && do_blank > 1) { - switch (do_blank) { - case FB_BLANK_VSYNC_SUSPEND: - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.vsstrt = vsstrt2hw(par->vtotal+4); - custom.vsstop = vsstop2hw(par->vtotal+4); - break; - case FB_BLANK_HSYNC_SUSPEND: - custom.hsstrt = hsstrt2hw(par->htotal+16); - custom.hsstop = hsstop2hw(par->htotal+16); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstrt2hw(par->vsstop); - break; - case FB_BLANK_POWERDOWN: - custom.hsstrt = hsstrt2hw(par->htotal+16); - custom.hsstop = hsstop2hw(par->htotal+16); - custom.vsstrt = vsstrt2hw(par->vtotal+4); - custom.vsstop = vsstop2hw(par->vtotal+4); - break; - } - if (!(par->beamcon0 & BMC0_VARBEAMEN)) { - custom.htotal = htotal2hw(par->htotal); - custom.vtotal = vtotal2hw(par->vtotal); - custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | - BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; - } - } - } else { - custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; - red = red0; - green = green0; - blue = blue0; - if (!IS_OCS) { - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstop2hw(par->vsstop); - custom.beamcon0 = par->beamcon0; - } - } -#if defined(CONFIG_FB_AMIGA_AGA) - if (IS_AGA) { - custom.bplcon3 = bplcon3; - custom.color[0] = rgb2hw8_high(red, green, blue); - custom.bplcon3 = bplcon3 | BPC3_LOCT; - custom.color[0] = rgb2hw8_low(red, green, blue); - custom.bplcon3 = bplcon3; - } else -#endif -#if defined(CONFIG_FB_AMIGA_ECS) - if (par->bplcon0 & BPC0_SHRES) { - u_short color, mask; - int i; - - mask = 0x3333; - color = rgb2hw2(red, green, blue); - for (i = 12; i >= 0; i -= 4) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - mask <<=2; color >>= 2; - for (i = 3; i >= 0; i--) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - } else -#endif - custom.color[0] = rgb2hw4(red, green, blue); - is_blanked = do_blank > 0 ? do_blank : 0; -} - -static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) -{ - struct amifb_par *par = ¤tpar; - - fix->crsr_width = fix->crsr_xsize = par->crsr.width; - fix->crsr_height = fix->crsr_ysize = par->crsr.height; - fix->crsr_color1 = 17; - fix->crsr_color2 = 18; - return 0; -} - -static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) -{ - struct amifb_par *par = ¤tpar; - register u_short *lspr, *sspr; -#ifdef __mc68000__ - register u_long datawords asm ("d2"); -#else - register u_long datawords; -#endif - register short delta; - register u_char color; - short height, width, bits, words; - int size, alloc; - - size = par->crsr.height*par->crsr.width; - alloc = var->height*var->width; - var->height = par->crsr.height; - var->width = par->crsr.width; - var->xspot = par->crsr.spot_x; - var->yspot = par->crsr.spot_y; - if (size > var->height*var->width) - return -ENAMETOOLONG; - if (!access_ok(VERIFY_WRITE, data, size)) - return -EFAULT; - delta = 1<<par->crsr.fmode; - lspr = lofsprite + (delta<<1); - if (par->bplcon0 & BPC0_LACE) - sspr = shfsprite + (delta<<1); - else - sspr = NULL; - for (height = (short)var->height-1; height >= 0; height--) { - bits = 0; words = delta; datawords = 0; - for (width = (short)var->width-1; width >= 0; width--) { - if (bits == 0) { - bits = 16; --words; -#ifdef __mc68000__ - asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" - : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); -#else - datawords = (*(lspr+delta) << 16) | (*lspr++); -#endif - } - --bits; -#ifdef __mc68000__ - asm volatile ( - "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " - "swap %1 ; lslw #1,%1 ; roxlb #1,%0" - : "=d" (color), "=d" (datawords) : "1" (datawords)); -#else - color = (((datawords >> 30) & 2) - | ((datawords >> 15) & 1)); - datawords <<= 1; -#endif - put_user(color, data++); - } - if (bits > 0) { - --words; ++lspr; - } - while (--words >= 0) - ++lspr; -#ifdef __mc68000__ - asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" - : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); -#else - lspr += delta; - if (sspr) { - u_short *tmp = lspr; - lspr = sspr; - sspr = tmp; - } -#endif - } - return 0; -} - -static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) -{ - struct amifb_par *par = ¤tpar; - register u_short *lspr, *sspr; -#ifdef __mc68000__ - register u_long datawords asm ("d2"); -#else - register u_long datawords; -#endif - register short delta; - u_short fmode; - short height, width, bits, words; + err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, + "fb vertb handler", info->par); + if (err) + goto disable_dma; - if (!var->width) - return -EINVAL; - else if (var->width <= 16) - fmode = TAG_FMODE_1; - else if (var->width <= 32) - fmode = TAG_FMODE_2; - else if (var->width <= 64) - fmode = TAG_FMODE_4; - else - return -EINVAL; - if (fmode > maxfmode) - return -EINVAL; - if (!var->height) - return -EINVAL; - if (!access_ok(VERIFY_READ, data, var->width*var->height)) - return -EFAULT; - delta = 1<<fmode; - lofsprite = shfsprite = (u_short *)spritememory; - lspr = lofsprite + (delta<<1); - if (par->bplcon0 & BPC0_LACE) { - if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE) - return -EINVAL; - memset(lspr, 0, (var->height+4)<<fmode<<2); - shfsprite += ((var->height+5)&-2)<<fmode; - sspr = shfsprite + (delta<<1); - } else { - if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE) - return -EINVAL; - memset(lspr, 0, (var->height+2)<<fmode<<2); - sspr = NULL; - } - for (height = (short)var->height-1; height >= 0; height--) { - bits = 16; words = delta; datawords = 0; - for (width = (short)var->width-1; width >= 0; width--) { - unsigned long tdata = 0; - get_user(tdata, data); - data++; -#ifdef __mc68000__ - asm volatile ( - "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " - "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" - : "=d" (datawords) - : "0" (datawords), "d" (tdata)); -#else - datawords = ((datawords << 1) & 0xfffefffe); - datawords |= tdata & 1; - datawords |= (tdata & 2) << (16-1); -#endif - if (--bits == 0) { - bits = 16; --words; -#ifdef __mc68000__ - asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); -#else - *(lspr+delta) = (u_short) (datawords >> 16); - *lspr++ = (u_short) (datawords & 0xffff); -#endif - } - } - if (bits < 16) { - --words; -#ifdef __mc68000__ - asm volatile ( - "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " - "swap %2 ; lslw %4,%2 ; movew %2,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); -#else - *(lspr+delta) = (u_short) (datawords >> (16+bits)); - *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); -#endif - } - while (--words >= 0) { -#ifdef __mc68000__ - asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); -#else - *(lspr+delta) = 0; - *lspr++ = 0; -#endif - } -#ifdef __mc68000__ - asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" - : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); -#else - lspr += delta; - if (sspr) { - u_short *tmp = lspr; - lspr = sspr; - sspr = tmp; - } -#endif - } - par->crsr.height = var->height; - par->crsr.width = var->width; - par->crsr.spot_x = var->xspot; - par->crsr.spot_y = var->yspot; - par->crsr.fmode = fmode; - if (IS_AGA) { - par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); - par->fmode |= sprfetchmode[fmode]; - custom.fmode = par->fmode; - } - return 0; -} + err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); + if (err) + goto free_irq; -static int ami_get_cursorstate(struct fb_cursorstate *state) -{ - struct amifb_par *par = ¤tpar; + dev_set_drvdata(&pdev->dev, info); - state->xoffset = par->crsr.crsr_x; - state->yoffset = par->crsr.crsr_y; - state->mode = cursormode; - return 0; -} + err = register_framebuffer(info); + if (err) + goto unset_drvdata; -static int ami_set_cursorstate(struct fb_cursorstate *state) -{ - struct amifb_par *par = ¤tpar; + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + info->node, info->fix.id, info->fix.smem_len>>10); - par->crsr.crsr_x = state->xoffset; - par->crsr.crsr_y = state->yoffset; - if ((cursormode = state->mode) == FB_CURSOR_OFF) - cursorstate = -1; - do_cursor = 1; return 0; -} - -static void ami_set_sprite(void) -{ - struct amifb_par *par = ¤tpar; - copins *copl, *cops; - u_short hs, vs, ve; - u_long pl, ps, pt; - short mx, my; - - cops = copdisplay.list[currentcop][0]; - copl = copdisplay.list[currentcop][1]; - ps = pl = ZTWO_PADDR(dummysprite); - mx = par->crsr.crsr_x-par->crsr.spot_x; - my = par->crsr.crsr_y-par->crsr.spot_y; - if (!(par->vmode & FB_VMODE_YWRAP)) { - mx -= par->xoffset; - my -= par->yoffset; - } - if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && - mx > -(short)par->crsr.width && mx < par->xres && - my > -(short)par->crsr.height && my < par->yres) { - pl = ZTWO_PADDR(lofsprite); - hs = par->diwstrt_h + (mx<<par->clk_shift) - 4; - vs = par->diwstrt_v + (my<<par->line_shift); - ve = vs + (par->crsr.height<<par->line_shift); - if (par->bplcon0 & BPC0_LACE) { - ps = ZTWO_PADDR(shfsprite); - lofsprite[0] = spr2hw_pos(vs, hs); - shfsprite[0] = spr2hw_pos(vs+1, hs); - if (mod2(vs)) { - lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); - shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1); - pt = pl; pl = ps; ps = pt; - } else { - lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1); - shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve); - } - } else { - lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); - lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); - } - } - copl[cop_spr0ptrh].w[1] = highw(pl); - copl[cop_spr0ptrl].w[1] = loww(pl); - if (par->bplcon0 & BPC0_LACE) { - cops[cop_spr0ptrh].w[1] = highw(ps); - cops[cop_spr0ptrl].w[1] = loww(ps); - } -} - - - /* - * Initialise the Copper Initialisation List - */ - -static void __init ami_init_copper(void) -{ - copins *cop = copdisplay.init; - u_long p; - int i; - - if (!IS_OCS) { - (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); - (cop++)->l = CMOVE(0x0181, diwstrt); - (cop++)->l = CMOVE(0x0281, diwstop); - (cop++)->l = CMOVE(0x0000, diwhigh); - } else - (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); - p = ZTWO_PADDR(dummysprite); - for (i = 0; i < 8; i++) { - (cop++)->l = CMOVE(0, spr[i].pos); - (cop++)->l = CMOVE(highw(p), sprpt[i]); - (cop++)->l = CMOVE2(loww(p), sprpt[i]); - } - - (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); - copdisplay.wait = cop; - (cop++)->l = CEND; - (cop++)->l = CMOVE(0, copjmp2); - cop->l = CEND; - - custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); - custom.copjmp1 = 0; -} -static void ami_reinit_copper(void) -{ - struct amifb_par *par = ¤tpar; - - copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; - copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4); +unset_drvdata: + dev_set_drvdata(&pdev->dev, NULL); + fb_dealloc_cmap(&info->cmap); +free_irq: + free_irq(IRQ_AMIGA_COPPER, info->par); +disable_dma: + custom.dmacon = DMAF_ALL | DMAF_MASTER; + if (videomemory) + iounmap((void *)videomemory); + chipfree(); +release: + framebuffer_release(info); + return err; } - /* - * Build the Copper List - */ - -static void ami_build_copper(void) -{ - struct amifb_par *par = ¤tpar; - copins *copl, *cops; - u_long p; - - currentcop = 1 - currentcop; - - copl = copdisplay.list[currentcop][1]; - - (copl++)->l = CWAIT(0, 10); - (copl++)->l = CMOVE(par->bplcon0, bplcon0); - (copl++)->l = CMOVE(0, sprpt[0]); - (copl++)->l = CMOVE2(0, sprpt[0]); - - if (par->bplcon0 & BPC0_LACE) { - cops = copdisplay.list[currentcop][0]; - - (cops++)->l = CWAIT(0, 10); - (cops++)->l = CMOVE(par->bplcon0, bplcon0); - (cops++)->l = CMOVE(0, sprpt[0]); - (cops++)->l = CMOVE2(0, sprpt[0]); - - (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt); - (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop); - (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); - (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); - if (!IS_OCS) { - (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1, - par->diwstop_h, par->diwstop_v+1), diwhigh); - (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, - par->diwstop_h, par->diwstop_v), diwhigh); -#if 0 - if (par->beamcon0 & BMC0_VARBEAMEN) { - (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt); - (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop); - (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); - (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); - } -#endif - } - p = ZTWO_PADDR(copdisplay.list[currentcop][0]); - (copl++)->l = CMOVE(highw(p), cop2lc); - (copl++)->l = CMOVE2(loww(p), cop2lc); - p = ZTWO_PADDR(copdisplay.list[currentcop][1]); - (cops++)->l = CMOVE(highw(p), cop2lc); - (cops++)->l = CMOVE2(loww(p), cop2lc); - copdisplay.rebuild[0] = cops; - } else { - (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); - (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); - if (!IS_OCS) { - (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, - par->diwstop_h, par->diwstop_v), diwhigh); -#if 0 - if (par->beamcon0 & BMC0_VARBEAMEN) { - (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); - (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); - } -#endif - } - } - copdisplay.rebuild[1] = copl; - - ami_update_par(); - ami_rebuild_copper(); -} - - /* - * Rebuild the Copper List - * - * We only change the things that are not static - */ - -static void ami_rebuild_copper(void) -{ - struct amifb_par *par = ¤tpar; - copins *copl, *cops; - u_short line, h_end1, h_end2; - short i; - u_long p; - - if (IS_AGA && maxfmode + par->clk_shift == 0) - h_end1 = par->diwstrt_h-64; - else - h_end1 = par->htotal-32; - h_end2 = par->ddfstop+64; - - ami_set_sprite(); - - copl = copdisplay.rebuild[1]; - p = par->bplpt0; - if (par->vmode & FB_VMODE_YWRAP) { - if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) { - if (par->yoffset > par->vyres-par->yres) { - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (copl++)->l = CMOVE(highw(p), bplpt[i]); - (copl++)->l = CMOVE2(loww(p), bplpt[i]); - } - line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1; - while (line >= 512) { - (copl++)->l = CWAIT(h_end1, 510); - line -= 512; - } - if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) - (copl++)->l = CWAIT(h_end1, line); - else - (copl++)->l = CWAIT(h_end2, line); - p = par->bplpt0wrap; - } - } else p = par->bplpt0wrap; - } - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (copl++)->l = CMOVE(highw(p), bplpt[i]); - (copl++)->l = CMOVE2(loww(p), bplpt[i]); - } - copl->l = CEND; - - if (par->bplcon0 & BPC0_LACE) { - cops = copdisplay.rebuild[0]; - p = par->bplpt0; - if (mod2(par->diwstrt_v)) - p -= par->next_line; - else - p += par->next_line; - if (par->vmode & FB_VMODE_YWRAP) { - if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) { - if (par->yoffset > par->vyres-par->yres+1) { - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (cops++)->l = CMOVE(highw(p), bplpt[i]); - (cops++)->l = CMOVE2(loww(p), bplpt[i]); - } - line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2; - while (line >= 512) { - (cops++)->l = CWAIT(h_end1, 510); - line -= 512; - } - if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) - (cops++)->l = CWAIT(h_end1, line); - else - (cops++)->l = CWAIT(h_end2, line); - p = par->bplpt0wrap; - if (mod2(par->diwstrt_v+par->vyres-par->yoffset)) - p -= par->next_line; - else - p += par->next_line; - } - } else p = par->bplpt0wrap - par->next_line; - } - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (cops++)->l = CMOVE(highw(p), bplpt[i]); - (cops++)->l = CMOVE2(loww(p), bplpt[i]); - } - cops->l = CEND; - } -} static int __exit amifb_remove(struct platform_device *pdev) { - unregister_framebuffer(&fb_info); - amifb_deinit(pdev); + struct fb_info *info = dev_get_drvdata(&pdev->dev); + + unregister_framebuffer(info); + dev_set_drvdata(&pdev->dev, NULL); + fb_dealloc_cmap(&info->cmap); + free_irq(IRQ_AMIGA_COPPER, info->par); + custom.dmacon = DMAF_ALL | DMAF_MASTER; + if (videomemory) + iounmap((void *)videomemory); + chipfree(); + framebuffer_release(info); amifb_video_off(); return 0; } diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 63409c122ae8..0d7b20d4285d 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -100,8 +100,11 @@ static int atmel_bl_update_status(struct backlight_device *bl) brightness = 0; lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); - lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, + if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE) + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, brightness ? contrast_ctr : 0); + else + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; @@ -682,14 +685,30 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, case FB_VISUAL_PSEUDOCOLOR: if (regno < 256) { - val = ((red >> 11) & 0x001f); - val |= ((green >> 6) & 0x03e0); - val |= ((blue >> 1) & 0x7c00); - - /* - * TODO: intensity bit. Maybe something like - * ~(red[10] ^ green[10] ^ blue[10]) & 1 - */ + if (cpu_is_at91sam9261() || cpu_is_at91sam9263() + || cpu_is_at91sam9rl()) { + /* old style I+BGR:555 */ + val = ((red >> 11) & 0x001f); + val |= ((green >> 6) & 0x03e0); + val |= ((blue >> 1) & 0x7c00); + + /* + * TODO: intensity bit. Maybe something like + * ~(red[10] ^ green[10] ^ blue[10]) & 1 + */ + } else { + /* new style BGR:565 / RGB:565 */ + if (sinfo->lcd_wiring_mode == + ATMEL_LCDC_WIRING_RGB) { + val = ((blue >> 11) & 0x001f); + val |= ((red >> 0) & 0xf800); + } else { + val = ((red >> 11) & 0x001f); + val |= ((blue >> 0) & 0xf800); + } + + val |= ((green >> 5) & 0x07e0); + } lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); ret = 0; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 44bdce4242ad..622f12b62a47 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -301,9 +301,9 @@ static struct fb_ops atyfb_ops = { .fb_sync = atyfb_sync, }; -static int noaccel; +static bool noaccel; #ifdef CONFIG_MTRR -static int nomtrr; +static bool nomtrr; #endif static int vram; static int pll; diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 150684882ef7..ce1506b75adf 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -263,19 +263,19 @@ static reg_val common_regs[] = { static char *mode_option; static char *monitor_layout; -static int noaccel = 0; +static bool noaccel = 0; static int default_dynclk = -2; -static int nomodeset = 0; -static int ignore_edid = 0; -static int mirror = 0; +static bool nomodeset = 0; +static bool ignore_edid = 0; +static bool mirror = 0; static int panel_yres = 0; -static int force_dfp = 0; -static int force_measure_pll = 0; +static bool force_dfp = 0; +static bool force_measure_pll = 0; #ifdef CONFIG_MTRR -static int nomtrr = 0; +static bool nomtrr = 0; #endif -static int force_sleep; -static int ignore_devlist; +static bool force_sleep; +static bool ignore_devlist; #ifdef CONFIG_PMAC_BACKLIGHT static int backlight = 1; #else diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 649cb35de4ed..de9da6774fd9 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -60,18 +60,6 @@ #include "au1100fb.h" -/* - * Sanity check. If this is a new Au1100 based board, search for - * the PB1100 ifdefs to make sure you modify the code accordingly. - */ -#if defined(CONFIG_MIPS_PB1100) - #include <asm/mach-pb1x00/pb1100.h> -#elif defined(CONFIG_MIPS_DB1100) - #include <asm/mach-db1x00/db1x00.h> -#else - #error "Unknown Au1100 board, Au1100 FB driver not supported" -#endif - #define DRIVER_NAME "au1100fb" #define DRIVER_DESC "LCD controller driver for AU1100 processors" diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 72005598040f..04e4479d5afd 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -44,6 +44,7 @@ #include <linux/slab.h> #include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1200fb.h> /* platform_data */ #include "au1200fb.h" #define DRIVER_NAME "au1200fb" @@ -143,6 +144,7 @@ struct au1200_lcd_iodata_t { /* Private, per-framebuffer management information (independent of the panel itself) */ struct au1200fb_device { struct fb_info *fb_info; /* FB driver info record */ + struct au1200fb_platdata *pd; int plane; unsigned char* fb_mem; /* FrameBuffer memory map */ @@ -201,9 +203,6 @@ struct window_settings { #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01 #endif -extern int board_au1200fb_panel_init (void); -extern int board_au1200fb_panel_shutdown (void); - /* * Default window configurations */ @@ -334,8 +333,6 @@ struct panel_settings uint32 mode_toyclksrc; uint32 mode_backlight; uint32 mode_auxpll; - int (*device_init)(void); - int (*device_shutdown)(void); #define Xres min_xres #define Yres min_yres u32 min_xres; /* Minimum horizontal resolution */ @@ -385,8 +382,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 320, 320, 240, 240, }, @@ -415,8 +410,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 640, 480, 640, 480, }, @@ -445,8 +438,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 800, 800, 600, 600, }, @@ -475,8 +466,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 6, /* 72MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 1024, 1024, 768, 768, }, @@ -505,8 +494,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 10, /* 120MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 1280, 1280, 1024, 1024, }, @@ -535,8 +522,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, 1024, 1024, 768, 768, }, @@ -568,8 +553,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, 640, 480, 640, 480, }, @@ -601,8 +584,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, 320, 320, 240, 240, }, @@ -634,11 +615,43 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, 856, 856, 480, 480, }, + [9] = { + .name = "DB1300_800x480", + .monspecs = { + .modedb = NULL, + .modedb_len = 0, + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 60, + .vfmax = 60, + .dclkmin = 6000000, + .dclkmax = 28000000, + .input = FB_DISP_RGB, + }, + .mode_screen = LCD_SCREEN_SX_N(800) | + LCD_SCREEN_SY_N(480), + .mode_horztiming = LCD_HORZTIMING_HPW_N(5) | + LCD_HORZTIMING_HND1_N(16) | + LCD_HORZTIMING_HND2_N(8), + .mode_verttiming = LCD_VERTTIMING_VPW_N(4) | + LCD_VERTTIMING_VND1_N(8) | + LCD_VERTTIMING_VND2_N(5), + .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(1) | + LCD_CLKCONTROL_IV | + LCD_CLKCONTROL_IH, + .mode_pwmdiv = 0x00000000, + .mode_pwmhi = 0x00000000, + .mode_outmask = 0x00FFFFFF, + .mode_fifoctrl = 0x2f2f2f2f, + .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ + .mode_backlight = 0x00000000, + .mode_auxpll = (48/12) * 2, + 800, 800, + 480, 480, + }, }; #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels)) @@ -764,7 +777,8 @@ static int au1200_setlocation (struct au1200fb_device *fbdev, int plane, return 0; } -static void au1200_setpanel (struct panel_settings *newpanel) +static void au1200_setpanel(struct panel_settings *newpanel, + struct au1200fb_platdata *pd) { /* * Perform global setup/init of LCD controller @@ -798,8 +812,8 @@ static void au1200_setpanel (struct panel_settings *newpanel) the controller, the clock cannot be turned off before first shutting down the controller. */ - if (panel->device_shutdown != NULL) - panel->device_shutdown(); + if (pd->panel_shutdown) + pd->panel_shutdown(); } /* Newpanel == NULL indicates a shutdown operation only */ @@ -852,7 +866,8 @@ static void au1200_setpanel (struct panel_settings *newpanel) au_sync(); /* Call init of panel */ - if (panel->device_init != NULL) panel->device_init(); + if (pd->panel_init) + pd->panel_init(); /* FIX!!!! not appropriate on panel change!!! Global setup/init */ lcd->intenable = 0; @@ -1185,6 +1200,8 @@ static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, */ static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi) { + struct au1200fb_device *fbdev = fbi->par; + /* Short-circuit screen blanking */ if (noblanking) return 0; @@ -1194,13 +1211,13 @@ static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi) case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: /* printk("turn on panel\n"); */ - au1200_setpanel(panel); + au1200_setpanel(panel, fbdev->pd); break; case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: /* printk("turn off panel\n"); */ - au1200_setpanel(NULL); + au1200_setpanel(NULL, fbdev->pd); break; default: break; @@ -1428,6 +1445,7 @@ static void get_window(unsigned int plane, static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { + struct au1200fb_device *fbdev = info->par; int plane; int val; @@ -1472,7 +1490,7 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, struct panel_settings *newpanel; panel_index = iodata.global.panel_choice; newpanel = &known_lcd_panels[panel_index]; - au1200_setpanel(newpanel); + au1200_setpanel(newpanel, fbdev->pd); } break; @@ -1588,22 +1606,102 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) /*-------------------------------------------------------------------------*/ -/* AU1200 LCD controller device driver */ +static int au1200fb_setup(struct au1200fb_platdata *pd) +{ + char *options = NULL; + char *this_opt, *endptr; + int num_panels = ARRAY_SIZE(known_lcd_panels); + int panel_idx = -1; + + fb_get_options(DRIVER_NAME, &options); + + if (!options) + goto out; + + while ((this_opt = strsep(&options, ",")) != NULL) { + /* Panel option - can be panel name, + * "bs" for board-switch, or number/index */ + if (!strncmp(this_opt, "panel:", 6)) { + int i; + long int li; + char *endptr; + this_opt += 6; + /* First check for index, which allows + * to short circuit this mess */ + li = simple_strtol(this_opt, &endptr, 0); + if (*endptr == '\0') + panel_idx = (int)li; + else if (strcmp(this_opt, "bs") == 0) + panel_idx = pd->panel_index(); + else { + for (i = 0; i < num_panels; i++) { + if (!strcmp(this_opt, + known_lcd_panels[i].name)) { + panel_idx = i; + break; + } + } + } + if ((panel_idx < 0) || (panel_idx >= num_panels)) + print_warn("Panel %s not supported!", this_opt); + else + panel_index = panel_idx; + + } else if (strncmp(this_opt, "nohwcursor", 10) == 0) + nohwcursor = 1; + else if (strncmp(this_opt, "devices:", 8) == 0) { + this_opt += 8; + device_count = simple_strtol(this_opt, &endptr, 0); + if ((device_count < 0) || + (device_count > MAX_DEVICE_COUNT)) + device_count = MAX_DEVICE_COUNT; + } else if (strncmp(this_opt, "wincfg:", 7) == 0) { + this_opt += 7; + window_index = simple_strtol(this_opt, &endptr, 0); + if ((window_index < 0) || + (window_index >= ARRAY_SIZE(windows))) + window_index = DEFAULT_WINDOW_INDEX; + } else if (strncmp(this_opt, "off", 3) == 0) + return 1; + else + print_warn("Unsupported option \"%s\"", this_opt); + } + +out: + return 0; +} + +/* AU1200 LCD controller device driver */ static int __devinit au1200fb_drv_probe(struct platform_device *dev) { struct au1200fb_device *fbdev; + struct au1200fb_platdata *pd; struct fb_info *fbi = NULL; unsigned long page; int bpp, plane, ret, irq; + print_info("" DRIVER_DESC ""); + + pd = dev->dev.platform_data; + if (!pd) + return -ENODEV; + + /* Setup driver with options */ + if (au1200fb_setup(pd)) + return -ENODEV; + + /* Point to the panel selected */ + panel = &known_lcd_panels[panel_index]; + win = &windows[window_index]; + + printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); + printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); + /* shut gcc up */ ret = 0; fbdev = NULL; - /* Kickstart the panel */ - au1200_setpanel(panel); - for (plane = 0; plane < device_count; ++plane) { bpp = winbpp(win->w[plane].mode_winctrl1); if (win->w[plane].xres == 0) @@ -1619,6 +1717,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) _au1200fb_infos[plane] = fbi; fbdev = fbi->par; fbdev->fb_info = fbi; + fbdev->pd = pd; fbdev->plane = plane; @@ -1680,6 +1779,11 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) goto failed; } + platform_set_drvdata(dev, pd); + + /* Kickstart the panel */ + au1200_setpanel(panel, pd); + return 0; failed: @@ -1699,12 +1803,13 @@ failed: static int __devexit au1200fb_drv_remove(struct platform_device *dev) { + struct au1200fb_platdata *pd = platform_get_drvdata(dev); struct au1200fb_device *fbdev; struct fb_info *fbi; int plane; /* Turn off the panel */ - au1200_setpanel(NULL); + au1200_setpanel(NULL, pd); for (plane = 0; plane < device_count; ++plane) { fbi = _au1200fb_infos[plane]; @@ -1732,7 +1837,8 @@ static int __devexit au1200fb_drv_remove(struct platform_device *dev) #ifdef CONFIG_PM static int au1200fb_drv_suspend(struct device *dev) { - au1200_setpanel(NULL); + struct au1200fb_platdata *pd = dev_get_drvdata(dev); + au1200_setpanel(NULL, pd); lcd->outmask = 0; au_sync(); @@ -1742,11 +1848,12 @@ static int au1200fb_drv_suspend(struct device *dev) static int au1200fb_drv_resume(struct device *dev) { + struct au1200fb_platdata *pd = dev_get_drvdata(dev); struct fb_info *fbi; int i; /* Kickstart the panel */ - au1200_setpanel(panel); + au1200_setpanel(panel, pd); for (i = 0; i < device_count; i++) { fbi = _au1200fb_infos[i]; @@ -1781,100 +1888,8 @@ static struct platform_driver au1200fb_driver = { /*-------------------------------------------------------------------------*/ -/* Kernel driver */ - -static int au1200fb_setup(void) -{ - char *options = NULL; - char *this_opt, *endptr; - int num_panels = ARRAY_SIZE(known_lcd_panels); - int panel_idx = -1; - - fb_get_options(DRIVER_NAME, &options); - - if (options) { - while ((this_opt = strsep(&options,",")) != NULL) { - /* Panel option - can be panel name, - * "bs" for board-switch, or number/index */ - if (!strncmp(this_opt, "panel:", 6)) { - int i; - long int li; - char *endptr; - this_opt += 6; - /* First check for index, which allows - * to short circuit this mess */ - li = simple_strtol(this_opt, &endptr, 0); - if (*endptr == '\0') { - panel_idx = (int)li; - } - else if (strcmp(this_opt, "bs") == 0) { - extern int board_au1200fb_panel(void); - panel_idx = board_au1200fb_panel(); - } - - else - for (i = 0; i < num_panels; i++) { - if (!strcmp(this_opt, known_lcd_panels[i].name)) { - panel_idx = i; - break; - } - } - - if ((panel_idx < 0) || (panel_idx >= num_panels)) { - print_warn("Panel %s not supported!", this_opt); - } - else - panel_index = panel_idx; - } - - else if (strncmp(this_opt, "nohwcursor", 10) == 0) { - nohwcursor = 1; - } - - else if (strncmp(this_opt, "devices:", 8) == 0) { - this_opt += 8; - device_count = simple_strtol(this_opt, - &endptr, 0); - if ((device_count < 0) || - (device_count > MAX_DEVICE_COUNT)) - device_count = MAX_DEVICE_COUNT; - } - - else if (strncmp(this_opt, "wincfg:", 7) == 0) { - this_opt += 7; - window_index = simple_strtol(this_opt, - &endptr, 0); - if ((window_index < 0) || - (window_index >= ARRAY_SIZE(windows))) - window_index = DEFAULT_WINDOW_INDEX; - } - - else if (strncmp(this_opt, "off", 3) == 0) - return 1; - /* Unsupported option */ - else { - print_warn("Unsupported option \"%s\"", this_opt); - } - } - } - return 0; -} - static int __init au1200fb_init(void) { - print_info("" DRIVER_DESC ""); - - /* Setup driver with options */ - if (au1200fb_setup()) - return -ENODEV; - - /* Point to the panel selected */ - panel = &known_lcd_panels[panel_index]; - win = &windows[window_index]; - - printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); - printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); - return platform_driver_register(&au1200fb_driver); } diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 66bc74d9ce2a..378276c9d3cf 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -146,7 +146,7 @@ static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask ret = adp8860_read(client, reg, ®_val); - if (!ret && ((reg_val & bit_mask) == 0)) { + if (!ret && ((reg_val & bit_mask) != bit_mask)) { reg_val |= bit_mask; ret = adp8860_write(client, reg, reg_val); } diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 6c68a6899e87..6735059376d6 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -160,7 +160,7 @@ static int adp8870_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask ret = adp8870_read(client, reg, ®_val); - if (!ret && ((reg_val & bit_mask) == 0)) { + if (!ret && ((reg_val & bit_mask) != bit_mask)) { reg_val |= bit_mask; ret = adp8870_write(client, reg, reg_val); } diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 4f5d1c4cb6ab..27d1d7a29c77 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -190,6 +190,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) priv->io_reg = regulator_get(&spi->dev, "vdd"); if (IS_ERR(priv->io_reg)) { + ret = PTR_ERR(priv->io_reg); dev_err(&spi->dev, "%s: Unable to get the IO regulator\n", __func__); goto err3; @@ -197,6 +198,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) priv->core_reg = regulator_get(&spi->dev, "vcore"); if (IS_ERR(priv->core_reg)) { + ret = PTR_ERR(priv->core_reg); dev_err(&spi->dev, "%s: Unable to get the core regulator\n", __func__); goto err4; diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 6df7c54db0a3..738c8ce7d132 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -280,52 +280,74 @@ MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); #endif /* CONFIG_PCI */ #ifdef CONFIG_ZORRO -static const struct zorro_device_id cirrusfb_zorro_table[] = { +struct zorrocl { + enum cirrus_board type; /* Board type */ + u32 regoffset; /* Offset of registers in first Zorro device */ + u32 ramsize; /* Size of video RAM in first Zorro device */ + /* If zero, use autoprobe on RAM device */ + u32 ramoffset; /* Offset of video RAM in first Zorro device */ + zorro_id ramid; /* Zorro ID of RAM device */ + zorro_id ramid2; /* Zorro ID of optional second RAM device */ +}; + +static const struct zorrocl zcl_sd64 __devinitconst = { + .type = BT_SD64, + .ramid = ZORRO_PROD_HELFRICH_SD64_RAM, +}; + +static const struct zorrocl zcl_piccolo __devinitconst = { + .type = BT_PICCOLO, + .ramid = ZORRO_PROD_HELFRICH_PICCOLO_RAM, +}; + +static const struct zorrocl zcl_picasso __devinitconst = { + .type = BT_PICASSO, + .ramid = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, +}; + +static const struct zorrocl zcl_spectrum __devinitconst = { + .type = BT_SPECTRUM, + .ramid = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, +}; + +static const struct zorrocl zcl_picasso4_z3 __devinitconst = { + .type = BT_PICASSO4, + .regoffset = 0x00600000, + .ramsize = 4 * MB_, + .ramoffset = 0x01000000, /* 0x02000000 for 64 MiB boards */ +}; + +static const struct zorrocl zcl_picasso4_z2 __devinitconst = { + .type = BT_PICASSO4, + .regoffset = 0x10000, + .ramid = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1, + .ramid2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2, +}; + + +static const struct zorro_device_id cirrusfb_zorro_table[] __devinitconst = { { - .id = ZORRO_PROD_HELFRICH_SD64_RAM, - .driver_data = BT_SD64, + .id = ZORRO_PROD_HELFRICH_SD64_REG, + .driver_data = (unsigned long)&zcl_sd64, }, { - .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, - .driver_data = BT_PICCOLO, + .id = ZORRO_PROD_HELFRICH_PICCOLO_REG, + .driver_data = (unsigned long)&zcl_piccolo, }, { - .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, - .driver_data = BT_PICASSO, + .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, + .driver_data = (unsigned long)&zcl_picasso, }, { - .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, - .driver_data = BT_SPECTRUM, + .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, + .driver_data = (unsigned long)&zcl_spectrum, }, { .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, - .driver_data = BT_PICASSO4, + .driver_data = (unsigned long)&zcl_picasso4_z3, + }, { + .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG, + .driver_data = (unsigned long)&zcl_picasso4_z2, }, { 0 } }; MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); - -static const struct { - zorro_id id2; - unsigned long size; -} cirrusfb_zorro_table2[] = { - [BT_SD64] = { - .id2 = ZORRO_PROD_HELFRICH_SD64_REG, - .size = 0x400000 - }, - [BT_PICCOLO] = { - .id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG, - .size = 0x200000 - }, - [BT_PICASSO] = { - .id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, - .size = 0x200000 - }, - [BT_SPECTRUM] = { - .id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, - .size = 0x200000 - }, - [BT_PICASSO4] = { - .id2 = 0, - .size = 0x400000 - } -}; #endif /* CONFIG_ZORRO */ #ifdef CIRRUSFB_DEBUG @@ -350,7 +372,7 @@ struct cirrusfb_info { void (*unmap)(struct fb_info *info); }; -static int noaccel __devinitdata; +static bool noaccel __devinitdata; static char *mode_option __devinitdata = "640x480@60"; /****************************************************************************/ @@ -1956,16 +1978,12 @@ static void cirrusfb_zorro_unmap(struct fb_info *info) struct cirrusfb_info *cinfo = info->par; struct zorro_dev *zdev = to_zorro_dev(info->device); - zorro_release_device(zdev); - - if (cinfo->btype == BT_PICASSO4) { - cinfo->regbase -= 0x600000; - iounmap((void *)cinfo->regbase); + if (info->fix.smem_start > 16 * MB_) iounmap(info->screen_base); - } else { - if (zorro_resource_start(zdev) > 0x01000000) - iounmap(info->screen_base); - } + if (info->fix.mmio_start > 16 * MB_) + iounmap(cinfo->regbase); + + zorro_release_device(zdev); } #endif /* CONFIG_ZORRO */ @@ -2222,115 +2240,116 @@ static struct pci_driver cirrusfb_pci_driver = { static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, const struct zorro_device_id *ent) { - struct cirrusfb_info *cinfo; struct fb_info *info; + int error; + const struct zorrocl *zcl; enum cirrus_board btype; - struct zorro_dev *z2 = NULL; - unsigned long board_addr, board_size, size; - int ret; - - btype = ent->driver_data; - if (cirrusfb_zorro_table2[btype].id2) - z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL); - size = cirrusfb_zorro_table2[btype].size; + unsigned long regbase, ramsize, rambase; + struct cirrusfb_info *cinfo; info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); if (!info) { printk(KERN_ERR "cirrusfb: could not allocate memory\n"); - ret = -ENOMEM; - goto err_out; + return -ENOMEM; + } + + zcl = (const struct zorrocl *)ent->driver_data; + btype = zcl->type; + regbase = zorro_resource_start(z) + zcl->regoffset; + ramsize = zcl->ramsize; + if (ramsize) { + rambase = zorro_resource_start(z) + zcl->ramoffset; + if (zorro_resource_len(z) == 64 * MB_) { + /* Quirk for 64 MiB Picasso IV */ + rambase += zcl->ramoffset; + } + } else { + struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL); + if (!ram || !zorro_resource_len(ram)) { + dev_err(info->device, "No video RAM found\n"); + error = -ENODEV; + goto err_release_fb; + } + rambase = zorro_resource_start(ram); + ramsize = zorro_resource_len(ram); + if (zcl->ramid2 && + (ram = zorro_find_device(zcl->ramid2, NULL))) { + if (zorro_resource_start(ram) != rambase + ramsize) { + dev_warn(info->device, + "Skipping non-contiguous RAM at %pR\n", + &ram->resource); + } else { + ramsize += zorro_resource_len(ram); + } + } } - dev_info(info->device, "%s board detected\n", - cirrusfb_board_info[btype].name); - - cinfo = info->par; - cinfo->btype = btype; - - assert(z); - assert(btype != BT_NONE); - - board_addr = zorro_resource_start(z); - board_size = zorro_resource_len(z); - info->screen_size = size; + dev_info(info->device, + "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n", + cirrusfb_board_info[btype].name, regbase, ramsize / MB_, + rambase); if (!zorro_request_device(z, "cirrusfb")) { - dev_err(info->device, "cannot reserve region 0x%lx, abort\n", - board_addr); - ret = -EBUSY; + dev_err(info->device, "Cannot reserve %pR\n", &z->resource); + error = -EBUSY; goto err_release_fb; } - ret = -EIO; - - if (btype == BT_PICASSO4) { - dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000); - - /* To be precise, for the P4 this is not the */ - /* begin of the board, but the begin of RAM. */ - /* for P4, map in its address space in 2 chunks (### TEST! ) */ - /* (note the ugly hardcoded 16M number) */ - cinfo->regbase = ioremap(board_addr, 16777216); - if (!cinfo->regbase) - goto err_release_region; - - dev_dbg(info->device, "Virtual address for board set to: $%p\n", - cinfo->regbase); - cinfo->regbase += 0x600000; - info->fix.mmio_start = board_addr + 0x600000; - - info->fix.smem_start = board_addr + 16777216; - info->screen_base = ioremap(info->fix.smem_start, 16777216); - if (!info->screen_base) - goto err_unmap_regbase; - } else { - dev_info(info->device, " REG at $%lx\n", - (unsigned long) z2->resource.start); - - info->fix.smem_start = board_addr; - if (board_addr > 0x01000000) - info->screen_base = ioremap(board_addr, board_size); - else - info->screen_base = (caddr_t) ZTWO_VADDR(board_addr); - if (!info->screen_base) - goto err_release_region; + cinfo = info->par; + cinfo->btype = btype; - /* set address for REG area of board */ - cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); - info->fix.mmio_start = z2->resource.start; + info->fix.mmio_start = regbase; + cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024) + : (caddr_t)ZTWO_VADDR(regbase); + if (!cinfo->regbase) { + dev_err(info->device, "Cannot map registers\n"); + error = -EIO; + goto err_release_dev; + } - dev_dbg(info->device, "Virtual address for board set to: $%p\n", - cinfo->regbase); + info->fix.smem_start = rambase; + info->screen_size = ramsize; + info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize) + : (caddr_t)ZTWO_VADDR(rambase); + if (!info->screen_base) { + dev_err(info->device, "Cannot map video RAM\n"); + error = -EIO; + goto err_unmap_reg; } + cinfo->unmap = cirrusfb_zorro_unmap; dev_info(info->device, - "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n", - board_size / MB_, board_addr); - - zorro_set_drvdata(z, info); + "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n", + ramsize / MB_, rambase); /* MCLK select etc. */ if (cirrusfb_board_info[btype].init_sr1f) vga_wseq(cinfo->regbase, CL_SEQR1F, cirrusfb_board_info[btype].sr1f); - ret = cirrusfb_register(info); - if (!ret) - return 0; + error = cirrusfb_register(info); + if (error) { + dev_err(info->device, "Failed to register device, error %d\n", + error); + goto err_unmap_ram; + } - if (btype == BT_PICASSO4 || board_addr > 0x01000000) + zorro_set_drvdata(z, info); + return 0; + +err_unmap_ram: + if (rambase > 16 * MB_) iounmap(info->screen_base); -err_unmap_regbase: - if (btype == BT_PICASSO4) - iounmap(cinfo->regbase - 0x600000); -err_release_region: - release_region(board_addr, board_size); +err_unmap_reg: + if (regbase > 16 * MB_) + iounmap(cinfo->regbase); +err_release_dev: + zorro_release_device(z); err_release_fb: framebuffer_release(info); -err_out: - return ret; + return error; } void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) @@ -2338,6 +2357,7 @@ void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) struct fb_info *info = zorro_get_drvdata(z); cirrusfb_cleanup(info); + zorro_set_drvdata(z, NULL); } static struct zorro_driver cirrusfb_zorro_driver = { diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 93317b5b8740..a122d9287d16 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -25,14 +25,13 @@ #include <asm/system.h> #include <asm/page.h> #include <asm/pgtable.h> +#include <asm/gio_device.h> + #include <video/newport.h> #include <linux/linux_logo.h> #include <linux/font.h> - -extern unsigned long sgi_gfxaddr; - #define FONT_DATA ((unsigned char *)font_vga_8x16.data) /* borrowed from fbcon.c */ @@ -304,12 +303,6 @@ static const char *newport_startup(void) { int i; - if (!sgi_gfxaddr) - return NULL; - - if (!npregs) - npregs = (struct newport_regs *)/* ioremap cannot fail */ - ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); npregs->cset.config = NPORT_CFG_GD0; if (newport_wait(npregs)) @@ -743,26 +736,58 @@ const struct consw newport_con = { .con_save_screen = DUMMY }; -#ifdef MODULE -static int __init newport_console_init(void) +static int newport_probe(struct gio_device *dev, + const struct gio_device_id *id) { - if (!sgi_gfxaddr) - return 0; + unsigned long newport_addr; - if (!npregs) - npregs = (struct newport_regs *)/* ioremap cannot fail */ - ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); + if (!dev->resource.start) + return -EINVAL; + + if (npregs) + return -EBUSY; /* we only support one Newport as console */ + + newport_addr = dev->resource.start + 0xF0000; + if (!request_mem_region(newport_addr, 0x10000, "Newport")) + return -ENODEV; + + npregs = (struct newport_regs *)/* ioremap cannot fail */ + ioremap(newport_addr, sizeof(struct newport_regs)); return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); } -module_init(newport_console_init); -static void __exit newport_console_exit(void) +static void newport_remove(struct gio_device *dev) { give_up_console(&newport_con); iounmap((void *)npregs); } + +static struct gio_device_id newport_ids[] = { + { .id = 0x7e }, + { .id = 0xff } +}; + +MODULE_ALIAS("gio:7e"); + +static struct gio_driver newport_driver = { + .name = "newport", + .id_table = newport_ids, + .probe = newport_probe, + .remove = newport_remove, +}; + +int __init newport_console_init(void) +{ + return gio_register_driver(&newport_driver); +} + +void __exit newport_console_exit(void) +{ + gio_unregister_driver(&newport_driver); +} + +module_init(newport_console_init); module_exit(newport_console_exit); -#endif MODULE_LICENSE("GPL"); diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 7b2c40abae15..0c189b32a4c5 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -420,7 +420,7 @@ static int __init init_control(struct fb_info_control *p) /* Try to pick a video mode out of NVRAM if we have one. */ #ifdef CONFIG_NVRAM - if (default_cmode == CMODE_NVRAM){ + if (default_cmode == CMODE_NVRAM) { cmode = nvram_read_byte(NV_CMODE); if(cmode < CMODE_8 || cmode > CMODE_32) cmode = CMODE_8; diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig deleted file mode 100644 index f99af931d4f8..000000000000 --- a/drivers/video/display/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -# -# Display drivers configuration -# - -menu "Display device support" - -config DISPLAY_SUPPORT - tristate "Display panel/monitor support" - ---help--- - This framework adds support for low-level control of a display. - This includes support for power. - - Enable this to be able to choose the drivers for controlling the - physical display panel/monitor on some platforms. This not only - covers LCD displays for PDAs but also other types of displays - such as CRT, TVout etc. - - To have support for your specific display panel you will have to - select the proper drivers which depend on this option. - -comment "Display hardware drivers" - depends on DISPLAY_SUPPORT - -endmenu diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile deleted file mode 100644 index c0ea832bf171..000000000000 --- a/drivers/video/display/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# Display drivers - -display-objs := display-sysfs.o - -obj-$(CONFIG_DISPLAY_SUPPORT) += display.o - diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c deleted file mode 100644 index 0c647d7af0ee..000000000000 --- a/drivers/video/display/display-sysfs.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * display-sysfs.c - Display output driver sysfs interface - * - * Copyright (C) 2007 James Simmons <jsimmons@infradead.org> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/module.h> -#include <linux/display.h> -#include <linux/ctype.h> -#include <linux/idr.h> -#include <linux/err.h> -#include <linux/kdev_t.h> -#include <linux/slab.h> - -static ssize_t display_show_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct display_device *dsp = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name); -} - -static ssize_t display_show_type(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct display_device *dsp = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type); -} - -static ssize_t display_show_contrast(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct display_device *dsp = dev_get_drvdata(dev); - ssize_t rc = -ENXIO; - - mutex_lock(&dsp->lock); - if (likely(dsp->driver) && dsp->driver->get_contrast) - rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp)); - mutex_unlock(&dsp->lock); - return rc; -} - -static ssize_t display_store_contrast(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct display_device *dsp = dev_get_drvdata(dev); - ssize_t ret = -EINVAL, size; - int contrast; - char *endp; - - contrast = simple_strtoul(buf, &endp, 0); - size = endp - buf; - - if (isspace(*endp)) - size++; - - if (size != count) - return ret; - - mutex_lock(&dsp->lock); - if (likely(dsp->driver && dsp->driver->set_contrast)) { - pr_debug("display: set contrast to %d\n", contrast); - dsp->driver->set_contrast(dsp, contrast); - ret = count; - } - mutex_unlock(&dsp->lock); - return ret; -} - -static ssize_t display_show_max_contrast(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct display_device *dsp = dev_get_drvdata(dev); - ssize_t rc = -ENXIO; - - mutex_lock(&dsp->lock); - if (likely(dsp->driver)) - rc = sprintf(buf, "%d\n", dsp->driver->max_contrast); - mutex_unlock(&dsp->lock); - return rc; -} - -static struct device_attribute display_attrs[] = { - __ATTR(name, S_IRUGO, display_show_name, NULL), - __ATTR(type, S_IRUGO, display_show_type, NULL), - __ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast), - __ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL), -}; - -static int display_suspend(struct device *dev, pm_message_t state) -{ - struct display_device *dsp = dev_get_drvdata(dev); - - mutex_lock(&dsp->lock); - if (likely(dsp->driver->suspend)) - dsp->driver->suspend(dsp, state); - mutex_unlock(&dsp->lock); - return 0; -}; - -static int display_resume(struct device *dev) -{ - struct display_device *dsp = dev_get_drvdata(dev); - - mutex_lock(&dsp->lock); - if (likely(dsp->driver->resume)) - dsp->driver->resume(dsp); - mutex_unlock(&dsp->lock); - return 0; -}; - -static struct mutex allocated_dsp_lock; -static DEFINE_IDR(allocated_dsp); -static struct class *display_class; - -struct display_device *display_device_register(struct display_driver *driver, - struct device *parent, void *devdata) -{ - struct display_device *new_dev = NULL; - int ret = -EINVAL; - - if (unlikely(!driver)) - return ERR_PTR(ret); - - mutex_lock(&allocated_dsp_lock); - ret = idr_pre_get(&allocated_dsp, GFP_KERNEL); - mutex_unlock(&allocated_dsp_lock); - if (!ret) - return ERR_PTR(ret); - - new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL); - if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) { - // Reserve the index for this display - mutex_lock(&allocated_dsp_lock); - ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx); - mutex_unlock(&allocated_dsp_lock); - - if (!ret) { - new_dev->dev = device_create(display_class, parent, - MKDEV(0, 0), new_dev, - "display%d", new_dev->idx); - if (!IS_ERR(new_dev->dev)) { - new_dev->parent = parent; - new_dev->driver = driver; - mutex_init(&new_dev->lock); - return new_dev; - } - mutex_lock(&allocated_dsp_lock); - idr_remove(&allocated_dsp, new_dev->idx); - mutex_unlock(&allocated_dsp_lock); - ret = -EINVAL; - } - } - kfree(new_dev); - return ERR_PTR(ret); -} -EXPORT_SYMBOL(display_device_register); - -void display_device_unregister(struct display_device *ddev) -{ - if (!ddev) - return; - // Free device - mutex_lock(&ddev->lock); - device_unregister(ddev->dev); - mutex_unlock(&ddev->lock); - // Mark device index as available - mutex_lock(&allocated_dsp_lock); - idr_remove(&allocated_dsp, ddev->idx); - mutex_unlock(&allocated_dsp_lock); - kfree(ddev); -} -EXPORT_SYMBOL(display_device_unregister); - -static int __init display_class_init(void) -{ - display_class = class_create(THIS_MODULE, "display"); - if (IS_ERR(display_class)) { - printk(KERN_ERR "Failed to create display class\n"); - display_class = NULL; - return -EINVAL; - } - display_class->dev_attrs = display_attrs; - display_class->suspend = display_suspend; - display_class->resume = display_resume; - mutex_init(&allocated_dsp_lock); - return 0; -} - -static void __exit display_class_exit(void) -{ - class_destroy(display_class); -} - -module_init(display_class_init); -module_exit(display_class_exit); - -MODULE_DESCRIPTION("Display Hardware handling"); -MODULE_AUTHOR("James Simmons <jsimmons@infradead.org>"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ad936295d8f4..ac9141b85356 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -967,6 +967,20 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { u32 activate = var->activate; + /* When using FOURCC mode, make sure the red, green, blue and + * transp fields are set to 0. + */ + if ((info->fix.capabilities & FB_CAP_FOURCC) && + var->grayscale > 1) { + if (var->red.offset || var->green.offset || + var->blue.offset || var->transp.offset || + var->red.length || var->green.length || + var->blue.length || var->transp.length || + var->red.msb_right || var->green.msb_right || + var->blue.msb_right || var->transp.msb_right) + return -EINVAL; + } + if (!info->fbops->fb_check_var) { *var = info->var; goto done; diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index a16beeb5f548..acf292bfba02 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -36,8 +36,7 @@ #include <linux/fsl-diu-fb.h> #include "edid.h" -#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */ - /* 1 for plane 0, 2 for plane 1&2 each */ +#define NUM_AOIS 5 /* 1 for plane 0, 2 for planes 1 & 2 each */ /* HW cursor parameters */ #define MAX_CURS 32 @@ -49,12 +48,6 @@ #define INT_PARERR 0x08 /* Display parameters error interrupt */ #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ -struct diu_addr { - void *vaddr; /* Virtual address */ - dma_addr_t paddr; /* Physical address */ - __u32 offset; -}; - /* * List of supported video modes * @@ -330,23 +323,6 @@ static unsigned int d_cache_line_size; static DEFINE_SPINLOCK(diu_lock); -struct fsl_diu_data { - struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; - /*FSL_AOI_NUM has one dummy AOI */ - struct device_attribute dev_attr; - struct diu_ad *dummy_ad; - void *dummy_aoi_virt; - unsigned int irq; - int fb_enabled; - enum fsl_diu_monitor_port monitor_port; - struct diu __iomem *diu_reg; - spinlock_t reg_lock; - struct diu_addr ad; - struct diu_addr gamma; - struct diu_addr pallete; - struct diu_addr cursor; -}; - enum mfb_index { PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */ PLANE1_AOI0, /* Plane 1, first AOI */ @@ -370,6 +346,42 @@ struct mfb_info { u8 *edid_data; }; +/** + * struct fsl_diu_data - per-DIU data structure + * @dma_addr: DMA address of this structure + * @fsl_diu_info: fb_info objects, one per AOI + * @dev_attr: sysfs structure + * @irq: IRQ + * @monitor_port: the monitor port this DIU is connected to + * @diu_reg: pointer to the DIU hardware registers + * @reg_lock: spinlock for register access + * @dummy_aoi: video buffer for the 4x4 32-bit dummy AOI + * dummy_ad: DIU Area Descriptor for the dummy AOI + * @ad[]: Area Descriptors for each real AOI + * @gamma: gamma color table + * @cursor: hardware cursor data + * + * This data structure must be allocated with 32-byte alignment, so that the + * internal fields can be aligned properly. + */ +struct fsl_diu_data { + dma_addr_t dma_addr; + struct fb_info fsl_diu_info[NUM_AOIS]; + struct mfb_info mfb[NUM_AOIS]; + struct device_attribute dev_attr; + unsigned int irq; + enum fsl_diu_monitor_port monitor_port; + struct diu __iomem *diu_reg; + spinlock_t reg_lock; + u8 dummy_aoi[4 * 4 * 4]; + struct diu_ad dummy_ad __aligned(8); + struct diu_ad ad[NUM_AOIS] __aligned(8); + u8 gamma[256 * 3] __aligned(32); + u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32); +} __aligned(32); + +/* Determine the DMA address of a member of the fsl_diu_data structure */ +#define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f)) static struct mfb_info mfb_template[] = { { @@ -449,37 +461,6 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s) return diu_ops.valid_monitor_port(port); } -/** - * fsl_diu_alloc - allocate memory for the DIU - * @size: number of bytes to allocate - * @param: returned physical address of memory - * - * This function allocates a physically-contiguous block of memory. - */ -static void *fsl_diu_alloc(size_t size, phys_addr_t *phys) -{ - void *virt; - - virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO); - if (virt) - *phys = virt_to_phys(virt); - - return virt; -} - -/** - * fsl_diu_free - release DIU memory - * @virt: pointer returned by fsl_diu_alloc() - * @size: number of bytes allocated by fsl_diu_alloc() - * - * This function releases memory allocated by fsl_diu_alloc(). - */ -static void fsl_diu_free(void *virt, size_t size) -{ - if (virt && size) - free_pages_exact(virt, size); -} - /* * Workaround for failed writing desc register of planes. * Needed with MPC5121 DIU rev 2.0 silicon. @@ -495,8 +476,8 @@ static void fsl_diu_enable_panel(struct fb_info *info) { struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; struct diu_ad *ad = mfbi->ad; - struct fsl_diu_data *machine_data = mfbi->parent; - struct diu __iomem *hw = machine_data->diu_reg; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; switch (mfbi->index) { case PLANE0: @@ -504,7 +485,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) wr_reg_wa(&hw->desc[0], ad->paddr); break; case PLANE1_AOI0: - cmfbi = machine_data->fsl_diu_info[2]->par; + cmfbi = &data->mfb[2]; if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ if (cmfbi->count > 0) /* AOI1 open */ ad->next_ad = @@ -515,7 +496,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) } break; case PLANE2_AOI0: - cmfbi = machine_data->fsl_diu_info[4]->par; + cmfbi = &data->mfb[4]; if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ if (cmfbi->count > 0) /* AOI1 open */ ad->next_ad = @@ -526,17 +507,17 @@ static void fsl_diu_enable_panel(struct fb_info *info) } break; case PLANE1_AOI1: - pmfbi = machine_data->fsl_diu_info[1]->par; + pmfbi = &data->mfb[1]; ad->next_ad = 0; - if (hw->desc[1] == machine_data->dummy_ad->paddr) + if (hw->desc[1] == data->dummy_ad.paddr) wr_reg_wa(&hw->desc[1], ad->paddr); else /* AOI0 open */ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); break; case PLANE2_AOI1: - pmfbi = machine_data->fsl_diu_info[3]->par; + pmfbi = &data->mfb[3]; ad->next_ad = 0; - if (hw->desc[2] == machine_data->dummy_ad->paddr) + if (hw->desc[2] == data->dummy_ad.paddr) wr_reg_wa(&hw->desc[2], ad->paddr); else /* AOI0 was open */ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); @@ -548,52 +529,52 @@ static void fsl_diu_disable_panel(struct fb_info *info) { struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; struct diu_ad *ad = mfbi->ad; - struct fsl_diu_data *machine_data = mfbi->parent; - struct diu __iomem *hw = machine_data->diu_reg; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; switch (mfbi->index) { case PLANE0: - if (hw->desc[0] != machine_data->dummy_ad->paddr) - wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr); + if (hw->desc[0] != data->dummy_ad.paddr) + wr_reg_wa(&hw->desc[0], data->dummy_ad.paddr); break; case PLANE1_AOI0: - cmfbi = machine_data->fsl_diu_info[2]->par; + cmfbi = &data->mfb[2]; if (cmfbi->count > 0) /* AOI1 is open */ wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); /* move AOI1 to the first */ else /* AOI1 was closed */ - wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr); /* close AOI 0 */ break; case PLANE2_AOI0: - cmfbi = machine_data->fsl_diu_info[4]->par; + cmfbi = &data->mfb[4]; if (cmfbi->count > 0) /* AOI1 is open */ wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); /* move AOI1 to the first */ else /* AOI1 was closed */ - wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr); /* close AOI 0 */ break; case PLANE1_AOI1: - pmfbi = machine_data->fsl_diu_info[1]->par; + pmfbi = &data->mfb[1]; if (hw->desc[1] != ad->paddr) { /* AOI1 is not the first in the chain */ if (pmfbi->count > 0) /* AOI0 is open, must be the first */ pmfbi->ad->next_ad = 0; } else /* AOI1 is the first in the chain */ - wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr); /* close AOI 1 */ break; case PLANE2_AOI1: - pmfbi = machine_data->fsl_diu_info[3]->par; + pmfbi = &data->mfb[3]; if (hw->desc[2] != ad->paddr) { /* AOI1 is not the first in the chain */ if (pmfbi->count > 0) /* AOI0 is open, must be the first */ pmfbi->ad->next_ad = 0; } else /* AOI1 is the first in the chain */ - wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr); /* close AOI 1 */ break; } @@ -602,39 +583,33 @@ static void fsl_diu_disable_panel(struct fb_info *info) static void enable_lcdc(struct fb_info *info) { struct mfb_info *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; - struct diu __iomem *hw = machine_data->diu_reg; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; - if (!machine_data->fb_enabled) { - out_be32(&hw->diu_mode, MFB_MODE1); - machine_data->fb_enabled++; - } + out_be32(&hw->diu_mode, MFB_MODE1); } static void disable_lcdc(struct fb_info *info) { struct mfb_info *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; - struct diu __iomem *hw = machine_data->diu_reg; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; - if (machine_data->fb_enabled) { - out_be32(&hw->diu_mode, 0); - machine_data->fb_enabled = 0; - } + out_be32(&hw->diu_mode, 0); } static void adjust_aoi_size_position(struct fb_var_screeninfo *var, struct fb_info *info) { struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; + struct fsl_diu_data *data = mfbi->parent; int available_height, upper_aoi_bottom; enum mfb_index index = mfbi->index; int lower_aoi_is_open, upper_aoi_is_open; __u32 base_plane_width, base_plane_height, upper_aoi_height; - base_plane_width = machine_data->fsl_diu_info[0]->var.xres; - base_plane_height = machine_data->fsl_diu_info[0]->var.yres; + base_plane_width = data->fsl_diu_info[0].var.xres; + base_plane_height = data->fsl_diu_info[0].var.yres; if (mfbi->x_aoi_d < 0) mfbi->x_aoi_d = 0; @@ -649,7 +624,7 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, break; case PLANE1_AOI0: case PLANE2_AOI0: - lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par; + lower_aoi_mfbi = data->fsl_diu_info[index+1].par; lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; if (var->xres > base_plane_width) var->xres = base_plane_width; @@ -667,9 +642,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, break; case PLANE1_AOI1: case PLANE2_AOI1: - upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par; - upper_aoi_height = - machine_data->fsl_diu_info[index-1]->var.yres; + upper_aoi_mfbi = data->fsl_diu_info[index-1].par; + upper_aoi_height = data->fsl_diu_info[index-1].var.yres; upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; if (var->xres > base_plane_width) @@ -809,33 +783,33 @@ static void update_lcdc(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; struct mfb_info *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; + struct fsl_diu_data *data = mfbi->parent; struct diu __iomem *hw; int i, j; - char __iomem *cursor_base, *gamma_table_base; + u8 *gamma_table_base; u32 temp; - hw = machine_data->diu_reg; + hw = data->diu_reg; + + diu_ops.set_monitor_port(data->monitor_port); + gamma_table_base = data->gamma; - diu_ops.set_monitor_port(machine_data->monitor_port); - gamma_table_base = machine_data->gamma.vaddr; - cursor_base = machine_data->cursor.vaddr; /* Prep for DIU init - gamma table, cursor table */ for (i = 0; i <= 2; i++) for (j = 0; j <= 255; j++) *gamma_table_base++ = j; - diu_ops.set_gamma_table(machine_data->monitor_port, - machine_data->gamma.vaddr); + if (diu_ops.set_gamma_table) + diu_ops.set_gamma_table(data->monitor_port, data->gamma); disable_lcdc(info); /* Program DIU registers */ - out_be32(&hw->gamma, machine_data->gamma.paddr); - out_be32(&hw->cursor, machine_data->cursor.paddr); + out_be32(&hw->gamma, DMA_ADDR(data, gamma)); + out_be32(&hw->cursor, DMA_ADDR(data, cursor)); out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ @@ -870,16 +844,17 @@ static void update_lcdc(struct fb_info *info) static int map_video_memory(struct fb_info *info) { - phys_addr_t phys; u32 smem_len = info->fix.line_length * info->var.yres_virtual; + void *p; - info->screen_base = fsl_diu_alloc(smem_len, &phys); - if (info->screen_base == NULL) { + p = alloc_pages_exact(smem_len, GFP_DMA | __GFP_ZERO); + if (!p) { dev_err(info->dev, "unable to allocate fb memory\n"); return -ENOMEM; } mutex_lock(&info->mm_lock); - info->fix.smem_start = (unsigned long) phys; + info->screen_base = p; + info->fix.smem_start = virt_to_phys(info->screen_base); info->fix.smem_len = smem_len; mutex_unlock(&info->mm_lock); info->screen_size = info->fix.smem_len; @@ -889,12 +864,17 @@ static int map_video_memory(struct fb_info *info) static void unmap_video_memory(struct fb_info *info) { - fsl_diu_free(info->screen_base, info->fix.smem_len); + void *p = info->screen_base; + size_t l = info->fix.smem_len; + mutex_lock(&info->mm_lock); info->screen_base = NULL; info->fix.smem_start = 0; info->fix.smem_len = 0; mutex_unlock(&info->mm_lock); + + if (p) + free_pages_exact(p, l); } /* @@ -913,6 +893,59 @@ static int fsl_diu_set_aoi(struct fb_info *info) return 0; } +/** + * fsl_diu_get_pixel_format: return the pixel format for a given color depth + * + * The pixel format is a 32-bit value that determine which bits in each + * pixel are to be used for each color. This is the default function used + * if the platform does not define its own version. + */ +static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel) +{ +#define PF_BYTE_F 0x10000000 +#define PF_ALPHA_C_MASK 0x0E000000 +#define PF_ALPHA_C_SHIFT 25 +#define PF_BLUE_C_MASK 0x01800000 +#define PF_BLUE_C_SHIFT 23 +#define PF_GREEN_C_MASK 0x00600000 +#define PF_GREEN_C_SHIFT 21 +#define PF_RED_C_MASK 0x00180000 +#define PF_RED_C_SHIFT 19 +#define PF_PALETTE 0x00040000 +#define PF_PIXEL_S_MASK 0x00030000 +#define PF_PIXEL_S_SHIFT 16 +#define PF_COMP_3_MASK 0x0000F000 +#define PF_COMP_3_SHIFT 12 +#define PF_COMP_2_MASK 0x00000F00 +#define PF_COMP_2_SHIFT 8 +#define PF_COMP_1_MASK 0x000000F0 +#define PF_COMP_1_SHIFT 4 +#define PF_COMP_0_MASK 0x0000000F +#define PF_COMP_0_SHIFT 0 + +#define MAKE_PF(alpha, red, blue, green, size, c0, c1, c2, c3) \ + cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \ + (blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \ + (red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \ + (c2 << PF_COMP_2_SHIFT) | (c1 << PF_COMP_1_SHIFT) | \ + (c0 << PF_COMP_0_SHIFT) | (size << PF_PIXEL_S_SHIFT)) + + switch (bits_per_pixel) { + case 32: + /* 0x88883316 */ + return MAKE_PF(3, 2, 0, 1, 3, 8, 8, 8, 8); + case 24: + /* 0x88082219 */ + return MAKE_PF(4, 0, 1, 2, 2, 0, 8, 8, 8); + case 16: + /* 0x65053118 */ + return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0); + default: + pr_err("fsl-diu: unsupported color depth %u\n", bits_per_pixel); + return 0; + } +} + /* * Using the fb_var_screeninfo in fb_info we set the resolution of this * particular framebuffer. This function alters the fb_fix_screeninfo stored @@ -926,11 +959,11 @@ static int fsl_diu_set_par(struct fb_info *info) unsigned long len; struct fb_var_screeninfo *var = &info->var; struct mfb_info *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; + struct fsl_diu_data *data = mfbi->parent; struct diu_ad *ad = mfbi->ad; struct diu __iomem *hw; - hw = machine_data->diu_reg; + hw = data->diu_reg; set_fix(info); mfbi->cursor_reset = 1; @@ -948,8 +981,12 @@ static int fsl_diu_set_par(struct fb_info *info) } } - ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port, - var->bits_per_pixel); + if (diu_ops.get_pixel_format) + ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port, + var->bits_per_pixel); + else + ad->pix_fmt = fsl_diu_get_pixel_format(var->bits_per_pixel); + ad->addr = cpu_to_le32(info->fix.smem_start); ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | var->xres_virtual) | mfbi->g_alpha; @@ -1208,21 +1245,6 @@ static struct fb_ops fsl_diu_ops = { .fb_release = fsl_diu_release, }; -static int init_fbinfo(struct fb_info *info) -{ - struct mfb_info *mfbi = info->par; - - info->device = NULL; - info->var.activate = FB_ACTIVATE_NOW; - info->fbops = &fsl_diu_ops; - info->flags = FBINFO_FLAG_DEFAULT; - info->pseudo_palette = &mfbi->pseudo_palette; - - /* Allocate colormap */ - fb_alloc_cmap(&info->cmap, 16, 0); - return 0; -} - static int __devinit install_fb(struct fb_info *info) { int rc; @@ -1232,8 +1254,15 @@ static int __devinit install_fb(struct fb_info *info) unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); int has_default_mode = 1; - if (init_fbinfo(info)) - return -EINVAL; + info->var.activate = FB_ACTIVATE_NOW; + info->fbops = &fsl_diu_ops; + info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK | + FBINFO_READS_FAST; + info->pseudo_palette = mfbi->pseudo_palette; + + rc = fb_alloc_cmap(&info->cmap, 16, 0); + if (rc) + return rc; if (mfbi->index == PLANE0) { if (mfbi->edid_data) { @@ -1359,16 +1388,16 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id) return IRQ_NONE; } -static int request_irq_local(struct fsl_diu_data *machine_data) +static int request_irq_local(struct fsl_diu_data *data) { - struct diu __iomem *hw = machine_data->diu_reg; + struct diu __iomem *hw = data->diu_reg; u32 ints; int ret; /* Read to clear the status */ in_be32(&hw->int_status); - ret = request_irq(machine_data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw); + ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw); if (!ret) { ints = INT_PARERR | INT_LS_BF_VS; #if !defined(CONFIG_NOT_COHERENT_CACHE) @@ -1383,14 +1412,14 @@ static int request_irq_local(struct fsl_diu_data *machine_data) return ret; } -static void free_irq_local(struct fsl_diu_data *machine_data) +static void free_irq_local(struct fsl_diu_data *data) { - struct diu __iomem *hw = machine_data->diu_reg; + struct diu __iomem *hw = data->diu_reg; /* Disable all LCDC interrupt */ out_be32(&hw->int_mask, 0x1f); - free_irq(machine_data->irq, NULL); + free_irq(data->irq, NULL); } #ifdef CONFIG_PM @@ -1400,20 +1429,20 @@ static void free_irq_local(struct fsl_diu_data *machine_data) */ static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state) { - struct fsl_diu_data *machine_data; + struct fsl_diu_data *data; - machine_data = dev_get_drvdata(&ofdev->dev); - disable_lcdc(machine_data->fsl_diu_info[0]); + data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(data->fsl_diu_info[0]); return 0; } static int fsl_diu_resume(struct platform_device *ofdev) { - struct fsl_diu_data *machine_data; + struct fsl_diu_data *data; - machine_data = dev_get_drvdata(&ofdev->dev); - enable_lcdc(machine_data->fsl_diu_info[0]); + data = dev_get_drvdata(&ofdev->dev); + enable_lcdc(data->fsl_diu_info[0]); return 0; } @@ -1423,56 +1452,24 @@ static int fsl_diu_resume(struct platform_device *ofdev) #define fsl_diu_resume NULL #endif /* CONFIG_PM */ -/* Align to 64-bit(8-byte), 32-byte, etc. */ -static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, - u32 bytes_align) -{ - u32 offset; - dma_addr_t mask; - - buf->vaddr = - dma_alloc_coherent(dev, size + bytes_align, &buf->paddr, - GFP_DMA | __GFP_ZERO); - if (!buf->vaddr) - return -ENOMEM; - - mask = bytes_align - 1; - offset = buf->paddr & mask; - if (offset) { - buf->offset = bytes_align - offset; - buf->paddr = buf->paddr + offset; - } else - buf->offset = 0; - - return 0; -} - -static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, - u32 bytes_align) -{ - dma_free_coherent(dev, size + bytes_align, buf->vaddr, - buf->paddr - buf->offset); -} - static ssize_t store_monitor(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { enum fsl_diu_monitor_port old_monitor_port; - struct fsl_diu_data *machine_data = + struct fsl_diu_data *data = container_of(attr, struct fsl_diu_data, dev_attr); - old_monitor_port = machine_data->monitor_port; - machine_data->monitor_port = fsl_diu_name_to_port(buf); + old_monitor_port = data->monitor_port; + data->monitor_port = fsl_diu_name_to_port(buf); - if (old_monitor_port != machine_data->monitor_port) { + if (old_monitor_port != data->monitor_port) { /* All AOIs need adjust pixel format * fsl_diu_set_par only change the pixsel format here * unlikely to fail. */ - fsl_diu_set_par(machine_data->fsl_diu_info[0]); - fsl_diu_set_par(machine_data->fsl_diu_info[1]); - fsl_diu_set_par(machine_data->fsl_diu_info[2]); - fsl_diu_set_par(machine_data->fsl_diu_info[3]); - fsl_diu_set_par(machine_data->fsl_diu_info[4]); + unsigned int i; + + for (i=0; i < NUM_AOIS; i++) + fsl_diu_set_par(&data->fsl_diu_info[i]); } return count; } @@ -1480,10 +1477,10 @@ static ssize_t store_monitor(struct device *device, static ssize_t show_monitor(struct device *device, struct device_attribute *attr, char *buf) { - struct fsl_diu_data *machine_data = + struct fsl_diu_data *data = container_of(attr, struct fsl_diu_data, dev_attr); - switch (machine_data->monitor_port) { + switch (data->monitor_port) { case FSL_DIU_PORT_DVI: return sprintf(buf, "DVI\n"); case FSL_DIU_PORT_LVDS: @@ -1499,28 +1496,52 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct mfb_info *mfbi; - phys_addr_t dummy_ad_addr = 0; - int ret, i, error = 0; - struct fsl_diu_data *machine_data; + struct fsl_diu_data *data; int diu_mode; + dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */ + unsigned int i; + int ret; - machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); - if (!machine_data) + data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data), + &dma_addr, GFP_DMA | __GFP_ZERO); + if (!data) return -ENOMEM; + data->dma_addr = dma_addr; + + /* + * dma_alloc_coherent() uses a page allocator, so the address is + * always page-aligned. We need the memory to be 32-byte aligned, + * so that's good. However, if one day the allocator changes, we + * need to catch that. It's not worth the effort to handle unaligned + * alloctions now because it's highly unlikely to ever be a problem. + */ + if ((unsigned long)data & 31) { + dev_err(&pdev->dev, "misaligned allocation"); + ret = -ENOMEM; + goto error; + } - spin_lock_init(&machine_data->reg_lock); + spin_lock_init(&data->reg_lock); - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { - machine_data->fsl_diu_info[i] = - framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev); - if (!machine_data->fsl_diu_info[i]) { - dev_err(&pdev->dev, "cannot allocate memory\n"); - ret = -ENOMEM; - goto error2; - } - mfbi = machine_data->fsl_diu_info[i]->par; + for (i = 0; i < NUM_AOIS; i++) { + struct fb_info *info = &data->fsl_diu_info[i]; + + info->device = &pdev->dev; + info->par = &data->mfb[i]; + + /* + * We store the physical address of the AD in the reserved + * 'paddr' field of the AD itself. + */ + data->ad[i].paddr = DMA_ADDR(data, ad[i]); + + info->fix.smem_start = 0; + + /* Initialize the AOI data structure */ + mfbi = info->par; memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); - mfbi->parent = machine_data; + mfbi->parent = data; + mfbi->ad = &data->ad[i]; if (mfbi->index == PLANE0) { const u8 *prop; @@ -1534,158 +1555,102 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) } } - machine_data->diu_reg = of_iomap(np, 0); - if (!machine_data->diu_reg) { + data->diu_reg = of_iomap(np, 0); + if (!data->diu_reg) { dev_err(&pdev->dev, "cannot map DIU registers\n"); ret = -EFAULT; - goto error2; + goto error; } - diu_mode = in_be32(&machine_data->diu_reg->diu_mode); + diu_mode = in_be32(&data->diu_reg->diu_mode); if (diu_mode == MFB_MODE0) - out_be32(&machine_data->diu_reg->diu_mode, 0); /* disable DIU */ + out_be32(&data->diu_reg->diu_mode, 0); /* disable DIU */ /* Get the IRQ of the DIU */ - machine_data->irq = irq_of_parse_and_map(np, 0); + data->irq = irq_of_parse_and_map(np, 0); - if (!machine_data->irq) { + if (!data->irq) { dev_err(&pdev->dev, "could not get DIU IRQ\n"); ret = -EINVAL; goto error; } - machine_data->monitor_port = monitor_port; - - /* Area descriptor memory pool aligns to 64-bit boundary */ - if (allocate_buf(&pdev->dev, &machine_data->ad, - sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) - return -ENOMEM; - - /* Get memory for Gamma Table - 32-byte aligned memory */ - if (allocate_buf(&pdev->dev, &machine_data->gamma, 768, 32)) { - ret = -ENOMEM; - goto error; - } - - /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ - if (allocate_buf(&pdev->dev, &machine_data->cursor, - MAX_CURS * MAX_CURS * 2, 32)) { - ret = -ENOMEM; - goto error; - } - - i = ARRAY_SIZE(machine_data->fsl_diu_info); - machine_data->dummy_ad = (struct diu_ad *)((u32)machine_data->ad.vaddr + - machine_data->ad.offset) + i; - machine_data->dummy_ad->paddr = machine_data->ad.paddr + - i * sizeof(struct diu_ad); - machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); - if (!machine_data->dummy_aoi_virt) { - ret = -ENOMEM; - goto error; - } - machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); - machine_data->dummy_ad->pix_fmt = 0x88882317; - machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); - machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); - machine_data->dummy_ad->offset_xyi = 0; - machine_data->dummy_ad->offset_xyd = 0; - machine_data->dummy_ad->next_ad = 0; + data->monitor_port = monitor_port; + + /* Initialize the dummy Area Descriptor */ + data->dummy_ad.addr = cpu_to_le32(DMA_ADDR(data, dummy_aoi)); + data->dummy_ad.pix_fmt = 0x88882317; + data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4); + data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) | 2); + data->dummy_ad.offset_xyi = 0; + data->dummy_ad.offset_xyd = 0; + data->dummy_ad.next_ad = 0; + data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad); /* * Let DIU display splash screen if it was pre-initialized * by the bootloader, set dummy area descriptor otherwise. */ if (diu_mode == MFB_MODE0) - out_be32(&machine_data->diu_reg->desc[0], - machine_data->dummy_ad->paddr); - - out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad->paddr); - out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad->paddr); - - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { - machine_data->fsl_diu_info[i]->fix.smem_start = 0; - mfbi = machine_data->fsl_diu_info[i]->par; - mfbi->ad = (struct diu_ad *)((u32)machine_data->ad.vaddr - + machine_data->ad.offset) + i; - mfbi->ad->paddr = - machine_data->ad.paddr + i * sizeof(struct diu_ad); - ret = install_fb(machine_data->fsl_diu_info[i]); + out_be32(&data->diu_reg->desc[0], data->dummy_ad.paddr); + + out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr); + out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr); + + for (i = 0; i < NUM_AOIS; i++) { + ret = install_fb(&data->fsl_diu_info[i]); if (ret) { dev_err(&pdev->dev, "could not register fb %d\n", i); goto error; } } - if (request_irq_local(machine_data)) { + if (request_irq_local(data)) { dev_err(&pdev->dev, "could not claim irq\n"); goto error; } - sysfs_attr_init(&machine_data->dev_attr.attr); - machine_data->dev_attr.attr.name = "monitor"; - machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; - machine_data->dev_attr.show = show_monitor; - machine_data->dev_attr.store = store_monitor; - error = device_create_file(machine_data->fsl_diu_info[0]->dev, - &machine_data->dev_attr); - if (error) { + sysfs_attr_init(&data->dev_attr.attr); + data->dev_attr.attr.name = "monitor"; + data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; + data->dev_attr.show = show_monitor; + data->dev_attr.store = store_monitor; + ret = device_create_file(&pdev->dev, &data->dev_attr); + if (ret) { dev_err(&pdev->dev, "could not create sysfs file %s\n", - machine_data->dev_attr.attr.name); + data->dev_attr.attr.name); } - dev_set_drvdata(&pdev->dev, machine_data); + dev_set_drvdata(&pdev->dev, data); return 0; error: - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) - uninstall_fb(machine_data->fsl_diu_info[i]); - - if (machine_data->ad.vaddr) - free_buf(&pdev->dev, &machine_data->ad, - sizeof(struct diu_ad) * FSL_AOI_NUM, 8); - if (machine_data->gamma.vaddr) - free_buf(&pdev->dev, &machine_data->gamma, 768, 32); - if (machine_data->cursor.vaddr) - free_buf(&pdev->dev, &machine_data->cursor, - MAX_CURS * MAX_CURS * 2, 32); - if (machine_data->dummy_aoi_virt) - fsl_diu_free(machine_data->dummy_aoi_virt, 64); - iounmap(machine_data->diu_reg); - -error2: - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) - if (machine_data->fsl_diu_info[i]) - framebuffer_release(machine_data->fsl_diu_info[i]); - kfree(machine_data); + for (i = 0; i < NUM_AOIS; i++) + uninstall_fb(&data->fsl_diu_info[i]); + + iounmap(data->diu_reg); + + dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, + data->dma_addr); return ret; } static int fsl_diu_remove(struct platform_device *pdev) { - struct fsl_diu_data *machine_data; + struct fsl_diu_data *data; int i; - machine_data = dev_get_drvdata(&pdev->dev); - disable_lcdc(machine_data->fsl_diu_info[0]); - free_irq_local(machine_data); - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) - uninstall_fb(machine_data->fsl_diu_info[i]); - if (machine_data->ad.vaddr) - free_buf(&pdev->dev, &machine_data->ad, - sizeof(struct diu_ad) * FSL_AOI_NUM, 8); - if (machine_data->gamma.vaddr) - free_buf(&pdev->dev, &machine_data->gamma, 768, 32); - if (machine_data->cursor.vaddr) - free_buf(&pdev->dev, &machine_data->cursor, - MAX_CURS * MAX_CURS * 2, 32); - if (machine_data->dummy_aoi_virt) - fsl_diu_free(machine_data->dummy_aoi_virt, 64); - iounmap(machine_data->diu_reg); - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) - if (machine_data->fsl_diu_info[i]) - framebuffer_release(machine_data->fsl_diu_info[i]); - kfree(machine_data); + data = dev_get_drvdata(&pdev->dev); + disable_lcdc(&data->fsl_diu_info[0]); + free_irq_local(data); + + for (i = 0; i < NUM_AOIS; i++) + uninstall_fb(&data->fsl_diu_info[i]); + + 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/grvga.c b/drivers/video/grvga.c index f37e02538203..da066c210923 100644 --- a/drivers/video/grvga.c +++ b/drivers/video/grvga.c @@ -70,7 +70,7 @@ static const struct fb_videomode grvga_modedb[] = { } }; -static struct fb_fix_screeninfo grvga_fix __initdata = { +static struct fb_fix_screeninfo grvga_fix __devinitdata = { .id = "AG SVGACTRL", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, @@ -267,7 +267,7 @@ static struct fb_ops grvga_ops = { .fb_imageblit = cfb_imageblit }; -static int __init grvga_parse_custom(char *options, +static int __devinit grvga_parse_custom(char *options, struct fb_var_screeninfo *screendata) { char *this_opt; diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 4394389caf68..c645f9282650 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -133,7 +133,7 @@ static struct fb_fix_screeninfo hga_fix __devinitdata = { /* Don't assume that tty1 will be the initial current console. */ static int release_io_port = 0; static int release_io_ports = 0; -static int nologo = 0; +static bool nologo = 0; /* ------------------------------------------------------------------------- * diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 318f6fb895b2..b83f36190cae 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -135,8 +135,8 @@ static struct pci_driver i810fb_driver = { static char *mode_option __devinitdata = NULL; static int vram __devinitdata = 4; static int bpp __devinitdata = 8; -static int mtrr __devinitdata; -static int accel __devinitdata; +static bool mtrr __devinitdata; +static bool accel __devinitdata; static int hsync1 __devinitdata; static int hsync2 __devinitdata; static int vsync1 __devinitdata; @@ -144,10 +144,10 @@ static int vsync2 __devinitdata; static int xres __devinitdata; static int yres; static int vyres __devinitdata; -static int sync __devinitdata; -static int extvga __devinitdata; -static int dcolor __devinitdata; -static int ddc3 __devinitdata = 2; +static bool sync __devinitdata; +static bool extvga __devinitdata; +static bool dcolor __devinitdata; +static bool ddc3 __devinitdata; /*------------------------------------------------------------*/ @@ -1776,7 +1776,7 @@ static void __devinit i810_init_defaults(struct i810fb_par *par, if (sync) par->dev_flags |= ALWAYS_SYNC; - par->ddc_num = ddc3; + par->ddc_num = (ddc3 ? 3 : 2); if (bpp < 8) bpp = 8; @@ -1999,7 +1999,7 @@ static int __devinit i810fb_setup(char *options) else if (!strncmp(this_opt, "dcolor", 6)) dcolor = 1; else if (!strncmp(this_opt, "ddc3", 4)) - ddc3 = 3; + ddc3 = true; else mode_option = this_opt; } diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 5ba399991050..c6afa33a4532 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -230,15 +230,15 @@ MODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS MODULE_LICENSE("Dual BSD/GPL"); MODULE_DEVICE_TABLE(pci, intelfb_pci_table); -static int accel = 1; +static bool accel = 1; static int vram = 4; -static int hwcursor = 0; -static int mtrr = 1; -static int fixed = 0; -static int noinit = 0; -static int noregister = 0; -static int probeonly = 0; -static int idonly = 0; +static bool hwcursor = 0; +static bool mtrr = 1; +static bool fixed = 0; +static bool noinit = 0; +static bool noregister = 0; +static bool probeonly = 0; +static bool idonly = 0; static int bailearly = 0; static int voffset = 48; static char *mode = NULL; @@ -263,7 +263,7 @@ module_param(probeonly, bool, 0); MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)"); module_param(idonly, bool, 0); MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)"); -module_param(bailearly, bool, 0); +module_param(bailearly, int, 0); MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)"); module_param(mode, charp, S_IRUGO); MODULE_PARM_DESC(mode, diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index ea7a8ccc830c..080c35b34bbb 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -21,7 +21,7 @@ #include <asm/bootinfo.h> #endif -static int nologo; +static bool nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 44bf8d4a216b..401a56e250bd 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -147,7 +147,6 @@ static struct fb_var_screeninfo vesafb_defined = { 39721L,48L,16L,33L,10L, 96L,2L,~0, /* No sync info */ FB_VMODE_NONINTERLACED, - 0, {0,0,0,0,0} }; diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index d7112c39614b..02796a4317a9 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -593,7 +593,6 @@ static struct fb_var_screeninfo matroxfb_dh_defined = { 39721L,48L,16L,33L,10L, 96L,2,0, /* no sync info */ FB_VMODE_NONINTERLACED, - 0, {0,0,0,0,0} }; static int matroxfb_dh_regit(const struct matrox_fb_info *minfo, diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 6ce34160da78..55bf6196b7a0 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c @@ -1053,18 +1053,7 @@ static struct platform_driver mbxfb_driver = { }, }; -int __devinit mbxfb_init(void) -{ - return platform_driver_register(&mbxfb_driver); -} - -static void __devexit mbxfb_exit(void) -{ - platform_driver_unregister(&mbxfb_driver); -} - -module_init(mbxfb_init); -module_exit(mbxfb_exit); +module_platform_driver(mbxfb_driver); MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device"); MODULE_AUTHOR("Mike Rapoport, Compulab"); diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index e3406ab31305..727a5149d818 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -245,6 +245,7 @@ struct mx3fb_data { uint32_t h_start_width; uint32_t v_start_width; + enum disp_data_mapping disp_data_fmt; }; struct dma_chan_request { @@ -287,11 +288,14 @@ static void mx3fb_write_reg(struct mx3fb_data *mx3fb, u32 value, unsigned long r __raw_writel(value, mx3fb->reg_base + reg); } -static const uint32_t di_mappings[] = { - 0x1600AAAA, 0x00E05555, 0x00070000, 3, /* RGB888 */ - 0x0005000F, 0x000B000F, 0x0011000F, 1, /* RGB666 */ - 0x0011000F, 0x000B000F, 0x0005000F, 1, /* BGR666 */ - 0x0004003F, 0x000A000F, 0x000F003F, 1 /* RGB565 */ +struct di_mapping { + uint32_t b0, b1, b2; +}; + +static const struct di_mapping di_mappings[] = { + [IPU_DISP_DATA_MAPPING_RGB666] = { 0x0005000f, 0x000b000f, 0x0011000f }, + [IPU_DISP_DATA_MAPPING_RGB565] = { 0x0004003f, 0x000a000f, 0x000f003f }, + [IPU_DISP_DATA_MAPPING_RGB888] = { 0x00070000, 0x000f0000, 0x00170000 }, }; static void sdc_fb_init(struct mx3fb_info *fbi) @@ -334,7 +338,7 @@ static void sdc_enable_channel(struct mx3fb_info *mx3_fbi) /* This enables the channel */ if (mx3_fbi->cookie < 0) { mx3_fbi->txd = dma_chan->device->device_prep_slave_sg(dma_chan, - &mx3_fbi->sg[0], 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT); + &mx3_fbi->sg[0], 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); if (!mx3_fbi->txd) { dev_err(mx3fb->dev, "Cannot allocate descriptor on %d\n", dma_chan->chan_id); @@ -425,7 +429,6 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel * @pixel_clk: desired pixel clock frequency in Hz. * @width: width of panel in pixels. * @height: height of panel in pixels. - * @pixel_fmt: pixel format of buffer as FOURCC ASCII code. * @h_start_width: number of pixel clocks between the HSYNC signal pulse * and the start of valid data. * @h_sync_width: width of the HSYNC signal in units of pixel clocks. @@ -442,7 +445,6 @@ static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel, uint32_t pixel_clk, uint16_t width, uint16_t height, - enum pixel_fmt pixel_fmt, uint16_t h_start_width, uint16_t h_sync_width, uint16_t h_end_width, uint16_t v_start_width, uint16_t v_sync_width, uint16_t v_end_width, @@ -453,6 +455,7 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel, uint32_t old_conf; uint32_t div; struct clk *ipu_clk; + const struct di_mapping *map; dev_dbg(mx3fb->dev, "panel size = %d x %d", width, height); @@ -540,36 +543,10 @@ static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel, sig.Vsync_pol << DI_D3_VSYNC_POL_SHIFT; mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL); - switch (pixel_fmt) { - case IPU_PIX_FMT_RGB24: - mx3fb_write_reg(mx3fb, di_mappings[0], DI_DISP3_B0_MAP); - mx3fb_write_reg(mx3fb, di_mappings[1], DI_DISP3_B1_MAP); - mx3fb_write_reg(mx3fb, di_mappings[2], DI_DISP3_B2_MAP); - mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) | - ((di_mappings[3] - 1) << 12), DI_DISP_ACC_CC); - break; - case IPU_PIX_FMT_RGB666: - mx3fb_write_reg(mx3fb, di_mappings[4], DI_DISP3_B0_MAP); - mx3fb_write_reg(mx3fb, di_mappings[5], DI_DISP3_B1_MAP); - mx3fb_write_reg(mx3fb, di_mappings[6], DI_DISP3_B2_MAP); - mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) | - ((di_mappings[7] - 1) << 12), DI_DISP_ACC_CC); - break; - case IPU_PIX_FMT_BGR666: - mx3fb_write_reg(mx3fb, di_mappings[8], DI_DISP3_B0_MAP); - mx3fb_write_reg(mx3fb, di_mappings[9], DI_DISP3_B1_MAP); - mx3fb_write_reg(mx3fb, di_mappings[10], DI_DISP3_B2_MAP); - mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) | - ((di_mappings[11] - 1) << 12), DI_DISP_ACC_CC); - break; - default: - mx3fb_write_reg(mx3fb, di_mappings[12], DI_DISP3_B0_MAP); - mx3fb_write_reg(mx3fb, di_mappings[13], DI_DISP3_B1_MAP); - mx3fb_write_reg(mx3fb, di_mappings[14], DI_DISP3_B2_MAP); - mx3fb_write_reg(mx3fb, mx3fb_read_reg(mx3fb, DI_DISP_ACC_CC) | - ((di_mappings[15] - 1) << 12), DI_DISP_ACC_CC); - break; - } + map = &di_mappings[mx3fb->disp_data_fmt]; + mx3fb_write_reg(mx3fb, map->b0, DI_DISP3_B0_MAP); + mx3fb_write_reg(mx3fb, map->b1, DI_DISP3_B1_MAP); + mx3fb_write_reg(mx3fb, map->b2, DI_DISP3_B2_MAP); spin_unlock_irqrestore(&mx3fb->lock, lock_flags); @@ -780,8 +757,6 @@ static int __set_par(struct fb_info *fbi, bool lock) if (sdc_init_panel(mx3fb, mode, (PICOS2KHZ(fbi->var.pixclock)) * 1000UL, fbi->var.xres, fbi->var.yres, - (fbi->var.sync & FB_SYNC_SWAP_RGB) ? - IPU_PIX_FMT_BGR666 : IPU_PIX_FMT_RGB666, fbi->var.left_margin, fbi->var.hsync_len, fbi->var.right_margin + @@ -1117,7 +1092,7 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var, async_tx_ack(mx3_fbi->txd); txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg + - mx3_fbi->cur_ipu_buf, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT); + mx3_fbi->cur_ipu_buf, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); if (!txd) { dev_err(fbi->device, "Error preparing a DMA transaction descriptor.\n"); @@ -1349,6 +1324,12 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan) const struct fb_videomode *mode; int ret, num_modes; + if (mx3fb_pdata->disp_data_fmt >= ARRAY_SIZE(di_mappings)) { + dev_err(dev, "Illegal display data format %d\n", + mx3fb_pdata->disp_data_fmt); + return -EINVAL; + } + ichan->client = mx3fb; irq = ichan->eof_irq; @@ -1402,6 +1383,8 @@ static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan) mx3fbi->mx3fb = mx3fb; mx3fbi->blank = FB_BLANK_NORMAL; + mx3fb->disp_data_fmt = mx3fb_pdata->disp_data_fmt; + init_completion(&mx3fbi->flip_cmpl); disable_irq(ichan->eof_irq); dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq); diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index eb3c5eea1a0f..4a89f889852d 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -902,18 +902,7 @@ static struct platform_driver mxsfb_driver = { }, }; -static int __init mxsfb_init(void) -{ - return platform_driver_register(&mxsfb_driver); -} - -static void __exit mxsfb_exit(void) -{ - platform_driver_unregister(&mxsfb_driver); -} - -module_init(mxsfb_init); -module_exit(mxsfb_exit); +module_platform_driver(mxsfb_driver); MODULE_DESCRIPTION("Freescale mxs framebuffer driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index feea7b1dc386..fb3f67391105 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -84,11 +84,11 @@ /* --------------------------------------------------------------------- */ -static int internal; -static int external; -static int libretto; -static int nostretch; -static int nopciburst; +static bool internal; +static bool external; +static bool libretto; +static bool nostretch; +static bool nopciburst; static char *mode_option __devinitdata = NULL; #ifdef MODULE diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index d1fbbd888cf4..e10f551ade21 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -762,18 +762,7 @@ static struct platform_driver nuc900fb_driver = { }, }; -int __devinit nuc900fb_init(void) -{ - return platform_driver_register(&nuc900fb_driver); -} - -static void __exit nuc900fb_cleanup(void) -{ - platform_driver_unregister(&nuc900fb_driver); -} - -module_init(nuc900fb_init); -module_exit(nuc900fb_cleanup); +module_platform_driver(nuc900fb_driver); MODULE_DESCRIPTION("Framebuffer driver for the NUC900"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c index 6978ae4ef83a..0fdd6f6873bf 100644 --- a/drivers/video/omap/lcd_ams_delta.c +++ b/drivers/video/omap/lcd_ams_delta.c @@ -198,7 +198,7 @@ static int ams_delta_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver ams_delta_panel_driver = { +static struct platform_driver ams_delta_panel_driver = { .probe = ams_delta_panel_probe, .remove = ams_delta_panel_remove, .suspend = ams_delta_panel_suspend, @@ -209,15 +209,4 @@ struct platform_driver ams_delta_panel_driver = { }, }; -static int __init ams_delta_panel_drv_init(void) -{ - return platform_driver_register(&ams_delta_panel_driver); -} - -static void __exit ams_delta_panel_drv_cleanup(void) -{ - platform_driver_unregister(&ams_delta_panel_driver); -} - -module_init(ams_delta_panel_drv_init); -module_exit(ams_delta_panel_drv_cleanup); +module_platform_driver(ams_delta_panel_driver); diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c index 622ad839fd9d..49bdeca81e50 100644 --- a/drivers/video/omap/lcd_h3.c +++ b/drivers/video/omap/lcd_h3.c @@ -113,7 +113,7 @@ static int h3_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver h3_panel_driver = { +static struct platform_driver h3_panel_driver = { .probe = h3_panel_probe, .remove = h3_panel_remove, .suspend = h3_panel_suspend, @@ -124,16 +124,4 @@ struct platform_driver h3_panel_driver = { }, }; -static int __init h3_panel_drv_init(void) -{ - return platform_driver_register(&h3_panel_driver); -} - -static void __exit h3_panel_drv_cleanup(void) -{ - platform_driver_unregister(&h3_panel_driver); -} - -module_init(h3_panel_drv_init); -module_exit(h3_panel_drv_cleanup); - +module_platform_driver(h3_panel_driver); diff --git a/drivers/video/omap/lcd_htcherald.c b/drivers/video/omap/lcd_htcherald.c index 4802419da83b..20f477851d54 100644 --- a/drivers/video/omap/lcd_htcherald.c +++ b/drivers/video/omap/lcd_htcherald.c @@ -104,7 +104,7 @@ static int htcherald_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver htcherald_panel_driver = { +static struct platform_driver htcherald_panel_driver = { .probe = htcherald_panel_probe, .remove = htcherald_panel_remove, .suspend = htcherald_panel_suspend, @@ -115,16 +115,4 @@ struct platform_driver htcherald_panel_driver = { }, }; -static int __init htcherald_panel_drv_init(void) -{ - return platform_driver_register(&htcherald_panel_driver); -} - -static void __exit htcherald_panel_drv_cleanup(void) -{ - platform_driver_unregister(&htcherald_panel_driver); -} - -module_init(htcherald_panel_drv_init); -module_exit(htcherald_panel_drv_cleanup); - +module_platform_driver(htcherald_panel_driver); diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c index 3271f1643b26..b38b1dd15ce3 100644 --- a/drivers/video/omap/lcd_inn1510.c +++ b/drivers/video/omap/lcd_inn1510.c @@ -98,7 +98,7 @@ static int innovator1510_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver innovator1510_panel_driver = { +static struct platform_driver innovator1510_panel_driver = { .probe = innovator1510_panel_probe, .remove = innovator1510_panel_remove, .suspend = innovator1510_panel_suspend, @@ -109,16 +109,4 @@ struct platform_driver innovator1510_panel_driver = { }, }; -static int __init innovator1510_panel_drv_init(void) -{ - return platform_driver_register(&innovator1510_panel_driver); -} - -static void __exit innovator1510_panel_drv_cleanup(void) -{ - platform_driver_unregister(&innovator1510_panel_driver); -} - -module_init(innovator1510_panel_drv_init); -module_exit(innovator1510_panel_drv_cleanup); - +module_platform_driver(innovator1510_panel_driver); diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c index 12cc52a70f96..7e8bd8e08a98 100644 --- a/drivers/video/omap/lcd_inn1610.c +++ b/drivers/video/omap/lcd_inn1610.c @@ -122,7 +122,7 @@ static int innovator1610_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver innovator1610_panel_driver = { +static struct platform_driver innovator1610_panel_driver = { .probe = innovator1610_panel_probe, .remove = innovator1610_panel_remove, .suspend = innovator1610_panel_suspend, @@ -133,16 +133,4 @@ struct platform_driver innovator1610_panel_driver = { }, }; -static int __init innovator1610_panel_drv_init(void) -{ - return platform_driver_register(&innovator1610_panel_driver); -} - -static void __exit innovator1610_panel_drv_cleanup(void) -{ - platform_driver_unregister(&innovator1610_panel_driver); -} - -module_init(innovator1610_panel_drv_init); -module_exit(innovator1610_panel_drv_cleanup); - +module_platform_driver(innovator1610_panel_driver); diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c index eb381db7fe51..8d546dd55e81 100644 --- a/drivers/video/omap/lcd_mipid.c +++ b/drivers/video/omap/lcd_mipid.c @@ -603,7 +603,6 @@ static int mipid_spi_remove(struct spi_device *spi) static struct spi_driver mipid_spi_driver = { .driver = { .name = MIPID_MODULE_NAME, - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = mipid_spi_probe, diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c index 6f8d13c41202..5914220dfa9c 100644 --- a/drivers/video/omap/lcd_osk.c +++ b/drivers/video/omap/lcd_osk.c @@ -116,7 +116,7 @@ static int osk_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver osk_panel_driver = { +static struct platform_driver osk_panel_driver = { .probe = osk_panel_probe, .remove = osk_panel_remove, .suspend = osk_panel_suspend, @@ -127,16 +127,4 @@ struct platform_driver osk_panel_driver = { }, }; -static int __init osk_panel_drv_init(void) -{ - return platform_driver_register(&osk_panel_driver); -} - -static void __exit osk_panel_drv_cleanup(void) -{ - platform_driver_unregister(&osk_panel_driver); -} - -module_init(osk_panel_drv_init); -module_exit(osk_panel_drv_cleanup); - +module_platform_driver(osk_panel_driver); diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c index 4cb301750d02..88c31eb0cd6c 100644 --- a/drivers/video/omap/lcd_palmte.c +++ b/drivers/video/omap/lcd_palmte.c @@ -97,7 +97,7 @@ static int palmte_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver palmte_panel_driver = { +static struct platform_driver palmte_panel_driver = { .probe = palmte_panel_probe, .remove = palmte_panel_remove, .suspend = palmte_panel_suspend, @@ -108,16 +108,4 @@ struct platform_driver palmte_panel_driver = { }, }; -static int __init palmte_panel_drv_init(void) -{ - return platform_driver_register(&palmte_panel_driver); -} - -static void __exit palmte_panel_drv_cleanup(void) -{ - platform_driver_unregister(&palmte_panel_driver); -} - -module_init(palmte_panel_drv_init); -module_exit(palmte_panel_drv_cleanup); - +module_platform_driver(palmte_panel_driver); diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c index b51b332e5a2b..aaf3c8ba1243 100644 --- a/drivers/video/omap/lcd_palmtt.c +++ b/drivers/video/omap/lcd_palmtt.c @@ -102,7 +102,7 @@ static int palmtt_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver palmtt_panel_driver = { +static struct platform_driver palmtt_panel_driver = { .probe = palmtt_panel_probe, .remove = palmtt_panel_remove, .suspend = palmtt_panel_suspend, @@ -113,15 +113,4 @@ struct platform_driver palmtt_panel_driver = { }, }; -static int __init palmtt_panel_drv_init(void) -{ - return platform_driver_register(&palmtt_panel_driver); -} - -static void __exit palmtt_panel_drv_cleanup(void) -{ - platform_driver_unregister(&palmtt_panel_driver); -} - -module_init(palmtt_panel_drv_init); -module_exit(palmtt_panel_drv_cleanup); +module_platform_driver(palmtt_panel_driver); diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c index 2334e56536bc..3b7d8aa1cf34 100644 --- a/drivers/video/omap/lcd_palmz71.c +++ b/drivers/video/omap/lcd_palmz71.c @@ -98,7 +98,7 @@ static int palmz71_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver palmz71_panel_driver = { +static struct platform_driver palmz71_panel_driver = { .probe = palmz71_panel_probe, .remove = palmz71_panel_remove, .suspend = palmz71_panel_suspend, @@ -109,15 +109,4 @@ struct platform_driver palmz71_panel_driver = { }, }; -static int __init palmz71_panel_drv_init(void) -{ - return platform_driver_register(&palmz71_panel_driver); -} - -static void __exit palmz71_panel_drv_cleanup(void) -{ - platform_driver_unregister(&palmz71_panel_driver); -} - -module_init(palmz71_panel_drv_init); -module_exit(palmz71_panel_drv_cleanup); +module_platform_driver(palmz71_panel_driver); diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 25d8e5103193..b291bfaac80e 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -47,9 +47,9 @@ static unsigned int def_rotate; static unsigned int def_mirror; #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE -static int manual_update = 1; +static bool manual_update = 1; #else -static int manual_update; +static bool manual_update; #endif static struct platform_device *fbdev_pdev; diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 8d8e1fe1901c..74d29b552901 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -41,7 +41,7 @@ config PANEL_NEC_NL8048HL11_01B config PANEL_PICODLP tristate "TI PICO DLP mini-projector" - depends on OMAP2_DSS && I2C + depends on OMAP2_DSS_DPI && I2C help A mini-projector used in TI's SDP4430 and EVM boards For more info please visit http://www.dlp.com/projector/ diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index dbd59b8e5b36..51a87e149e24 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -803,7 +803,6 @@ static int acx565akm_spi_remove(struct spi_device *spi) static struct spi_driver acx565akm_spi_driver = { .driver = { .name = "acx565akm", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = acx565akm_spi_probe, diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 519c47d2057f..28b9a6d61b0f 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -297,6 +297,72 @@ static struct panel_config generic_dpi_panels[] = { .name = "apollon", }, + /* FocalTech ETM070003DH6 */ + { + { + .x_res = 800, + .y_res = 480, + + .pixel_clock = 28000, + + .hsw = 48, + .hfp = 40, + .hbp = 40, + + .vsw = 3, + .vfp = 13, + .vbp = 29, + }, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + .name = "focaltech_etm070003dh6", + }, + + /* Microtips Technologies - UMSH-8173MD */ + { + { + .x_res = 800, + .y_res = 480, + + .pixel_clock = 34560, + + .hsw = 13, + .hfp = 101, + .hbp = 101, + + .vsw = 23, + .vfp = 1, + .vbp = 1, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "microtips_umsh_8173md", + }, + + /* OrtusTech COM43H4M10XTC */ + { + { + .x_res = 480, + .y_res = 272, + + .pixel_clock = 8000, + + .hsw = 41, + .hfp = 8, + .hbp = 4, + + .vsw = 10, + .vfp = 4, + .vbp = 2, + }, + .config = OMAP_DSS_LCD_TFT, + + .name = "ortustech_com43h4m10xtc", + }, }; struct panel_drv_data { diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index 150e8bae35a1..dc9408dc93d1 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -708,7 +708,6 @@ static int mipid_spi_remove(struct spi_device *spi) static struct spi_driver mipid_spi_driver = { .driver = { .name = "lcd_mipid", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = mipid_spi_probe, diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 2ba9d0ca187c..0eb31caddca8 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -163,50 +163,93 @@ static void nec_8048_panel_remove(struct omap_dss_device *dssdev) kfree(necd); } -static int nec_8048_panel_enable(struct omap_dss_device *dssdev) +static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) { - int r = 0; + int r; struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); struct backlight_device *bl = necd->bl; + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + r = omapdss_dpi_display_enable(dssdev); + if (r) + goto err0; + if (dssdev->platform_enable) { r = dssdev->platform_enable(dssdev); if (r) - return r; + goto err1; } r = nec_8048_bl_update_status(bl); if (r < 0) dev_err(&dssdev->dev, "failed to set lcd brightness\n"); - r = omapdss_dpi_display_enable(dssdev); - + return 0; +err1: + omapdss_dpi_display_disable(dssdev); +err0: return r; } -static void nec_8048_panel_disable(struct omap_dss_device *dssdev) +static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) { struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); struct backlight_device *bl = necd->bl; - omapdss_dpi_display_disable(dssdev); + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return; bl->props.brightness = 0; nec_8048_bl_update_status(bl); if (dssdev->platform_disable) dssdev->platform_disable(dssdev); + + omapdss_dpi_display_disable(dssdev); +} + +static int nec_8048_panel_enable(struct omap_dss_device *dssdev) +{ + int r; + + r = nec_8048_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; +} + +static void nec_8048_panel_disable(struct omap_dss_device *dssdev) +{ + nec_8048_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) { - nec_8048_panel_disable(dssdev); + nec_8048_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + return 0; } static int nec_8048_panel_resume(struct omap_dss_device *dssdev) { - return nec_8048_panel_enable(dssdev); + int r; + + r = nec_8048_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; } static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) @@ -303,7 +346,6 @@ static struct spi_driver nec_8048_spi_driver = { .resume = nec_8048_spi_resume, .driver = { .name = "nec_8048_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, }; diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 80c3f6ab1a94..00c5c615585f 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -198,12 +198,6 @@ struct taal_data { bool te_enabled; atomic_t do_update; - struct { - u16 x; - u16 y; - u16 w; - u16 h; - } update_region; int channel; struct delayed_work te_timeout_work; @@ -1188,6 +1182,10 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (r) goto err; + r = dsi_enable_video_output(dssdev, td->channel); + if (r) + goto err; + td->enabled = 1; if (!td->intro_printed) { @@ -1217,6 +1215,8 @@ static void taal_power_off(struct omap_dss_device *dssdev) struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; + dsi_disable_video_output(dssdev, td->channel); + r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); if (!r) r = taal_sleep_in(td); @@ -1394,12 +1394,8 @@ static irqreturn_t taal_te_isr(int irq, void *data) if (old) { cancel_delayed_work(&td->te_timeout_work); - r = omap_dsi_update(dssdev, td->channel, - td->update_region.x, - td->update_region.y, - td->update_region.w, - td->update_region.h, - taal_framedone_cb, dssdev); + r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, + dssdev); if (r) goto err; } @@ -1444,26 +1440,20 @@ static int taal_update(struct omap_dss_device *dssdev, goto err; } - r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); - if (r) - goto err; - - r = taal_set_update_window(td, x, y, w, h); + /* XXX no need to send this every frame, but dsi break if not done */ + r = taal_set_update_window(td, 0, 0, + td->panel_config->timings.x_res, + td->panel_config->timings.y_res); if (r) goto err; if (td->te_enabled && panel_data->use_ext_te) { - td->update_region.x = x; - td->update_region.y = y; - td->update_region.w = w; - td->update_region.h = h; - barrier(); schedule_delayed_work(&td->te_timeout_work, msecs_to_jiffies(250)); atomic_set(&td->do_update, 1); } else { - r = omap_dsi_update(dssdev, td->channel, x, y, w, h, - taal_framedone_cb, dssdev); + r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, + dssdev); if (r) goto err; } diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 2462b9ec6662..e6649aa89591 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -512,7 +512,6 @@ static int __devexit tpo_td043_spi_remove(struct spi_device *spi) static struct spi_driver tpo_td043_spi_driver = { .driver = { .name = "tpo_td043mtea1_panel_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = tpo_td043_spi_probe, diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index bd34ac5b2026..5c450b0f94d0 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o -omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o +omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ + manager.o overlay.o apply.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c new file mode 100644 index 000000000000..052dc874cd3d --- /dev/null +++ b/drivers/video/omap2/dss/apply.c @@ -0,0 +1,1324 @@ +/* + * Copyright (C) 2011 Texas Instruments + * Author: Tomi Valkeinen <tomi.valkeinen@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/>. + */ + +#define DSS_SUBSYS_NAME "APPLY" + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/jiffies.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +/* + * We have 4 levels of cache for the dispc settings. First two are in SW and + * the latter two in HW. + * + * set_info() + * v + * +--------------------+ + * | user_info | + * +--------------------+ + * v + * apply() + * v + * +--------------------+ + * | info | + * +--------------------+ + * v + * write_regs() + * v + * +--------------------+ + * | shadow registers | + * +--------------------+ + * v + * VFP or lcd/digit_enable + * v + * +--------------------+ + * | registers | + * +--------------------+ + */ + +struct ovl_priv_data { + + bool user_info_dirty; + struct omap_overlay_info user_info; + + bool info_dirty; + struct omap_overlay_info info; + + bool shadow_info_dirty; + + bool extra_info_dirty; + bool shadow_extra_info_dirty; + + bool enabled; + enum omap_channel channel; + u32 fifo_low, fifo_high; + + /* + * True if overlay is to be enabled. Used to check and calculate configs + * for the overlay before it is enabled in the HW. + */ + bool enabling; +}; + +struct mgr_priv_data { + + bool user_info_dirty; + struct omap_overlay_manager_info user_info; + + bool info_dirty; + struct omap_overlay_manager_info info; + + bool shadow_info_dirty; + + /* If true, GO bit is up and shadow registers cannot be written. + * Never true for manual update displays */ + bool busy; + + /* If true, dispc output is enabled */ + bool updating; + + /* If true, a display is enabled using this manager */ + bool enabled; +}; + +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 irq_enabled; +} dss_data; + +/* protects dss_data */ +static spinlock_t data_lock; +/* lock for blocking functions */ +static DEFINE_MUTEX(apply_lock); +static DECLARE_COMPLETION(extra_updated_completion); + +static void dss_register_vsync_isr(void); + +static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl) +{ + return &dss_data.ovl_priv_data_array[ovl->id]; +} + +static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) +{ + return &dss_data.mgr_priv_data_array[mgr->id]; +} + +void dss_apply_init(void) +{ + const int num_ovls = dss_feat_get_num_ovls(); + int i; + + spin_lock_init(&data_lock); + + for (i = 0; i < num_ovls; ++i) { + struct ovl_priv_data *op; + + op = &dss_data.ovl_priv_data_array[i]; + + op->info.global_alpha = 255; + + switch (i) { + case 0: + op->info.zorder = 0; + break; + case 1: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; + break; + case 2: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; + break; + case 3: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; + break; + } + + op->user_info = op->info; + } +} + +static bool ovl_manual_update(struct omap_overlay *ovl) +{ + return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; +} + +static bool mgr_manual_update(struct omap_overlay_manager *mgr) +{ + return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; +} + +static int dss_check_settings_low(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev, bool applying) +{ + struct omap_overlay_info *oi; + struct omap_overlay_manager_info *mi; + struct omap_overlay *ovl; + struct omap_overlay_info *ois[MAX_DSS_OVERLAYS]; + struct ovl_priv_data *op; + struct mgr_priv_data *mp; + + mp = get_mgr_priv(mgr); + + if (applying && mp->user_info_dirty) + mi = &mp->user_info; + else + mi = &mp->info; + + /* collect the infos to be tested into the array */ + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + + if (!op->enabled && !op->enabling) + oi = NULL; + else if (applying && op->user_info_dirty) + oi = &op->user_info; + else + oi = &op->info; + + ois[ovl->id] = oi; + } + + return dss_mgr_check(mgr, dssdev, mi, ois); +} + +/* + * check manager and overlay settings using overlay_info from data->info + */ +static int dss_check_settings(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev) +{ + return dss_check_settings_low(mgr, dssdev, false); +} + +/* + * check manager and overlay settings using overlay_info from ovl->info if + * dirty and from data->info otherwise + */ +static int dss_check_settings_apply(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev) +{ + return dss_check_settings_low(mgr, dssdev, true); +} + +static bool need_isr(void) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + int i; + + for (i = 0; i < num_mgrs; ++i) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + struct omap_overlay *ovl; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled) + continue; + + if (mgr_manual_update(mgr)) { + /* to catch FRAMEDONE */ + if (mp->updating) + return true; + } else { + /* to catch GO bit going down */ + if (mp->busy) + return true; + + /* to write new values to registers */ + if (mp->info_dirty) + return true; + + /* to set GO bit */ + if (mp->shadow_info_dirty) + return true; + + list_for_each_entry(ovl, &mgr->overlays, list) { + struct ovl_priv_data *op; + + op = get_ovl_priv(ovl); + + /* + * NOTE: we check extra_info flags even for + * disabled overlays, as extra_infos need to be + * always written. + */ + + /* to write new values to registers */ + if (op->extra_info_dirty) + return true; + + /* to set GO bit */ + if (op->shadow_extra_info_dirty) + return true; + + if (!op->enabled) + continue; + + /* to write new values to registers */ + if (op->info_dirty) + return true; + + /* to set GO bit */ + if (op->shadow_info_dirty) + return true; + } + } + } + + return false; +} + +static bool need_go(struct omap_overlay_manager *mgr) +{ + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + struct ovl_priv_data *op; + + mp = get_mgr_priv(mgr); + + if (mp->shadow_info_dirty) + return true; + + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + if (op->shadow_info_dirty || op->shadow_extra_info_dirty) + return true; + } + + return false; +} + +/* returns true if an extra_info field is currently being updated */ +static bool extra_info_update_ongoing(void) +{ + const int num_ovls = omap_dss_get_num_overlays(); + struct ovl_priv_data *op; + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + int i; + + for (i = 0; i < num_ovls; ++i) { + ovl = omap_dss_get_overlay(i); + op = get_ovl_priv(ovl); + + if (!ovl->manager) + continue; + + mp = get_mgr_priv(ovl->manager); + + if (!mp->enabled) + continue; + + if (!mp->updating) + continue; + + if (op->extra_info_dirty || op->shadow_extra_info_dirty) + return true; + } + + return false; +} + +/* wait until no extra_info updates are pending */ +static void wait_pending_extra_info_updates(void) +{ + bool updating; + unsigned long flags; + unsigned long t; + + spin_lock_irqsave(&data_lock, flags); + + updating = extra_info_update_ongoing(); + + if (!updating) { + spin_unlock_irqrestore(&data_lock, flags); + return; + } + + init_completion(&extra_updated_completion); + + spin_unlock_irqrestore(&data_lock, flags); + + t = msecs_to_jiffies(500); + wait_for_completion_timeout(&extra_updated_completion, t); + + updating = extra_info_update_ongoing(); + + WARN_ON(updating); +} + +int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) +{ + unsigned long timeout = msecs_to_jiffies(500); + struct mgr_priv_data *mp; + u32 irq; + int r; + int i; + struct omap_dss_device *dssdev = mgr->device; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + if (mgr_manual_update(mgr)) + return 0; + + 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); + dirty = mp->info_dirty; + shadow_dirty = mp->shadow_info_dirty; + spin_unlock_irqrestore(&data_lock, flags); + + if (!dirty && !shadow_dirty) { + r = 0; + break; + } + + /* 4 iterations is the worst case: + * 1 - initial iteration, dirty = true (between VFP and VSYNC) + * 2 - first VSYNC, dirty = true + * 3 - dirty = false, shadow_dirty = true + * 4 - shadow_dirty = false */ + if (i++ == 3) { + DSSERR("mgr(%d)->wait_for_go() not finishing\n", + mgr->id); + r = 0; + break; + } + + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); + if (r == -ERESTARTSYS) + break; + + if (r) { + DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); + break; + } + } + + return r; +} + +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; + u32 irq; + int r; + int i; + + if (!ovl->manager) + return 0; + + dssdev = ovl->manager->device; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + if (ovl_manual_update(ovl)) + return 0; + + irq = dispc_mgr_get_vsync_irq(ovl->manager->id); + + op = get_ovl_priv(ovl); + i = 0; + while (1) { + unsigned long flags; + bool shadow_dirty, dirty; + + spin_lock_irqsave(&data_lock, flags); + dirty = op->info_dirty; + shadow_dirty = op->shadow_info_dirty; + spin_unlock_irqrestore(&data_lock, flags); + + if (!dirty && !shadow_dirty) { + r = 0; + break; + } + + /* 4 iterations is the worst case: + * 1 - initial iteration, dirty = true (between VFP and VSYNC) + * 2 - first VSYNC, dirty = true + * 3 - dirty = false, shadow_dirty = true + * 4 - shadow_dirty = false */ + if (i++ == 3) { + DSSERR("ovl(%d)->wait_for_go() not finishing\n", + ovl->id); + r = 0; + break; + } + + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); + if (r == -ERESTARTSYS) + break; + + if (r) { + DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); + break; + } + } + + return r; +} + +static void dss_ovl_write_regs(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + struct omap_overlay_info *oi; + bool ilace, replication; + struct mgr_priv_data *mp; + int r; + + DSSDBGF("%d", ovl->id); + + if (!op->enabled || !op->info_dirty) + return; + + oi = &op->info; + + replication = dss_use_replication(ovl->manager->device, oi->color_mode); + + ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; + + r = dispc_ovl_setup(ovl->id, oi, ilace, replication); + if (r) { + /* + * We can't do much here, as this function can be called from + * vsync interrupt. + */ + DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id); + + /* This will leave fifo configurations in a nonoptimal state */ + op->enabled = false; + dispc_ovl_enable(ovl->id, false); + return; + } + + mp = get_mgr_priv(ovl->manager); + + op->info_dirty = false; + if (mp->updating) + op->shadow_info_dirty = true; +} + +static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + struct mgr_priv_data *mp; + + DSSDBGF("%d", ovl->id); + + if (!op->extra_info_dirty) + return; + + /* note: write also when op->enabled == false, so that the ovl gets + * disabled */ + + dispc_ovl_enable(ovl->id, op->enabled); + dispc_ovl_set_channel_out(ovl->id, op->channel); + dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); + + mp = get_mgr_priv(ovl->manager); + + op->extra_info_dirty = false; + if (mp->updating) + op->shadow_extra_info_dirty = true; +} + +static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + struct omap_overlay *ovl; + + DSSDBGF("%d", mgr->id); + + if (!mp->enabled) + return; + + WARN_ON(mp->busy); + + /* Commit overlay settings */ + list_for_each_entry(ovl, &mgr->overlays, list) { + dss_ovl_write_regs(ovl); + dss_ovl_write_regs_extra(ovl); + } + + if (mp->info_dirty) { + dispc_mgr_setup(mgr->id, &mp->info); + + mp->info_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; + + for (i = 0; i < num_mgrs; ++i) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + int r; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) + continue; + + r = dss_check_settings(mgr, mgr->device); + if (r) { + DSSERR("cannot write registers for manager %s: " + "illegal configuration\n", mgr->name); + continue; + } + + dss_mgr_write_regs(mgr); + } +} + +static void dss_set_go_bits(void) +{ + const int num_mgrs = omap_dss_get_num_overlay_managers(); + int i; + + 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 || mgr_manual_update(mgr) || mp->busy) + continue; + + if (!need_go(mgr)) + continue; + + mp->busy = true; + + if (!dss_data.irq_enabled && need_isr()) + dss_register_vsync_isr(); + + dispc_mgr_go(mgr->id); + } + +} + +void dss_mgr_start_update(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + int r; + + spin_lock_irqsave(&data_lock, flags); + + WARN_ON(mp->updating); + + r = dss_check_settings(mgr, mgr->device); + if (r) { + DSSERR("cannot start manual update: illegal configuration\n"); + spin_unlock_irqrestore(&data_lock, flags); + return; + } + + dss_mgr_write_regs(mgr); + + mp->updating = true; + + if (!dss_data.irq_enabled && need_isr()) + dss_register_vsync_isr(); + + dispc_mgr_enable(mgr->id, true); + + spin_unlock_irqrestore(&data_lock, flags); +} + +static void dss_apply_irq_handler(void *data, u32 mask); + +static void dss_register_vsync_isr(void) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + u32 mask; + int r, i; + + mask = 0; + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_vsync_irq(i); + + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_framedone_irq(i); + + r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); + WARN_ON(r); + + dss_data.irq_enabled = true; +} + +static void dss_unregister_vsync_isr(void) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + u32 mask; + int r, i; + + mask = 0; + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_vsync_irq(i); + + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_framedone_irq(i); + + r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); + WARN_ON(r); + + dss_data.irq_enabled = false; +} + +static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) +{ + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + struct ovl_priv_data *op; + + mp = get_mgr_priv(mgr); + mp->shadow_info_dirty = false; + + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + op->shadow_info_dirty = false; + op->shadow_extra_info_dirty = false; + } +} + +static void dss_apply_irq_handler(void *data, u32 mask) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + int i; + bool extra_updating; + + spin_lock(&data_lock); + + /* clear busy, updating flags, shadow_dirty flags */ + for (i = 0; i < num_mgrs; i++) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + bool was_updating; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled) + continue; + + was_updating = mp->updating; + mp->updating = dispc_mgr_is_enabled(i); + + if (!mgr_manual_update(mgr)) { + bool was_busy = mp->busy; + mp->busy = dispc_mgr_go_busy(i); + + if (was_busy && !mp->busy) + mgr_clear_shadow_dirty(mgr); + } else { + if (was_updating && !mp->updating) + mgr_clear_shadow_dirty(mgr); + } + } + + dss_write_regs(); + dss_set_go_bits(); + + extra_updating = extra_info_update_ongoing(); + if (!extra_updating) + complete_all(&extra_updated_completion); + + if (!need_isr()) + dss_unregister_vsync_isr(); + + spin_unlock(&data_lock); +} + +static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op; + + op = get_ovl_priv(ovl); + + if (!op->user_info_dirty) + return; + + op->user_info_dirty = false; + op->info_dirty = true; + op->info = op->user_info; +} + +static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp; + + mp = get_mgr_priv(mgr); + + if (!mp->user_info_dirty) + return; + + mp->user_info_dirty = false; + mp->info_dirty = true; + mp->info = mp->user_info; +} + +int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) +{ + unsigned long flags; + struct omap_overlay *ovl; + int r; + + DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); + + spin_lock_irqsave(&data_lock, flags); + + r = dss_check_settings_apply(mgr, mgr->device); + if (r) { + spin_unlock_irqrestore(&data_lock, flags); + DSSERR("failed to apply settings: illegal configuration.\n"); + return r; + } + + /* Configure overlays */ + list_for_each_entry(ovl, &mgr->overlays, list) + omap_dss_mgr_apply_ovl(ovl); + + /* Configure manager */ + omap_dss_mgr_apply_mgr(mgr); + + dss_write_regs(); + dss_set_go_bits(); + + spin_unlock_irqrestore(&data_lock, flags); + + return 0; +} + +static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable) +{ + struct ovl_priv_data *op; + + op = get_ovl_priv(ovl); + + if (op->enabled == enable) + return; + + op->enabled = enable; + op->extra_info_dirty = true; +} + +static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, + u32 fifo_low, u32 fifo_high) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + + if (op->fifo_low == fifo_low && op->fifo_high == fifo_high) + return; + + op->fifo_low = fifo_low; + op->fifo_high = fifo_high; + op->extra_info_dirty = true; +} + +static void dss_ovl_setup_fifo(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + struct omap_dss_device *dssdev; + u32 size, burst_size; + u32 fifo_low, fifo_high; + + if (!op->enabled && !op->enabling) + return; + + dssdev = ovl->manager->device; + + size = dispc_ovl_get_fifo_size(ovl->id); + + burst_size = dispc_ovl_get_burst_size(ovl->id); + + switch (dssdev->type) { + case OMAP_DISPLAY_TYPE_DPI: + case OMAP_DISPLAY_TYPE_DBI: + case OMAP_DISPLAY_TYPE_SDI: + case OMAP_DISPLAY_TYPE_VENC: + case OMAP_DISPLAY_TYPE_HDMI: + default_get_overlay_fifo_thresholds(ovl->id, size, + burst_size, &fifo_low, &fifo_high); + break; +#ifdef CONFIG_OMAP2_DSS_DSI + case OMAP_DISPLAY_TYPE_DSI: + dsi_get_overlay_fifo_thresholds(ovl->id, size, + burst_size, &fifo_low, &fifo_high); + break; +#endif + default: + BUG(); + } + + dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); +} + +static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) +{ + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + + mp = get_mgr_priv(mgr); + + if (!mp->enabled) + return; + + list_for_each_entry(ovl, &mgr->overlays, list) + dss_ovl_setup_fifo(ovl); +} + +static void dss_setup_fifos(void) +{ + 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); + } +} + +int dss_mgr_enable(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + int r; + + mutex_lock(&apply_lock); + + if (mp->enabled) + goto out; + + spin_lock_irqsave(&data_lock, flags); + + mp->enabled = true; + + r = dss_check_settings(mgr, mgr->device); + if (r) { + DSSERR("failed to enable manager %d: check_settings failed\n", + mgr->id); + goto err; + } + + dss_setup_fifos(); + + dss_write_regs(); + dss_set_go_bits(); + + if (!mgr_manual_update(mgr)) + mp->updating = true; + + spin_unlock_irqrestore(&data_lock, flags); + + if (!mgr_manual_update(mgr)) + dispc_mgr_enable(mgr->id, true); + +out: + mutex_unlock(&apply_lock); + + return 0; + +err: + mp->enabled = false; + spin_unlock_irqrestore(&data_lock, flags); + mutex_unlock(&apply_lock); + return r; +} + +void dss_mgr_disable(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + + mutex_lock(&apply_lock); + + if (!mp->enabled) + goto out; + + if (!mgr_manual_update(mgr)) + dispc_mgr_enable(mgr->id, false); + + spin_lock_irqsave(&data_lock, flags); + + mp->updating = false; + mp->enabled = false; + + spin_unlock_irqrestore(&data_lock, flags); + +out: + mutex_unlock(&apply_lock); +} + +int dss_mgr_set_info(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + int r; + + r = dss_mgr_simple_check(mgr, info); + if (r) + return r; + + spin_lock_irqsave(&data_lock, flags); + + mp->user_info = *info; + mp->user_info_dirty = true; + + spin_unlock_irqrestore(&data_lock, flags); + + return 0; +} + +void dss_mgr_get_info(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + + spin_lock_irqsave(&data_lock, flags); + + *info = mp->user_info; + + spin_unlock_irqrestore(&data_lock, flags); +} + +int dss_mgr_set_device(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev) +{ + int r; + + mutex_lock(&apply_lock); + + if (dssdev->manager) { + DSSERR("display '%s' already has a manager '%s'\n", + dssdev->name, dssdev->manager->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); + r = -EINVAL; + goto err; + } + + dssdev->manager = mgr; + mgr->device = dssdev; + + mutex_unlock(&apply_lock); + + return 0; +err: + mutex_unlock(&apply_lock); + return r; +} + +int dss_mgr_unset_device(struct omap_overlay_manager *mgr) +{ + int r; + + mutex_lock(&apply_lock); + + if (!mgr->device) { + DSSERR("failed to unset display, display 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) { + r = -EINVAL; + goto err; + } + + mgr->device->manager = NULL; + mgr->device = NULL; + + mutex_unlock(&apply_lock); + + return 0; +err: + mutex_unlock(&apply_lock); + return r; +} + + +int dss_ovl_set_info(struct omap_overlay *ovl, + struct omap_overlay_info *info) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + r = dss_ovl_simple_check(ovl, info); + if (r) + return r; + + spin_lock_irqsave(&data_lock, flags); + + op->user_info = *info; + op->user_info_dirty = true; + + spin_unlock_irqrestore(&data_lock, flags); + + return 0; +} + +void dss_ovl_get_info(struct omap_overlay *ovl, + struct omap_overlay_info *info) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + + spin_lock_irqsave(&data_lock, flags); + + *info = op->user_info; + + spin_unlock_irqrestore(&data_lock, flags); +} + +int dss_ovl_set_manager(struct omap_overlay *ovl, + struct omap_overlay_manager *mgr) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + if (!mgr) + return -EINVAL; + + mutex_lock(&apply_lock); + + if (ovl->manager) { + DSSERR("overlay '%s' already has a manager '%s'\n", + ovl->name, ovl->manager->name); + r = -EINVAL; + goto err; + } + + spin_lock_irqsave(&data_lock, flags); + + if (op->enabled) { + spin_unlock_irqrestore(&data_lock, flags); + DSSERR("overlay has to be disabled to change the manager\n"); + r = -EINVAL; + goto err; + } + + op->channel = mgr->id; + op->extra_info_dirty = true; + + ovl->manager = mgr; + list_add_tail(&ovl->list, &mgr->overlays); + + spin_unlock_irqrestore(&data_lock, flags); + + /* XXX: When there is an overlay on a DSI manual update display, and + * the overlay is first disabled, then moved to tv, and enabled, we + * seem to get SYNC_LOST_DIGIT error. + * + * Waiting doesn't seem to help, but updating the manual update display + * after disabling the overlay seems to fix this. This hints that the + * overlay is perhaps somehow tied to the LCD output until the output + * is updated. + * + * Userspace workaround for this is to update the LCD after disabling + * the overlay, but before moving the overlay to TV. + */ + + mutex_unlock(&apply_lock); + + return 0; +err: + mutex_unlock(&apply_lock); + return r; +} + +int dss_ovl_unset_manager(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + mutex_lock(&apply_lock); + + if (!ovl->manager) { + DSSERR("failed to detach overlay: manager not set\n"); + r = -EINVAL; + goto err; + } + + spin_lock_irqsave(&data_lock, flags); + + if (op->enabled) { + spin_unlock_irqrestore(&data_lock, flags); + DSSERR("overlay has to be disabled to unset the manager\n"); + r = -EINVAL; + goto err; + } + + op->channel = -1; + + ovl->manager = NULL; + list_del(&ovl->list); + + spin_unlock_irqrestore(&data_lock, flags); + + mutex_unlock(&apply_lock); + + return 0; +err: + mutex_unlock(&apply_lock); + return r; +} + +bool dss_ovl_is_enabled(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + bool e; + + spin_lock_irqsave(&data_lock, flags); + + e = op->enabled; + + spin_unlock_irqrestore(&data_lock, flags); + + return e; +} + +int dss_ovl_enable(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + mutex_lock(&apply_lock); + + if (op->enabled) { + r = 0; + goto err1; + } + + if (ovl->manager == NULL || ovl->manager->device == NULL) { + r = -EINVAL; + goto err1; + } + + spin_lock_irqsave(&data_lock, flags); + + op->enabling = true; + + r = dss_check_settings(ovl->manager, ovl->manager->device); + if (r) { + DSSERR("failed to enable overlay %d: check_settings failed\n", + ovl->id); + goto err2; + } + + dss_setup_fifos(); + + op->enabling = false; + dss_apply_ovl_enable(ovl, true); + + dss_write_regs(); + dss_set_go_bits(); + + spin_unlock_irqrestore(&data_lock, flags); + + mutex_unlock(&apply_lock); + + return 0; +err2: + op->enabling = false; + spin_unlock_irqrestore(&data_lock, flags); +err1: + mutex_unlock(&apply_lock); + return r; +} + +int dss_ovl_disable(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + mutex_lock(&apply_lock); + + if (!op->enabled) { + r = 0; + goto err; + } + + if (ovl->manager == NULL || ovl->manager->device == NULL) { + r = -EINVAL; + goto err; + } + + 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); + + mutex_unlock(&apply_lock); + + return 0; + +err: + mutex_unlock(&apply_lock); + return r; +} + diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 86ec12e16c7c..8613f86fb56d 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -50,7 +50,7 @@ module_param_named(def_disp, def_disp_name, charp, 0); MODULE_PARM_DESC(def_disp, "default display name"); #ifdef DEBUG -unsigned int dss_debug; +bool dss_debug; module_param_named(debug, dss_debug, bool, 0644); #endif @@ -178,6 +178,8 @@ static int omap_dss_probe(struct platform_device *pdev) dss_features_init(); + dss_apply_init(); + dss_init_overlay_managers(pdev); dss_init_overlays(pdev); diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 5c81533eacaa..a5ec7f37c185 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -64,22 +64,6 @@ struct omap_dispc_isr_data { u32 mask; }; -struct dispc_h_coef { - s8 hc4; - s8 hc3; - u8 hc2; - s8 hc1; - s8 hc0; -}; - -struct dispc_v_coef { - s8 vc22; - s8 vc2; - u8 vc1; - s8 vc0; - s8 vc00; -}; - enum omap_burst_size { BURST_SIZE_X2 = 0, BURST_SIZE_X4 = 1, @@ -438,6 +422,34 @@ static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel) return mgr ? mgr->device : NULL; } +u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) +{ + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return DISPC_IRQ_VSYNC; + case OMAP_DSS_CHANNEL_LCD2: + return DISPC_IRQ_VSYNC2; + case OMAP_DSS_CHANNEL_DIGIT: + return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; + default: + BUG(); + } +} + +u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) +{ + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return DISPC_IRQ_FRAMEDONE; + case OMAP_DSS_CHANNEL_LCD2: + return DISPC_IRQ_FRAMEDONE2; + case OMAP_DSS_CHANNEL_DIGIT: + return 0; + default: + BUG(); + } +} + bool dispc_mgr_go_busy(enum omap_channel channel) { int bit; @@ -533,105 +545,27 @@ static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value) dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); } -static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, - int vscaleup, int five_taps, - enum omap_color_component color_comp) -{ - /* Coefficients for horizontal up-sampling */ - static const struct dispc_h_coef coef_hup[8] = { - { 0, 0, 128, 0, 0 }, - { -1, 13, 124, -8, 0 }, - { -2, 30, 112, -11, -1 }, - { -5, 51, 95, -11, -2 }, - { 0, -9, 73, 73, -9 }, - { -2, -11, 95, 51, -5 }, - { -1, -11, 112, 30, -2 }, - { 0, -8, 124, 13, -1 }, - }; - - /* Coefficients for vertical up-sampling */ - static const struct dispc_v_coef coef_vup_3tap[8] = { - { 0, 0, 128, 0, 0 }, - { 0, 3, 123, 2, 0 }, - { 0, 12, 111, 5, 0 }, - { 0, 32, 89, 7, 0 }, - { 0, 0, 64, 64, 0 }, - { 0, 7, 89, 32, 0 }, - { 0, 5, 111, 12, 0 }, - { 0, 2, 123, 3, 0 }, - }; - - static const struct dispc_v_coef coef_vup_5tap[8] = { - { 0, 0, 128, 0, 0 }, - { -1, 13, 124, -8, 0 }, - { -2, 30, 112, -11, -1 }, - { -5, 51, 95, -11, -2 }, - { 0, -9, 73, 73, -9 }, - { -2, -11, 95, 51, -5 }, - { -1, -11, 112, 30, -2 }, - { 0, -8, 124, 13, -1 }, - }; - - /* Coefficients for horizontal down-sampling */ - static const struct dispc_h_coef coef_hdown[8] = { - { 0, 36, 56, 36, 0 }, - { 4, 40, 55, 31, -2 }, - { 8, 44, 54, 27, -5 }, - { 12, 48, 53, 22, -7 }, - { -9, 17, 52, 51, 17 }, - { -7, 22, 53, 48, 12 }, - { -5, 27, 54, 44, 8 }, - { -2, 31, 55, 40, 4 }, - }; - - /* Coefficients for vertical down-sampling */ - static const struct dispc_v_coef coef_vdown_3tap[8] = { - { 0, 36, 56, 36, 0 }, - { 0, 40, 57, 31, 0 }, - { 0, 45, 56, 27, 0 }, - { 0, 50, 55, 23, 0 }, - { 0, 18, 55, 55, 0 }, - { 0, 23, 55, 50, 0 }, - { 0, 27, 56, 45, 0 }, - { 0, 31, 57, 40, 0 }, - }; - - static const struct dispc_v_coef coef_vdown_5tap[8] = { - { 0, 36, 56, 36, 0 }, - { 4, 40, 55, 31, -2 }, - { 8, 44, 54, 27, -5 }, - { 12, 48, 53, 22, -7 }, - { -9, 17, 52, 51, 17 }, - { -7, 22, 53, 48, 12 }, - { -5, 27, 54, 44, 8 }, - { -2, 31, 55, 40, 4 }, - }; - - const struct dispc_h_coef *h_coef; - const struct dispc_v_coef *v_coef; +static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, + int fir_vinc, int five_taps, + enum omap_color_component color_comp) +{ + const struct dispc_coef *h_coef, *v_coef; int i; - if (hscaleup) - h_coef = coef_hup; - else - h_coef = coef_hdown; - - if (vscaleup) - v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap; - else - v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap; + h_coef = dispc_ovl_get_scale_coef(fir_hinc, true); + v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps); for (i = 0; i < 8; i++) { u32 h, hv; - h = FLD_VAL(h_coef[i].hc0, 7, 0) - | FLD_VAL(h_coef[i].hc1, 15, 8) - | FLD_VAL(h_coef[i].hc2, 23, 16) - | FLD_VAL(h_coef[i].hc3, 31, 24); - hv = FLD_VAL(h_coef[i].hc4, 7, 0) - | FLD_VAL(v_coef[i].vc0, 15, 8) - | FLD_VAL(v_coef[i].vc1, 23, 16) - | FLD_VAL(v_coef[i].vc2, 31, 24); + h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0) + | FLD_VAL(h_coef[i].hc1_vc0, 15, 8) + | FLD_VAL(h_coef[i].hc2_vc1, 23, 16) + | FLD_VAL(h_coef[i].hc3_vc2, 31, 24); + hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0) + | FLD_VAL(v_coef[i].hc1_vc0, 15, 8) + | FLD_VAL(v_coef[i].hc2_vc1, 23, 16) + | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { dispc_ovl_write_firh_reg(plane, i, h); @@ -646,8 +580,8 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, if (five_taps) { for (i = 0; i < 8; i++) { u32 v; - v = FLD_VAL(v_coef[i].vc00, 7, 0) - | FLD_VAL(v_coef[i].vc22, 15, 8); + v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) + | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) dispc_ovl_write_firv_reg(plane, i, v); else @@ -875,8 +809,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); } -static void dispc_ovl_set_channel_out(enum omap_plane plane, - enum omap_channel channel) +void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) { int shift; u32 val; @@ -923,6 +856,39 @@ static void dispc_ovl_set_channel_out(enum omap_plane plane, dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } +static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) +{ + int shift; + u32 val; + enum omap_channel channel; + + switch (plane) { + case OMAP_DSS_GFX: + shift = 8; + break; + case OMAP_DSS_VIDEO1: + case OMAP_DSS_VIDEO2: + case OMAP_DSS_VIDEO3: + shift = 16; + break; + default: + BUG(); + } + + val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + + if (dss_has_feature(FEAT_MGR_LCD2)) { + if (FLD_GET(val, 31, 30) == 0) + channel = FLD_GET(val, shift, shift); + else + channel = OMAP_DSS_CHANNEL_LCD2; + } else { + channel = FLD_GET(val, shift, shift); + } + + return channel; +} + static void dispc_ovl_set_burst_size(enum omap_plane plane, enum omap_burst_size burst_size) { @@ -964,7 +930,7 @@ void dispc_enable_gamma_table(bool enable) REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); } -void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) { u16 reg; @@ -978,7 +944,7 @@ void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) REG_FLD_MOD(reg, enable, 15, 15); } -void dispc_mgr_set_cpr_coef(enum omap_channel channel, +static void dispc_mgr_set_cpr_coef(enum omap_channel channel, struct omap_dss_cpr_coefs *coefs) { u32 coef_r, coef_g, coef_b; @@ -1057,8 +1023,7 @@ u32 dispc_ovl_get_fifo_size(enum omap_plane plane) return dispc.fifo_size[plane]; } -static void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, - u32 high) +void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) { u8 hi_start, hi_end, lo_start, lo_end; u32 unit; @@ -1169,17 +1134,12 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane, enum omap_color_component color_comp) { int fir_hinc, fir_vinc; - int hscaleup, vscaleup; - - hscaleup = orig_width <= out_width; - vscaleup = orig_height <= out_height; - - dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps, - color_comp); fir_hinc = 1024 * orig_width / out_width; fir_vinc = 1024 * orig_height / out_height; + dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps, + color_comp); dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); } @@ -1654,6 +1614,9 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, u32 fclk = 0; u64 tmp, pclk = dispc_mgr_pclk_rate(channel); + if (height <= out_height && width <= out_width) + return (unsigned long) pclk; + if (height > out_height) { struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); unsigned int ppl = dssdev->panel.timings.x_res; @@ -1708,7 +1671,16 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, else vf = 1; - return dispc_mgr_pclk_rate(channel) * vf * hf; + if (cpu_is_omap24xx()) { + if (vf > 1 && hf > 1) + return dispc_mgr_pclk_rate(channel) * 4; + else + return dispc_mgr_pclk_rate(channel) * 2; + } else if (cpu_is_omap34xx()) { + return dispc_mgr_pclk_rate(channel) * vf * hf; + } else { + return dispc_mgr_pclk_rate(channel) * hf; + } } static int dispc_ovl_calc_scaling(enum omap_plane plane, @@ -1718,6 +1690,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, { struct omap_overlay *ovl = omap_dss_get_overlay(plane); const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + const int maxsinglelinewidth = + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); unsigned long fclk = 0; if (width == out_width && height == out_height) @@ -1734,28 +1708,40 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, out_height > height * 8) return -EINVAL; - /* Must use 5-tap filter? */ - *five_taps = height > out_height * 2; - - if (!*five_taps) { + if (cpu_is_omap24xx()) { + if (width > maxsinglelinewidth) + DSSERR("Cannot scale max input width exceeded"); + *five_taps = false; + fclk = calc_fclk(channel, width, height, out_width, + out_height); + } else if (cpu_is_omap34xx()) { + if (width > (maxsinglelinewidth * 2)) { + DSSERR("Cannot setup scaling"); + DSSERR("width exceeds maximum width possible"); + return -EINVAL; + } + fclk = calc_fclk_five_taps(channel, width, height, out_width, + out_height, color_mode); + if (width > maxsinglelinewidth) { + if (height > out_height && height < out_height * 2) + *five_taps = false; + else { + DSSERR("cannot setup scaling with five taps"); + return -EINVAL; + } + } + if (!*five_taps) + fclk = calc_fclk(channel, width, height, out_width, + out_height); + } else { + if (width > maxsinglelinewidth) { + DSSERR("Cannot scale width exceeds max line width"); + return -EINVAL; + } fclk = calc_fclk(channel, width, height, out_width, out_height); - - /* Try 5-tap filter if 3-tap fclk is too high */ - if (cpu_is_omap34xx() && height > out_height && - fclk > dispc_fclk_rate()) - *five_taps = true; - } - - if (width > (2048 >> *five_taps)) { - DSSERR("failed to set up scaling, fclk too low\n"); - return -EINVAL; } - if (*five_taps) - fclk = calc_fclk_five_taps(channel, width, height, - out_width, out_height, color_mode); - DSSDBG("required fclk rate = %lu Hz\n", fclk); DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); @@ -1771,11 +1757,10 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, } int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool ilace, enum omap_channel channel, bool replication, - u32 fifo_low, u32 fifo_high) + bool ilace, bool replication) { struct omap_overlay *ovl = omap_dss_get_overlay(plane); - bool five_taps = false; + bool five_taps = true; bool fieldmode = 0; int r, cconv = 0; unsigned offset0, offset1; @@ -1783,36 +1768,43 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, s32 pix_inc; u16 frame_height = oi->height; unsigned int field_offset = 0; + u16 outw, outh; + 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, ilace %d chan %d repl %d " - "fifo_low %d fifo high %d\n", plane, oi->paddr, oi->p_uv_addr, + "%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, fifo_low, fifo_high); + oi->mirror, ilace, channel, replication); if (oi->paddr == 0) return -EINVAL; - if (ilace && oi->height == oi->out_height) + outw = oi->out_width == 0 ? oi->width : oi->out_width; + outh = oi->out_height == 0 ? oi->height : oi->out_height; + + if (ilace && oi->height == outh) fieldmode = 1; if (ilace) { if (fieldmode) oi->height /= 2; oi->pos_y /= 2; - oi->out_height /= 2; + outh /= 2; DSSDBG("adjusting for ilace: height %d, pos_y %d, " "out_height %d\n", - oi->height, oi->pos_y, oi->out_height); + oi->height, oi->pos_y, outh); } if (!dss_feat_color_mode_supported(plane, oi->color_mode)) return -EINVAL; r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, - oi->out_width, oi->out_height, oi->color_mode, + outw, outh, oi->color_mode, &five_taps); if (r) return r; @@ -1830,10 +1822,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, * so the integer part must be added to the base address of the * bottom field. */ - if (!oi->height || oi->height == oi->out_height) + if (!oi->height || oi->height == outh) field_offset = 0; else - field_offset = oi->height / oi->out_height / 2; + field_offset = oi->height / outh / 2; } /* Fields are independent but interleaved in memory. */ @@ -1869,7 +1861,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, dispc_ovl_set_pix_inc(plane, pix_inc); DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, - oi->height, oi->out_width, oi->out_height); + oi->height, outw, outh); dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); @@ -1877,10 +1869,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { dispc_ovl_set_scaling(plane, oi->width, oi->height, - oi->out_width, oi->out_height, + outw, outh, ilace, five_taps, fieldmode, oi->color_mode, oi->rotation); - dispc_ovl_set_vid_size(plane, oi->out_width, oi->out_height); + dispc_ovl_set_vid_size(plane, outw, outh); dispc_ovl_set_vid_color_conv(plane, cconv); } @@ -1891,10 +1883,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); dispc_ovl_setup_global_alpha(plane, oi->global_alpha); - dispc_ovl_set_channel_out(plane, channel); - dispc_ovl_enable_replication(plane, replication); - dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high); return 0; } @@ -1916,10 +1905,14 @@ static void dispc_disable_isr(void *data, u32 mask) static void _enable_lcd_out(enum omap_channel channel, bool enable) { - if (channel == OMAP_DSS_CHANNEL_LCD2) + if (channel == OMAP_DSS_CHANNEL_LCD2) { REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); - else + /* flush posted write */ + dispc_read_reg(DISPC_CONTROL2); + } else { REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); + dispc_read_reg(DISPC_CONTROL); + } } static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) @@ -1967,6 +1960,8 @@ static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) static void _enable_digit_out(bool enable) { REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); + /* flush posted write */ + dispc_read_reg(DISPC_CONTROL); } static void dispc_mgr_enable_digit_out(bool enable) @@ -2124,25 +2119,12 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) } -void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) +static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) { dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); } -u32 dispc_mgr_get_default_color(enum omap_channel channel) -{ - u32 l; - - BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && - channel != OMAP_DSS_CHANNEL_LCD && - channel != OMAP_DSS_CHANNEL_LCD2); - - l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); - - return l; -} - -void dispc_mgr_set_trans_key(enum omap_channel ch, +static void dispc_mgr_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { @@ -2156,26 +2138,7 @@ void dispc_mgr_set_trans_key(enum omap_channel ch, dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); } -void dispc_mgr_get_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type *type, - u32 *trans_key) -{ - if (type) { - if (ch == OMAP_DSS_CHANNEL_LCD) - *type = REG_GET(DISPC_CONFIG, 11, 11); - else if (ch == OMAP_DSS_CHANNEL_DIGIT) - *type = REG_GET(DISPC_CONFIG, 13, 13); - else if (ch == OMAP_DSS_CHANNEL_LCD2) - *type = REG_GET(DISPC_CONFIG2, 11, 11); - else - BUG(); - } - - if (trans_key) - *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); -} - -void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) +static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) { if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); @@ -2185,7 +2148,8 @@ void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); } -void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) +static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, + bool enable) { if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) return; @@ -2196,40 +2160,20 @@ void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); } -bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch) -{ - bool enabled; - - if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) - return false; - - if (ch == OMAP_DSS_CHANNEL_LCD) - enabled = REG_GET(DISPC_CONFIG, 18, 18); - else if (ch == OMAP_DSS_CHANNEL_DIGIT) - enabled = REG_GET(DISPC_CONFIG, 19, 19); - else - BUG(); - - return enabled; -} - -bool dispc_mgr_trans_key_enabled(enum omap_channel ch) +void dispc_mgr_setup(enum omap_channel channel, + struct omap_overlay_manager_info *info) { - bool enabled; - - if (ch == OMAP_DSS_CHANNEL_LCD) - enabled = REG_GET(DISPC_CONFIG, 10, 10); - else if (ch == OMAP_DSS_CHANNEL_DIGIT) - enabled = REG_GET(DISPC_CONFIG, 12, 12); - else if (ch == OMAP_DSS_CHANNEL_LCD2) - enabled = REG_GET(DISPC_CONFIG2, 10, 10); - else - BUG(); - - return enabled; + dispc_mgr_set_default_color(channel, info->default_color); + dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); + dispc_mgr_enable_trans_key(channel, info->trans_enabled); + dispc_mgr_enable_alpha_fixed_zorder(channel, + info->partial_alpha_enabled); + if (dss_has_feature(FEAT_CPR)) { + dispc_mgr_enable_cpr(channel, info->cpr_enable); + dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); + } } - void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) { int code; @@ -3184,7 +3128,8 @@ static void dispc_error_worker(struct work_struct *work) for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { struct omap_overlay_manager *mgr; mgr = omap_dss_get_overlay_manager(i); - mgr->device->driver->disable(mgr->device); + if (mgr->device && mgr->device->driver) + mgr->device->driver->disable(mgr->device); } } diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index c06efc38983e..5836bd1650f9 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h @@ -97,6 +97,17 @@ #define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ DISPC_PRELOAD_OFFSET(n)) +/* DISPC up/downsampling FIR filter coefficient structure */ +struct dispc_coef { + s8 hc4_vc22; + s8 hc3_vc2; + u8 hc2_vc1; + s8 hc1_vc0; + s8 hc0_vc00; +}; + +const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps); + /* DISPC manager/channel specific registers */ static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) { diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c new file mode 100644 index 000000000000..069bccbb3f12 --- /dev/null +++ b/drivers/video/omap2/dss/dispc_coefs.c @@ -0,0 +1,326 @@ +/* + * linux/drivers/video/omap2/dss/dispc_coefs.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Chandrabhanu Mahapatra <cmahapatra@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 <video/omapdss.h> +#include "dispc.h" + +#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) + +static const struct dispc_coef coef3_M8[8] = { + { 0, 0, 128, 0, 0 }, + { 0, -4, 123, 9, 0 }, + { 0, -4, 108, 87, 0 }, + { 0, -2, 87, 43, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 43, 87, -2, 0 }, + { 0, 24, 108, -4, 0 }, + { 0, 9, 123, -4, 0 }, +}; + +static const struct dispc_coef coef3_M9[8] = { + { 0, 6, 116, 6, 0 }, + { 0, 0, 112, 16, 0 }, + { 0, -2, 100, 30, 0 }, + { 0, -2, 83, 47, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 47, 83, -2, 0 }, + { 0, 30, 100, -2, 0 }, + { 0, 16, 112, 0, 0 }, +}; + +static const struct dispc_coef coef3_M10[8] = { + { 0, 10, 108, 10, 0 }, + { 0, 3, 104, 21, 0 }, + { 0, 0, 94, 34, 0 }, + { 0, -1, 80, 49, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 49, 80, -1, 0 }, + { 0, 34, 94, 0, 0 }, + { 0, 21, 104, 3, 0 }, +}; + +static const struct dispc_coef coef3_M11[8] = { + { 0, 14, 100, 14, 0 }, + { 0, 6, 98, 24, 0 }, + { 0, 2, 90, 36, 0 }, + { 0, 0, 78, 50, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 50, 78, 0, 0 }, + { 0, 36, 90, 2, 0 }, + { 0, 24, 98, 6, 0 }, +}; + +static const struct dispc_coef coef3_M12[8] = { + { 0, 16, 96, 16, 0 }, + { 0, 9, 93, 26, 0 }, + { 0, 4, 86, 38, 0 }, + { 0, 1, 76, 51, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 51, 76, 1, 0 }, + { 0, 38, 86, 4, 0 }, + { 0, 26, 93, 9, 0 }, +}; + +static const struct dispc_coef coef3_M13[8] = { + { 0, 18, 92, 18, 0 }, + { 0, 10, 90, 28, 0 }, + { 0, 5, 83, 40, 0 }, + { 0, 1, 75, 52, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 52, 75, 1, 0 }, + { 0, 40, 83, 5, 0 }, + { 0, 28, 90, 10, 0 }, +}; + +static const struct dispc_coef coef3_M14[8] = { + { 0, 20, 88, 20, 0 }, + { 0, 12, 86, 30, 0 }, + { 0, 6, 81, 41, 0 }, + { 0, 2, 74, 52, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 52, 74, 2, 0 }, + { 0, 41, 81, 6, 0 }, + { 0, 30, 86, 12, 0 }, +}; + +static const struct dispc_coef coef3_M16[8] = { + { 0, 22, 84, 22, 0 }, + { 0, 14, 82, 32, 0 }, + { 0, 8, 78, 42, 0 }, + { 0, 3, 72, 53, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 53, 72, 3, 0 }, + { 0, 42, 78, 8, 0 }, + { 0, 32, 82, 14, 0 }, +}; + +static const struct dispc_coef coef3_M19[8] = { + { 0, 24, 80, 24, 0 }, + { 0, 16, 79, 33, 0 }, + { 0, 9, 76, 43, 0 }, + { 0, 4, 70, 54, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 54, 70, 4, 0 }, + { 0, 43, 76, 9, 0 }, + { 0, 33, 79, 16, 0 }, +}; + +static const struct dispc_coef coef3_M22[8] = { + { 0, 25, 78, 25, 0 }, + { 0, 17, 77, 34, 0 }, + { 0, 10, 74, 44, 0 }, + { 0, 5, 69, 54, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 54, 69, 5, 0 }, + { 0, 44, 74, 10, 0 }, + { 0, 34, 77, 17, 0 }, +}; + +static const struct dispc_coef coef3_M26[8] = { + { 0, 26, 76, 26, 0 }, + { 0, 19, 74, 35, 0 }, + { 0, 11, 72, 45, 0 }, + { 0, 5, 69, 54, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 54, 69, 5, 0 }, + { 0, 45, 72, 11, 0 }, + { 0, 35, 74, 19, 0 }, +}; + +static const struct dispc_coef coef3_M32[8] = { + { 0, 27, 74, 27, 0 }, + { 0, 19, 73, 36, 0 }, + { 0, 12, 71, 45, 0 }, + { 0, 6, 68, 54, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 54, 68, 6, 0 }, + { 0, 45, 71, 12, 0 }, + { 0, 36, 73, 19, 0 }, +}; + +static const struct dispc_coef coef5_M8[8] = { + { 0, 0, 128, 0, 0 }, + { -2, 14, 125, -10, 1 }, + { -6, 33, 114, -15, 2 }, + { -10, 55, 98, -16, 1 }, + { 0, -14, 78, 78, -14 }, + { 1, -16, 98, 55, -10 }, + { 2, -15, 114, 33, -6 }, + { 1, -10, 125, 14, -2 }, +}; + +static const struct dispc_coef coef5_M9[8] = { + { -3, 10, 114, 10, -3 }, + { -6, 24, 110, 0, -1 }, + { -8, 40, 103, -7, 0 }, + { -11, 58, 91, -11, 1 }, + { 0, -12, 76, 76, -12 }, + { 1, -11, 91, 58, -11 }, + { 0, -7, 103, 40, -8 }, + { -1, 0, 111, 24, -6 }, +}; + +static const struct dispc_coef coef5_M10[8] = { + { -4, 18, 100, 18, -4 }, + { -6, 30, 99, 8, -3 }, + { -8, 44, 93, 0, -1 }, + { -9, 58, 84, -5, 0 }, + { 0, -8, 72, 72, -8 }, + { 0, -5, 84, 58, -9 }, + { -1, 0, 93, 44, -8 }, + { -3, 8, 99, 30, -6 }, +}; + +static const struct dispc_coef coef5_M11[8] = { + { -5, 23, 92, 23, -5 }, + { -6, 34, 90, 13, -3 }, + { -6, 45, 85, 6, -2 }, + { -6, 57, 78, 0, -1 }, + { 0, -4, 68, 68, -4 }, + { -1, 0, 78, 57, -6 }, + { -2, 6, 85, 45, -6 }, + { -3, 13, 90, 34, -6 }, +}; + +static const struct dispc_coef coef5_M12[8] = { + { -4, 26, 84, 26, -4 }, + { -5, 36, 82, 18, -3 }, + { -4, 46, 78, 10, -2 }, + { -3, 55, 72, 5, -1 }, + { 0, 0, 64, 64, 0 }, + { -1, 5, 72, 55, -3 }, + { -2, 10, 78, 46, -4 }, + { -3, 18, 82, 36, -5 }, +}; + +static const struct dispc_coef coef5_M13[8] = { + { -3, 28, 78, 28, -3 }, + { -3, 37, 76, 21, -3 }, + { -2, 45, 73, 14, -2 }, + { 0, 53, 68, 8, -1 }, + { 0, 3, 61, 61, 3 }, + { -1, 8, 68, 53, 0 }, + { -2, 14, 73, 45, -2 }, + { -3, 21, 76, 37, -3 }, +}; + +static const struct dispc_coef coef5_M14[8] = { + { -2, 30, 72, 30, -2 }, + { -1, 37, 71, 23, -2 }, + { 0, 45, 69, 16, -2 }, + { 3, 52, 64, 10, -1 }, + { 0, 6, 58, 58, 6 }, + { -1, 10, 64, 52, 3 }, + { -2, 16, 69, 45, 0 }, + { -2, 23, 71, 37, -1 }, +}; + +static const struct dispc_coef coef5_M16[8] = { + { 0, 31, 66, 31, 0 }, + { 1, 38, 65, 25, -1 }, + { 3, 44, 62, 20, -1 }, + { 6, 49, 59, 14, 0 }, + { 0, 10, 54, 54, 10 }, + { 0, 14, 59, 49, 6 }, + { -1, 20, 62, 44, 3 }, + { -1, 25, 65, 38, 1 }, +}; + +static const struct dispc_coef coef5_M19[8] = { + { 3, 32, 58, 32, 3 }, + { 4, 38, 58, 27, 1 }, + { 7, 42, 55, 23, 1 }, + { 10, 46, 54, 18, 0 }, + { 0, 14, 50, 50, 14 }, + { 0, 18, 54, 46, 10 }, + { 1, 23, 55, 42, 7 }, + { 1, 27, 58, 38, 4 }, +}; + +static const struct dispc_coef coef5_M22[8] = { + { 4, 33, 54, 33, 4 }, + { 6, 37, 54, 28, 3 }, + { 9, 41, 53, 24, 1 }, + { 12, 45, 51, 20, 0 }, + { 0, 16, 48, 48, 16 }, + { 0, 20, 51, 45, 12 }, + { 1, 24, 53, 41, 9 }, + { 3, 28, 54, 37, 6 }, +}; + +static const struct dispc_coef coef5_M26[8] = { + { 6, 33, 50, 33, 6 }, + { 8, 36, 51, 29, 4 }, + { 11, 40, 50, 25, 2 }, + { 14, 43, 48, 22, 1 }, + { 0, 18, 46, 46, 18 }, + { 1, 22, 48, 43, 14 }, + { 2, 25, 50, 40, 11 }, + { 4, 29, 51, 36, 8 }, +}; + +static const struct dispc_coef coef5_M32[8] = { + { 7, 33, 48, 33, 7 }, + { 10, 36, 48, 29, 5 }, + { 13, 39, 47, 26, 3 }, + { 16, 42, 46, 23, 1 }, + { 0, 19, 45, 45, 19 }, + { 1, 23, 46, 42, 16 }, + { 3, 26, 47, 39, 13 }, + { 5, 29, 48, 36, 10 }, +}; + +const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps) +{ + int i; + static const struct { + int Mmin; + int Mmax; + const struct dispc_coef *coef_3; + const struct dispc_coef *coef_5; + } coefs[] = { + { 27, 32, coef3_M32, coef5_M32 }, + { 23, 26, coef3_M26, coef5_M26 }, + { 20, 22, coef3_M22, coef5_M22 }, + { 17, 19, coef3_M19, coef5_M19 }, + { 15, 16, coef3_M16, coef5_M16 }, + { 14, 14, coef3_M14, coef5_M14 }, + { 13, 13, coef3_M13, coef5_M13 }, + { 12, 12, coef3_M12, coef5_M12 }, + { 11, 11, coef3_M11, coef5_M11 }, + { 10, 10, coef3_M10, coef5_M10 }, + { 9, 9, coef3_M9, coef5_M9 }, + { 4, 8, coef3_M8, coef5_M8 }, + /* + * When upscaling more than two times, blockiness and outlines + * around the image are observed when M8 tables are used. M11, + * M16 and M19 tables are used to prevent this. + */ + { 3, 3, coef3_M11, coef5_M11 }, + { 2, 2, coef3_M16, coef5_M16 }, + { 0, 1, coef3_M19, coef5_M19 }, + }; + + inc /= 128; + for (i = 0; i < ARRAY_LEN(coefs); ++i) + if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax) + return five_taps ? coefs[i].coef_5 : coefs[i].coef_3; + return NULL; +} diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 976ac23dcd0c..395d658a94fc 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -223,10 +223,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - dssdev->manager->enable(dssdev->manager); + r = dss_mgr_enable(dssdev->manager); + if (r) + goto err_mgr_enable; return 0; +err_mgr_enable: err_set_mode: if (dpi_use_dsi_pll(dssdev)) dsi_pll_uninit(dpi.dsidev, true); @@ -249,7 +252,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) { - dssdev->manager->disable(dssdev->manager); + dss_mgr_disable(dssdev->manager); if (dpi_use_dsi_pll(dssdev)) { dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 5abf8e7e7456..d4d676c82c12 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -203,6 +203,21 @@ struct dsi_reg { u16 idx; }; typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); #define DSI_MAX_NR_ISRS 2 +#define DSI_MAX_NR_LANES 5 + +enum dsi_lane_function { + DSI_LANE_UNUSED = 0, + DSI_LANE_CLK, + DSI_LANE_DATA1, + DSI_LANE_DATA2, + DSI_LANE_DATA3, + DSI_LANE_DATA4, +}; + +struct dsi_lane_config { + enum dsi_lane_function function; + u8 polarity; +}; struct dsi_isr_data { omap_dsi_isr_t isr; @@ -223,24 +238,6 @@ enum dsi_vc_source { DSI_VC_SOURCE_VP, }; -enum dsi_lane { - DSI_CLK_P = 1 << 0, - DSI_CLK_N = 1 << 1, - DSI_DATA1_P = 1 << 2, - DSI_DATA1_N = 1 << 3, - DSI_DATA2_P = 1 << 4, - DSI_DATA2_N = 1 << 5, - DSI_DATA3_P = 1 << 6, - DSI_DATA3_N = 1 << 7, - DSI_DATA4_P = 1 << 8, - DSI_DATA4_N = 1 << 9, -}; - -struct dsi_update_region { - u16 x, y, w, h; - struct omap_dss_device *device; -}; - struct dsi_irq_stats { unsigned long last_reset; unsigned irq_count; @@ -290,7 +287,9 @@ struct dsi_data { struct dsi_isr_tables isr_tables_copy; int update_channel; - struct dsi_update_region update_region; +#ifdef DEBUG + unsigned update_bytes; +#endif bool te_enabled; bool ulps_enabled; @@ -327,7 +326,10 @@ struct dsi_data { unsigned long fint_min, fint_max; unsigned long lpdiv_max; - int num_data_lanes; + unsigned num_lanes_supported; + + struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; + unsigned num_lanes_used; unsigned scp_clk_refcount; }; @@ -340,8 +342,8 @@ struct dsi_packet_sent_handler_data { static struct platform_device *dsi_pdev_map[MAX_NUM_DSI]; #ifdef DEBUG -static unsigned int dsi_perf; -module_param_named(dsi_perf, dsi_perf, bool, 0644); +static bool dsi_perf; +module_param(dsi_perf, bool, 0644); #endif static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev) @@ -413,14 +415,29 @@ static void dsi_completion_handler(void *data, u32 mask) static inline int wait_for_bit_change(struct platform_device *dsidev, const struct dsi_reg idx, int bitnum, int value) { - int t = 100000; + unsigned long timeout; + ktime_t wait; + int t; - while (REG_GET(dsidev, idx, bitnum, bitnum) != value) { - if (--t == 0) - return !value; + /* first busyloop to see if the bit changes right away */ + t = 100; + while (t-- > 0) { + if (REG_GET(dsidev, idx, bitnum, bitnum) == value) + return value; } - return value; + /* then loop for 500ms, sleeping for 1ms in between */ + timeout = jiffies + msecs_to_jiffies(500); + while (time_before(jiffies, timeout)) { + if (REG_GET(dsidev, idx, bitnum, bitnum) == value) + return value; + + wait = ns_to_ktime(1000 * 1000); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_hrtimeout(&wait, HRTIMER_MODE_REL); + } + + return !value; } u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) @@ -454,7 +471,6 @@ static void dsi_perf_mark_start(struct platform_device *dsidev) static void dsi_perf_show(struct platform_device *dsidev, const char *name) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_dss_device *dssdev = dsi->update_region.device; ktime_t t, setup_time, trans_time; u32 total_bytes; u32 setup_us, trans_us, total_us; @@ -476,9 +492,7 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) total_us = setup_us + trans_us; - total_bytes = dsi->update_region.w * - dsi->update_region.h * - dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; + total_bytes = dsi->update_bytes; printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " "%u bytes, %u kbytes/sec\n", @@ -1720,17 +1734,19 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", cinfo->clkin4ddr, cinfo->regm); - seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n", - dss_get_generic_clk_source_name(dispc_clk_src), - dss_feat_get_clk_source_name(dispc_clk_src), + seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n", + dss_feat_get_clk_source_name(dsi_module == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC), cinfo->dsi_pll_hsdiv_dispc_clk, cinfo->regm_dispc, dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? "off" : "on"); - seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n", - dss_get_generic_clk_source_name(dsi_clk_src), - dss_feat_get_clk_source_name(dsi_clk_src), + seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n", + dss_feat_get_clk_source_name(dsi_module == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI), cinfo->dsi_pll_hsdiv_dsi_clk, cinfo->regm_dsi, dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? @@ -2029,34 +2045,6 @@ static int dsi_cio_power(struct platform_device *dsidev, return 0; } -/* Number of data lanes present on DSI interface */ -static inline int dsi_get_num_data_lanes(struct platform_device *dsidev) -{ - /* DSI on OMAP3 doesn't have register DSI_GNQ, set number - * of data lanes as 2 by default */ - if (dss_has_feature(FEAT_DSI_GNQ)) - return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */ - else - return 2; -} - -/* Number of data lanes used by the dss device */ -static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev) -{ - int num_data_lanes = 0; - - if (dssdev->phy.dsi.data1_lane != 0) - num_data_lanes++; - if (dssdev->phy.dsi.data2_lane != 0) - num_data_lanes++; - if (dssdev->phy.dsi.data3_lane != 0) - num_data_lanes++; - if (dssdev->phy.dsi.data4_lane != 0) - num_data_lanes++; - - return num_data_lanes; -} - static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) { int val; @@ -2088,59 +2076,112 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) } } -static void dsi_set_lane_config(struct omap_dss_device *dssdev) +static int dsi_parse_lane_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - u32 r; - int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + u8 lanes[DSI_MAX_NR_LANES]; + u8 polarities[DSI_MAX_NR_LANES]; + int num_lanes, i; + + static const enum dsi_lane_function functions[] = { + DSI_LANE_CLK, + DSI_LANE_DATA1, + DSI_LANE_DATA2, + DSI_LANE_DATA3, + DSI_LANE_DATA4, + }; + + lanes[0] = dssdev->phy.dsi.clk_lane; + lanes[1] = dssdev->phy.dsi.data1_lane; + lanes[2] = dssdev->phy.dsi.data2_lane; + lanes[3] = dssdev->phy.dsi.data3_lane; + lanes[4] = dssdev->phy.dsi.data4_lane; + polarities[0] = dssdev->phy.dsi.clk_pol; + polarities[1] = dssdev->phy.dsi.data1_pol; + polarities[2] = dssdev->phy.dsi.data2_pol; + polarities[3] = dssdev->phy.dsi.data3_pol; + polarities[4] = dssdev->phy.dsi.data4_pol; - int clk_lane = dssdev->phy.dsi.clk_lane; - int data1_lane = dssdev->phy.dsi.data1_lane; - int data2_lane = dssdev->phy.dsi.data2_lane; - int clk_pol = dssdev->phy.dsi.clk_pol; - int data1_pol = dssdev->phy.dsi.data1_pol; - int data2_pol = dssdev->phy.dsi.data2_pol; + num_lanes = 0; + + for (i = 0; i < dsi->num_lanes_supported; ++i) + dsi->lanes[i].function = DSI_LANE_UNUSED; + + for (i = 0; i < dsi->num_lanes_supported; ++i) { + int num; + + if (lanes[i] == DSI_LANE_UNUSED) + break; + + num = lanes[i] - 1; + + if (num >= dsi->num_lanes_supported) + return -EINVAL; + + if (dsi->lanes[num].function != DSI_LANE_UNUSED) + return -EINVAL; + + dsi->lanes[num].function = functions[i]; + dsi->lanes[num].polarity = polarities[i]; + num_lanes++; + } + + if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported) + return -EINVAL; + + dsi->num_lanes_used = num_lanes; + + return 0; +} + +static int dsi_set_lane_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); + static const u8 offsets[] = { 0, 4, 8, 12, 16 }; + static const enum dsi_lane_function functions[] = { + DSI_LANE_CLK, + DSI_LANE_DATA1, + DSI_LANE_DATA2, + DSI_LANE_DATA3, + DSI_LANE_DATA4, + }; + u32 r; + int i; r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); - r = FLD_MOD(r, clk_lane, 2, 0); - r = FLD_MOD(r, clk_pol, 3, 3); - r = FLD_MOD(r, data1_lane, 6, 4); - r = FLD_MOD(r, data1_pol, 7, 7); - r = FLD_MOD(r, data2_lane, 10, 8); - r = FLD_MOD(r, data2_pol, 11, 11); - if (num_data_lanes_dssdev > 2) { - int data3_lane = dssdev->phy.dsi.data3_lane; - int data3_pol = dssdev->phy.dsi.data3_pol; - - r = FLD_MOD(r, data3_lane, 14, 12); - r = FLD_MOD(r, data3_pol, 15, 15); + + for (i = 0; i < dsi->num_lanes_used; ++i) { + unsigned offset = offsets[i]; + unsigned polarity, lane_number; + unsigned t; + + for (t = 0; t < dsi->num_lanes_supported; ++t) + if (dsi->lanes[t].function == functions[i]) + break; + + if (t == dsi->num_lanes_supported) + return -EINVAL; + + lane_number = t; + polarity = dsi->lanes[t].polarity; + + r = FLD_MOD(r, lane_number + 1, offset + 2, offset); + r = FLD_MOD(r, polarity, offset + 3, offset + 3); } - if (num_data_lanes_dssdev > 3) { - int data4_lane = dssdev->phy.dsi.data4_lane; - int data4_pol = dssdev->phy.dsi.data4_pol; - r = FLD_MOD(r, data4_lane, 18, 16); - r = FLD_MOD(r, data4_pol, 19, 19); + /* clear the unused lanes */ + for (; i < dsi->num_lanes_supported; ++i) { + unsigned offset = offsets[i]; + + r = FLD_MOD(r, 0, offset + 2, offset); + r = FLD_MOD(r, 0, offset + 3, offset + 3); } - dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); - /* The configuration of the DSI complex I/O (number of data lanes, - position, differential order) should not be changed while - DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for - the hardware to take into account a new configuration of the complex - I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to - follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, - then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set - DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the - DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the - DSI complex I/O configuration is unknown. */ + dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); - /* - REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); - REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0); - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); - REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); - */ + return 0; } static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) @@ -2230,49 +2271,28 @@ static void dsi_cio_timings(struct platform_device *dsidev) dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); } +/* 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, - enum dsi_lane lanes) + 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 clk_lane = dssdev->phy.dsi.clk_lane; - int data1_lane = dssdev->phy.dsi.data1_lane; - int data2_lane = dssdev->phy.dsi.data2_lane; - int data3_lane = dssdev->phy.dsi.data3_lane; - int data4_lane = dssdev->phy.dsi.data4_lane; - int clk_pol = dssdev->phy.dsi.clk_pol; - int data1_pol = dssdev->phy.dsi.data1_pol; - int data2_pol = dssdev->phy.dsi.data2_pol; - int data3_pol = dssdev->phy.dsi.data3_pol; - int data4_pol = dssdev->phy.dsi.data4_pol; - - u32 l = 0; - u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26; - - if (lanes & DSI_CLK_P) - l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1)); - if (lanes & DSI_CLK_N) - l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0)); - - if (lanes & DSI_DATA1_P) - l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1)); - if (lanes & DSI_DATA1_N) - l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0)); - - if (lanes & DSI_DATA2_P) - l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1)); - if (lanes & DSI_DATA2_N) - l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0)); - - if (lanes & DSI_DATA3_P) - l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1)); - if (lanes & DSI_DATA3_N) - l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0)); - - if (lanes & DSI_DATA4_P) - l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1)); - if (lanes & DSI_DATA4_N) - l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0)); + int i; + u32 l; + u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26; + + l = 0; + + for (i = 0; i < dsi->num_lanes_supported; ++i) { + unsigned p = dsi->lanes[i].polarity; + + if (mask_p & (1 << i)) + l |= 1 << (i * 2 + (p ? 0 : 1)); + + if (mask_n & (1 << i)) + l |= 1 << (i * 2 + (p ? 1 : 0)); + } + /* * Bits in REGLPTXSCPDAT4TO0DXDY: * 17: DY0 18: DX0 @@ -2305,51 +2325,40 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - int t; - int bits[3]; - bool in_use[3]; - - if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { - bits[0] = 28; - bits[1] = 27; - bits[2] = 26; - } else { - bits[0] = 24; - bits[1] = 25; - bits[2] = 26; - } - - in_use[0] = false; - in_use[1] = false; - in_use[2] = false; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + int t, i; + bool in_use[DSI_MAX_NR_LANES]; + static const u8 offsets_old[] = { 28, 27, 26 }; + static const u8 offsets_new[] = { 24, 25, 26, 27, 28 }; + const u8 *offsets; + + if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) + offsets = offsets_old; + else + offsets = offsets_new; - if (dssdev->phy.dsi.clk_lane != 0) - in_use[dssdev->phy.dsi.clk_lane - 1] = true; - if (dssdev->phy.dsi.data1_lane != 0) - in_use[dssdev->phy.dsi.data1_lane - 1] = true; - if (dssdev->phy.dsi.data2_lane != 0) - in_use[dssdev->phy.dsi.data2_lane - 1] = true; + for (i = 0; i < dsi->num_lanes_supported; ++i) + in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED; t = 100000; while (true) { u32 l; - int i; int ok; l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); ok = 0; - for (i = 0; i < 3; ++i) { - if (!in_use[i] || (l & (1 << bits[i]))) + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (!in_use[i] || (l & (1 << offsets[i]))) ok++; } - if (ok == 3) + if (ok == dsi->num_lanes_supported) break; if (--t == 0) { - for (i = 0; i < 3; ++i) { - if (!in_use[i] || (l & (1 << bits[i]))) + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (!in_use[i] || (l & (1 << offsets[i]))) continue; DSSERR("CIO TXCLKESC%d domain not coming " \ @@ -2362,22 +2371,20 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) return 0; } +/* return bitmask of enabled lanes, lane0 being the lsb */ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) { - unsigned lanes = 0; + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + unsigned mask = 0; + int i; - if (dssdev->phy.dsi.clk_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.clk_lane - 1); - if (dssdev->phy.dsi.data1_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.data1_lane - 1); - if (dssdev->phy.dsi.data2_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.data2_lane - 1); - if (dssdev->phy.dsi.data3_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.data3_lane - 1); - if (dssdev->phy.dsi.data4_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.data4_lane - 1); + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (dsi->lanes[i].function != DSI_LANE_UNUSED) + mask |= 1 << i; + } - return lanes; + return mask; } static int dsi_cio_init(struct omap_dss_device *dssdev) @@ -2385,7 +2392,6 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; - int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); u32 l; DSSDBGF(); @@ -2407,7 +2413,9 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) goto err_scp_clk_dom; } - dsi_set_lane_config(dssdev); + r = dsi_set_lane_config(dssdev); + if (r) + goto err_scp_clk_dom; /* set TX STOP MODE timer to maximum for this operation */ l = dsi_read_reg(dsidev, DSI_TIMING1); @@ -2418,7 +2426,8 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_TIMING1, l); if (dsi->ulps_enabled) { - u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P; + unsigned mask_p; + int i; DSSDBG("manual ulps exit\n"); @@ -2427,16 +2436,19 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) * ULPS exit sequence, as after reset the DSS HW thinks * that we are not in ULPS mode, and refuses to send the * sequence. So we need to send the ULPS exit sequence - * manually. + * manually by setting positive lines high and negative lines + * low for 1ms. */ - if (num_data_lanes_dssdev > 2) - lane_mask |= DSI_DATA3_P; + mask_p = 0; - if (num_data_lanes_dssdev > 3) - lane_mask |= DSI_DATA4_P; + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (dsi->lanes[i].function == DSI_LANE_UNUSED) + continue; + mask_p |= 1 << i; + } - dsi_cio_enable_lane_override(dssdev, lane_mask); + dsi_cio_enable_lane_override(dssdev, mask_p, 0); } r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); @@ -2913,6 +2925,9 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel) REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ + /* flush posted write */ + dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); + return 0; } @@ -3513,7 +3528,8 @@ static int dsi_enter_ulps(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); - int r; + int r, i; + unsigned mask; DSSDBGF(); @@ -3524,9 +3540,11 @@ static int dsi_enter_ulps(struct platform_device *dsidev) if (dsi->ulps_enabled) return 0; + /* DDR_CLK_ALWAYS_ON */ if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { - DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n"); - return -EIO; + dsi_if_enable(dsidev, 0); + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); + dsi_if_enable(dsidev, 1); } dsi_sync_vc(dsidev, 0); @@ -3556,10 +3574,19 @@ static int dsi_enter_ulps(struct platform_device *dsidev) if (r) return r; + mask = 0; + + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (dsi->lanes[i].function == DSI_LANE_UNUSED) + continue; + mask |= 1 << i; + } /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ /* LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2), - 7, 5); + REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5); + + /* flush posted write and wait for SCP interface to finish the write */ + dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); if (wait_for_completion_timeout(&completion, msecs_to_jiffies(1000)) == 0) { @@ -3572,8 +3599,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); /* Reset LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), - 7, 5); + REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5); + + /* flush posted write and wait for SCP interface to finish the write */ + dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); @@ -3836,6 +3865,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) static void dsi_proto_timings(struct omap_dss_device *dssdev) { 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; unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; @@ -3843,7 +3873,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) unsigned ddr_clk_pre, ddr_clk_post; unsigned enter_hs_mode_lat, exit_hs_mode_lat; unsigned ths_eot; - int ndl = dsi_get_num_data_lanes_dssdev(dssdev); + int ndl = dsi->num_lanes_used - 1; u32 r; r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); @@ -3945,68 +3975,82 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) } } -int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel) +int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); u8 data_type; u16 word_count; + int r; - switch (dssdev->panel.dsi_pix_fmt) { - case OMAP_DSS_DSI_FMT_RGB888: - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; - break; - case OMAP_DSS_DSI_FMT_RGB666: - data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; - break; - case OMAP_DSS_DSI_FMT_RGB666_PACKED: - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; - break; - case OMAP_DSS_DSI_FMT_RGB565: - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; - break; - default: - BUG(); - }; + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + switch (dssdev->panel.dsi_pix_fmt) { + case OMAP_DSS_DSI_FMT_RGB888: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; + break; + case OMAP_DSS_DSI_FMT_RGB666: + data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; + break; + case OMAP_DSS_DSI_FMT_RGB666_PACKED: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; + break; + case OMAP_DSS_DSI_FMT_RGB565: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; + break; + default: + BUG(); + }; - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); - /* MODE, 1 = video mode */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); + /* 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(dssdev->panel.timings.x_res * bpp, 8); - dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); + dsi_vc_write_long_header(dsidev, channel, data_type, + word_count, 0); - dsi_vc_enable(dsidev, channel, true); - dsi_if_enable(dsidev, true); + dsi_vc_enable(dsidev, channel, true); + dsi_if_enable(dsidev, true); + } - dssdev->manager->enable(dssdev->manager); + r = dss_mgr_enable(dssdev->manager); + if (r) { + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); + } + + return r; + } return 0; } -EXPORT_SYMBOL(dsi_video_mode_enable); +EXPORT_SYMBOL(dsi_enable_video_output); -void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel) +void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); - /* MODE, 0 = command mode */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); + /* MODE, 0 = command mode */ + REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); - dsi_vc_enable(dsidev, channel, true); - dsi_if_enable(dsidev, true); + dsi_vc_enable(dsidev, channel, true); + dsi_if_enable(dsidev, true); + } - dssdev->manager->disable(dssdev->manager); + dss_mgr_disable(dssdev->manager); } -EXPORT_SYMBOL(dsi_video_mode_disable); +EXPORT_SYMBOL(dsi_disable_video_output); static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h) + u16 w, u16 h) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); @@ -4021,8 +4065,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, const unsigned channel = dsi->update_channel; const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); - DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", - x, y, w, h); + DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); @@ -4070,7 +4113,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, msecs_to_jiffies(250)); BUG_ON(r == 0); - dss_start_update(dssdev); + dss_mgr_start_update(dssdev->manager); if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait @@ -4146,66 +4189,27 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) #endif } -int omap_dsi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h, - bool enlarge_update_area) +int omap_dsi_update(struct omap_dss_device *dssdev, int channel, + void (*callback)(int, void *), void *data) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u16 dw, dh; - 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; - dsi_perf_mark_setup(dsidev); - dss_setup_partial_planes(dssdev, x, y, w, h, - enlarge_update_area); - dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); - - return 0; -} -EXPORT_SYMBOL(omap_dsi_prepare_update); - -int omap_dsi_update(struct omap_dss_device *dssdev, - int channel, - u16 x, u16 y, u16 w, u16 h, - void (*callback)(int, void *), void *data) -{ - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - dsi->update_channel = channel; - /* OMAP DSS cannot send updates of odd widths. - * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON - * here to make sure we catch erroneous updates. Otherwise we'll only - * see rather obscure HW error happening, as DSS halts. */ - BUG_ON(x % 2 == 1); - dsi->framedone_callback = callback; dsi->framedone_data = data; - dsi->update_region.x = x; - dsi->update_region.y = y; - dsi->update_region.w = w; - dsi->update_region.h = h; - dsi->update_region.device = dssdev; + dssdev->driver->get_resolution(dssdev, &dw, &dh); - dsi_update_screen_dispc(dssdev, x, y, w, h); +#ifdef DEBUG + dsi->update_bytes = dw * dh * + dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; +#endif + dsi_update_screen_dispc(dssdev, dw, dh); return 0; } @@ -4218,6 +4222,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) int r; if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { + u16 dw, dh; u32 irq; struct omap_video_timings timings = { .hsw = 1, @@ -4228,6 +4233,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) .vbp = 0, }; + dssdev->driver->get_resolution(dssdev, &dw, &dh); + timings.x_res = dw; + timings.y_res = dh; + irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; @@ -4330,6 +4339,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) int dsi_module = dsi_get_dsidev_id(dsidev); int r; + r = dsi_parse_lane_config(dssdev); + if (r) { + DSSERR("illegal lane config"); + goto err0; + } + r = dsi_pll_init(dsidev, true, true); if (r) goto err0; @@ -4521,7 +4536,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - int dsi_module = dsi_get_dsidev_id(dsidev); DSSDBG("DSI init\n"); @@ -4543,12 +4557,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) dsi->vdds_dsi_reg = vdds_dsi; } - if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) { - DSSERR("DSI%d can't support more than %d data lanes\n", - dsi_module + 1, dsi->num_data_lanes); - return -EINVAL; - } - return 0; } @@ -4771,7 +4779,13 @@ static int omap_dsihw_probe(struct platform_device *dsidev) dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); + /* DSI on OMAP3 doesn't have register DSI_GNQ, set number + * of data to 3 by default */ + if (dss_has_feature(FEAT_DSI_GNQ)) + /* NB_DATA_LANES */ + dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9); + else + dsi->num_lanes_supported = 3; dsi_runtime_put(dsidev); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 6308fc59fc9e..32ff69fb3333 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -28,7 +28,7 @@ #endif #ifdef DEBUG -extern unsigned int dss_debug; +extern bool dss_debug; #ifdef DSS_SUBSYS_NAME #define DSSDBG(format, ...) \ if (dss_debug) \ @@ -163,6 +163,34 @@ struct bus_type *dss_get_bus(void); struct regulator *dss_get_vdds_dsi(void); struct regulator *dss_get_vdds_sdi(void); +/* apply */ +void dss_apply_init(void); +int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr); +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); +void dss_mgr_start_update(struct omap_overlay_manager *mgr); +int omap_dss_mgr_apply(struct omap_overlay_manager *mgr); + +int dss_mgr_enable(struct omap_overlay_manager *mgr); +void dss_mgr_disable(struct omap_overlay_manager *mgr); +int dss_mgr_set_info(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info); +void dss_mgr_get_info(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info); +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); + +bool dss_ovl_is_enabled(struct omap_overlay *ovl); +int dss_ovl_enable(struct omap_overlay *ovl); +int dss_ovl_disable(struct omap_overlay *ovl); +int dss_ovl_set_info(struct omap_overlay *ovl, + struct omap_overlay_info *info); +void dss_ovl_get_info(struct omap_overlay *ovl, + struct omap_overlay_info *info); +int dss_ovl_set_manager(struct omap_overlay *ovl, + struct omap_overlay_manager *mgr); +int dss_ovl_unset_manager(struct omap_overlay *ovl); + /* display */ int dss_suspend_all_devices(void); int dss_resume_all_devices(void); @@ -181,21 +209,22 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane, /* manager */ int dss_init_overlay_managers(struct platform_device *pdev); void dss_uninit_overlay_managers(struct platform_device *pdev); -int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); -void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h, - bool enlarge_update_area); -void dss_start_update(struct omap_dss_device *dssdev); +int dss_mgr_simple_check(struct omap_overlay_manager *mgr, + const struct omap_overlay_manager_info *info); +int dss_mgr_check(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev, + struct omap_overlay_manager_info *info, + struct omap_overlay_info **overlay_infos); /* overlay */ void dss_init_overlays(struct platform_device *pdev); void dss_uninit_overlays(struct platform_device *pdev); -int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev); void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); -#ifdef L4_EXAMPLE -void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr); -#endif 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, struct omap_dss_device *dssdev); /* DSS */ int dss_init_platform_driver(void); @@ -399,21 +428,22 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, struct dispc_clock_info *cinfo); +void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); u32 dispc_ovl_get_fifo_size(enum omap_plane plane); u32 dispc_ovl_get_burst_size(enum omap_plane plane); int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool ilace, enum omap_channel channel, bool replication, - u32 fifo_low, u32 fifo_high); + bool ilace, bool replication); int dispc_ovl_enable(enum omap_plane plane, bool enable); - +void dispc_ovl_set_channel_out(enum omap_plane plane, + enum omap_channel channel); void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); -void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable); -void dispc_mgr_set_cpr_coef(enum omap_channel channel, - struct omap_dss_cpr_coefs *coefs); +u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); +u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); bool dispc_mgr_go_busy(enum omap_channel channel); void dispc_mgr_go(enum omap_channel channel); +bool dispc_mgr_is_enabled(enum omap_channel channel); void dispc_mgr_enable(enum omap_channel channel, bool enable); bool dispc_mgr_is_channel_enabled(enum omap_channel channel); void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); @@ -421,18 +451,6 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable); void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); void dispc_mgr_set_lcd_display_type(enum omap_channel channel, enum omap_lcd_display_type type); -void dispc_mgr_set_default_color(enum omap_channel channel, u32 color); -u32 dispc_mgr_get_default_color(enum omap_channel channel); -void dispc_mgr_set_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type type, - u32 trans_key); -void dispc_mgr_get_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type *type, - u32 *trans_key); -void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable); -void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable); -bool dispc_mgr_trans_key_enabled(enum omap_channel ch); -bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch); void dispc_mgr_set_lcd_timings(enum omap_channel channel, struct omap_video_timings *timings); void dispc_mgr_set_pol_freq(enum omap_channel channel, @@ -443,6 +461,8 @@ int dispc_mgr_set_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo); int dispc_mgr_get_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo); +void dispc_mgr_setup(enum omap_channel channel, + struct omap_overlay_manager_info *info); /* VENC */ #ifdef CONFIG_OMAP2_DSS_VENC diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index b402699168a5..afcb59301c37 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -304,6 +304,11 @@ static const struct dss_param_range omap2_dss_param_range[] = { [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, + /* + * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC + * scaler cannot scale a image with width more than 768. + */ + [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, }; static const struct dss_param_range omap3_dss_param_range[] = { @@ -316,6 +321,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, + [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, }; static const struct dss_param_range omap4_dss_param_range[] = { @@ -328,6 +334,7 @@ static const struct dss_param_range omap4_dss_param_range[] = { [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, + [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, }; /* OMAP2 DSS Features */ @@ -465,6 +472,10 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { .dump_core = ti_hdmi_4xxx_core_dump, .dump_pll = ti_hdmi_4xxx_pll_dump, .dump_phy = ti_hdmi_4xxx_phy_dump, +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) + .audio_enable = ti_hdmi_4xxx_wp_audio_enable, +#endif }; diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 6a6c05dd45ce..cd833bbaac3d 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -86,6 +86,7 @@ enum dss_range_param { FEAT_PARAM_DSIPLL_FINT, FEAT_PARAM_DSIPLL_LPDIV, FEAT_PARAM_DOWNSCALE, + FEAT_PARAM_LINEWIDTH, }; /* DSS Feature Functions */ diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index c56378c555b0..b4c270edb915 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -333,7 +333,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) if (r) return r; - dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); + dss_mgr_disable(dssdev->manager); p = &dssdev->panel.timings; @@ -387,9 +387,16 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); - dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 1); + r = dss_mgr_enable(dssdev->manager); + if (r) + goto err_mgr_enable; return 0; + +err_mgr_enable: + hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); + hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); + hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); err: hdmi_runtime_put(); return -EIO; @@ -397,7 +404,7 @@ err: static void hdmi_power_off(struct omap_dss_device *dssdev) { - dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); + dss_mgr_disable(dssdev->manager); hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); @@ -554,11 +561,44 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) -static int hdmi_audio_hw_params(struct hdmi_ip_data *ip_data, - struct snd_pcm_substream *substream, +static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct platform_device *pdev = to_platform_device(codec->dev); + struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); + int err = 0; + + if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) { + dev_err(&pdev->dev, "Cannot enable/disable audio\n"); + return -ENODEV; + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ip_data->ops->audio_enable(ip_data, true); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ip_data->ops->audio_enable(ip_data, false); + break; + default: + err = -EINVAL; + } + return err; +} + +static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); struct hdmi_audio_format audio_format; struct hdmi_audio_dma audio_dma; struct hdmi_core_audio_config core_cfg; @@ -698,7 +738,16 @@ static int hdmi_audio_startup(struct snd_pcm_substream *substream, return 0; } +static int hdmi_audio_codec_probe(struct snd_soc_codec *codec) +{ + struct hdmi_ip_data *priv = &hdmi.ip_data; + + snd_soc_codec_set_drvdata(codec, priv); + return 0; +} + static struct snd_soc_codec_driver hdmi_audio_codec_drv = { + .probe = hdmi_audio_codec_probe, }; static struct snd_soc_dai_ops hdmi_audio_codec_ops = { diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 6e63845cc7d7..d1858e71c64e 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -26,17 +26,15 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/spinlock.h> #include <linux/jiffies.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" static int num_managers; -static struct list_head manager_list; +static struct omap_overlay_manager *managers; static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) { @@ -106,7 +104,11 @@ put_device: static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color); + 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, @@ -144,8 +146,11 @@ 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 = mgr->info.trans_key_type; + 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]); @@ -185,7 +190,11 @@ static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key); + 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, @@ -217,7 +226,11 @@ static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled); + 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, @@ -249,10 +262,14 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, 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", - mgr->info.partial_alpha_enabled); + info.partial_alpha_enabled); } static ssize_t manager_alpha_blending_enabled_store( @@ -287,7 +304,11 @@ static ssize_t manager_alpha_blending_enabled_store( static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable); + 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, @@ -469,143 +490,6 @@ static struct kobj_type manager_ktype = { .default_attrs = manager_sysfs_attrs, }; -/* - * We have 4 levels of cache for the dispc settings. First two are in SW and - * the latter two in HW. - * - * +--------------------+ - * |overlay/manager_info| - * +--------------------+ - * v - * apply() - * v - * +--------------------+ - * | dss_cache | - * +--------------------+ - * v - * configure() - * v - * +--------------------+ - * | shadow registers | - * +--------------------+ - * v - * VFP or lcd/digit_enable - * v - * +--------------------+ - * | registers | - * +--------------------+ - */ - -struct overlay_cache_data { - /* If true, cache changed, but not written to shadow registers. Set - * in apply(), cleared when registers written. */ - bool dirty; - /* If true, shadow registers contain changed values not yet in real - * registers. Set when writing to shadow registers, cleared at - * VSYNC/EVSYNC */ - bool shadow_dirty; - - bool enabled; - - struct omap_overlay_info info; - - enum omap_channel channel; - bool replication; - bool ilace; - - u32 fifo_low; - u32 fifo_high; -}; - -struct manager_cache_data { - /* If true, cache changed, but not written to shadow registers. Set - * in apply(), cleared when registers written. */ - bool dirty; - /* If true, shadow registers contain changed values not yet in real - * registers. Set when writing to shadow registers, cleared at - * VSYNC/EVSYNC */ - bool shadow_dirty; - - struct omap_overlay_manager_info info; - - bool manual_update; - bool do_manual_update; - - /* manual update region */ - u16 x, y, w, h; - - /* enlarge the update area if the update area contains scaled - * overlays */ - bool enlarge_update_area; -}; - -static struct { - spinlock_t lock; - struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; - struct manager_cache_data manager_cache[MAX_DSS_MANAGERS]; - - bool irq_enabled; -} dss_cache; - - - -static int omap_dss_set_device(struct omap_overlay_manager *mgr, - struct omap_dss_device *dssdev) -{ - int i; - int r; - - if (dssdev->manager) { - DSSERR("display '%s' already has a manager '%s'\n", - dssdev->name, dssdev->manager->name); - return -EINVAL; - } - - if ((mgr->supported_displays & dssdev->type) == 0) { - DSSERR("display '%s' does not support manager '%s'\n", - dssdev->name, mgr->name); - return -EINVAL; - } - - for (i = 0; i < mgr->num_overlays; i++) { - struct omap_overlay *ovl = mgr->overlays[i]; - - if (ovl->manager != mgr || !ovl->info.enabled) - continue; - - r = dss_check_overlay(ovl, dssdev); - if (r) - return r; - } - - dssdev->manager = mgr; - mgr->device = dssdev; - mgr->device_changed = true; - - return 0; -} - -static int omap_dss_unset_device(struct omap_overlay_manager *mgr) -{ - if (!mgr->device) { - DSSERR("failed to unset display, display not set.\n"); - return -EINVAL; - } - - /* - * Don't allow currently enabled displays to have the overlay manager - * pulled out from underneath them - */ - if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) - return -EINVAL; - - mgr->device->manager = NULL; - mgr->device = NULL; - mgr->device_changed = true; - - return 0; -} - static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); @@ -624,1022 +508,169 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); } -static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) -{ - unsigned long timeout = msecs_to_jiffies(500); - struct manager_cache_data *mc; - u32 irq; - int r; - int i; - struct omap_dss_device *dssdev = mgr->device; - - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) - return 0; - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - } else { - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; - } - - mc = &dss_cache.manager_cache[mgr->id]; - i = 0; - while (1) { - unsigned long flags; - bool shadow_dirty, dirty; - - spin_lock_irqsave(&dss_cache.lock, flags); - dirty = mc->dirty; - shadow_dirty = mc->shadow_dirty; - spin_unlock_irqrestore(&dss_cache.lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } - - /* 4 iterations is the worst case: - * 1 - initial iteration, dirty = true (between VFP and VSYNC) - * 2 - first VSYNC, dirty = true - * 3 - dirty = false, shadow_dirty = true - * 4 - shadow_dirty = false */ - if (i++ == 3) { - DSSERR("mgr(%d)->wait_for_go() not finishing\n", - mgr->id); - r = 0; - break; - } - - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; - - if (r) { - DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); - break; - } - } - - return r; -} - -int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) -{ - unsigned long timeout = msecs_to_jiffies(500); - struct overlay_cache_data *oc; - struct omap_dss_device *dssdev; - u32 irq; - int r; - int i; - - if (!ovl->manager) - return 0; - - dssdev = ovl->manager->device; - - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) - return 0; - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - } else { - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; - } - - oc = &dss_cache.overlay_cache[ovl->id]; - i = 0; - while (1) { - unsigned long flags; - bool shadow_dirty, dirty; - - spin_lock_irqsave(&dss_cache.lock, flags); - dirty = oc->dirty; - shadow_dirty = oc->shadow_dirty; - spin_unlock_irqrestore(&dss_cache.lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } - - /* 4 iterations is the worst case: - * 1 - initial iteration, dirty = true (between VFP and VSYNC) - * 2 - first VSYNC, dirty = true - * 3 - dirty = false, shadow_dirty = true - * 4 - shadow_dirty = false */ - if (i++ == 3) { - DSSERR("ovl(%d)->wait_for_go() not finishing\n", - ovl->id); - r = 0; - break; - } - - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; - - if (r) { - DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); - break; - } - } - - return r; -} - -static int overlay_enabled(struct omap_overlay *ovl) -{ - return ovl->info.enabled && ovl->manager && ovl->manager->device; -} - -/* Is rect1 a subset of rect2? */ -static bool rectangle_subset(int x1, int y1, int w1, int h1, - int x2, int y2, int w2, int h2) -{ - if (x1 < x2 || y1 < y2) - return false; - - if (x1 + w1 > x2 + w2) - return false; - - if (y1 + h1 > y2 + h2) - return false; - - return true; -} - -/* Do rect1 and rect2 overlap? */ -static bool rectangle_intersects(int x1, int y1, int w1, int h1, - int x2, int y2, int w2, int h2) -{ - if (x1 >= x2 + w2) - return false; - - if (x2 >= x1 + w1) - return false; - - if (y1 >= y2 + h2) - return false; - - if (y2 >= y1 + h1) - return false; - - return true; -} - -static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc) -{ - struct omap_overlay_info *oi = &oc->info; - - if (oi->out_width != 0 && oi->width != oi->out_width) - return true; - - if (oi->out_height != 0 && oi->height != oi->out_height) - return true; - - return false; -} - -static int configure_overlay(enum omap_plane plane) +int dss_init_overlay_managers(struct platform_device *pdev) { - struct overlay_cache_data *c; - struct manager_cache_data *mc; - struct omap_overlay_info *oi, new_oi; - struct omap_overlay_manager_info *mi; - u16 outw, outh; - u16 x, y, w, h; - u32 paddr; - int r; - u16 orig_w, orig_h, orig_outw, orig_outh; + int i, r; - DSSDBGF("%d", plane); + num_managers = dss_feat_get_num_mgrs(); - c = &dss_cache.overlay_cache[plane]; - oi = &c->info; + managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, + GFP_KERNEL); - if (!c->enabled) { - dispc_ovl_enable(plane, 0); - return 0; - } + BUG_ON(managers == NULL); - mc = &dss_cache.manager_cache[c->channel]; - mi = &mc->info; - - x = oi->pos_x; - y = oi->pos_y; - w = oi->width; - h = oi->height; - outw = oi->out_width == 0 ? oi->width : oi->out_width; - outh = oi->out_height == 0 ? oi->height : oi->out_height; - paddr = oi->paddr; - - orig_w = w; - orig_h = h; - orig_outw = outw; - orig_outh = outh; - - if (mc->manual_update && mc->do_manual_update) { - unsigned bpp; - unsigned scale_x_m = w, scale_x_d = outw; - unsigned scale_y_m = h, scale_y_d = outh; - - /* If the overlay is outside the update region, disable it */ - if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, - x, y, outw, outh)) { - dispc_ovl_enable(plane, 0); - return 0; - } + for (i = 0; i < num_managers; ++i) { + struct omap_overlay_manager *mgr = &managers[i]; - switch (oi->color_mode) { - case OMAP_DSS_COLOR_NV12: - bpp = 8; - break; - case OMAP_DSS_COLOR_RGB16: - case OMAP_DSS_COLOR_ARGB16: - case OMAP_DSS_COLOR_YUV2: - case OMAP_DSS_COLOR_UYVY: - case OMAP_DSS_COLOR_RGBA16: - case OMAP_DSS_COLOR_RGBX16: - case OMAP_DSS_COLOR_ARGB16_1555: - case OMAP_DSS_COLOR_XRGB16_1555: - bpp = 16; + switch (i) { + case 0: + mgr->name = "lcd"; + mgr->id = OMAP_DSS_CHANNEL_LCD; break; - - case OMAP_DSS_COLOR_RGB24P: - bpp = 24; + case 1: + mgr->name = "tv"; + mgr->id = OMAP_DSS_CHANNEL_DIGIT; break; - - case OMAP_DSS_COLOR_RGB24U: - case OMAP_DSS_COLOR_ARGB32: - case OMAP_DSS_COLOR_RGBA32: - case OMAP_DSS_COLOR_RGBX32: - bpp = 32; + case 2: + mgr->name = "lcd2"; + mgr->id = OMAP_DSS_CHANNEL_LCD2; break; - - default: - BUG(); } - if (mc->x > oi->pos_x) { - x = 0; - outw -= (mc->x - oi->pos_x); - paddr += (mc->x - oi->pos_x) * - scale_x_m / scale_x_d * bpp / 8; - } else { - x = oi->pos_x - mc->x; - } - - if (mc->y > oi->pos_y) { - y = 0; - outh -= (mc->y - oi->pos_y); - paddr += (mc->y - oi->pos_y) * - scale_y_m / scale_y_d * - oi->screen_width * bpp / 8; - } else { - y = oi->pos_y - mc->y; - } - - if (mc->w < (x + outw)) - outw -= (x + outw) - (mc->w); - - if (mc->h < (y + outh)) - outh -= (y + outh) - (mc->h); - - w = w * outw / orig_outw; - h = h * outh / orig_outh; - - /* YUV mode overlay's input width has to be even and the - * algorithm above may adjust the width to be odd. - * - * Here we adjust the width if needed, preferring to increase - * the width if the original width was bigger. - */ - if ((w & 1) && - (oi->color_mode == OMAP_DSS_COLOR_YUV2 || - oi->color_mode == OMAP_DSS_COLOR_UYVY)) { - if (orig_w > w) - w += 1; - else - w -= 1; - } - } - - new_oi = *oi; - - /* update new_oi members which could have been possibly updated */ - new_oi.pos_x = x; - new_oi.pos_y = y; - new_oi.width = w; - new_oi.height = h; - new_oi.out_width = outw; - new_oi.out_height = outh; - new_oi.paddr = paddr; - - r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel, - c->replication, c->fifo_low, c->fifo_high); - if (r) { - /* this shouldn't happen */ - DSSERR("dispc_ovl_setup failed for ovl %d\n", plane); - dispc_ovl_enable(plane, 0); - return r; - } - - dispc_ovl_enable(plane, 1); - - return 0; -} - -static void configure_manager(enum omap_channel channel) -{ - struct omap_overlay_manager_info *mi; - - DSSDBGF("%d", channel); - - /* picking info from the cache */ - mi = &dss_cache.manager_cache[channel].info; - - dispc_mgr_set_default_color(channel, mi->default_color); - dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key); - dispc_mgr_enable_trans_key(channel, mi->trans_enabled); - dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled); - if (dss_has_feature(FEAT_CPR)) { - dispc_mgr_enable_cpr(channel, mi->cpr_enable); - dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs); - } -} - -/* configure_dispc() tries to write values from cache to shadow registers. - * It writes only to those managers/overlays that are not busy. - * returns 0 if everything could be written to shadow registers. - * returns 1 if not everything could be written to shadow registers. */ -static int configure_dispc(void) -{ - struct overlay_cache_data *oc; - struct manager_cache_data *mc; - const int num_ovls = dss_feat_get_num_ovls(); - const int num_mgrs = dss_feat_get_num_mgrs(); - int i; - int r; - bool mgr_busy[MAX_DSS_MANAGERS]; - bool mgr_go[MAX_DSS_MANAGERS]; - bool busy; - - r = 0; - busy = false; - - for (i = 0; i < num_mgrs; i++) { - mgr_busy[i] = dispc_mgr_go_busy(i); - mgr_go[i] = false; - } - - /* Commit overlay settings */ - for (i = 0; i < num_ovls; ++i) { - oc = &dss_cache.overlay_cache[i]; - mc = &dss_cache.manager_cache[oc->channel]; + mgr->set_device = &dss_mgr_set_device; + mgr->unset_device = &dss_mgr_unset_device; + 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; - if (!oc->dirty) - continue; + mgr->caps = 0; + mgr->supported_displays = + dss_feat_get_supported_displays(mgr->id); - if (mc->manual_update && !mc->do_manual_update) - continue; + INIT_LIST_HEAD(&mgr->overlays); - if (mgr_busy[oc->channel]) { - busy = true; - continue; - } + r = kobject_init_and_add(&mgr->kobj, &manager_ktype, + &pdev->dev.kobj, "manager%d", i); - r = configure_overlay(i); if (r) - DSSERR("configure_overlay %d failed\n", i); - - oc->dirty = false; - oc->shadow_dirty = true; - mgr_go[oc->channel] = true; - } - - /* Commit manager settings */ - for (i = 0; i < num_mgrs; ++i) { - mc = &dss_cache.manager_cache[i]; - - if (!mc->dirty) - continue; - - if (mc->manual_update && !mc->do_manual_update) - continue; - - if (mgr_busy[i]) { - busy = true; - continue; - } - - configure_manager(i); - mc->dirty = false; - mc->shadow_dirty = true; - mgr_go[i] = true; - } - - /* set GO */ - for (i = 0; i < num_mgrs; ++i) { - mc = &dss_cache.manager_cache[i]; - - if (!mgr_go[i]) - continue; - - /* We don't need GO with manual update display. LCD iface will - * always be turned off after frame, and new settings will be - * taken in to use at next update */ - if (!mc->manual_update) - dispc_mgr_go(i); - } - - if (busy) - r = 1; - else - r = 0; - - return r; -} - -/* Make the coordinates even. There are some strange problems with OMAP and - * partial DSI update when the update widths are odd. */ -static void make_even(u16 *x, u16 *w) -{ - u16 x1, x2; - - x1 = *x; - x2 = *x + *w; - - x1 &= ~1; - x2 = ALIGN(x2, 2); - - *x = x1; - *w = x2 - x1; -} - -/* Configure dispc for partial update. Return possibly modified update - * area */ -void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) -{ - struct overlay_cache_data *oc; - struct manager_cache_data *mc; - struct omap_overlay_info *oi; - const int num_ovls = dss_feat_get_num_ovls(); - struct omap_overlay_manager *mgr; - int i; - u16 x, y, w, h; - unsigned long flags; - bool area_changed; - - x = *xi; - y = *yi; - w = *wi; - h = *hi; - - DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n", - *xi, *yi, *wi, *hi); - - mgr = dssdev->manager; - - if (!mgr) { - DSSDBG("no manager\n"); - return; + DSSERR("failed to create sysfs file\n"); } - make_even(&x, &w); - - spin_lock_irqsave(&dss_cache.lock, flags); - - /* - * Execute the outer loop until the inner loop has completed - * once without increasing the update area. This will ensure that - * all scaled overlays end up completely within the update area. - */ - do { - area_changed = false; - - /* We need to show the whole overlay if it is scaled. So look - * for those, and make the update area larger if found. - * Also mark the overlay cache dirty */ - for (i = 0; i < num_ovls; ++i) { - unsigned x1, y1, x2, y2; - unsigned outw, outh; - - oc = &dss_cache.overlay_cache[i]; - oi = &oc->info; - - if (oc->channel != mgr->id) - continue; - - oc->dirty = true; - - if (!enlarge_update_area) - continue; - - if (!oc->enabled) - continue; - - if (!dispc_is_overlay_scaled(oc)) - continue; - - outw = oi->out_width == 0 ? - oi->width : oi->out_width; - outh = oi->out_height == 0 ? - oi->height : oi->out_height; - - /* is the overlay outside the update region? */ - if (!rectangle_intersects(x, y, w, h, - oi->pos_x, oi->pos_y, - outw, outh)) - continue; - - /* if the overlay totally inside the update region? */ - if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh, - x, y, w, h)) - continue; - - if (x > oi->pos_x) - x1 = oi->pos_x; - else - x1 = x; - - if (y > oi->pos_y) - y1 = oi->pos_y; - else - y1 = y; - - if ((x + w) < (oi->pos_x + outw)) - x2 = oi->pos_x + outw; - else - x2 = x + w; - - if ((y + h) < (oi->pos_y + outh)) - y2 = oi->pos_y + outh; - else - y2 = y + h; - - x = x1; - y = y1; - w = x2 - x1; - h = y2 - y1; - - make_even(&x, &w); - - DSSDBG("changing upd area due to ovl(%d) " - "scaling %d,%d %dx%d\n", - i, x, y, w, h); - - area_changed = true; - } - } while (area_changed); - - mc = &dss_cache.manager_cache[mgr->id]; - mc->do_manual_update = true; - mc->enlarge_update_area = enlarge_update_area; - mc->x = x; - mc->y = y; - mc->w = w; - mc->h = h; - - configure_dispc(); - - mc->do_manual_update = false; - - spin_unlock_irqrestore(&dss_cache.lock, flags); - - *xi = x; - *yi = y; - *wi = w; - *hi = h; + return 0; } -void dss_start_update(struct omap_dss_device *dssdev) +void dss_uninit_overlay_managers(struct platform_device *pdev) { - struct manager_cache_data *mc; - struct overlay_cache_data *oc; - const int num_ovls = dss_feat_get_num_ovls(); - const int num_mgrs = dss_feat_get_num_mgrs(); - struct omap_overlay_manager *mgr; int i; - mgr = dssdev->manager; + for (i = 0; i < num_managers; ++i) { + struct omap_overlay_manager *mgr = &managers[i]; - for (i = 0; i < num_ovls; ++i) { - oc = &dss_cache.overlay_cache[i]; - if (oc->channel != mgr->id) - continue; - - oc->shadow_dirty = false; - } - - for (i = 0; i < num_mgrs; ++i) { - mc = &dss_cache.manager_cache[i]; - if (mgr->id != i) - continue; - - mc->shadow_dirty = false; + kobject_del(&mgr->kobj); + kobject_put(&mgr->kobj); } - dssdev->manager->enable(dssdev->manager); + kfree(managers); + managers = NULL; + num_managers = 0; } -static void dss_apply_irq_handler(void *data, u32 mask) +int omap_dss_get_num_overlay_managers(void) { - struct manager_cache_data *mc; - struct overlay_cache_data *oc; - const int num_ovls = dss_feat_get_num_ovls(); - const int num_mgrs = dss_feat_get_num_mgrs(); - int i, r; - bool mgr_busy[MAX_DSS_MANAGERS]; - u32 irq_mask; - - for (i = 0; i < num_mgrs; i++) - mgr_busy[i] = dispc_mgr_go_busy(i); - - spin_lock(&dss_cache.lock); - - for (i = 0; i < num_ovls; ++i) { - oc = &dss_cache.overlay_cache[i]; - if (!mgr_busy[oc->channel]) - oc->shadow_dirty = false; - } - - for (i = 0; i < num_mgrs; ++i) { - mc = &dss_cache.manager_cache[i]; - if (!mgr_busy[i]) - mc->shadow_dirty = false; - } - - r = configure_dispc(); - if (r == 1) - goto end; - - /* re-read busy flags */ - for (i = 0; i < num_mgrs; i++) - mgr_busy[i] = dispc_mgr_go_busy(i); - - /* keep running as long as there are busy managers, so that - * we can collect overlay-applied information */ - for (i = 0; i < num_mgrs; ++i) { - if (mgr_busy[i]) - goto end; - } - - irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN; - if (dss_has_feature(FEAT_MGR_LCD2)) - irq_mask |= DISPC_IRQ_VSYNC2; - - omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask); - dss_cache.irq_enabled = false; - -end: - spin_unlock(&dss_cache.lock); + return num_managers; } +EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); -static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) +struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) { - struct overlay_cache_data *oc; - struct manager_cache_data *mc; - int i; - struct omap_overlay *ovl; - int num_planes_enabled = 0; - bool use_fifomerge; - unsigned long flags; - int r; - - DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); - - r = dispc_runtime_get(); - if (r) - return r; - - spin_lock_irqsave(&dss_cache.lock, flags); - - /* Configure overlays */ - for (i = 0; i < omap_dss_get_num_overlays(); ++i) { - struct omap_dss_device *dssdev; - - ovl = omap_dss_get_overlay(i); - - oc = &dss_cache.overlay_cache[ovl->id]; - - if (ovl->manager_changed) { - ovl->manager_changed = false; - ovl->info_dirty = true; - } - - if (!overlay_enabled(ovl)) { - if (oc->enabled) { - oc->enabled = false; - oc->dirty = true; - } - continue; - } - - if (!ovl->info_dirty) { - if (oc->enabled) - ++num_planes_enabled; - continue; - } - - dssdev = ovl->manager->device; - - if (dss_check_overlay(ovl, dssdev)) { - if (oc->enabled) { - oc->enabled = false; - oc->dirty = true; - } - continue; - } - - ovl->info_dirty = false; - oc->dirty = true; - oc->info = ovl->info; - - oc->replication = - dss_use_replication(dssdev, ovl->info.color_mode); - - oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC; - - oc->channel = ovl->manager->id; - - oc->enabled = true; - - ++num_planes_enabled; - } - - /* Configure managers */ - list_for_each_entry(mgr, &manager_list, list) { - struct omap_dss_device *dssdev; + if (num >= num_managers) + return NULL; - mc = &dss_cache.manager_cache[mgr->id]; - - if (mgr->device_changed) { - mgr->device_changed = false; - mgr->info_dirty = true; - } - - if (!mgr->info_dirty) - continue; - - if (!mgr->device) - continue; - - dssdev = mgr->device; - - mgr->info_dirty = false; - mc->dirty = true; - mc->info = mgr->info; - - mc->manual_update = - dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; - } - - /* XXX TODO: Try to get fifomerge working. The problem is that it - * affects both managers, not individually but at the same time. This - * means the change has to be well synchronized. I guess the proper way - * is to have a two step process for fifo merge: - * fifomerge enable: - * 1. disable other planes, leaving one plane enabled - * 2. wait until the planes are disabled on HW - * 3. config merged fifo thresholds, enable fifomerge - * fifomerge disable: - * 1. config unmerged fifo thresholds, disable fifomerge - * 2. wait until fifo changes are in HW - * 3. enable planes - */ - use_fifomerge = false; - - /* Configure overlay fifos */ - for (i = 0; i < omap_dss_get_num_overlays(); ++i) { - struct omap_dss_device *dssdev; - u32 size, burst_size; - - ovl = omap_dss_get_overlay(i); - - oc = &dss_cache.overlay_cache[ovl->id]; - - if (!oc->enabled) - continue; - - dssdev = ovl->manager->device; - - size = dispc_ovl_get_fifo_size(ovl->id); - if (use_fifomerge) - size *= 3; - - burst_size = dispc_ovl_get_burst_size(ovl->id); - - switch (dssdev->type) { - case OMAP_DISPLAY_TYPE_DPI: - case OMAP_DISPLAY_TYPE_DBI: - case OMAP_DISPLAY_TYPE_SDI: - case OMAP_DISPLAY_TYPE_VENC: - case OMAP_DISPLAY_TYPE_HDMI: - default_get_overlay_fifo_thresholds(ovl->id, size, - burst_size, &oc->fifo_low, - &oc->fifo_high); - break; -#ifdef CONFIG_OMAP2_DSS_DSI - case OMAP_DISPLAY_TYPE_DSI: - dsi_get_overlay_fifo_thresholds(ovl->id, size, - burst_size, &oc->fifo_low, - &oc->fifo_high); - break; -#endif - default: - BUG(); - } - } - - r = 0; - if (!dss_cache.irq_enabled) { - u32 mask; - - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN; - if (dss_has_feature(FEAT_MGR_LCD2)) - mask |= DISPC_IRQ_VSYNC2; - - r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); - dss_cache.irq_enabled = true; - } - configure_dispc(); - - spin_unlock_irqrestore(&dss_cache.lock, flags); - - dispc_runtime_put(); - - return r; + return &managers[num]; } +EXPORT_SYMBOL(omap_dss_get_overlay_manager); -static int dss_check_manager(struct omap_overlay_manager *mgr) +int dss_mgr_simple_check(struct omap_overlay_manager *mgr, + const struct omap_overlay_manager_info *info) { if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { /* * OMAP3 supports only graphics source transparency color key * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 - * Alpha Mode + * Alpha Mode. */ - if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled - && mgr->info.trans_key_type != - OMAP_DSS_COLOR_KEY_GFX_DST) + if (info->partial_alpha_enabled && info->trans_enabled + && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { + DSSERR("check_manager: illegal transparency key\n"); return -EINVAL; + } } return 0; } -static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr, - struct omap_overlay_manager_info *info) -{ - int r; - struct omap_overlay_manager_info old_info; - - old_info = mgr->info; - mgr->info = *info; - - r = dss_check_manager(mgr); - if (r) { - mgr->info = old_info; - return r; - } - - mgr->info_dirty = true; - - return 0; -} - -static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, - struct omap_overlay_manager_info *info) +static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, + struct omap_overlay_info **overlay_infos) { - *info = mgr->info; -} + struct omap_overlay *ovl1, *ovl2; + struct omap_overlay_info *info1, *info2; -static int dss_mgr_enable(struct omap_overlay_manager *mgr) -{ - dispc_mgr_enable(mgr->id, 1); - return 0; -} + list_for_each_entry(ovl1, &mgr->overlays, list) { + info1 = overlay_infos[ovl1->id]; -static int dss_mgr_disable(struct omap_overlay_manager *mgr) -{ - dispc_mgr_enable(mgr->id, 0); - return 0; -} - -static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager) -{ - ++num_managers; - list_add_tail(&manager->list, &manager_list); -} - -int dss_init_overlay_managers(struct platform_device *pdev) -{ - int i, r; - - spin_lock_init(&dss_cache.lock); - - INIT_LIST_HEAD(&manager_list); - - num_managers = 0; - - for (i = 0; i < dss_feat_get_num_mgrs(); ++i) { - struct omap_overlay_manager *mgr; - mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); - - BUG_ON(mgr == NULL); - - switch (i) { - case 0: - mgr->name = "lcd"; - mgr->id = OMAP_DSS_CHANNEL_LCD; - break; - case 1: - mgr->name = "tv"; - mgr->id = OMAP_DSS_CHANNEL_DIGIT; - break; - case 2: - mgr->name = "lcd2"; - mgr->id = OMAP_DSS_CHANNEL_LCD2; - break; - } - - mgr->set_device = &omap_dss_set_device; - mgr->unset_device = &omap_dss_unset_device; - mgr->apply = &omap_dss_mgr_apply; - mgr->set_manager_info = &omap_dss_mgr_set_info; - mgr->get_manager_info = &omap_dss_mgr_get_info; - mgr->wait_for_go = &dss_mgr_wait_for_go; - mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; - - mgr->enable = &dss_mgr_enable; - mgr->disable = &dss_mgr_disable; - - mgr->caps = 0; - mgr->supported_displays = - dss_feat_get_supported_displays(mgr->id); + if (info1 == NULL) + continue; - dss_overlay_setup_dispc_manager(mgr); + list_for_each_entry(ovl2, &mgr->overlays, list) { + if (ovl1 == ovl2) + continue; - omap_dss_add_overlay_manager(mgr); + info2 = overlay_infos[ovl2->id]; - r = kobject_init_and_add(&mgr->kobj, &manager_ktype, - &pdev->dev.kobj, "manager%d", i); + if (info2 == NULL) + continue; - if (r) { - DSSERR("failed to create sysfs file\n"); - continue; + if (info1->zorder == info2->zorder) { + DSSERR("overlays %d and %d have the same " + "zorder %d\n", + ovl1->id, ovl2->id, info1->zorder); + return -EINVAL; + } } } return 0; } -void dss_uninit_overlay_managers(struct platform_device *pdev) +int dss_mgr_check(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev, + struct omap_overlay_manager_info *info, + struct omap_overlay_info **overlay_infos) { - struct omap_overlay_manager *mgr; + struct omap_overlay *ovl; + int r; - while (!list_empty(&manager_list)) { - mgr = list_first_entry(&manager_list, - struct omap_overlay_manager, list); - list_del(&mgr->list); - kobject_del(&mgr->kobj); - kobject_put(&mgr->kobj); - kfree(mgr); + if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { + r = dss_mgr_check_zorder(mgr, overlay_infos); + if (r) + return r; } - num_managers = 0; -} + list_for_each_entry(ovl, &mgr->overlays, list) { + struct omap_overlay_info *oi; + int r; -int omap_dss_get_num_overlay_managers(void) -{ - return num_managers; -} -EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); + oi = overlay_infos[ovl->id]; -struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) -{ - int i = 0; - struct omap_overlay_manager *mgr; + if (oi == NULL) + continue; - list_for_each_entry(mgr, &manager_list, list) { - if (i++ == num) - return mgr; + r = dss_ovl_check(ovl, oi, dssdev); + if (r) + return r; } - return NULL; + return 0; } -EXPORT_SYMBOL(omap_dss_get_overlay_manager); - diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index ab8e40e48759..6e821810deec 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -38,7 +38,7 @@ #include "dss_features.h" static int num_overlays; -static struct list_head overlay_list; +static struct omap_overlay *overlays; static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) { @@ -124,19 +124,31 @@ err: 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", - ovl->info.width, ovl->info.height); + info.width, info.height); } static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width); + 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", - ovl->info.pos_x, ovl->info.pos_y); + info.pos_x, info.pos_y); } static ssize_t overlay_position_store(struct omap_overlay *ovl, @@ -170,8 +182,12 @@ static ssize_t overlay_position_store(struct omap_overlay *ovl, 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", - ovl->info.out_width, ovl->info.out_height); + info.out_width, info.out_height); } static ssize_t overlay_output_size_store(struct omap_overlay *ovl, @@ -205,7 +221,7 @@ static ssize_t overlay_output_size_store(struct omap_overlay *ovl, static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled); + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); } static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, @@ -213,33 +229,30 @@ static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, { int r; bool enable; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); r = strtobool(buf, &enable); if (r) return r; - info.enabled = enable; + if (enable) + r = ovl->enable(ovl); + else + r = ovl->disable(ovl); - 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_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", - ovl->info.global_alpha); + info.global_alpha); } static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, @@ -276,8 +289,12 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, 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", - ovl->info.pre_mult_alpha); + info.pre_mult_alpha); } static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, @@ -313,7 +330,11 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder); + 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, @@ -430,183 +451,6 @@ static struct kobj_type overlay_ktype = { .default_attrs = overlay_sysfs_attrs, }; -/* Check if overlay parameters are compatible with display */ -int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) -{ - struct omap_overlay_info *info; - u16 outw, outh; - u16 dw, dh; - int i; - - if (!dssdev) - return 0; - - if (!ovl->info.enabled) - return 0; - - info = &ovl->info; - - if (info->paddr == 0) { - DSSDBG("check_overlay failed: paddr 0\n"); - return -EINVAL; - } - - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n", - ovl->id, - info->pos_x, info->pos_y, - info->width, info->height, - info->out_width, info->out_height, - dw, dh); - - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { - outw = info->width; - outh = info->height; - } else { - if (info->out_width == 0) - outw = info->width; - else - outw = info->out_width; - - if (info->out_height == 0) - outh = info->height; - else - outh = info->out_height; - } - - if (dw < info->pos_x + outw) { - DSSDBG("check_overlay failed 1: %d < %d + %d\n", - dw, info->pos_x, outw); - return -EINVAL; - } - - if (dh < info->pos_y + outh) { - DSSDBG("check_overlay failed 2: %d < %d + %d\n", - dh, info->pos_y, outh); - return -EINVAL; - } - - if ((ovl->supported_modes & info->color_mode) == 0) { - DSSERR("overlay doesn't support mode %d\n", info->color_mode); - return -EINVAL; - } - - if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) { - if (info->zorder < 0 || info->zorder > 3) { - DSSERR("zorder out of range: %d\n", - info->zorder); - return -EINVAL; - } - /* - * Check that zorder doesn't match with zorder of any other - * overlay which is enabled and is also connected to the same - * manager - */ - for (i = 0; i < omap_dss_get_num_overlays(); i++) { - struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i); - - if (tmp_ovl->id != ovl->id && - tmp_ovl->manager == ovl->manager && - tmp_ovl->info.enabled == true && - tmp_ovl->info.zorder == info->zorder) { - DSSERR("%s and %s have same zorder: %d\n", - ovl->name, tmp_ovl->name, info->zorder); - return -EINVAL; - } - } - } - - return 0; -} - -static int dss_ovl_set_overlay_info(struct omap_overlay *ovl, - struct omap_overlay_info *info) -{ - int r; - struct omap_overlay_info old_info; - - old_info = ovl->info; - ovl->info = *info; - - if (ovl->manager) { - r = dss_check_overlay(ovl, ovl->manager->device); - if (r) { - ovl->info = old_info; - return r; - } - } - - ovl->info_dirty = true; - - return 0; -} - -static void dss_ovl_get_overlay_info(struct omap_overlay *ovl, - struct omap_overlay_info *info) -{ - *info = ovl->info; -} - -static int dss_ovl_wait_for_go(struct omap_overlay *ovl) -{ - return dss_mgr_wait_for_go_ovl(ovl); -} - -static int omap_dss_set_manager(struct omap_overlay *ovl, - struct omap_overlay_manager *mgr) -{ - if (!mgr) - return -EINVAL; - - if (ovl->manager) { - DSSERR("overlay '%s' already has a manager '%s'\n", - ovl->name, ovl->manager->name); - return -EINVAL; - } - - if (ovl->info.enabled) { - DSSERR("overlay has to be disabled to change the manager\n"); - return -EINVAL; - } - - ovl->manager = mgr; - ovl->manager_changed = true; - - /* XXX: When there is an overlay on a DSI manual update display, and - * the overlay is first disabled, then moved to tv, and enabled, we - * seem to get SYNC_LOST_DIGIT error. - * - * Waiting doesn't seem to help, but updating the manual update display - * after disabling the overlay seems to fix this. This hints that the - * overlay is perhaps somehow tied to the LCD output until the output - * is updated. - * - * Userspace workaround for this is to update the LCD after disabling - * the overlay, but before moving the overlay to TV. - */ - - return 0; -} - -static int omap_dss_unset_manager(struct omap_overlay *ovl) -{ - if (!ovl->manager) { - DSSERR("failed to detach overlay: manager not set\n"); - return -EINVAL; - } - - if (ovl->info.enabled) { - DSSERR("overlay has to be disabled to unset the manager\n"); - return -EINVAL; - } - - ovl->manager = NULL; - ovl->manager_changed = true; - - return 0; -} - int omap_dss_get_num_overlays(void) { return num_overlays; @@ -615,134 +459,65 @@ EXPORT_SYMBOL(omap_dss_get_num_overlays); struct omap_overlay *omap_dss_get_overlay(int num) { - int i = 0; - struct omap_overlay *ovl; + if (num >= num_overlays) + return NULL; - list_for_each_entry(ovl, &overlay_list, list) { - if (i++ == num) - return ovl; - } - - return NULL; + return &overlays[num]; } EXPORT_SYMBOL(omap_dss_get_overlay); -static void omap_dss_add_overlay(struct omap_overlay *overlay) -{ - ++num_overlays; - list_add_tail(&overlay->list, &overlay_list); -} - -static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS]; - -void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr) -{ - mgr->num_overlays = dss_feat_get_num_ovls(); - mgr->overlays = dispc_overlays; -} - -#ifdef L4_EXAMPLE -static struct omap_overlay *l4_overlays[1]; -void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr) -{ - mgr->num_overlays = 1; - mgr->overlays = l4_overlays; -} -#endif - void dss_init_overlays(struct platform_device *pdev) { int i, r; - INIT_LIST_HEAD(&overlay_list); + num_overlays = dss_feat_get_num_ovls(); - num_overlays = 0; + overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays, + GFP_KERNEL); - for (i = 0; i < dss_feat_get_num_ovls(); ++i) { - struct omap_overlay *ovl; - ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); + BUG_ON(overlays == NULL); - BUG_ON(ovl == NULL); + for (i = 0; i < num_overlays; ++i) { + struct omap_overlay *ovl = &overlays[i]; switch (i) { case 0: ovl->name = "gfx"; ovl->id = OMAP_DSS_GFX; - ovl->info.global_alpha = 255; - ovl->info.zorder = 0; break; case 1: ovl->name = "vid1"; ovl->id = OMAP_DSS_VIDEO1; - ovl->info.global_alpha = 255; - ovl->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; break; case 2: ovl->name = "vid2"; ovl->id = OMAP_DSS_VIDEO2; - ovl->info.global_alpha = 255; - ovl->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; break; case 3: ovl->name = "vid3"; ovl->id = OMAP_DSS_VIDEO3; - ovl->info.global_alpha = 255; - ovl->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; break; } - ovl->set_manager = &omap_dss_set_manager; - ovl->unset_manager = &omap_dss_unset_manager; - ovl->set_overlay_info = &dss_ovl_set_overlay_info; - ovl->get_overlay_info = &dss_ovl_get_overlay_info; - ovl->wait_for_go = &dss_ovl_wait_for_go; + ovl->is_enabled = &dss_ovl_is_enabled; + ovl->enable = &dss_ovl_enable; + ovl->disable = &dss_ovl_disable; + ovl->set_manager = &dss_ovl_set_manager; + ovl->unset_manager = &dss_ovl_unset_manager; + 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->caps = dss_feat_get_overlay_caps(ovl->id); ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); - omap_dss_add_overlay(ovl); - r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, &pdev->dev.kobj, "overlay%d", i); - if (r) { - DSSERR("failed to create sysfs file\n"); - continue; - } - - dispc_overlays[i] = ovl; - } - -#ifdef L4_EXAMPLE - { - struct omap_overlay *ovl; - ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); - - BUG_ON(ovl == NULL); - - ovl->name = "l4"; - ovl->supported_modes = OMAP_DSS_COLOR_RGB24U; - - ovl->set_manager = &omap_dss_set_manager; - ovl->unset_manager = &omap_dss_unset_manager; - ovl->set_overlay_info = &dss_ovl_set_overlay_info; - ovl->get_overlay_info = &dss_ovl_get_overlay_info; - - omap_dss_add_overlay(ovl); - - r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, - &pdev->dev.kobj, "overlayl4"); - if (r) DSSERR("failed to create sysfs file\n"); - - l4_overlays[0] = ovl; } -#endif } /* connect overlays to the new device, if not already connected. if force @@ -795,8 +570,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) ovl = omap_dss_get_overlay(i); if (!ovl->manager || force) { if (ovl->manager) - omap_dss_unset_manager(ovl); - omap_dss_set_manager(ovl, mgr); + ovl->unset_manager(ovl); + ovl->set_manager(ovl, mgr); } } @@ -806,17 +581,95 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) void dss_uninit_overlays(struct platform_device *pdev) { - struct omap_overlay *ovl; + int i; + + for (i = 0; i < num_overlays; ++i) { + struct omap_overlay *ovl = &overlays[i]; - while (!list_empty(&overlay_list)) { - ovl = list_first_entry(&overlay_list, - struct omap_overlay, list); - list_del(&ovl->list); kobject_del(&ovl->kobj); kobject_put(&ovl->kobj); - kfree(ovl); } + kfree(overlays); + overlays = NULL; num_overlays = 0; } +int dss_ovl_simple_check(struct omap_overlay *ovl, + const struct omap_overlay_info *info) +{ + if (info->paddr == 0) { + DSSERR("check_overlay: paddr cannot be 0\n"); + return -EINVAL; + } + + if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { + if (info->out_width != 0 && info->width != info->out_width) { + DSSERR("check_overlay: overlay %d doesn't support " + "scaling\n", ovl->id); + return -EINVAL; + } + + if (info->out_height != 0 && info->height != info->out_height) { + DSSERR("check_overlay: overlay %d doesn't support " + "scaling\n", ovl->id); + return -EINVAL; + } + } + + if ((ovl->supported_modes & info->color_mode) == 0) { + DSSERR("check_overlay: overlay %d doesn't support mode %d\n", + ovl->id, info->color_mode); + return -EINVAL; + } + + if (info->zorder >= omap_dss_get_num_overlays()) { + DSSERR("check_overlay: zorder %d too high\n", info->zorder); + return -EINVAL; + } + + return 0; +} + +int dss_ovl_check(struct omap_overlay *ovl, + struct omap_overlay_info *info, struct omap_dss_device *dssdev) +{ + u16 outw, outh; + u16 dw, dh; + + if (dssdev == NULL) + return 0; + + dssdev->driver->get_resolution(dssdev, &dw, &dh); + + if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { + outw = info->width; + outh = info->height; + } else { + if (info->out_width == 0) + outw = info->width; + else + outw = info->out_width; + + if (info->out_height == 0) + outh = info->height; + else + outh = info->out_height; + } + + if (dw < info->pos_x + outw) { + DSSERR("overlay %d horizontally not inside the display area " + "(%d + %d >= %d)\n", + ovl->id, info->pos_x, outw, dw); + return -EINVAL; + } + + if (dh < info->pos_y + outh) { + DSSERR("overlay %d vertically not inside the display area " + "(%d + %d >= %d)\n", + ovl->id, info->pos_y, outh, dh); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 1130c608a561..814bb9500dca 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -784,7 +784,6 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, if (*w == 0 || *h == 0) return -EINVAL; - dss_setup_partial_planes(dssdev, x, y, w, h, true); dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); return 0; diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 40305ad7841e..8266ca0d666b 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -123,10 +123,14 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) goto err_sdi_enable; mdelay(2); - dssdev->manager->enable(dssdev->manager); + r = dss_mgr_enable(dssdev->manager); + if (r) + goto err_mgr_enable; return 0; +err_mgr_enable: + dss_sdi_disable(); err_sdi_enable: err_set_dispc_clock_div: err_set_dss_clock_div: @@ -145,7 +149,7 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - dssdev->manager->disable(dssdev->manager); + dss_mgr_disable(dssdev->manager); dss_sdi_disable(); diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 2c3443dabb14..7503f7f619a7 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -110,6 +110,11 @@ struct ti_hdmi_ip_ops { void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) + void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start); +#endif + }; struct hdmi_ip_data { @@ -134,5 +139,8 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); - +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable); +#endif #endif diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index e1a6ce518af6..9af81f18f163 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -1204,36 +1204,13 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, return 0; } -int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, - struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable) { - int err = 0; - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - REG_FLD_MOD(hdmi_av_base(ip_data), - HDMI_CORE_AV_AUD_MODE, 1, 0, 0); - REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, 1, 31, 31); - REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, 1, 30, 30); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - REG_FLD_MOD(hdmi_av_base(ip_data), - HDMI_CORE_AV_AUD_MODE, 0, 0, 0); - REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, 0, 30, 30); - REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, 0, 31, 31); - break; - default: - err = -EINVAL; - } - return err; + REG_FLD_MOD(hdmi_av_base(ip_data), + HDMI_CORE_AV_AUD_MODE, enable, 0, 0); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, enable, 31, 31); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, enable, 30, 30); } #endif diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index 204095632d27..a442998980f1 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h @@ -576,9 +576,6 @@ struct hdmi_core_audio_config { #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) -int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, - struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai); int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, u32 sample_freq, u32 *n, u32 *cts); void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 7533458ba4d2..b3e9f9091581 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -417,9 +417,10 @@ static const struct venc_config *venc_timings_to_config( BUG(); } -static void venc_power_on(struct omap_dss_device *dssdev) +static int venc_power_on(struct omap_dss_device *dssdev) { u32 l; + int r; venc_reset(); venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); @@ -447,7 +448,22 @@ static void venc_power_on(struct omap_dss_device *dssdev) if (dssdev->platform_enable) dssdev->platform_enable(dssdev); - dssdev->manager->enable(dssdev->manager); + r = dss_mgr_enable(dssdev->manager); + if (r) + goto err; + + return 0; + +err: + 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); + + return r; } static void venc_power_off(struct omap_dss_device *dssdev) @@ -455,7 +471,7 @@ static void venc_power_off(struct omap_dss_device *dssdev) venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - dssdev->manager->disable(dssdev->manager); + dss_mgr_disable(dssdev->manager); if (dssdev->platform_disable) dssdev->platform_disable(dssdev); @@ -504,7 +520,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) if (r) goto err1; - venc_power_on(dssdev); + r = venc_power_on(dssdev); + if (r) + goto err2; venc.wss_data = 0; @@ -512,6 +530,8 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) mutex_unlock(&venc.venc_lock); return 0; +err2: + venc_runtime_put(); err1: omap_dss_stop_device(dssdev); err0: diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index df7bcce5b107..16ba6196f330 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -111,28 +111,22 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) set_fb_fix(fbi); } - if (pi->enabled) { - struct omap_overlay_info info; + if (!pi->enabled) { + r = ovl->disable(ovl); + if (r) + goto undo; + } + if (pi->enabled) { r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, pi->out_width, pi->out_height); if (r) goto undo; - - ovl->get_overlay_info(ovl, &info); - - if (!info.enabled) { - info.enabled = pi->enabled; - r = ovl->set_overlay_info(ovl, &info); - if (r) - goto undo; - } } else { struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); - info.enabled = pi->enabled; info.pos_x = pi->pos_x; info.pos_y = pi->pos_y; info.out_width = pi->out_width; @@ -146,6 +140,12 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) if (ovl->manager) ovl->manager->apply(ovl->manager); + if (pi->enabled) { + r = ovl->enable(ovl); + if (r) + goto undo; + } + /* Release the locks in a specific order to keep lockdep happy */ if (old_rg->id > new_rg->id) { omapfb_put_mem_region(old_rg); @@ -189,19 +189,19 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) memset(pi, 0, sizeof(*pi)); } else { struct omap_overlay *ovl; - struct omap_overlay_info *ovli; + struct omap_overlay_info ovli; ovl = ofbi->overlays[0]; - ovli = &ovl->info; + ovl->get_overlay_info(ovl, &ovli); - pi->pos_x = ovli->pos_x; - pi->pos_y = ovli->pos_y; - pi->enabled = ovli->enabled; + pi->pos_x = ovli.pos_x; + pi->pos_y = ovli.pos_y; + pi->enabled = ovl->is_enabled(ovl); pi->channel_out = 0; /* xxx */ pi->mirror = 0; pi->mem_idx = get_mem_idx(ofbi); - pi->out_width = ovli->out_width; - pi->out_height = ovli->out_height; + pi->out_width = ovli.out_width; + pi->out_height = ovli.out_height; } return 0; @@ -238,7 +238,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) continue; for (j = 0; j < ofbi2->num_overlays; j++) { - if (ofbi2->overlays[j]->info.enabled) { + struct omap_overlay *ovl; + ovl = ofbi2->overlays[j]; + if (ovl->is_enabled(ovl)) { r = -EBUSY; goto out; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 70aa47de7146..ce158311ff59 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -43,18 +43,18 @@ static char *def_mode; static char *def_vram; -static int def_vrfb; +static bool def_vrfb; static int def_rotate; -static int def_mirror; +static bool def_mirror; static bool auto_update; static unsigned int auto_update_freq; module_param(auto_update, bool, 0); module_param(auto_update_freq, uint, 0644); #ifdef DEBUG -unsigned int omapfb_debug; +bool omapfb_debug; module_param_named(debug, omapfb_debug, bool, 0644); -static unsigned int omapfb_test_pattern; +static bool omapfb_test_pattern; module_param_named(test, omapfb_test_pattern, bool, 0644); #endif @@ -970,16 +970,20 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) outh = var->yres; } } else { - outw = ovl->info.out_width; - outh = ovl->info.out_height; + struct omap_overlay_info info; + ovl->get_overlay_info(ovl, &info); + outw = info.out_width; + outh = info.out_height; } if (init) { posx = 0; posy = 0; } else { - posx = ovl->info.pos_x; - posy = ovl->info.pos_y; + struct omap_overlay_info info; + ovl->get_overlay_info(ovl, &info); + posx = info.pos_x; + posy = info.pos_y; } r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); @@ -2067,6 +2071,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) if (ofbi->num_overlays > 0) { struct omap_overlay *ovl = ofbi->overlays[0]; + ovl->manager->apply(ovl->manager); + r = omapfb_overlay_enable(ovl, 1); if (r) { diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 1694d5148f32..e8d8cc76a435 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -473,7 +473,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, continue; for (j = 0; j < ofbi2->num_overlays; j++) { - if (ofbi2->overlays[j]->info.enabled) { + struct omap_overlay *ovl; + ovl = ofbi2->overlays[j]; + if (ovl->is_enabled(ovl)) { r = -EBUSY; goto out; } diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index fdf0edeccf4e..c0bdc9b54ecf 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -32,7 +32,7 @@ #include <video/omapdss.h> #ifdef DEBUG -extern unsigned int omapfb_debug; +extern bool omapfb_debug; #define DBG(format, ...) \ do { \ if (omapfb_debug) \ @@ -181,13 +181,10 @@ static inline void omapfb_unlock(struct omapfb2_device *fbdev) static inline int omapfb_overlay_enable(struct omap_overlay *ovl, int enable) { - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - if (info.enabled == enable) - return 0; - info.enabled = enable; - return ovl->set_overlay_info(ovl, &info); + if (enable) + return ovl->enable(ovl); + else + return ovl->disable(ovl); } static inline struct omapfb2_mem_region * diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index dc7bfa91e57a..df31a24a5026 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -78,12 +78,12 @@ static char *mode_option __devinitdata; * these flags allow the user to specify that requests for +ve sync * should be silently turned in -ve sync. */ -static int lowhsync; -static int lowvsync; -static int noaccel __devinitdata; +static bool lowhsync; +static bool lowvsync; +static bool noaccel __devinitdata; /* mtrr option */ #ifdef CONFIG_MTRR -static int nomtrr __devinitdata; +static bool nomtrr __devinitdata; #endif /* diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 6632ee5ecb7e..055e527a8e45 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -57,11 +57,11 @@ */ static int hwcursor = 1; static char *mode_option __devinitdata; -static int noaccel __devinitdata; +static bool noaccel __devinitdata; /* mtrr option */ #ifdef CONFIG_MTRR -static int nomtrr __devinitdata; +static bool nomtrr __devinitdata; #endif /* diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c index b2252fea2858..6d30428e9cf9 100644 --- a/drivers/video/pnx4008/pnxrgbfb.c +++ b/drivers/video/pnx4008/pnxrgbfb.c @@ -193,17 +193,6 @@ static struct platform_driver rgbfb_driver = { .remove = rgbfb_remove, }; -static int __init rgbfb_init(void) -{ - return platform_driver_register(&rgbfb_driver); -} - -static void __exit rgbfb_exit(void) -{ - platform_driver_unregister(&rgbfb_driver); -} - -module_init(rgbfb_init); -module_exit(rgbfb_exit); +module_platform_driver(rgbfb_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c index 50e00395240f..c5c741452cac 100644 --- a/drivers/video/pnx4008/sdum.c +++ b/drivers/video/pnx4008/sdum.c @@ -856,17 +856,6 @@ static struct platform_driver sdum_driver = { .resume = sdum_resume, }; -int __init sdum_init(void) -{ - return platform_driver_register(&sdum_driver); -} - -static void __exit sdum_exit(void) -{ - platform_driver_unregister(&sdum_driver); -}; - -module_init(sdum_init); -module_exit(sdum_exit); +module_platform_driver(sdum_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index 18ead6f0184d..8384b941f6ba 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c @@ -832,17 +832,7 @@ static struct platform_driver pxa168fb_driver = { .remove = __devexit_p(pxa168fb_remove), }; -static int __init pxa168fb_init(void) -{ - return platform_driver_register(&pxa168fb_driver); -} -module_init(pxa168fb_init); - -static void __exit pxa168fb_exit(void) -{ - platform_driver_unregister(&pxa168fb_driver); -} -module_exit(pxa168fb_exit); +module_platform_driver(pxa168fb_driver); MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> " "Green Wan <gwan@marvell.com>"); diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 1ed8b366618d..1d71c08a818f 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -747,20 +747,7 @@ static struct platform_driver pxa3xx_gcu_driver = { }, }; -static int __init -pxa3xx_gcu_init(void) -{ - return platform_driver_register(&pxa3xx_gcu_driver); -} - -static void __exit -pxa3xx_gcu_exit(void) -{ - platform_driver_unregister(&pxa3xx_gcu_driver); -} - -module_init(pxa3xx_gcu_init); -module_exit(pxa3xx_gcu_exit); +module_platform_driver(pxa3xx_gcu_driver); MODULE_DESCRIPTION("PXA3xx graphics controller unit driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index d8ab7be4fd6b..2f58cf9c813b 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -207,9 +207,9 @@ MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); /* command line data, set in rivafb_setup() */ static int flatpanel __devinitdata = -1; /* Autodetect later */ static int forceCRTC __devinitdata = -1; -static int noaccel __devinitdata = 0; +static bool noaccel __devinitdata = 0; #ifdef CONFIG_MTRR -static int nomtrr __devinitdata = 0; +static bool nomtrr __devinitdata = 0; #endif #ifdef CONFIG_PMAC_BACKLIGHT static int backlight __devinitdata = 1; @@ -218,7 +218,7 @@ static int backlight __devinitdata = 0; #endif static char *mode_option __devinitdata = NULL; -static int strictmode = 0; +static bool strictmode = 0; static struct fb_fix_screeninfo __devinitdata rivafb_fix = { .type = FB_TYPE_PACKED_PIXELS, diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 0753b1cfcb8b..0c63b69b6340 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -192,6 +192,7 @@ struct s3c_fb_vsync { * @regs: The mapped hardware registers. * @variant: Variant information for this hardware. * @enabled: A bitmask of enabled hardware windows. + * @output_on: Flag if the physical output is enabled. * @pdata: The platform configuration data passed with the device. * @windows: The hardware windows that have been claimed. * @irq_no: IRQ line number @@ -208,6 +209,7 @@ struct s3c_fb { struct s3c_fb_variant variant; unsigned char enabled; + bool output_on; struct s3c_fb_platdata *pdata; struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; @@ -441,6 +443,39 @@ static void shadow_protect_win(struct s3c_fb_win *win, bool protect) } /** + * s3c_fb_enable() - Set the state of the main LCD output + * @sfb: The main framebuffer state. + * @enable: The state to set. + */ +static void s3c_fb_enable(struct s3c_fb *sfb, int enable) +{ + u32 vidcon0 = readl(sfb->regs + VIDCON0); + + if (enable && !sfb->output_on) + pm_runtime_get_sync(sfb->dev); + + if (enable) { + vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; + } else { + /* see the note in the framebuffer datasheet about + * why you cannot take both of these bits down at the + * same time. */ + + if (vidcon0 & VIDCON0_ENVID) { + vidcon0 |= VIDCON0_ENVID; + vidcon0 &= ~VIDCON0_ENVID_F; + } + } + + writel(vidcon0, sfb->regs + VIDCON0); + + if (!enable && sfb->output_on) + pm_runtime_put_sync(sfb->dev); + + sfb->output_on = enable; +} + +/** * s3c_fb_set_par() - framebuffer request to set new framebuffer state. * @info: The framebuffer to change. * @@ -461,6 +496,8 @@ static int s3c_fb_set_par(struct fb_info *info) dev_dbg(sfb->dev, "setting framebuffer parameters\n"); + pm_runtime_get_sync(sfb->dev); + shadow_protect_win(win, 1); switch (var->bits_per_pixel) { @@ -510,9 +547,10 @@ static int s3c_fb_set_par(struct fb_info *info) if (sfb->variant.is_2443) data |= (1 << 5); - data |= VIDCON0_ENVID | VIDCON0_ENVID_F; writel(data, regs + VIDCON0); + s3c_fb_enable(sfb, 1); + data = VIDTCON0_VBPD(var->upper_margin - 1) | VIDTCON0_VFPD(var->lower_margin - 1) | VIDTCON0_VSPW(var->vsync_len - 1); @@ -574,6 +612,7 @@ static int s3c_fb_set_par(struct fb_info *info) } data = WINCONx_ENWIN; + sfb->enabled |= (1 << win->index); /* note, since we have to round up the bits-per-pixel, we end up * relying on the bitfield information for r/g/b/a to work out @@ -621,7 +660,8 @@ static int s3c_fb_set_par(struct fb_info *info) } else if (var->transp.length == 1) data |= WINCON1_BPPMODE_25BPP_A1888 | WINCON1_BLD_PIX; - else if (var->transp.length == 4) + else if ((var->transp.length == 4) || + (var->transp.length == 8)) data |= WINCON1_BPPMODE_28BPP_A4888 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; else @@ -654,6 +694,8 @@ static int s3c_fb_set_par(struct fb_info *info) shadow_protect_win(win, 0); + pm_runtime_put_sync(sfb->dev); + return 0; } @@ -725,6 +767,8 @@ static int s3c_fb_setcolreg(unsigned regno, dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n", __func__, win->index, regno, red, green, blue); + pm_runtime_get_sync(sfb->dev); + switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: /* true-colour, use pseudo-palette */ @@ -752,39 +796,15 @@ static int s3c_fb_setcolreg(unsigned regno, break; default: + pm_runtime_put_sync(sfb->dev); return 1; /* unknown type */ } + pm_runtime_put_sync(sfb->dev); return 0; } /** - * s3c_fb_enable() - Set the state of the main LCD output - * @sfb: The main framebuffer state. - * @enable: The state to set. - */ -static void s3c_fb_enable(struct s3c_fb *sfb, int enable) -{ - u32 vidcon0 = readl(sfb->regs + VIDCON0); - - if (enable) - vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; - else { - /* see the note in the framebuffer datasheet about - * why you cannot take both of these bits down at the - * same time. */ - - if (!(vidcon0 & VIDCON0_ENVID)) - return; - - vidcon0 |= VIDCON0_ENVID; - vidcon0 &= ~VIDCON0_ENVID_F; - } - - writel(vidcon0, sfb->regs + VIDCON0); -} - -/** * s3c_fb_blank() - blank or unblank the given window * @blank_mode: The blank state from FB_BLANK_* * @info: The framebuffer to blank. @@ -800,6 +820,8 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); + pm_runtime_get_sync(sfb->dev); + wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4)); switch (blank_mode) { @@ -810,12 +832,16 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) case FB_BLANK_NORMAL: /* disable the DMA and display 0x0 (black) */ + shadow_protect_win(win, 1); writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0), sfb->regs + sfb->variant.winmap + (index * 4)); + shadow_protect_win(win, 0); break; case FB_BLANK_UNBLANK: + shadow_protect_win(win, 1); writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4)); + shadow_protect_win(win, 0); wincon |= WINCONx_ENWIN; sfb->enabled |= (1 << index); break; @@ -823,10 +849,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: default: + pm_runtime_put_sync(sfb->dev); return 1; } + shadow_protect_win(win, 1); writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); + shadow_protect_win(win, 0); /* Check the enabled state to see if we need to be running the * main LCD interface, as if there are no active windows then @@ -845,8 +874,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) /* we're stuck with this until we can do something about overriding * the power control using the blanking event for a single fb. */ - if (index == sfb->pdata->default_win) + if (index == sfb->pdata->default_win) { + shadow_protect_win(win, 1); s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); + shadow_protect_win(win, 0); + } + + pm_runtime_put_sync(sfb->dev); return 0; } @@ -870,6 +904,8 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, void __iomem *buf = sfb->regs + win->index * 8; unsigned int start_boff, end_boff; + pm_runtime_get_sync(sfb->dev); + /* Offset in bytes to the start of the displayed area */ start_boff = var->yoffset * info->fix.line_length; /* X offset depends on the current bpp */ @@ -888,6 +924,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, break; default: dev_err(sfb->dev, "invalid bpp\n"); + pm_runtime_put_sync(sfb->dev); return -EINVAL; } } @@ -903,6 +940,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, shadow_protect_win(win, 0); + pm_runtime_put_sync(sfb->dev); return 0; } @@ -992,11 +1030,16 @@ static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc) if (crtc != 0) return -ENODEV; + pm_runtime_get_sync(sfb->dev); + count = sfb->vsync_info.count; s3c_fb_enable_irq(sfb); ret = wait_event_interruptible_timeout(sfb->vsync_info.wait, count != sfb->vsync_info.count, msecs_to_jiffies(VSYNC_TIMEOUT_MSEC)); + + pm_runtime_put_sync(sfb->dev); + if (ret == 0) return -ETIMEDOUT; @@ -1027,30 +1070,8 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, return ret; } -static int s3c_fb_open(struct fb_info *info, int user) -{ - struct s3c_fb_win *win = info->par; - struct s3c_fb *sfb = win->parent; - - pm_runtime_get_sync(sfb->dev); - - return 0; -} - -static int s3c_fb_release(struct fb_info *info, int user) -{ - struct s3c_fb_win *win = info->par; - struct s3c_fb *sfb = win->parent; - - pm_runtime_put_sync(sfb->dev); - - return 0; -} - static struct fb_ops s3c_fb_ops = { .owner = THIS_MODULE, - .fb_open = s3c_fb_open, - .fb_release = s3c_fb_release, .fb_check_var = s3c_fb_check_var, .fb_set_par = s3c_fb_set_par, .fb_blank = s3c_fb_blank, @@ -1452,7 +1473,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) dev_err(dev, "failed to create window %d\n", win); for (; win >= 0; win--) s3c_fb_release_win(sfb, sfb->windows[win]); - goto err_irq; + goto err_pm_runtime; } } @@ -1461,7 +1482,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) return 0; -err_irq: +err_pm_runtime: + pm_runtime_put_sync(sfb->dev); free_irq(sfb->irq_no, sfb); err_ioremap: @@ -1471,6 +1493,8 @@ err_req_region: release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); err_lcd_clk: + pm_runtime_disable(sfb->dev); + if (!sfb->variant.has_clksel) { clk_disable(sfb->lcd_clk); clk_put(sfb->lcd_clk); @@ -1524,7 +1548,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int s3c_fb_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1571,10 +1595,15 @@ static int s3c_fb_resume(struct device *dev) for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { void __iomem *regs = sfb->regs + sfb->variant.keycon; + win = sfb->windows[win_no]; + if (!win) + continue; + shadow_protect_win(win, 1); regs += (win_no * 8); writel(0xffffff, regs + WKEYCON0); writel(0xffffff, regs + WKEYCON1); + shadow_protect_win(win, 0); } /* restore framebuffers */ @@ -1589,27 +1618,19 @@ static int s3c_fb_resume(struct device *dev) return 0; } +#endif +#ifdef CONFIG_PM_RUNTIME static int s3c_fb_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s3c_fb *sfb = platform_get_drvdata(pdev); - struct s3c_fb_win *win; - int win_no; - - for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { - win = sfb->windows[win_no]; - if (!win) - continue; - - /* use the blank function to push into power-down */ - s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); - } if (!sfb->variant.has_clksel) clk_disable(sfb->lcd_clk); clk_disable(sfb->bus_clk); + return 0; } @@ -1618,8 +1639,6 @@ static int s3c_fb_runtime_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s3c_fb *sfb = platform_get_drvdata(pdev); struct s3c_fb_platdata *pd = sfb->pdata; - struct s3c_fb_win *win; - int win_no; clk_enable(sfb->bus_clk); @@ -1630,39 +1649,10 @@ static int s3c_fb_runtime_resume(struct device *dev) pd->setup_gpio(); writel(pd->vidcon1, sfb->regs + VIDCON1); - /* zero all windows before we do anything */ - for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) - s3c_fb_clear_win(sfb, win_no); - - for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { - void __iomem *regs = sfb->regs + sfb->variant.keycon; - - regs += (win_no * 8); - writel(0xffffff, regs + WKEYCON0); - writel(0xffffff, regs + WKEYCON1); - } - - /* restore framebuffers */ - for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { - win = sfb->windows[win_no]; - if (!win) - continue; - - dev_dbg(&pdev->dev, "resuming window %d\n", win_no); - s3c_fb_set_par(win->fbinfo); - } - return 0; } - -#else -#define s3c_fb_suspend NULL -#define s3c_fb_resume NULL -#define s3c_fb_runtime_suspend NULL -#define s3c_fb_runtime_resume NULL #endif - #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4)) #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8)) @@ -1985,10 +1975,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = { MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); static const struct dev_pm_ops s3cfb_pm_ops = { - .suspend = s3c_fb_suspend, - .resume = s3c_fb_resume, - .runtime_suspend = s3c_fb_runtime_suspend, - .runtime_resume = s3c_fb_runtime_resume, + SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume) + SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume, + NULL) }; static struct platform_driver s3c_fb_driver = { @@ -2002,18 +1991,7 @@ static struct platform_driver s3c_fb_driver = { }, }; -static int __init s3c_fb_init(void) -{ - return platform_driver_register(&s3c_fb_driver); -} - -static void __exit s3c_fb_cleanup(void) -{ - platform_driver_unregister(&s3c_fb_driver); -} - -module_init(s3c_fb_init); -module_exit(s3c_fb_cleanup); +module_platform_driver(s3c_fb_driver); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver"); diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index ee4c0df217f7..77f34c614c86 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -26,8 +26,8 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/cpufreq.h> +#include <linux/io.h> -#include <asm/io.h> #include <asm/div64.h> #include <asm/mach/map.h> @@ -45,10 +45,10 @@ #ifdef CONFIG_FB_S3C2410_DEBUG static int debug = 1; #else -static int debug = 0; +static int debug; #endif -#define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); } +#define dprintk(msg...) if (debug) printk(KERN_DEBUG "s3c2410fb: " msg); /* useful functions */ @@ -567,11 +567,10 @@ static int s3c2410fb_blank(int blank_mode, struct fb_info *info) tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; - if (blank_mode == FB_BLANK_POWERDOWN) { + if (blank_mode == FB_BLANK_POWERDOWN) s3c2410fb_lcd_enable(fbi, 0); - } else { + else s3c2410fb_lcd_enable(fbi, 1); - } if (blank_mode == FB_BLANK_UNBLANK) writel(0x0, tpal_reg); @@ -812,7 +811,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) #endif -static char driver_name[] = "s3c2410fb"; +static const char driver_name[] = "s3c2410fb"; static int __devinit s3c24xxfb_probe(struct platform_device *pdev, enum s3c_drv_type drv_type) @@ -881,7 +880,10 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, goto release_mem; } - info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE); + if (drv_type == DRV_S3C2412) + info->irq_base = info->io + S3C2412_LCDINTBASE; + else + info->irq_base = info->io + S3C2410_LCDINTBASE; dprintk("devinit\n"); @@ -927,7 +929,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, clk_enable(info->clk); dprintk("got and enabled clock\n"); - msleep(1); + usleep_range(1000, 1000); info->clk_rate = clk_get_rate(info->clk); @@ -975,9 +977,8 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, /* create device files */ ret = device_create_file(&pdev->dev, &dev_attr_debug); - if (ret) { + if (ret) printk(KERN_ERR "failed to add debug attribute\n"); - } printk(KERN_INFO "fb%d: %s frame buffer device\n", fbinfo->node, fbinfo->fix.id); @@ -1027,7 +1028,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev) s3c2410fb_cpufreq_deregister(info); s3c2410fb_lcd_enable(info, 0); - msleep(1); + usleep_range(1000, 1000); s3c2410fb_unmap_video_memory(fbinfo); @@ -1064,7 +1065,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) */ - msleep(1); + usleep_range(1000, 1000); clk_disable(info->clk); return 0; @@ -1076,7 +1077,7 @@ static int s3c2410fb_resume(struct platform_device *dev) struct s3c2410fb_info *info = fbinfo->par; clk_enable(info->clk); - msleep(1); + usleep_range(1000, 1000); s3c2410fb_init_registers(fbinfo); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 946a949f4c7d..2c80246b18b8 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -727,7 +727,7 @@ static int s3fb_set_par(struct fb_info *info) if (par->chip == CHIP_988_VIRGE_VX) { vga_wcrt(par->state.vgabase, 0x50, 0x00); vga_wcrt(par->state.vgabase, 0x67, 0x50); - + msleep(10); /* screen remains blank sometimes without this */ vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09); vga_wcrt(par->state.vgabase, 0x66, 0x90); } @@ -901,7 +901,8 @@ static int s3fb_set_par(struct fb_info *info) /* Set Data Transfer Position */ hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8; - value = clamp((htotal + hsstart + 1) / 2, hsstart + 4, htotal + 1); + /* + 2 is needed for Virge/VX, does no harm on other cards */ + value = clamp((htotal + hsstart + 1) / 2 + 2, hsstart + 4, htotal + 1); svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value); memset_io(info->screen_base, 0x00, screen_size); @@ -1216,6 +1217,31 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->screen_size = 2 << 20; break; } + } else if (par->chip == CHIP_988_VIRGE_VX) { + switch ((regval & 0x60) >> 5) { + case 0: /* 2MB */ + info->screen_size = 2 << 20; + break; + case 1: /* 4MB */ + info->screen_size = 4 << 20; + break; + case 2: /* 6MB */ + info->screen_size = 6 << 20; + break; + case 3: /* 8MB */ + info->screen_size = 8 << 20; + break; + } + /* off-screen memory */ + regval = vga_rcrt(par->state.vgabase, 0x37); + switch ((regval & 0x60) >> 5) { + case 1: /* 4MB */ + info->screen_size -= 4 << 20; + break; + case 2: /* 2MB */ + info->screen_size -= 2 << 20; + break; + } } else info->screen_size = s3_memsizes[regval >> 5] << 10; info->fix.smem_len = info->screen_size; diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c index 37d764ad56b0..3c1de981a18c 100644 --- a/drivers/video/sbuslib.c +++ b/drivers/video/sbuslib.c @@ -76,7 +76,7 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map, map_offset = (physbase + map[i].poff) & POFF_MASK; break; } - if (!map_size){ + if (!map_size) { page += PAGE_SIZE; continue; } diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 45e47d847163..83b16e237a0e 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c @@ -585,18 +585,7 @@ static struct platform_driver sh7760_lcdc_driver = { .remove = __devexit_p(sh7760fb_remove), }; -static int __init sh7760fb_init(void) -{ - return platform_driver_register(&sh7760_lcdc_driver); -} - -static void __exit sh7760fb_exit(void) -{ - platform_driver_unregister(&sh7760_lcdc_driver); -} - -module_init(sh7760fb_init); -module_exit(sh7760fb_exit); +module_platform_driver(sh7760_lcdc_driver); MODULE_AUTHOR("Nobuhiro Iwamatsu, Manuel Lauss"); MODULE_DESCRIPTION("FBdev for SH7760/63 integrated LCD Controller"); diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 72ee96bc6b3e..05151b82f40f 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ +#include <linux/bitmap.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/init.h> @@ -41,6 +42,7 @@ #define VMCTR1 0x0020 #define VMCTR2 0x0024 #define VMLEN1 0x0028 +#define VMLEN2 0x002c #define CMTSRTREQ 0x0070 #define CMTSRTCTR 0x00d0 @@ -51,8 +53,7 @@ struct sh_mipi { void __iomem *base; void __iomem *linkbase; struct clk *dsit_clk; - struct clk *dsip_clk; - struct device *dev; + struct platform_device *pdev; void *next_board_data; void (*next_display_on)(void *board_data, struct fb_info *info); @@ -124,35 +125,15 @@ static void sh_mipi_shutdown(struct platform_device *pdev) sh_mipi_dsi_enable(mipi, false); } -static void mipi_display_on(void *arg, struct fb_info *info) -{ - struct sh_mipi *mipi = arg; - - pm_runtime_get_sync(mipi->dev); - sh_mipi_dsi_enable(mipi, true); - - if (mipi->next_display_on) - mipi->next_display_on(mipi->next_board_data, info); -} - -static void mipi_display_off(void *arg) -{ - struct sh_mipi *mipi = arg; - - if (mipi->next_display_off) - mipi->next_display_off(mipi->next_board_data); - - sh_mipi_dsi_enable(mipi, false); - pm_runtime_put(mipi->dev); -} - static int __init sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) { void __iomem *base = mipi->base; struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; - u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000; + u32 pctype, datatype, pixfmt, linelength, vmctr2; + u32 tmp, top, bottom, delay, div; bool yuv; + int bpp; /* * Select data format. MIPI DSI is not hot-pluggable, so, we just use @@ -253,6 +234,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, (!yuv && ch->interface_type != RGB24)) return -EINVAL; + if (!pdata->lane) + return -EINVAL; + /* reset DSI link */ iowrite32(0x00000001, base + SYSCTRL); /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */ @@ -262,15 +246,6 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, /* setup DSI link */ /* - * Default = ULPS enable | - * Contention detection enabled | - * EoT packet transmission enable | - * CRC check enable | - * ECC check enable - * additionally enable first two lanes - */ - iowrite32(0x00003703, base + SYSCONF); - /* * T_wakeup = 0x7000 * T_hs-trail = 3 * T_hs-prepare = 3 @@ -290,15 +265,24 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, iowrite32(0x0fffffff, base + TATOVSET); /* Peripheral reset timeout, default 0xffffffff */ iowrite32(0x0fffffff, base + PRTOVSET); - /* Enable timeout counters */ - iowrite32(0x00000f00, base + DSICTRL); /* Interrupts not used, disable all */ iowrite32(0, base + DSIINTE); /* DSI-Tx bias on */ iowrite32(0x00000001, base + PHYCTRL); udelay(200); - /* Deassert resets, power on, set multiplier */ - iowrite32(0x03070b01, base + PHYCTRL); + /* Deassert resets, power on */ + iowrite32(0x03070001, base + PHYCTRL); + + /* + * Default = ULPS enable | + * Contention detection enabled | + * EoT packet transmission enable | + * CRC check enable | + * ECC check enable + */ + bitmap_fill((unsigned long *)&tmp, pdata->lane); + tmp |= 0x00003700; + iowrite32(tmp, base + SYSCONF); /* setup l-bridge */ @@ -316,18 +300,68 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, * Non-burst mode with sync pulses: VSE and HSE are output, * HSA period allowed, no commands in LP */ + vmctr2 = 0; + if (pdata->flags & SH_MIPI_DSI_VSEE) + vmctr2 |= 1 << 23; + if (pdata->flags & SH_MIPI_DSI_HSEE) + vmctr2 |= 1 << 22; + if (pdata->flags & SH_MIPI_DSI_HSAE) + vmctr2 |= 1 << 21; + if (pdata->flags & SH_MIPI_DSI_BL2E) + vmctr2 |= 1 << 17; if (pdata->flags & SH_MIPI_DSI_HSABM) - vmctr2 |= 0x20; - if (pdata->flags & SH_MIPI_DSI_HSPBM) - vmctr2 |= 0x10; + vmctr2 |= 1 << 5; + if (pdata->flags & SH_MIPI_DSI_HBPBM) + vmctr2 |= 1 << 4; + if (pdata->flags & SH_MIPI_DSI_HFPBM) + vmctr2 |= 1 << 3; iowrite32(vmctr2, mipi->linkbase + VMCTR2); /* - * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see - * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default - * (unused if VMCTR2[HSABM] = 0) + * VMLEN1 = RGBLEN | HSALEN + * + * see + * Video mode - Blanking Packet setting + */ + top = linelength << 16; /* RGBLEN */ + bottom = 0x00000001; + if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */ + bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10; + iowrite32(top | bottom , mipi->linkbase + VMLEN1); + + /* + * VMLEN2 = HBPLEN | HFPLEN + * + * see + * Video mode - Blanking Packet setting */ - iowrite32(1 | (linelength << 16), mipi->linkbase + VMLEN1); + top = 0x00010000; + bottom = 0x00000001; + delay = 0; + + div = 1; /* HSbyteCLK is calculation base + * HS4divCLK = HSbyteCLK/2 + * HS6divCLK is not supported for now */ + if (pdata->flags & SH_MIPI_DSI_HS4divCLK) + div = 2; + + if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */ + top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin; + top = ((pdata->lane * top / div) - 10) << 16; + } + if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */ + bottom = ch->lcd_cfg[0].right_margin; + bottom = (pdata->lane * bottom / div) - 12; + } + + bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */ + if ((pdata->lane / div) > bpp) { + tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */ + tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */ + delay = (pdata->lane * tmp); + } + + iowrite32(top | (bottom + delay) , mipi->linkbase + VMLEN2); msleep(5); @@ -352,9 +386,56 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, pixfmt << 4); sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON); + /* Enable timeout counters */ + iowrite32(0x00000f00, base + DSICTRL); + return 0; } +static void mipi_display_on(void *arg, struct fb_info *info) +{ + struct sh_mipi *mipi = arg; + struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; + int ret; + + pm_runtime_get_sync(&mipi->pdev->dev); + + ret = pdata->set_dot_clock(mipi->pdev, mipi->base, 1); + if (ret < 0) + goto mipi_display_on_fail1; + + ret = sh_mipi_setup(mipi, pdata); + if (ret < 0) + goto mipi_display_on_fail2; + + sh_mipi_dsi_enable(mipi, true); + + if (mipi->next_display_on) + mipi->next_display_on(mipi->next_board_data, info); + + return; + +mipi_display_on_fail1: + pm_runtime_put_sync(&mipi->pdev->dev); +mipi_display_on_fail2: + pdata->set_dot_clock(mipi->pdev, mipi->base, 0); +} + +static void mipi_display_off(void *arg) +{ + struct sh_mipi *mipi = arg; + struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; + + if (mipi->next_display_off) + mipi->next_display_off(mipi->next_board_data); + + sh_mipi_dsi_enable(mipi, false); + + pdata->set_dot_clock(mipi->pdev, mipi->base, 0); + + pm_runtime_put_sync(&mipi->pdev->dev); +} + static int __init sh_mipi_probe(struct platform_device *pdev) { struct sh_mipi *mipi; @@ -363,11 +444,13 @@ static int __init sh_mipi_probe(struct platform_device *pdev) struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); unsigned long rate, f_current; int idx = pdev->id, ret; - char dsip_clk[] = "dsi.p_clk"; if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata) return -ENODEV; + if (!pdata->set_dot_clock) + return -EINVAL; + mutex_lock(&array_lock); if (idx < 0) for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++) @@ -408,7 +491,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev) goto emap2; } - mipi->dev = &pdev->dev; + mipi->pdev = pdev; mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk"); if (IS_ERR(mipi->dsit_clk)) { @@ -428,44 +511,15 @@ static int __init sh_mipi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate); - sprintf(dsip_clk, "dsi%1.1dp_clk", idx); - mipi->dsip_clk = clk_get(&pdev->dev, dsip_clk); - if (IS_ERR(mipi->dsip_clk)) { - ret = PTR_ERR(mipi->dsip_clk); - goto eclkpget; - } - - f_current = clk_get_rate(mipi->dsip_clk); - /* Between 10 and 50MHz */ - rate = clk_round_rate(mipi->dsip_clk, 24000000); - if (rate > 0 && rate != f_current) - ret = clk_set_rate(mipi->dsip_clk, rate); - else - ret = rate; - if (ret < 0) - goto esetprate; - - dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate); - - msleep(10); - ret = clk_enable(mipi->dsit_clk); if (ret < 0) goto eclkton; - ret = clk_enable(mipi->dsip_clk); - if (ret < 0) - goto eclkpon; - mipi_dsi[idx] = mipi; pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); - ret = sh_mipi_setup(mipi, pdata); - if (ret < 0) - goto emipisetup; - mutex_unlock(&array_lock); platform_set_drvdata(pdev, mipi); @@ -482,16 +536,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev) return 0; -emipisetup: - mipi_dsi[idx] = NULL; - pm_runtime_disable(&pdev->dev); - clk_disable(mipi->dsip_clk); -eclkpon: - clk_disable(mipi->dsit_clk); eclkton: -esetprate: - clk_put(mipi->dsip_clk); -eclkpget: esettrate: clk_put(mipi->dsit_clk); eclktget: @@ -542,10 +587,9 @@ static int __exit sh_mipi_remove(struct platform_device *pdev) pdata->lcd_chan->board_cfg.board_data = NULL; pm_runtime_disable(&pdev->dev); - clk_disable(mipi->dsip_clk); clk_disable(mipi->dsit_clk); clk_put(mipi->dsit_clk); - clk_put(mipi->dsip_clk); + iounmap(mipi->linkbase); if (res2) release_mem_region(res2->start, resource_size(res2)); diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index facffc254976..aac5b369d73c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> +#include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/ioctl.h> #include <linux/slab.h> @@ -102,7 +103,7 @@ struct sh_mobile_lcdc_priv { struct sh_mobile_lcdc_chan ch[2]; struct notifier_block notifier; int started; - int forced_bpp; /* 2 channel LCDC must share bpp setting */ + int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ struct sh_mobile_meram_info *meram_dev; }; @@ -215,6 +216,47 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { lcdc_sys_read_data, }; +static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var) +{ + if (var->grayscale > 1) + return var->grayscale; + + switch (var->bits_per_pixel) { + case 16: + return V4L2_PIX_FMT_RGB565; + case 24: + return V4L2_PIX_FMT_BGR24; + case 32: + return V4L2_PIX_FMT_BGR32; + default: + return 0; + } +} + +static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) +{ + return var->grayscale > 1; +} + +static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var) +{ + if (var->grayscale <= 1) + return false; + + switch (var->grayscale) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + return true; + + default: + return false; + } +} + static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) { if (atomic_inc_and_test(&priv->hw_usecnt)) { @@ -420,7 +462,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) tmp = ((display_var->xres & 7) << 24) | ((display_h_total & 7) << 16) | ((display_var->hsync_len & 7) << 8) | - hsync_pos; + (hsync_pos & 7); lcdc_write_chan(ch, LDHAJR, tmp); } @@ -435,7 +477,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; unsigned long tmp; - int bpp = 0; int k, m; /* Enable LCDC channels. Read data from external memory, avoid using the @@ -454,9 +495,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) if (!ch->enabled) continue; - if (!bpp) - bpp = ch->info->var.bits_per_pixel; - /* Power supply */ lcdc_write_chan(ch, LDPMR, 0); @@ -487,31 +525,37 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) sh_mobile_lcdc_geometry(ch); - if (ch->info->var.nonstd) { - tmp = (ch->info->var.nonstd << 16); - switch (ch->info->var.bits_per_pixel) { - case 12: - tmp |= LDDFR_YF_420; - break; - case 16: - tmp |= LDDFR_YF_422; - break; - case 24: - default: - tmp |= LDDFR_YF_444; - break; - } - } else { - switch (ch->info->var.bits_per_pixel) { - case 16: - tmp = LDDFR_PKF_RGB16; - break; - case 24: - tmp = LDDFR_PKF_RGB24; + switch (sh_mobile_format_fourcc(&ch->info->var)) { + case V4L2_PIX_FMT_RGB565: + tmp = LDDFR_PKF_RGB16; + break; + case V4L2_PIX_FMT_BGR24: + tmp = LDDFR_PKF_RGB24; + break; + case V4L2_PIX_FMT_BGR32: + tmp = LDDFR_PKF_ARGB32; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + tmp = LDDFR_CC | LDDFR_YF_420; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + tmp = LDDFR_CC | LDDFR_YF_422; + break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + tmp = LDDFR_CC | LDDFR_YF_444; + break; + } + + if (sh_mobile_format_is_yuv(&ch->info->var)) { + switch (ch->info->var.colorspace) { + case V4L2_COLORSPACE_REC709: + tmp |= LDDFR_CF1; break; - case 32: - default: - tmp = LDDFR_PKF_ARGB32; + case V4L2_COLORSPACE_JPEG: + tmp |= LDDFR_CF0; break; } } @@ -519,7 +563,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) lcdc_write_chan(ch, LDDFR, tmp); lcdc_write_chan(ch, LDMLSR, ch->pitch); lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); - if (ch->info->var.nonstd) + if (sh_mobile_format_is_yuv(&ch->info->var)) lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); /* When using deferred I/O mode, configure the LCDC for one-shot @@ -536,21 +580,23 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) } /* Word and long word swap. */ - if (priv->ch[0].info->var.nonstd) + switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV42: + tmp = LDDDSR_LS | LDDDSR_WS; + break; + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV24: tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; - else { - switch (bpp) { - case 16: - tmp = LDDDSR_LS | LDDDSR_WS; - break; - case 24: - tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; - break; - case 32: - default: - tmp = LDDDSR_LS; - break; - } + break; + case V4L2_PIX_FMT_BGR32: + default: + tmp = LDDDSR_LS; + break; } lcdc_write(priv, _LDDDSR, tmp); @@ -622,12 +668,24 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->meram_enabled = 0; } - if (!ch->info->var.nonstd) - pixelformat = SH_MOBILE_MERAM_PF_RGB; - else if (ch->info->var.bits_per_pixel == 24) - pixelformat = SH_MOBILE_MERAM_PF_NV24; - else + switch (sh_mobile_format_fourcc(&ch->info->var)) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: pixelformat = SH_MOBILE_MERAM_PF_NV; + break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + pixelformat = SH_MOBILE_MERAM_PF_NV24; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_BGR32: + default: + pixelformat = SH_MOBILE_MERAM_PF_RGB; + break; + } ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, ch->info->var.yres, pixelformat, @@ -845,6 +903,7 @@ static struct fb_fix_screeninfo sh_mobile_lcdc_fix = { .xpanstep = 0, .ypanstep = 1, .ywrapstep = 0, + .capabilities = FB_CAP_FOURCC, }; static void sh_mobile_lcdc_fillrect(struct fb_info *info, @@ -877,8 +936,9 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, unsigned long new_pan_offset; unsigned long base_addr_y, base_addr_c; unsigned long c_offset; + bool yuv = sh_mobile_format_is_yuv(&info->var); - if (!info->var.nonstd) + if (!yuv) new_pan_offset = var->yoffset * info->fix.line_length + var->xoffset * (info->var.bits_per_pixel / 8); else @@ -892,7 +952,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, /* Set the source address for the next refresh */ base_addr_y = ch->dma_handle + new_pan_offset; - if (info->var.nonstd) { + if (yuv) { /* Set y offset */ c_offset = var->yoffset * info->fix.line_length * (info->var.bits_per_pixel - 8) / 8; @@ -900,7 +960,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, + info->var.xres * info->var.yres_virtual + c_offset; /* Set x offset */ - if (info->var.bits_per_pixel == 24) + if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24) base_addr_c += 2 * var->xoffset; else base_addr_c += var->xoffset; @@ -924,7 +984,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, ch->base_addr_c = base_addr_c; lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); - if (info->var.nonstd) + if (yuv) lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); if (lcdc_chan_is_sublcd(ch)) @@ -1100,51 +1160,84 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; - if (var->bits_per_pixel <= 16) { /* RGB 565 */ - var->bits_per_pixel = 16; - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ - var->bits_per_pixel = 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->transp.offset = 0; - var->transp.length = 0; - } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ - var->bits_per_pixel = 32; - 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->transp.offset = 24; - var->transp.length = 8; - } else - return -EINVAL; + if (sh_mobile_format_is_fourcc(var)) { + switch (var->grayscale) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + var->bits_per_pixel = 12; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + var->bits_per_pixel = 16; + break; + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + var->bits_per_pixel = 24; + break; + case V4L2_PIX_FMT_BGR32: + var->bits_per_pixel = 32; + break; + default: + return -EINVAL; + } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; + /* Default to RGB and JPEG color-spaces for RGB and YUV formats + * respectively. + */ + if (!sh_mobile_format_is_yuv(var)) + var->colorspace = V4L2_COLORSPACE_SRGB; + else if (var->colorspace != V4L2_COLORSPACE_REC709) + var->colorspace = V4L2_COLORSPACE_JPEG; + } else { + if (var->bits_per_pixel <= 16) { /* RGB 565 */ + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ + var->bits_per_pixel = 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->transp.offset = 0; + var->transp.length = 0; + } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ + var->bits_per_pixel = 32; + 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->transp.offset = 24; + var->transp.length = 8; + } else + return -EINVAL; + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + } /* Make sure we don't exceed our allocated memory. */ if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > info->fix.smem_len) return -EINVAL; - /* only accept the forced_bpp for dual channel configurations */ - if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel) + /* only accept the forced_fourcc for dual channel configurations */ + if (p->forced_fourcc && + p->forced_fourcc != sh_mobile_format_fourcc(var)) return -EINVAL; return 0; @@ -1158,7 +1251,7 @@ static int sh_mobile_set_par(struct fb_info *info) sh_mobile_lcdc_stop(ch->lcdc); - if (info->var.nonstd) + if (sh_mobile_format_is_yuv(&info->var)) info->fix.line_length = info->var.xres; else info->fix.line_length = info->var.xres @@ -1170,6 +1263,14 @@ static int sh_mobile_set_par(struct fb_info *info) info->fix.line_length = line_length; } + if (sh_mobile_format_is_fourcc(&info->var)) { + info->fix.type = FB_TYPE_FOURCC; + info->fix.visual = FB_VISUAL_FOURCC; + } else { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + } + return ret; } @@ -1464,9 +1565,9 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) { unsigned int size = mode->yres * mode->xres; - /* NV12 buffers must have even number of lines */ - if ((cfg->nonstd) && cfg->bpp == 12 && - (mode->yres & 0x1)) { + /* NV12/NV21 buffers must have even number of lines */ + if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || + cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { dev_err(dev, "yres must be multiple of 2 for YCbCr420 " "mode.\n"); return -EINVAL; @@ -1484,14 +1585,6 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, dev_dbg(dev, "Found largest videomode %ux%u\n", max_mode->xres, max_mode->yres); - /* Initialize fixed screen information. Restrict pan to 2 lines steps - * for NV12. - */ - info->fix = sh_mobile_lcdc_fix; - info->fix.smem_len = max_size * 2 * cfg->bpp / 8; - if (cfg->nonstd && cfg->bpp == 12) - info->fix.ypanstep = 2; - /* Create the mode list. */ if (cfg->lcd_cfg == NULL) { mode = &default_720p; @@ -1509,19 +1602,38 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, */ var = &info->var; fb_videomode_to_var(var, mode); - var->bits_per_pixel = cfg->bpp; var->width = cfg->lcd_size_cfg.width; var->height = cfg->lcd_size_cfg.height; var->yres_virtual = var->yres * 2; var->activate = FB_ACTIVATE_NOW; + switch (cfg->fourcc) { + case V4L2_PIX_FMT_RGB565: + var->bits_per_pixel = 16; + break; + case V4L2_PIX_FMT_BGR24: + var->bits_per_pixel = 24; + break; + case V4L2_PIX_FMT_BGR32: + var->bits_per_pixel = 32; + break; + default: + var->grayscale = cfg->fourcc; + break; + } + + /* Make sure the memory size check won't fail. smem_len is initialized + * later based on var. + */ + info->fix.smem_len = UINT_MAX; ret = sh_mobile_check_var(var, info); if (ret) return ret; + max_size = max_size * var->bits_per_pixel / 8 * 2; + /* Allocate frame buffer memory and color map. */ - buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle, - GFP_KERNEL); + buf = dma_alloc_coherent(dev, max_size, &ch->dma_handle, GFP_KERNEL); if (!buf) { dev_err(dev, "unable to allocate buffer\n"); return -ENOMEM; @@ -1530,16 +1642,27 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); if (ret < 0) { dev_err(dev, "unable to allocate cmap\n"); - dma_free_coherent(dev, info->fix.smem_len, - buf, ch->dma_handle); + dma_free_coherent(dev, max_size, buf, ch->dma_handle); return ret; } + /* Initialize fixed screen information. Restrict pan to 2 lines steps + * for NV12 and NV21. + */ + info->fix = sh_mobile_lcdc_fix; info->fix.smem_start = ch->dma_handle; - if (var->nonstd) + info->fix.smem_len = max_size; + if (cfg->fourcc == V4L2_PIX_FMT_NV12 || + cfg->fourcc == V4L2_PIX_FMT_NV21) + info->fix.ypanstep = 2; + + if (sh_mobile_format_is_yuv(var)) { info->fix.line_length = var->xres; - else - info->fix.line_length = var->xres * (cfg->bpp / 8); + info->fix.visual = FB_VISUAL_FOURCC; + } else { + info->fix.line_length = var->xres * var->bits_per_pixel / 8; + info->fix.visual = FB_VISUAL_TRUECOLOR; + } info->screen_base = buf; info->device = dev; @@ -1626,9 +1749,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) goto err1; } - /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */ + /* for dual channel LCDC (MAIN + SUB) force shared format setting */ if (num_channels == 2) - priv->forced_bpp = pdata->ch[0].bpp; + priv->forced_fourcc = pdata->ch[0].fourcc; priv->base = ioremap_nocache(res->start, resource_size(res)); if (!priv->base) @@ -1675,13 +1798,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) if (error < 0) goto err1; - dev_info(info->dev, - "registered %s/%s as %dx%d %dbpp.\n", - pdev->name, - (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? - "mainlcd" : "sublcd", - info->var.xres, info->var.yres, - ch->cfg.bpp); + dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n", + pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? + "mainlcd" : "sublcd", info->var.xres, info->var.yres, + info->var.bits_per_pixel); /* deferred io mode: disable clock to save power */ if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) @@ -1709,18 +1829,7 @@ static struct platform_driver sh_mobile_lcdc_driver = { .remove = sh_mobile_lcdc_remove, }; -static int __init sh_mobile_lcdc_init(void) -{ - return platform_driver_register(&sh_mobile_lcdc_driver); -} - -static void __exit sh_mobile_lcdc_exit(void) -{ - platform_driver_unregister(&sh_mobile_lcdc_driver); -} - -module_init(sh_mobile_lcdc_init); -module_exit(sh_mobile_lcdc_exit); +module_platform_driver(sh_mobile_lcdc_driver); MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index 4d63490209cd..f45d83ecfd21 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c @@ -679,18 +679,7 @@ static struct platform_driver sh_mobile_meram_driver = { .remove = sh_mobile_meram_remove, }; -static int __init sh_mobile_meram_init(void) -{ - return platform_driver_register(&sh_mobile_meram_driver); -} - -static void __exit sh_mobile_meram_exit(void) -{ - platform_driver_unregister(&sh_mobile_meram_driver); -} - -module_init(sh_mobile_meram_init); -module_exit(sh_mobile_meram_exit); +module_platform_driver(sh_mobile_meram_driver); MODULE_DESCRIPTION("SuperH Mobile MERAM driver"); MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama"); diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index a78254cf8e83..3690effbedcc 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -2230,18 +2230,7 @@ static struct platform_driver sm501fb_driver = { }, }; -static int __devinit sm501fb_init(void) -{ - return platform_driver_register(&sm501fb_driver); -} - -static void __exit sm501fb_cleanup(void) -{ - platform_driver_unregister(&sm501fb_driver); -} - -module_init(sm501fb_init); -module_exit(sm501fb_cleanup); +module_platform_driver(sm501fb_driver); module_param_named(mode, fb_mode, charp, 0); MODULE_PARM_DESC(mode, diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c index 3c22994ea31a..ccbfef5e828f 100644 --- a/drivers/video/smscufx.c +++ b/drivers/video/smscufx.c @@ -130,8 +130,8 @@ static struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); /* module options */ -static int console; /* Optionally allow fbcon to consume first framebuffer */ -static int fb_defio = true; /* Optionally enable fb_defio mmap support */ +static bool console; /* Optionally allow fbcon to consume first framebuffer */ +static bool fb_defio = true; /* Optionally enable fb_defio mmap support */ /* ufx keeps a list of urbs for efficient bulk transfers */ static void ufx_urb_completion(struct urb *urb); diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 2301c275d63a..111fb32e8769 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -93,11 +93,11 @@ /* initialized by setup */ -static int vgapass; /* enable VGA passthrough cable */ +static bool vgapass; /* enable VGA passthrough cable */ static int mem; /* mem size in MB, 0 = autodetect */ -static int clipping = 1; /* use clipping (slower, safer) */ +static bool clipping = 1; /* use clipping (slower, safer) */ static int gfxclk; /* force FBI freq in Mhz . Dangerous */ -static int slowpci; /* slow PCI settings */ +static bool slowpci; /* slow PCI settings */ /* Possible default video modes: 800x600@60, 640x480@75, 1024x768@76, 640x480@60 diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index a99b994c9b6b..e026724a3a56 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -169,7 +169,7 @@ static int nowrap = 1; /* not implemented (yet) */ static int hwcursor = 1; static char *mode_option __devinitdata; /* mtrr option */ -static int nomtrr __devinitdata; +static bool nomtrr __devinitdata; /* ------------------------------------------------------------------------- * Hardware-specific funcions diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 1f868d0187a2..a19773149bd7 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -69,9 +69,9 @@ static struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); /* module options */ -static int console = 1; /* Allow fbcon to open framebuffer */ -static int fb_defio = 1; /* Detect mmap writes using page faults */ -static int shadow = 1; /* Optionally disable shadow framebuffer */ +static bool console = 1; /* Allow fbcon to open framebuffer */ +static bool fb_defio = 1; /* Detect mmap writes using page faults */ +static bool shadow = 1; /* Optionally disable shadow framebuffer */ /* dlfb keeps a list of urbs for efficient bulk transfers */ static void dlfb_urb_completion(struct urb *urb); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 7f8472cc993b..e7f69ef572dc 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -44,11 +44,11 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = { }; static int mtrr __devinitdata = 3; /* enable mtrr by default */ -static int blank = 1; /* enable blanking by default */ +static bool blank = 1; /* enable blanking by default */ static int ypan = 1; /* 0: scroll, 1: ypan, 2: ywrap */ static bool pmi_setpal __devinitdata = true; /* use PMI for palette changes */ -static int nocrtc __devinitdata; /* ignore CRTC settings */ -static int noedid __devinitdata; /* don't try DDC transfers */ +static bool nocrtc __devinitdata; /* ignore CRTC settings */ +static bool noedid __devinitdata; /* don't try DDC transfers */ static int vram_remap __devinitdata; /* set amt. of memory to be used */ static int vram_total __devinitdata; /* set total amount of memory */ static u16 maxclk __devinitdata; /* maximum pixel clock */ diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index bf2f78065cf9..501a922aa9dc 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -110,7 +110,7 @@ static struct fb_fix_screeninfo vfb_fix __devinitdata = { .accel = FB_ACCEL_NONE, }; -static int vfb_enable __initdata = 0; /* disabled by default */ +static bool vfb_enable __initdata = 0; /* disabled by default */ module_param(vfb_enable, bool, 0); static int vfb_check_var(struct fb_var_screeninfo *var, diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 777c21dd7a6b..2a5fe6ede845 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c @@ -457,18 +457,7 @@ static struct platform_driver vt8500lcd_driver = { }, }; -static int __init vt8500lcd_init(void) -{ - return platform_driver_register(&vt8500lcd_driver); -} - -static void __exit vt8500lcd_exit(void) -{ - platform_driver_unregister(&vt8500lcd_driver); -} - -module_init(vt8500lcd_init); -module_exit(vt8500lcd_exit); +module_platform_driver(vt8500lcd_driver); MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 2375e5bbf572..90a2e30272ad 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -1620,18 +1620,7 @@ static struct platform_driver w100fb_driver = { }, }; -int __init w100fb_init(void) -{ - return platform_driver_register(&w100fb_driver); -} - -void __exit w100fb_cleanup(void) -{ - platform_driver_unregister(&w100fb_driver); -} - -module_init(w100fb_init); -module_exit(w100fb_cleanup); +module_platform_driver(w100fb_driver); MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c index 96e34a569169..c8703bd61b74 100644 --- a/drivers/video/wm8505fb.c +++ b/drivers/video/wm8505fb.c @@ -404,18 +404,7 @@ static struct platform_driver wm8505fb_driver = { }, }; -static int __init wm8505fb_init(void) -{ - return platform_driver_register(&wm8505fb_driver); -} - -static void __exit wm8505fb_exit(void) -{ - platform_driver_unregister(&wm8505fb_driver); -} - -module_init(wm8505fb_init); -module_exit(wm8505fb_exit); +module_platform_driver(wm8505fb_driver); MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); diff --git a/drivers/video/wmt_ge_rops.c b/drivers/video/wmt_ge_rops.c index 45832b7ef7d2..55be3865015b 100644 --- a/drivers/video/wmt_ge_rops.c +++ b/drivers/video/wmt_ge_rops.c @@ -167,18 +167,7 @@ static struct platform_driver wmt_ge_rops_driver = { }, }; -static int __init wmt_ge_rops_init(void) -{ - return platform_driver_register(&wmt_ge_rops_driver); -} - -static void __exit wmt_ge_rops_exit(void) -{ - platform_driver_unregister(&wmt_ge_rops_driver); -} - -module_init(wmt_ge_rops_init); -module_exit(wmt_ge_rops_exit); +module_platform_driver(wmt_ge_rops_driver); MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com"); MODULE_DESCRIPTION("Accelerators for raster operations using " diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index fcb6cd90f64d..18084525402a 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -511,25 +511,7 @@ static struct platform_driver xilinxfb_of_driver = { }, }; - -/* --------------------------------------------------------------------- - * Module setup and teardown - */ - -static int __init -xilinxfb_init(void) -{ - return platform_driver_register(&xilinxfb_of_driver); -} - -static void __exit -xilinxfb_cleanup(void) -{ - platform_driver_unregister(&xilinxfb_of_driver); -} - -module_init(xilinxfb_init); -module_exit(xilinxfb_cleanup); +module_platform_driver(xilinxfb_of_driver); MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); MODULE_DESCRIPTION("Xilinx TFT frame buffer driver"); diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index d4d8d1fdccc4..e45ca2b4bfbe 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -100,7 +100,7 @@ MODULE_PARM_DESC(f71862fg_pin, "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63" " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")"); -static int nowayout = WATCHDOG_NOWAYOUT; +static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0444); MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index eed5436ffb51..20feb4d3d791 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -55,7 +55,7 @@ module_param(timeout, ushort, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in ticks. (0<timeout<65536, default=65535)"); -static int reset = 1; +static bool reset = 1; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset"); diff --git a/drivers/xen/biomerge.c b/drivers/xen/biomerge.c index ba6eda4b5143..0edb91c0de6b 100644 --- a/drivers/xen/biomerge.c +++ b/drivers/xen/biomerge.c @@ -1,5 +1,6 @@ #include <linux/bio.h> #include <linux/io.h> +#include <linux/export.h> #include <xen/page.h> bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, @@ -11,3 +12,4 @@ bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) && ((mfn1 == mfn2) || ((mfn1+1) == mfn2)); } +EXPORT_SYMBOL(xen_biovec_phys_mergeable); diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index 3832e303c33a..596e6a7b17d6 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c @@ -221,7 +221,7 @@ static int register_balloon(struct device *dev) { int i, error; - error = bus_register(&balloon_subsys); + error = subsys_system_register(&balloon_subsys, NULL); if (error) return error; diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c index 52fed16d8701..30d7be026c18 100644 --- a/drivers/xen/xen-pciback/conf_space.c +++ b/drivers/xen/xen-pciback/conf_space.c @@ -16,7 +16,7 @@ #include "conf_space.h" #include "conf_space_quirks.h" -static int permissive; +static bool permissive; module_param(permissive, bool, 0644); /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word, diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index 8e1c44d8ab46..d5dcf8d5d3d9 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c @@ -16,7 +16,7 @@ #define INVALID_EVTCHN_IRQ (-1) struct workqueue_struct *xen_pcibk_wq; -static int __read_mostly passthrough; +static bool __read_mostly passthrough; module_param(passthrough, bool, S_IRUGO); MODULE_PARM_DESC(passthrough, "Option to specify how to export PCI topology to guest:\n"\ diff --git a/firmware/Makefile b/firmware/Makefile index 5f43bfba3c7a..0d15a3d113a2 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -82,7 +82,6 @@ fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \ fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \ advansys/3550.bin advansys/38C0800.bin -fw-shipped-$(CONFIG_SCSI_ISCI) += isci/isci_firmware.bin fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \ qlogic/12160.bin fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin diff --git a/firmware/isci/isci_firmware.bin.ihex b/firmware/isci/isci_firmware.bin.ihex deleted file mode 100644 index 2e6619570072..000000000000 --- a/firmware/isci/isci_firmware.bin.ihex +++ /dev/null @@ -1,16 +0,0 @@ -:10000000495343554F454D42E80018100002000087 -:1000100000000000000000000101000000000000DE -:10002000FFFFCF5F0100000008DD0B0000FC0F00A8 -:10003000097C0B006EFC0A00FFFFCF5F010000008F -:1000400008DD0B0000FC0F00097C0B006EFC0A00B1 -:10005000FFFFCF5F0100000008DD0B0000FC0F0078 -:10006000097C0B006EFC0A00FFFFCF5F010000005F -:1000700008DD0B0000FC0F00097C0B006EFC0A0081 -:100080000101000000000000FFFFCF5F0200000040 -:1000900008DD0B0000FC0F00097C0B006EFC0A0061 -:1000A000FFFFCF5F0200000008DD0B0000FC0F0027 -:1000B000097C0B006EFC0A00FFFFCF5F020000000E -:1000C00008DD0B0000FC0F00097C0B006EFC0A0031 -:1000D000FFFFCF5F0200000008DD0B0000FC0F00F7 -:0800E000097C0B006EFC0A0014 -:00000001FF @@ -476,14 +476,21 @@ static void kiocb_batch_init(struct kiocb_batch *batch, long total) batch->count = total; } -static void kiocb_batch_free(struct kiocb_batch *batch) +static void kiocb_batch_free(struct kioctx *ctx, struct kiocb_batch *batch) { struct kiocb *req, *n; + if (list_empty(&batch->head)) + return; + + spin_lock_irq(&ctx->ctx_lock); list_for_each_entry_safe(req, n, &batch->head, ki_batch) { list_del(&req->ki_batch); + list_del(&req->ki_list); kmem_cache_free(kiocb_cachep, req); + ctx->reqs_active--; } + spin_unlock_irq(&ctx->ctx_lock); } /* @@ -1742,7 +1749,7 @@ long do_io_submit(aio_context_t ctx_id, long nr, } blk_finish_plug(&plug); - kiocb_batch_free(&batch); + kiocb_batch_free(ctx, &batch); put_ioctx(ctx); return i ? i : ret; } diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 9ef5b2914407..da8876d38a7b 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -76,7 +76,7 @@ static int autofs4_write(struct autofs_sb_info *sbi, data += wr; bytes -= wr; } - mutex_lock(&sbi->pipe_mutex); + mutex_unlock(&sbi->pipe_mutex); set_fs(fs); diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig index ecb9fd3be143..d33f01c08b60 100644 --- a/fs/btrfs/Kconfig +++ b/fs/btrfs/Kconfig @@ -31,3 +31,22 @@ config BTRFS_FS_POSIX_ACL Linux website <http://acl.bestbits.at/>. If you don't know what Access Control Lists are, say N + +config BTRFS_FS_CHECK_INTEGRITY + bool "Btrfs with integrity check tool compiled in (DANGEROUS)" + depends on BTRFS_FS + help + Adds code that examines all block write requests (including + writes of the super block). The goal is to verify that the + state of the filesystem on disk is always consistent, i.e., + after a power-loss or kernel panic event the filesystem is + in a consistent state. + + If the integrity check tool is included and activated in + the mount options, plenty of kernel memory is used, and + plenty of additional CPU cycles are spent. Enabling this + functionality is not intended for normal use. + + In most cases, unless you are a btrfs developer who needs + to verify the integrity of (super)-block write requests + during the run of a regression test, say N diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index c0ddfd29c5e5..0c4fa2befae7 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -8,6 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ export.o tree-log.o free-space-cache.o zlib.o lzo.o \ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ - reada.o backref.o + reada.o backref.o ulist.o btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o +btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 22c64fff1bd5..b9a843226de8 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -19,18 +19,789 @@ #include "ctree.h" #include "disk-io.h" #include "backref.h" +#include "ulist.h" +#include "transaction.h" +#include "delayed-ref.h" -struct __data_ref { +/* + * this structure records all encountered refs on the way up to the root + */ +struct __prelim_ref { struct list_head list; - u64 inum; - u64 root; - u64 extent_data_item_offset; + u64 root_id; + struct btrfs_key key; + int level; + int count; + u64 parent; + u64 wanted_disk_byte; }; -struct __shared_ref { - struct list_head list; +static int __add_prelim_ref(struct list_head *head, u64 root_id, + struct btrfs_key *key, int level, u64 parent, + u64 wanted_disk_byte, int count) +{ + struct __prelim_ref *ref; + + /* in case we're adding delayed refs, we're holding the refs spinlock */ + ref = kmalloc(sizeof(*ref), GFP_ATOMIC); + if (!ref) + return -ENOMEM; + + ref->root_id = root_id; + if (key) + ref->key = *key; + else + memset(&ref->key, 0, sizeof(ref->key)); + + ref->level = level; + ref->count = count; + ref->parent = parent; + ref->wanted_disk_byte = wanted_disk_byte; + list_add_tail(&ref->list, head); + + return 0; +} + +static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, + struct ulist *parents, + struct extent_buffer *eb, int level, + u64 wanted_objectid, u64 wanted_disk_byte) +{ + int ret; + int slot; + struct btrfs_file_extent_item *fi; + struct btrfs_key key; u64 disk_byte; -}; + +add_parent: + ret = ulist_add(parents, eb->start, 0, GFP_NOFS); + if (ret < 0) + return ret; + + if (level != 0) + return 0; + + /* + * if the current leaf is full with EXTENT_DATA items, we must + * check the next one if that holds a reference as well. + * ref->count cannot be used to skip this check. + * repeat this until we don't find any additional EXTENT_DATA items. + */ + while (1) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + return ret; + if (ret) + return 0; + + eb = path->nodes[0]; + for (slot = 0; slot < btrfs_header_nritems(eb); ++slot) { + btrfs_item_key_to_cpu(eb, &key, slot); + if (key.objectid != wanted_objectid || + key.type != BTRFS_EXTENT_DATA_KEY) + return 0; + fi = btrfs_item_ptr(eb, slot, + struct btrfs_file_extent_item); + disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); + if (disk_byte == wanted_disk_byte) + goto add_parent; + } + } + + return 0; +} + +/* + * resolve an indirect backref in the form (root_id, key, level) + * to a logical address + */ +static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, + struct __prelim_ref *ref, + struct ulist *parents) +{ + struct btrfs_path *path; + struct btrfs_root *root; + struct btrfs_key root_key; + struct btrfs_key key = {0}; + struct extent_buffer *eb; + int ret = 0; + int root_level; + int level = ref->level; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + root_key.objectid = ref->root_id; + root_key.type = BTRFS_ROOT_ITEM_KEY; + root_key.offset = (u64)-1; + root = btrfs_read_fs_root_no_name(fs_info, &root_key); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto out; + } + + rcu_read_lock(); + root_level = btrfs_header_level(root->node); + rcu_read_unlock(); + + if (root_level + 1 == level) + goto out; + + path->lowest_level = level; + ret = btrfs_search_slot(NULL, root, &ref->key, path, 0, 0); + pr_debug("search slot in root %llu (level %d, ref count %d) returned " + "%d for key (%llu %u %llu)\n", + (unsigned long long)ref->root_id, level, ref->count, ret, + (unsigned long long)ref->key.objectid, ref->key.type, + (unsigned long long)ref->key.offset); + if (ret < 0) + goto out; + + eb = path->nodes[level]; + if (!eb) { + WARN_ON(1); + ret = 1; + goto out; + } + + if (level == 0) { + if (ret == 1 && path->slots[0] >= btrfs_header_nritems(eb)) { + ret = btrfs_next_leaf(root, path); + if (ret) + goto out; + eb = path->nodes[0]; + } + + btrfs_item_key_to_cpu(eb, &key, path->slots[0]); + } + + /* the last two parameters will only be used for level == 0 */ + ret = add_all_parents(root, path, parents, eb, level, key.objectid, + ref->wanted_disk_byte); +out: + btrfs_free_path(path); + return ret; +} + +/* + * resolve all indirect backrefs from the list + */ +static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, + struct list_head *head) +{ + int err; + int ret = 0; + struct __prelim_ref *ref; + struct __prelim_ref *ref_safe; + struct __prelim_ref *new_ref; + struct ulist *parents; + struct ulist_node *node; + + parents = ulist_alloc(GFP_NOFS); + if (!parents) + return -ENOMEM; + + /* + * _safe allows us to insert directly after the current item without + * iterating over the newly inserted items. + * we're also allowed to re-assign ref during iteration. + */ + list_for_each_entry_safe(ref, ref_safe, head, list) { + if (ref->parent) /* already direct */ + continue; + if (ref->count == 0) + continue; + err = __resolve_indirect_ref(fs_info, ref, parents); + if (err) { + if (ret == 0) + ret = err; + continue; + } + + /* we put the first parent into the ref at hand */ + node = ulist_next(parents, NULL); + ref->parent = node ? node->val : 0; + + /* additional parents require new refs being added here */ + while ((node = ulist_next(parents, node))) { + new_ref = kmalloc(sizeof(*new_ref), GFP_NOFS); + if (!new_ref) { + ret = -ENOMEM; + break; + } + memcpy(new_ref, ref, sizeof(*ref)); + new_ref->parent = node->val; + list_add(&new_ref->list, &ref->list); + } + ulist_reinit(parents); + } + + ulist_free(parents); + return ret; +} + +/* + * merge two lists of backrefs and adjust counts accordingly + * + * mode = 1: merge identical keys, if key is set + * mode = 2: merge identical parents + */ +static int __merge_refs(struct list_head *head, int mode) +{ + struct list_head *pos1; + + list_for_each(pos1, head) { + struct list_head *n2; + struct list_head *pos2; + struct __prelim_ref *ref1; + + ref1 = list_entry(pos1, struct __prelim_ref, list); + + if (mode == 1 && ref1->key.type == 0) + continue; + for (pos2 = pos1->next, n2 = pos2->next; pos2 != head; + pos2 = n2, n2 = pos2->next) { + struct __prelim_ref *ref2; + + ref2 = list_entry(pos2, struct __prelim_ref, list); + + if (mode == 1) { + if (memcmp(&ref1->key, &ref2->key, + sizeof(ref1->key)) || + ref1->level != ref2->level || + ref1->root_id != ref2->root_id) + continue; + ref1->count += ref2->count; + } else { + if (ref1->parent != ref2->parent) + continue; + ref1->count += ref2->count; + } + list_del(&ref2->list); + kfree(ref2); + } + + } + return 0; +} + +/* + * add all currently queued delayed refs from this head whose seq nr is + * smaller or equal that seq to the list + */ +static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, + struct btrfs_key *info_key, + struct list_head *prefs) +{ + struct btrfs_delayed_extent_op *extent_op = head->extent_op; + struct rb_node *n = &head->node.rb_node; + int sgn; + int ret; + + if (extent_op && extent_op->update_key) + btrfs_disk_key_to_cpu(info_key, &extent_op->key); + + while ((n = rb_prev(n))) { + struct btrfs_delayed_ref_node *node; + node = rb_entry(n, struct btrfs_delayed_ref_node, + rb_node); + if (node->bytenr != head->node.bytenr) + break; + WARN_ON(node->is_head); + + if (node->seq > seq) + continue; + + switch (node->action) { + case BTRFS_ADD_DELAYED_EXTENT: + case BTRFS_UPDATE_DELAYED_HEAD: + WARN_ON(1); + continue; + case BTRFS_ADD_DELAYED_REF: + sgn = 1; + break; + case BTRFS_DROP_DELAYED_REF: + sgn = -1; + break; + default: + BUG_ON(1); + } + switch (node->type) { + case BTRFS_TREE_BLOCK_REF_KEY: { + struct btrfs_delayed_tree_ref *ref; + + ref = btrfs_delayed_node_to_tree_ref(node); + ret = __add_prelim_ref(prefs, ref->root, info_key, + ref->level + 1, 0, node->bytenr, + node->ref_mod * sgn); + break; + } + case BTRFS_SHARED_BLOCK_REF_KEY: { + struct btrfs_delayed_tree_ref *ref; + + ref = btrfs_delayed_node_to_tree_ref(node); + ret = __add_prelim_ref(prefs, ref->root, info_key, + ref->level + 1, ref->parent, + node->bytenr, + node->ref_mod * sgn); + break; + } + case BTRFS_EXTENT_DATA_REF_KEY: { + struct btrfs_delayed_data_ref *ref; + struct btrfs_key key; + + ref = btrfs_delayed_node_to_data_ref(node); + + key.objectid = ref->objectid; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = ref->offset; + ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0, + node->bytenr, + node->ref_mod * sgn); + break; + } + case BTRFS_SHARED_DATA_REF_KEY: { + struct btrfs_delayed_data_ref *ref; + struct btrfs_key key; + + ref = btrfs_delayed_node_to_data_ref(node); + + key.objectid = ref->objectid; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = ref->offset; + ret = __add_prelim_ref(prefs, ref->root, &key, 0, + ref->parent, node->bytenr, + node->ref_mod * sgn); + break; + } + default: + WARN_ON(1); + } + BUG_ON(ret); + } + + return 0; +} + +/* + * add all inline backrefs for bytenr to the list + */ +static int __add_inline_refs(struct btrfs_fs_info *fs_info, + struct btrfs_path *path, u64 bytenr, + struct btrfs_key *info_key, int *info_level, + struct list_head *prefs) +{ + int ret; + int slot; + struct extent_buffer *leaf; + struct btrfs_key key; + unsigned long ptr; + unsigned long end; + struct btrfs_extent_item *ei; + u64 flags; + u64 item_size; + + /* + * enumerate all inline refs + */ + leaf = path->nodes[0]; + slot = path->slots[0] - 1; + + item_size = btrfs_item_size_nr(leaf, slot); + BUG_ON(item_size < sizeof(*ei)); + + ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); + flags = btrfs_extent_flags(leaf, ei); + + ptr = (unsigned long)(ei + 1); + end = (unsigned long)ei + item_size; + + if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { + struct btrfs_tree_block_info *info; + struct btrfs_disk_key disk_key; + + info = (struct btrfs_tree_block_info *)ptr; + *info_level = btrfs_tree_block_level(leaf, info); + btrfs_tree_block_key(leaf, info, &disk_key); + btrfs_disk_key_to_cpu(info_key, &disk_key); + ptr += sizeof(struct btrfs_tree_block_info); + BUG_ON(ptr > end); + } else { + BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA)); + } + + while (ptr < end) { + struct btrfs_extent_inline_ref *iref; + u64 offset; + int type; + + iref = (struct btrfs_extent_inline_ref *)ptr; + type = btrfs_extent_inline_ref_type(leaf, iref); + offset = btrfs_extent_inline_ref_offset(leaf, iref); + + switch (type) { + case BTRFS_SHARED_BLOCK_REF_KEY: + ret = __add_prelim_ref(prefs, 0, info_key, + *info_level + 1, offset, + bytenr, 1); + break; + case BTRFS_SHARED_DATA_REF_KEY: { + struct btrfs_shared_data_ref *sdref; + int count; + + sdref = (struct btrfs_shared_data_ref *)(iref + 1); + count = btrfs_shared_data_ref_count(leaf, sdref); + ret = __add_prelim_ref(prefs, 0, NULL, 0, offset, + bytenr, count); + break; + } + case BTRFS_TREE_BLOCK_REF_KEY: + ret = __add_prelim_ref(prefs, offset, info_key, + *info_level + 1, 0, bytenr, 1); + break; + case BTRFS_EXTENT_DATA_REF_KEY: { + struct btrfs_extent_data_ref *dref; + int count; + u64 root; + + dref = (struct btrfs_extent_data_ref *)(&iref->offset); + count = btrfs_extent_data_ref_count(leaf, dref); + key.objectid = btrfs_extent_data_ref_objectid(leaf, + dref); + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = btrfs_extent_data_ref_offset(leaf, dref); + root = btrfs_extent_data_ref_root(leaf, dref); + ret = __add_prelim_ref(prefs, root, &key, 0, 0, bytenr, + count); + break; + } + default: + WARN_ON(1); + } + BUG_ON(ret); + ptr += btrfs_extent_inline_ref_size(type); + } + + return 0; +} + +/* + * add all non-inline backrefs for bytenr to the list + */ +static int __add_keyed_refs(struct btrfs_fs_info *fs_info, + struct btrfs_path *path, u64 bytenr, + struct btrfs_key *info_key, int info_level, + struct list_head *prefs) +{ + struct btrfs_root *extent_root = fs_info->extent_root; + int ret; + int slot; + struct extent_buffer *leaf; + struct btrfs_key key; + + while (1) { + ret = btrfs_next_item(extent_root, path); + if (ret < 0) + break; + if (ret) { + ret = 0; + break; + } + + slot = path->slots[0]; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &key, slot); + + if (key.objectid != bytenr) + break; + if (key.type < BTRFS_TREE_BLOCK_REF_KEY) + continue; + if (key.type > BTRFS_SHARED_DATA_REF_KEY) + break; + + switch (key.type) { + case BTRFS_SHARED_BLOCK_REF_KEY: + ret = __add_prelim_ref(prefs, 0, info_key, + info_level + 1, key.offset, + bytenr, 1); + break; + case BTRFS_SHARED_DATA_REF_KEY: { + struct btrfs_shared_data_ref *sdref; + int count; + + sdref = btrfs_item_ptr(leaf, slot, + struct btrfs_shared_data_ref); + count = btrfs_shared_data_ref_count(leaf, sdref); + ret = __add_prelim_ref(prefs, 0, NULL, 0, key.offset, + bytenr, count); + break; + } + case BTRFS_TREE_BLOCK_REF_KEY: + ret = __add_prelim_ref(prefs, key.offset, info_key, + info_level + 1, 0, bytenr, 1); + break; + case BTRFS_EXTENT_DATA_REF_KEY: { + struct btrfs_extent_data_ref *dref; + int count; + u64 root; + + dref = btrfs_item_ptr(leaf, slot, + struct btrfs_extent_data_ref); + count = btrfs_extent_data_ref_count(leaf, dref); + key.objectid = btrfs_extent_data_ref_objectid(leaf, + dref); + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = btrfs_extent_data_ref_offset(leaf, dref); + root = btrfs_extent_data_ref_root(leaf, dref); + ret = __add_prelim_ref(prefs, root, &key, 0, 0, + bytenr, count); + break; + } + default: + WARN_ON(1); + } + BUG_ON(ret); + } + + return ret; +} + +/* + * this adds all existing backrefs (inline backrefs, backrefs and delayed + * refs) for the given bytenr to the refs list, merges duplicates and resolves + * indirect refs to their parent bytenr. + * When roots are found, they're added to the roots list + * + * FIXME some caching might speed things up + */ +static int find_parent_nodes(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, u64 bytenr, + u64 seq, struct ulist *refs, struct ulist *roots) +{ + struct btrfs_key key; + struct btrfs_path *path; + struct btrfs_key info_key = { 0 }; + struct btrfs_delayed_ref_root *delayed_refs = NULL; + struct btrfs_delayed_ref_head *head = NULL; + int info_level = 0; + int ret; + struct list_head prefs_delayed; + struct list_head prefs; + struct __prelim_ref *ref; + + INIT_LIST_HEAD(&prefs); + INIT_LIST_HEAD(&prefs_delayed); + + key.objectid = bytenr; + key.type = BTRFS_EXTENT_ITEM_KEY; + key.offset = (u64)-1; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + /* + * grab both a lock on the path and a lock on the delayed ref head. + * We need both to get a consistent picture of how the refs look + * at a specified point in time + */ +again: + ret = btrfs_search_slot(trans, fs_info->extent_root, &key, path, 0, 0); + if (ret < 0) + goto out; + BUG_ON(ret == 0); + + /* + * look if there are updates for this ref queued and lock the head + */ + delayed_refs = &trans->transaction->delayed_refs; + spin_lock(&delayed_refs->lock); + head = btrfs_find_delayed_ref_head(trans, bytenr); + if (head) { + if (!mutex_trylock(&head->mutex)) { + atomic_inc(&head->node.refs); + spin_unlock(&delayed_refs->lock); + + btrfs_release_path(path); + + /* + * Mutex was contended, block until it's + * released and try again + */ + mutex_lock(&head->mutex); + mutex_unlock(&head->mutex); + btrfs_put_delayed_ref(&head->node); + goto again; + } + ret = __add_delayed_refs(head, seq, &info_key, &prefs_delayed); + if (ret) + goto out; + } + spin_unlock(&delayed_refs->lock); + + if (path->slots[0]) { + struct extent_buffer *leaf; + int slot; + + leaf = path->nodes[0]; + slot = path->slots[0] - 1; + btrfs_item_key_to_cpu(leaf, &key, slot); + if (key.objectid == bytenr && + key.type == BTRFS_EXTENT_ITEM_KEY) { + ret = __add_inline_refs(fs_info, path, bytenr, + &info_key, &info_level, &prefs); + if (ret) + goto out; + ret = __add_keyed_refs(fs_info, path, bytenr, &info_key, + info_level, &prefs); + if (ret) + goto out; + } + } + btrfs_release_path(path); + + /* + * when adding the delayed refs above, the info_key might not have + * been known yet. Go over the list and replace the missing keys + */ + list_for_each_entry(ref, &prefs_delayed, list) { + if ((ref->key.offset | ref->key.type | ref->key.objectid) == 0) + memcpy(&ref->key, &info_key, sizeof(ref->key)); + } + list_splice_init(&prefs_delayed, &prefs); + + ret = __merge_refs(&prefs, 1); + if (ret) + goto out; + + ret = __resolve_indirect_refs(fs_info, &prefs); + if (ret) + goto out; + + ret = __merge_refs(&prefs, 2); + if (ret) + goto out; + + while (!list_empty(&prefs)) { + ref = list_first_entry(&prefs, struct __prelim_ref, list); + list_del(&ref->list); + if (ref->count < 0) + WARN_ON(1); + if (ref->count && ref->root_id && ref->parent == 0) { + /* no parent == root of tree */ + ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS); + BUG_ON(ret < 0); + } + if (ref->count && ref->parent) { + ret = ulist_add(refs, ref->parent, 0, GFP_NOFS); + BUG_ON(ret < 0); + } + kfree(ref); + } + +out: + if (head) + mutex_unlock(&head->mutex); + btrfs_free_path(path); + while (!list_empty(&prefs)) { + ref = list_first_entry(&prefs, struct __prelim_ref, list); + list_del(&ref->list); + kfree(ref); + } + while (!list_empty(&prefs_delayed)) { + ref = list_first_entry(&prefs_delayed, struct __prelim_ref, + list); + list_del(&ref->list); + kfree(ref); + } + + return ret; +} + +/* + * Finds all leafs with a reference to the specified combination of bytenr and + * offset. key_list_head will point to a list of corresponding keys (caller must + * free each list element). The leafs will be stored in the leafs ulist, which + * must be freed with ulist_free. + * + * returns 0 on success, <0 on error + */ +static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, u64 bytenr, + u64 num_bytes, u64 seq, struct ulist **leafs) +{ + struct ulist *tmp; + int ret; + + tmp = ulist_alloc(GFP_NOFS); + if (!tmp) + return -ENOMEM; + *leafs = ulist_alloc(GFP_NOFS); + if (!*leafs) { + ulist_free(tmp); + return -ENOMEM; + } + + ret = find_parent_nodes(trans, fs_info, bytenr, seq, *leafs, tmp); + ulist_free(tmp); + + if (ret < 0 && ret != -ENOENT) { + ulist_free(*leafs); + return ret; + } + + return 0; +} + +/* + * walk all backrefs for a given extent to find all roots that reference this + * extent. Walking a backref means finding all extents that reference this + * extent and in turn walk the backrefs of those, too. Naturally this is a + * recursive process, but here it is implemented in an iterative fashion: We + * find all referencing extents for the extent in question and put them on a + * list. In turn, we find all referencing extents for those, further appending + * to the list. The way we iterate the list allows adding more elements after + * the current while iterating. The process stops when we reach the end of the + * list. Found roots are added to the roots list. + * + * returns 0 on success, < 0 on error. + */ +int btrfs_find_all_roots(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, u64 bytenr, + u64 num_bytes, u64 seq, struct ulist **roots) +{ + struct ulist *tmp; + struct ulist_node *node = NULL; + int ret; + + tmp = ulist_alloc(GFP_NOFS); + if (!tmp) + return -ENOMEM; + *roots = ulist_alloc(GFP_NOFS); + if (!*roots) { + ulist_free(tmp); + return -ENOMEM; + } + + while (1) { + ret = find_parent_nodes(trans, fs_info, bytenr, seq, + tmp, *roots); + if (ret < 0 && ret != -ENOENT) { + ulist_free(tmp); + ulist_free(*roots); + return ret; + } + node = ulist_next(tmp, node); + if (!node) + break; + bytenr = node->val; + } + + ulist_free(tmp); + return 0; +} + static int __inode_info(u64 inum, u64 ioff, u8 key_type, struct btrfs_root *fs_root, struct btrfs_path *path, @@ -181,8 +952,11 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); if (found_key->type != BTRFS_EXTENT_ITEM_KEY || found_key->objectid > logical || - found_key->objectid + found_key->offset <= logical) + found_key->objectid + found_key->offset <= logical) { + pr_debug("logical %llu is not within any extent\n", + (unsigned long long)logical); return -ENOENT; + } eb = path->nodes[0]; item_size = btrfs_item_size_nr(eb, path->slots[0]); @@ -191,6 +965,13 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); flags = btrfs_extent_flags(eb, ei); + pr_debug("logical %llu is at position %llu within the extent (%llu " + "EXTENT_ITEM %llu) flags %#llx size %u\n", + (unsigned long long)logical, + (unsigned long long)(logical - found_key->objectid), + (unsigned long long)found_key->objectid, + (unsigned long long)found_key->offset, + (unsigned long long)flags, item_size); if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) return BTRFS_EXTENT_FLAG_TREE_BLOCK; if (flags & BTRFS_EXTENT_FLAG_DATA) @@ -287,128 +1068,11 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, return 0; } -static int __data_list_add(struct list_head *head, u64 inum, - u64 extent_data_item_offset, u64 root) -{ - struct __data_ref *ref; - - ref = kmalloc(sizeof(*ref), GFP_NOFS); - if (!ref) - return -ENOMEM; - - ref->inum = inum; - ref->extent_data_item_offset = extent_data_item_offset; - ref->root = root; - list_add_tail(&ref->list, head); - - return 0; -} - -static int __data_list_add_eb(struct list_head *head, struct extent_buffer *eb, - struct btrfs_extent_data_ref *dref) -{ - return __data_list_add(head, btrfs_extent_data_ref_objectid(eb, dref), - btrfs_extent_data_ref_offset(eb, dref), - btrfs_extent_data_ref_root(eb, dref)); -} - -static int __shared_list_add(struct list_head *head, u64 disk_byte) -{ - struct __shared_ref *ref; - - ref = kmalloc(sizeof(*ref), GFP_NOFS); - if (!ref) - return -ENOMEM; - - ref->disk_byte = disk_byte; - list_add_tail(&ref->list, head); - - return 0; -} - -static int __iter_shared_inline_ref_inodes(struct btrfs_fs_info *fs_info, - u64 logical, u64 inum, - u64 extent_data_item_offset, - u64 extent_offset, - struct btrfs_path *path, - struct list_head *data_refs, - iterate_extent_inodes_t *iterate, - void *ctx) -{ - u64 ref_root; - u32 item_size; - struct btrfs_key key; - struct extent_buffer *eb; - struct btrfs_extent_item *ei; - struct btrfs_extent_inline_ref *eiref; - struct __data_ref *ref; - int ret; - int type; - int last; - unsigned long ptr = 0; - - WARN_ON(!list_empty(data_refs)); - ret = extent_from_logical(fs_info, logical, path, &key); - if (ret & BTRFS_EXTENT_FLAG_DATA) - ret = -EIO; - if (ret < 0) - goto out; - - eb = path->nodes[0]; - ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); - item_size = btrfs_item_size_nr(eb, path->slots[0]); - - ret = 0; - ref_root = 0; - /* - * as done in iterate_extent_inodes, we first build a list of refs to - * iterate, then free the path and then iterate them to avoid deadlocks. - */ - do { - last = __get_extent_inline_ref(&ptr, eb, ei, item_size, - &eiref, &type); - if (last < 0) { - ret = last; - goto out; - } - if (type == BTRFS_TREE_BLOCK_REF_KEY || - type == BTRFS_SHARED_BLOCK_REF_KEY) { - ref_root = btrfs_extent_inline_ref_offset(eb, eiref); - ret = __data_list_add(data_refs, inum, - extent_data_item_offset, - ref_root); - } - } while (!ret && !last); - - btrfs_release_path(path); - - if (ref_root == 0) { - printk(KERN_ERR "btrfs: failed to find tree block ref " - "for shared data backref %llu\n", logical); - WARN_ON(1); - ret = -EIO; - } - -out: - while (!list_empty(data_refs)) { - ref = list_first_entry(data_refs, struct __data_ref, list); - list_del(&ref->list); - if (!ret) - ret = iterate(ref->inum, extent_offset + - ref->extent_data_item_offset, - ref->root, ctx); - kfree(ref); - } - - return ret; -} - -static int __iter_shared_inline_ref(struct btrfs_fs_info *fs_info, - u64 logical, u64 orig_extent_item_objectid, - u64 extent_offset, struct btrfs_path *path, - struct list_head *data_refs, - iterate_extent_inodes_t *iterate, - void *ctx) +static int iterate_leaf_refs(struct btrfs_fs_info *fs_info, + struct btrfs_path *path, u64 logical, + u64 orig_extent_item_objectid, + u64 extent_item_pos, u64 root, + iterate_extent_inodes_t *iterate, void *ctx) { u64 disk_byte; struct btrfs_key key; @@ -416,8 +1080,10 @@ static int __iter_shared_inline_ref(struct btrfs_fs_info *fs_info, struct extent_buffer *eb; int slot; int nritems; - int ret; - int found = 0; + int ret = 0; + int extent_type; + u64 data_offset; + u64 data_len; eb = read_tree_block(fs_info->tree_root, logical, fs_info->tree_root->leafsize, 0); @@ -435,149 +1101,99 @@ static int __iter_shared_inline_ref(struct btrfs_fs_info *fs_info, if (key.type != BTRFS_EXTENT_DATA_KEY) continue; fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); - if (!fi) { - free_extent_buffer(eb); - return -EIO; - } + extent_type = btrfs_file_extent_type(eb, fi); + if (extent_type == BTRFS_FILE_EXTENT_INLINE) + continue; + /* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */ disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); - if (disk_byte != orig_extent_item_objectid) { - if (found) - break; - else - continue; - } - ++found; - ret = __iter_shared_inline_ref_inodes(fs_info, logical, - key.objectid, - key.offset, - extent_offset, path, - data_refs, - iterate, ctx); - if (ret) - break; - } + if (disk_byte != orig_extent_item_objectid) + continue; - if (!found) { - printk(KERN_ERR "btrfs: failed to follow shared data backref " - "to parent %llu\n", logical); - WARN_ON(1); - ret = -EIO; + data_offset = btrfs_file_extent_offset(eb, fi); + data_len = btrfs_file_extent_num_bytes(eb, fi); + + if (extent_item_pos < data_offset || + extent_item_pos >= data_offset + data_len) + continue; + + pr_debug("ref for %llu resolved, key (%llu EXTEND_DATA %llu), " + "root %llu\n", orig_extent_item_objectid, + key.objectid, key.offset, root); + ret = iterate(key.objectid, + key.offset + (extent_item_pos - data_offset), + root, ctx); + if (ret) { + pr_debug("stopping iteration because ret=%d\n", ret); + break; + } } free_extent_buffer(eb); + return ret; } /* * calls iterate() for every inode that references the extent identified by - * the given parameters. will use the path given as a parameter and return it - * released. + * the given parameters. * when the iterator function returns a non-zero value, iteration stops. + * path is guaranteed to be in released state when iterate() is called. */ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - u64 extent_item_objectid, - u64 extent_offset, + u64 extent_item_objectid, u64 extent_item_pos, iterate_extent_inodes_t *iterate, void *ctx) { - unsigned long ptr = 0; - int last; int ret; - int type; - u64 logical; - u32 item_size; - struct btrfs_extent_inline_ref *eiref; - struct btrfs_extent_data_ref *dref; - struct extent_buffer *eb; - struct btrfs_extent_item *ei; - struct btrfs_key key; struct list_head data_refs = LIST_HEAD_INIT(data_refs); struct list_head shared_refs = LIST_HEAD_INIT(shared_refs); - struct __data_ref *ref_d; - struct __shared_ref *ref_s; - - eb = path->nodes[0]; - ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); - item_size = btrfs_item_size_nr(eb, path->slots[0]); - - /* first we iterate the inline refs, ... */ - do { - last = __get_extent_inline_ref(&ptr, eb, ei, item_size, - &eiref, &type); - if (last == -ENOENT) { - ret = 0; - break; - } - if (last < 0) { - ret = last; - break; - } + struct btrfs_trans_handle *trans; + struct ulist *refs; + struct ulist *roots; + struct ulist_node *ref_node = NULL; + struct ulist_node *root_node = NULL; + struct seq_list seq_elem; + struct btrfs_delayed_ref_root *delayed_refs; + + trans = btrfs_join_transaction(fs_info->extent_root); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + pr_debug("resolving all inodes for extent %llu\n", + extent_item_objectid); + + delayed_refs = &trans->transaction->delayed_refs; + spin_lock(&delayed_refs->lock); + btrfs_get_delayed_seq(delayed_refs, &seq_elem); + spin_unlock(&delayed_refs->lock); + + ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, + extent_item_pos, seq_elem.seq, + &refs); - if (type == BTRFS_EXTENT_DATA_REF_KEY) { - dref = (struct btrfs_extent_data_ref *)(&eiref->offset); - ret = __data_list_add_eb(&data_refs, eb, dref); - } else if (type == BTRFS_SHARED_DATA_REF_KEY) { - logical = btrfs_extent_inline_ref_offset(eb, eiref); - ret = __shared_list_add(&shared_refs, logical); - } - } while (!ret && !last); + if (ret) + goto out; - /* ... then we proceed to in-tree references and ... */ - while (!ret) { - ++path->slots[0]; - if (path->slots[0] > btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(fs_info->extent_root, path); - if (ret) { - if (ret == 1) - ret = 0; /* we're done */ - break; - } - eb = path->nodes[0]; - } - btrfs_item_key_to_cpu(eb, &key, path->slots[0]); - if (key.objectid != extent_item_objectid) + while (!ret && (ref_node = ulist_next(refs, ref_node))) { + ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, -1, + seq_elem.seq, &roots); + if (ret) break; - if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { - dref = btrfs_item_ptr(eb, path->slots[0], - struct btrfs_extent_data_ref); - ret = __data_list_add_eb(&data_refs, eb, dref); - } else if (key.type == BTRFS_SHARED_DATA_REF_KEY) { - ret = __shared_list_add(&shared_refs, key.offset); + while (!ret && (root_node = ulist_next(roots, root_node))) { + pr_debug("root %llu references leaf %llu\n", + root_node->val, ref_node->val); + ret = iterate_leaf_refs(fs_info, path, ref_node->val, + extent_item_objectid, + extent_item_pos, root_node->val, + iterate, ctx); } } - btrfs_release_path(path); - - /* - * ... only at the very end we can process the refs we found. this is - * because the iterator function we call is allowed to make tree lookups - * and we have to avoid deadlocks. additionally, we need more tree - * lookups ourselves for shared data refs. - */ - while (!list_empty(&data_refs)) { - ref_d = list_first_entry(&data_refs, struct __data_ref, list); - list_del(&ref_d->list); - if (!ret) - ret = iterate(ref_d->inum, extent_offset + - ref_d->extent_data_item_offset, - ref_d->root, ctx); - kfree(ref_d); - } - - while (!list_empty(&shared_refs)) { - ref_s = list_first_entry(&shared_refs, struct __shared_ref, - list); - list_del(&ref_s->list); - if (!ret) - ret = __iter_shared_inline_ref(fs_info, - ref_s->disk_byte, - extent_item_objectid, - extent_offset, path, - &data_refs, - iterate, ctx); - kfree(ref_s); - } - + ulist_free(refs); + ulist_free(roots); +out: + btrfs_put_delayed_seq(delayed_refs, &seq_elem); + btrfs_end_transaction(trans, fs_info->extent_root); return ret; } @@ -586,19 +1202,20 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, iterate_extent_inodes_t *iterate, void *ctx) { int ret; - u64 offset; + u64 extent_item_pos; struct btrfs_key found_key; ret = extent_from_logical(fs_info, logical, path, &found_key); + btrfs_release_path(path); if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) ret = -EINVAL; if (ret < 0) return ret; - offset = logical - found_key.objectid; + extent_item_pos = logical - found_key.objectid; ret = iterate_extent_inodes(fs_info, path, found_key.objectid, - offset, iterate, ctx); + extent_item_pos, iterate, ctx); return ret; } @@ -643,6 +1260,10 @@ static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) { name_len = btrfs_inode_ref_name_len(eb, iref); /* path must be released before calling iterate()! */ + pr_debug("following ref at offset %u for inode %llu in " + "tree %llu\n", cur, + (unsigned long long)found_key.objectid, + (unsigned long long)fs_root->objectid); ret = iterate(parent, iref, eb, ctx); if (ret) { free_extent_buffer(eb); @@ -683,10 +1304,14 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref, return PTR_ERR(fspath); if (fspath > fspath_min) { + pr_debug("path resolved: %s\n", fspath); ipath->fspath->val[i] = (u64)(unsigned long)fspath; ++ipath->fspath->elem_cnt; ipath->fspath->bytes_left = fspath - fspath_min; } else { + pr_debug("missed path, not enough space. missing bytes: %lu, " + "constructed so far: %s\n", + (unsigned long)(fspath_min - fspath), fspath_min); ++ipath->fspath->elem_missed; ipath->fspath->bytes_missing += fspath_min - fspath; ipath->fspath->bytes_left = 0; diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h index 92618837cb8f..d00dfa9ca934 100644 --- a/fs/btrfs/backref.h +++ b/fs/btrfs/backref.h @@ -20,6 +20,7 @@ #define __BTRFS_BACKREF__ #include "ioctl.h" +#include "ulist.h" struct inode_fs_paths { struct btrfs_path *btrfs_path; @@ -54,6 +55,10 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, int paths_from_inode(u64 inum, struct inode_fs_paths *ipath); +int btrfs_find_all_roots(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, u64 bytenr, + u64 num_bytes, u64 seq, struct ulist **roots); + struct btrfs_data_container *init_data_container(u32 total_bytes); struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, struct btrfs_path *path); diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 634608d2a6d0..9b9b15fd5204 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -51,6 +51,9 @@ struct btrfs_inode { /* held while logging the inode in tree-log.c */ struct mutex log_mutex; + /* held while doing delalloc reservations */ + struct mutex delalloc_mutex; + /* used to order data wrt metadata */ struct btrfs_ordered_inode_tree ordered_tree; diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c new file mode 100644 index 000000000000..ad0b3ba735b7 --- /dev/null +++ b/fs/btrfs/check-integrity.c @@ -0,0 +1,3068 @@ +/* + * Copyright (C) STRATO AG 2011. 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 v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +/* + * This module can be used to catch cases when the btrfs kernel + * code executes write requests to the disk that bring the file + * system in an inconsistent state. In such a state, a power-loss + * or kernel panic event would cause that the data on disk is + * lost or at least damaged. + * + * Code is added that examines all block write requests during + * runtime (including writes of the super block). Three rules + * are verified and an error is printed on violation of the + * rules: + * 1. It is not allowed to write a disk block which is + * currently referenced by the super block (either directly + * or indirectly). + * 2. When a super block is written, it is verified that all + * referenced (directly or indirectly) blocks fulfill the + * following requirements: + * 2a. All referenced blocks have either been present when + * the file system was mounted, (i.e., they have been + * referenced by the super block) or they have been + * written since then and the write completion callback + * was called and a FLUSH request to the device where + * these blocks are located was received and completed. + * 2b. All referenced blocks need to have a generation + * number which is equal to the parent's number. + * + * One issue that was found using this module was that the log + * tree on disk became temporarily corrupted because disk blocks + * that had been in use for the log tree had been freed and + * reused too early, while being referenced by the written super + * block. + * + * The search term in the kernel log that can be used to filter + * on the existence of detected integrity issues is + * "btrfs: attempt". + * + * The integrity check is enabled via mount options. These + * mount options are only supported if the integrity check + * tool is compiled by defining BTRFS_FS_CHECK_INTEGRITY. + * + * Example #1, apply integrity checks to all metadata: + * mount /dev/sdb1 /mnt -o check_int + * + * Example #2, apply integrity checks to all metadata and + * to data extents: + * mount /dev/sdb1 /mnt -o check_int_data + * + * Example #3, apply integrity checks to all metadata and dump + * the tree that the super block references to kernel messages + * each time after a super block was written: + * mount /dev/sdb1 /mnt -o check_int,check_int_print_mask=263 + * + * If the integrity check tool is included and activated in + * the mount options, plenty of kernel memory is used, and + * plenty of additional CPU cycles are spent. Enabling this + * functionality is not intended for normal use. In most + * cases, unless you are a btrfs developer who needs to verify + * the integrity of (super)-block write requests, do not + * enable the config option BTRFS_FS_CHECK_INTEGRITY to + * include and compile the integrity check tool. + */ + +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/buffer_head.h> +#include <linux/mutex.h> +#include <linux/crc32c.h> +#include <linux/genhd.h> +#include <linux/blkdev.h> +#include "ctree.h" +#include "disk-io.h" +#include "transaction.h" +#include "extent_io.h" +#include "disk-io.h" +#include "volumes.h" +#include "print-tree.h" +#include "locking.h" +#include "check-integrity.h" + +#define BTRFSIC_BLOCK_HASHTABLE_SIZE 0x10000 +#define BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE 0x10000 +#define BTRFSIC_DEV2STATE_HASHTABLE_SIZE 0x100 +#define BTRFSIC_BLOCK_MAGIC_NUMBER 0x14491051 +#define BTRFSIC_BLOCK_LINK_MAGIC_NUMBER 0x11070807 +#define BTRFSIC_DEV2STATE_MAGIC_NUMBER 0x20111530 +#define BTRFSIC_BLOCK_STACK_FRAME_MAGIC_NUMBER 20111300 +#define BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL (200 - 6) /* in characters, + * excluding " [...]" */ +#define BTRFSIC_BLOCK_SIZE PAGE_SIZE + +#define BTRFSIC_GENERATION_UNKNOWN ((u64)-1) + +/* + * The definition of the bitmask fields for the print_mask. + * They are specified with the mount option check_integrity_print_mask. + */ +#define BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE 0x00000001 +#define BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION 0x00000002 +#define BTRFSIC_PRINT_MASK_TREE_AFTER_SB_WRITE 0x00000004 +#define BTRFSIC_PRINT_MASK_TREE_BEFORE_SB_WRITE 0x00000008 +#define BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH 0x00000010 +#define BTRFSIC_PRINT_MASK_END_IO_BIO_BH 0x00000020 +#define BTRFSIC_PRINT_MASK_VERBOSE 0x00000040 +#define BTRFSIC_PRINT_MASK_VERY_VERBOSE 0x00000080 +#define BTRFSIC_PRINT_MASK_INITIAL_TREE 0x00000100 +#define BTRFSIC_PRINT_MASK_INITIAL_ALL_TREES 0x00000200 +#define BTRFSIC_PRINT_MASK_INITIAL_DATABASE 0x00000400 +#define BTRFSIC_PRINT_MASK_NUM_COPIES 0x00000800 +#define BTRFSIC_PRINT_MASK_TREE_WITH_ALL_MIRRORS 0x00001000 + +struct btrfsic_dev_state; +struct btrfsic_state; + +struct btrfsic_block { + u32 magic_num; /* only used for debug purposes */ + unsigned int is_metadata:1; /* if it is meta-data, not data-data */ + unsigned int is_superblock:1; /* if it is one of the superblocks */ + unsigned int is_iodone:1; /* if is done by lower subsystem */ + unsigned int iodone_w_error:1; /* error was indicated to endio */ + unsigned int never_written:1; /* block was added because it was + * referenced, not because it was + * written */ + unsigned int mirror_num:2; /* large enough to hold + * BTRFS_SUPER_MIRROR_MAX */ + struct btrfsic_dev_state *dev_state; + u64 dev_bytenr; /* key, physical byte num on disk */ + u64 logical_bytenr; /* logical byte num on disk */ + u64 generation; + struct btrfs_disk_key disk_key; /* extra info to print in case of + * issues, will not always be correct */ + struct list_head collision_resolving_node; /* list node */ + struct list_head all_blocks_node; /* list node */ + + /* the following two lists contain block_link items */ + struct list_head ref_to_list; /* list */ + struct list_head ref_from_list; /* list */ + struct btrfsic_block *next_in_same_bio; + void *orig_bio_bh_private; + union { + bio_end_io_t *bio; + bh_end_io_t *bh; + } orig_bio_bh_end_io; + int submit_bio_bh_rw; + u64 flush_gen; /* only valid if !never_written */ +}; + +/* + * Elements of this type are allocated dynamically and required because + * each block object can refer to and can be ref from multiple blocks. + * The key to lookup them in the hashtable is the dev_bytenr of + * the block ref to plus the one from the block refered from. + * The fact that they are searchable via a hashtable and that a + * ref_cnt is maintained is not required for the btrfs integrity + * check algorithm itself, it is only used to make the output more + * beautiful in case that an error is detected (an error is defined + * as a write operation to a block while that block is still referenced). + */ +struct btrfsic_block_link { + u32 magic_num; /* only used for debug purposes */ + u32 ref_cnt; + struct list_head node_ref_to; /* list node */ + struct list_head node_ref_from; /* list node */ + struct list_head collision_resolving_node; /* list node */ + struct btrfsic_block *block_ref_to; + struct btrfsic_block *block_ref_from; + u64 parent_generation; +}; + +struct btrfsic_dev_state { + u32 magic_num; /* only used for debug purposes */ + struct block_device *bdev; + struct btrfsic_state *state; + struct list_head collision_resolving_node; /* list node */ + struct btrfsic_block dummy_block_for_bio_bh_flush; + u64 last_flush_gen; + char name[BDEVNAME_SIZE]; +}; + +struct btrfsic_block_hashtable { + struct list_head table[BTRFSIC_BLOCK_HASHTABLE_SIZE]; +}; + +struct btrfsic_block_link_hashtable { + struct list_head table[BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE]; +}; + +struct btrfsic_dev_state_hashtable { + struct list_head table[BTRFSIC_DEV2STATE_HASHTABLE_SIZE]; +}; + +struct btrfsic_block_data_ctx { + u64 start; /* virtual bytenr */ + u64 dev_bytenr; /* physical bytenr on device */ + u32 len; + struct btrfsic_dev_state *dev; + char *data; + struct buffer_head *bh; /* do not use if set to NULL */ +}; + +/* This structure is used to implement recursion without occupying + * any stack space, refer to btrfsic_process_metablock() */ +struct btrfsic_stack_frame { + u32 magic; + u32 nr; + int error; + int i; + int limit_nesting; + int num_copies; + int mirror_num; + struct btrfsic_block *block; + struct btrfsic_block_data_ctx *block_ctx; + struct btrfsic_block *next_block; + struct btrfsic_block_data_ctx next_block_ctx; + struct btrfs_header *hdr; + struct btrfsic_stack_frame *prev; +}; + +/* Some state per mounted filesystem */ +struct btrfsic_state { + u32 print_mask; + int include_extent_data; + int csum_size; + struct list_head all_blocks_list; + struct btrfsic_block_hashtable block_hashtable; + struct btrfsic_block_link_hashtable block_link_hashtable; + struct btrfs_root *root; + u64 max_superblock_generation; + struct btrfsic_block *latest_superblock; +}; + +static void btrfsic_block_init(struct btrfsic_block *b); +static struct btrfsic_block *btrfsic_block_alloc(void); +static void btrfsic_block_free(struct btrfsic_block *b); +static void btrfsic_block_link_init(struct btrfsic_block_link *n); +static struct btrfsic_block_link *btrfsic_block_link_alloc(void); +static void btrfsic_block_link_free(struct btrfsic_block_link *n); +static void btrfsic_dev_state_init(struct btrfsic_dev_state *ds); +static struct btrfsic_dev_state *btrfsic_dev_state_alloc(void); +static void btrfsic_dev_state_free(struct btrfsic_dev_state *ds); +static void btrfsic_block_hashtable_init(struct btrfsic_block_hashtable *h); +static void btrfsic_block_hashtable_add(struct btrfsic_block *b, + struct btrfsic_block_hashtable *h); +static void btrfsic_block_hashtable_remove(struct btrfsic_block *b); +static struct btrfsic_block *btrfsic_block_hashtable_lookup( + struct block_device *bdev, + u64 dev_bytenr, + struct btrfsic_block_hashtable *h); +static void btrfsic_block_link_hashtable_init( + struct btrfsic_block_link_hashtable *h); +static void btrfsic_block_link_hashtable_add( + struct btrfsic_block_link *l, + struct btrfsic_block_link_hashtable *h); +static void btrfsic_block_link_hashtable_remove(struct btrfsic_block_link *l); +static struct btrfsic_block_link *btrfsic_block_link_hashtable_lookup( + struct block_device *bdev_ref_to, + u64 dev_bytenr_ref_to, + struct block_device *bdev_ref_from, + u64 dev_bytenr_ref_from, + struct btrfsic_block_link_hashtable *h); +static void btrfsic_dev_state_hashtable_init( + struct btrfsic_dev_state_hashtable *h); +static void btrfsic_dev_state_hashtable_add( + struct btrfsic_dev_state *ds, + struct btrfsic_dev_state_hashtable *h); +static void btrfsic_dev_state_hashtable_remove(struct btrfsic_dev_state *ds); +static struct btrfsic_dev_state *btrfsic_dev_state_hashtable_lookup( + struct block_device *bdev, + struct btrfsic_dev_state_hashtable *h); +static struct btrfsic_stack_frame *btrfsic_stack_frame_alloc(void); +static void btrfsic_stack_frame_free(struct btrfsic_stack_frame *sf); +static int btrfsic_process_superblock(struct btrfsic_state *state, + struct btrfs_fs_devices *fs_devices); +static int btrfsic_process_metablock(struct btrfsic_state *state, + struct btrfsic_block *block, + struct btrfsic_block_data_ctx *block_ctx, + struct btrfs_header *hdr, + int limit_nesting, int force_iodone_flag); +static int btrfsic_create_link_to_next_block( + struct btrfsic_state *state, + struct btrfsic_block *block, + struct btrfsic_block_data_ctx + *block_ctx, u64 next_bytenr, + int limit_nesting, + struct btrfsic_block_data_ctx *next_block_ctx, + struct btrfsic_block **next_blockp, + int force_iodone_flag, + int *num_copiesp, int *mirror_nump, + struct btrfs_disk_key *disk_key, + u64 parent_generation); +static int btrfsic_handle_extent_data(struct btrfsic_state *state, + struct btrfsic_block *block, + struct btrfsic_block_data_ctx *block_ctx, + u32 item_offset, int force_iodone_flag); +static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len, + struct btrfsic_block_data_ctx *block_ctx_out, + int mirror_num); +static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr, + u32 len, struct block_device *bdev, + struct btrfsic_block_data_ctx *block_ctx_out); +static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx); +static int btrfsic_read_block(struct btrfsic_state *state, + struct btrfsic_block_data_ctx *block_ctx); +static void btrfsic_dump_database(struct btrfsic_state *state); +static int btrfsic_test_for_metadata(struct btrfsic_state *state, + const u8 *data, unsigned int size); +static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, + u64 dev_bytenr, u8 *mapped_data, + unsigned int len, struct bio *bio, + int *bio_is_patched, + struct buffer_head *bh, + int submit_bio_bh_rw); +static int btrfsic_process_written_superblock( + struct btrfsic_state *state, + struct btrfsic_block *const block, + struct btrfs_super_block *const super_hdr); +static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status); +static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate); +static int btrfsic_is_block_ref_by_superblock(const struct btrfsic_state *state, + const struct btrfsic_block *block, + int recursion_level); +static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state, + struct btrfsic_block *const block, + int recursion_level); +static void btrfsic_print_add_link(const struct btrfsic_state *state, + const struct btrfsic_block_link *l); +static void btrfsic_print_rem_link(const struct btrfsic_state *state, + const struct btrfsic_block_link *l); +static char btrfsic_get_block_type(const struct btrfsic_state *state, + const struct btrfsic_block *block); +static void btrfsic_dump_tree(const struct btrfsic_state *state); +static void btrfsic_dump_tree_sub(const struct btrfsic_state *state, + const struct btrfsic_block *block, + int indent_level); +static struct btrfsic_block_link *btrfsic_block_link_lookup_or_add( + struct btrfsic_state *state, + struct btrfsic_block_data_ctx *next_block_ctx, + struct btrfsic_block *next_block, + struct btrfsic_block *from_block, + u64 parent_generation); +static struct btrfsic_block *btrfsic_block_lookup_or_add( + struct btrfsic_state *state, + struct btrfsic_block_data_ctx *block_ctx, + const char *additional_string, + int is_metadata, + int is_iodone, + int never_written, + int mirror_num, + int *was_created); +static int btrfsic_process_superblock_dev_mirror( + struct btrfsic_state *state, + struct btrfsic_dev_state *dev_state, + struct btrfs_device *device, + int superblock_mirror_num, + struct btrfsic_dev_state **selected_dev_state, + struct btrfs_super_block *selected_super); +static struct btrfsic_dev_state *btrfsic_dev_state_lookup( + struct block_device *bdev); +static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state, + u64 bytenr, + struct btrfsic_dev_state *dev_state, + u64 dev_bytenr, char *data); + +static struct mutex btrfsic_mutex; +static int btrfsic_is_initialized; +static struct btrfsic_dev_state_hashtable btrfsic_dev_state_hashtable; + + +static void btrfsic_block_init(struct btrfsic_block *b) +{ + b->magic_num = BTRFSIC_BLOCK_MAGIC_NUMBER; + b->dev_state = NULL; + b->dev_bytenr = 0; + b->logical_bytenr = 0; + b->generation = BTRFSIC_GENERATION_UNKNOWN; + b->disk_key.objectid = 0; + b->disk_key.type = 0; + b->disk_key.offset = 0; + b->is_metadata = 0; + b->is_superblock = 0; + b->is_iodone = 0; + b->iodone_w_error = 0; + b->never_written = 0; + b->mirror_num = 0; + b->next_in_same_bio = NULL; + b->orig_bio_bh_private = NULL; + b->orig_bio_bh_end_io.bio = NULL; + INIT_LIST_HEAD(&b->collision_resolving_node); + INIT_LIST_HEAD(&b->all_blocks_node); + INIT_LIST_HEAD(&b->ref_to_list); + INIT_LIST_HEAD(&b->ref_from_list); + b->submit_bio_bh_rw = 0; + b->flush_gen = 0; +} + +static struct btrfsic_block *btrfsic_block_alloc(void) +{ + struct btrfsic_block *b; + + b = kzalloc(sizeof(*b), GFP_NOFS); + if (NULL != b) + btrfsic_block_init(b); + + return b; +} + +static void btrfsic_block_free(struct btrfsic_block *b) +{ + BUG_ON(!(NULL == b || BTRFSIC_BLOCK_MAGIC_NUMBER == b->magic_num)); + kfree(b); +} + +static void btrfsic_block_link_init(struct btrfsic_block_link *l) +{ + l->magic_num = BTRFSIC_BLOCK_LINK_MAGIC_NUMBER; + l->ref_cnt = 1; + INIT_LIST_HEAD(&l->node_ref_to); + INIT_LIST_HEAD(&l->node_ref_from); + INIT_LIST_HEAD(&l->collision_resolving_node); + l->block_ref_to = NULL; + l->block_ref_from = NULL; +} + +static struct btrfsic_block_link *btrfsic_block_link_alloc(void) +{ + struct btrfsic_block_link *l; + + l = kzalloc(sizeof(*l), GFP_NOFS); + if (NULL != l) + btrfsic_block_link_init(l); + + return l; +} + +static void btrfsic_block_link_free(struct btrfsic_block_link *l) +{ + BUG_ON(!(NULL == l || BTRFSIC_BLOCK_LINK_MAGIC_NUMBER == l->magic_num)); + kfree(l); +} + +static void btrfsic_dev_state_init(struct btrfsic_dev_state *ds) +{ + ds->magic_num = BTRFSIC_DEV2STATE_MAGIC_NUMBER; + ds->bdev = NULL; + ds->state = NULL; + ds->name[0] = '\0'; + INIT_LIST_HEAD(&ds->collision_resolving_node); + ds->last_flush_gen = 0; + btrfsic_block_init(&ds->dummy_block_for_bio_bh_flush); + ds->dummy_block_for_bio_bh_flush.is_iodone = 1; + ds->dummy_block_for_bio_bh_flush.dev_state = ds; +} + +static struct btrfsic_dev_state *btrfsic_dev_state_alloc(void) +{ + struct btrfsic_dev_state *ds; + + ds = kzalloc(sizeof(*ds), GFP_NOFS); + if (NULL != ds) + btrfsic_dev_state_init(ds); + + return ds; +} + +static void btrfsic_dev_state_free(struct btrfsic_dev_state *ds) +{ + BUG_ON(!(NULL == ds || + BTRFSIC_DEV2STATE_MAGIC_NUMBER == ds->magic_num)); + kfree(ds); +} + +static void btrfsic_block_hashtable_init(struct btrfsic_block_hashtable *h) +{ + int i; + + for (i = 0; i < BTRFSIC_BLOCK_HASHTABLE_SIZE; i++) + INIT_LIST_HEAD(h->table + i); +} + +static void btrfsic_block_hashtable_add(struct btrfsic_block *b, + struct btrfsic_block_hashtable *h) +{ + const unsigned int hashval = + (((unsigned int)(b->dev_bytenr >> 16)) ^ + ((unsigned int)((uintptr_t)b->dev_state->bdev))) & + (BTRFSIC_BLOCK_HASHTABLE_SIZE - 1); + + list_add(&b->collision_resolving_node, h->table + hashval); +} + +static void btrfsic_block_hashtable_remove(struct btrfsic_block *b) +{ + list_del(&b->collision_resolving_node); +} + +static struct btrfsic_block *btrfsic_block_hashtable_lookup( + struct block_device *bdev, + u64 dev_bytenr, + struct btrfsic_block_hashtable *h) +{ + const unsigned int hashval = + (((unsigned int)(dev_bytenr >> 16)) ^ + ((unsigned int)((uintptr_t)bdev))) & + (BTRFSIC_BLOCK_HASHTABLE_SIZE - 1); + struct list_head *elem; + + list_for_each(elem, h->table + hashval) { + struct btrfsic_block *const b = + list_entry(elem, struct btrfsic_block, + collision_resolving_node); + + if (b->dev_state->bdev == bdev && b->dev_bytenr == dev_bytenr) + return b; + } + + return NULL; +} + +static void btrfsic_block_link_hashtable_init( + struct btrfsic_block_link_hashtable *h) +{ + int i; + + for (i = 0; i < BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE; i++) + INIT_LIST_HEAD(h->table + i); +} + +static void btrfsic_block_link_hashtable_add( + struct btrfsic_block_link *l, + struct btrfsic_block_link_hashtable *h) +{ + const unsigned int hashval = + (((unsigned int)(l->block_ref_to->dev_bytenr >> 16)) ^ + ((unsigned int)(l->block_ref_from->dev_bytenr >> 16)) ^ + ((unsigned int)((uintptr_t)l->block_ref_to->dev_state->bdev)) ^ + ((unsigned int)((uintptr_t)l->block_ref_from->dev_state->bdev))) + & (BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE - 1); + + BUG_ON(NULL == l->block_ref_to); + BUG_ON(NULL == l->block_ref_from); + list_add(&l->collision_resolving_node, h->table + hashval); +} + +static void btrfsic_block_link_hashtable_remove(struct btrfsic_block_link *l) +{ + list_del(&l->collision_resolving_node); +} + +static struct btrfsic_block_link *btrfsic_block_link_hashtable_lookup( + struct block_device *bdev_ref_to, + u64 dev_bytenr_ref_to, + struct block_device *bdev_ref_from, + u64 dev_bytenr_ref_from, + struct btrfsic_block_link_hashtable *h) +{ + const unsigned int hashval = + (((unsigned int)(dev_bytenr_ref_to >> 16)) ^ + ((unsigned int)(dev_bytenr_ref_from >> 16)) ^ + ((unsigned int)((uintptr_t)bdev_ref_to)) ^ + ((unsigned int)((uintptr_t)bdev_ref_from))) & + (BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE - 1); + struct list_head *elem; + + list_for_each(elem, h->table + hashval) { + struct btrfsic_block_link *const l = + list_entry(elem, struct btrfsic_block_link, + collision_resolving_node); + + BUG_ON(NULL == l->block_ref_to); + BUG_ON(NULL == l->block_ref_from); + if (l->block_ref_to->dev_state->bdev == bdev_ref_to && + l->block_ref_to->dev_bytenr == dev_bytenr_ref_to && + l->block_ref_from->dev_state->bdev == bdev_ref_from && + l->block_ref_from->dev_bytenr == dev_bytenr_ref_from) + return l; + } + + return NULL; +} + +static void btrfsic_dev_state_hashtable_init( + struct btrfsic_dev_state_hashtable *h) +{ + int i; + + for (i = 0; i < BTRFSIC_DEV2STATE_HASHTABLE_SIZE; i++) + INIT_LIST_HEAD(h->table + i); +} + +static void btrfsic_dev_state_hashtable_add( + struct btrfsic_dev_state *ds, + struct btrfsic_dev_state_hashtable *h) +{ + const unsigned int hashval = + (((unsigned int)((uintptr_t)ds->bdev)) & + (BTRFSIC_DEV2STATE_HASHTABLE_SIZE - 1)); + + list_add(&ds->collision_resolving_node, h->table + hashval); +} + +static void btrfsic_dev_state_hashtable_remove(struct btrfsic_dev_state *ds) +{ + list_del(&ds->collision_resolving_node); +} + +static struct btrfsic_dev_state *btrfsic_dev_state_hashtable_lookup( + struct block_device *bdev, + struct btrfsic_dev_state_hashtable *h) +{ + const unsigned int hashval = + (((unsigned int)((uintptr_t)bdev)) & + (BTRFSIC_DEV2STATE_HASHTABLE_SIZE - 1)); + struct list_head *elem; + + list_for_each(elem, h->table + hashval) { + struct btrfsic_dev_state *const ds = + list_entry(elem, struct btrfsic_dev_state, + collision_resolving_node); + + if (ds->bdev == bdev) + return ds; + } + + return NULL; +} + +static int btrfsic_process_superblock(struct btrfsic_state *state, + struct btrfs_fs_devices *fs_devices) +{ + int ret; + struct btrfs_super_block *selected_super; + struct list_head *dev_head = &fs_devices->devices; + struct btrfs_device *device; + struct btrfsic_dev_state *selected_dev_state = NULL; + int pass; + + BUG_ON(NULL == state); + selected_super = kmalloc(sizeof(*selected_super), GFP_NOFS); + if (NULL == selected_super) { + printk(KERN_INFO "btrfsic: error, kmalloc failed!\n"); + return -1; + } + + list_for_each_entry(device, dev_head, dev_list) { + int i; + struct btrfsic_dev_state *dev_state; + + if (!device->bdev || !device->name) + continue; + + dev_state = btrfsic_dev_state_lookup(device->bdev); + BUG_ON(NULL == dev_state); + for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { + ret = btrfsic_process_superblock_dev_mirror( + state, dev_state, device, i, + &selected_dev_state, selected_super); + if (0 != ret && 0 == i) { + kfree(selected_super); + return ret; + } + } + } + + if (NULL == state->latest_superblock) { + printk(KERN_INFO "btrfsic: no superblock found!\n"); + kfree(selected_super); + return -1; + } + + state->csum_size = btrfs_super_csum_size(selected_super); + + for (pass = 0; pass < 3; pass++) { + int num_copies; + int mirror_num; + u64 next_bytenr; + + switch (pass) { + case 0: + next_bytenr = btrfs_super_root(selected_super); + if (state->print_mask & + BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION) + printk(KERN_INFO "root@%llu\n", + (unsigned long long)next_bytenr); + break; + case 1: + next_bytenr = btrfs_super_chunk_root(selected_super); + if (state->print_mask & + BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION) + printk(KERN_INFO "chunk@%llu\n", + (unsigned long long)next_bytenr); + break; + case 2: + next_bytenr = btrfs_super_log_root(selected_super); + if (0 == next_bytenr) + continue; + if (state->print_mask & + BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION) + printk(KERN_INFO "log@%llu\n", + (unsigned long long)next_bytenr); + break; + } + + num_copies = + btrfs_num_copies(&state->root->fs_info->mapping_tree, + next_bytenr, PAGE_SIZE); + if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) + printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", + (unsigned long long)next_bytenr, num_copies); + + for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { + struct btrfsic_block *next_block; + struct btrfsic_block_data_ctx tmp_next_block_ctx; + struct btrfsic_block_link *l; + struct btrfs_header *hdr; + + ret = btrfsic_map_block(state, next_bytenr, PAGE_SIZE, + &tmp_next_block_ctx, + mirror_num); + if (ret) { + printk(KERN_INFO "btrfsic:" + " btrfsic_map_block(root @%llu," + " mirror %d) failed!\n", + (unsigned long long)next_bytenr, + mirror_num); + kfree(selected_super); + return -1; + } + + next_block = btrfsic_block_hashtable_lookup( + tmp_next_block_ctx.dev->bdev, + tmp_next_block_ctx.dev_bytenr, + &state->block_hashtable); + BUG_ON(NULL == next_block); + + l = btrfsic_block_link_hashtable_lookup( + tmp_next_block_ctx.dev->bdev, + tmp_next_block_ctx.dev_bytenr, + state->latest_superblock->dev_state-> + bdev, + state->latest_superblock->dev_bytenr, + &state->block_link_hashtable); + BUG_ON(NULL == l); + + ret = btrfsic_read_block(state, &tmp_next_block_ctx); + if (ret < (int)BTRFSIC_BLOCK_SIZE) { + printk(KERN_INFO + "btrfsic: read @logical %llu failed!\n", + (unsigned long long) + tmp_next_block_ctx.start); + btrfsic_release_block_ctx(&tmp_next_block_ctx); + kfree(selected_super); + return -1; + } + + hdr = (struct btrfs_header *)tmp_next_block_ctx.data; + ret = btrfsic_process_metablock(state, + next_block, + &tmp_next_block_ctx, + hdr, + BTRFS_MAX_LEVEL + 3, 1); + btrfsic_release_block_ctx(&tmp_next_block_ctx); + } + } + + kfree(selected_super); + return ret; +} + +static int btrfsic_process_superblock_dev_mirror( + struct btrfsic_state *state, + struct btrfsic_dev_state *dev_state, + struct btrfs_device *device, + int superblock_mirror_num, + struct btrfsic_dev_state **selected_dev_state, + struct btrfs_super_block *selected_super) +{ + struct btrfs_super_block *super_tmp; + u64 dev_bytenr; + struct buffer_head *bh; + struct btrfsic_block *superblock_tmp; + int pass; + struct block_device *const superblock_bdev = device->bdev; + + /* super block bytenr is always the unmapped device bytenr */ + dev_bytenr = btrfs_sb_offset(superblock_mirror_num); + bh = __bread(superblock_bdev, dev_bytenr / 4096, 4096); + if (NULL == bh) + return -1; + super_tmp = (struct btrfs_super_block *) + (bh->b_data + (dev_bytenr & 4095)); + + if (btrfs_super_bytenr(super_tmp) != dev_bytenr || + strncmp((char *)(&(super_tmp->magic)), BTRFS_MAGIC, + sizeof(super_tmp->magic)) || + memcmp(device->uuid, super_tmp->dev_item.uuid, BTRFS_UUID_SIZE)) { + brelse(bh); + return 0; + } + + superblock_tmp = + btrfsic_block_hashtable_lookup(superblock_bdev, + dev_bytenr, + &state->block_hashtable); + if (NULL == superblock_tmp) { + superblock_tmp = btrfsic_block_alloc(); + if (NULL == superblock_tmp) { + printk(KERN_INFO "btrfsic: error, kmalloc failed!\n"); + brelse(bh); + return -1; + } + /* for superblock, only the dev_bytenr makes sense */ + superblock_tmp->dev_bytenr = dev_bytenr; + superblock_tmp->dev_state = dev_state; + superblock_tmp->logical_bytenr = dev_bytenr; + superblock_tmp->generation = btrfs_super_generation(super_tmp); + superblock_tmp->is_metadata = 1; + superblock_tmp->is_superblock = 1; + superblock_tmp->is_iodone = 1; + superblock_tmp->never_written = 0; + superblock_tmp->mirror_num = 1 + superblock_mirror_num; + if (state->print_mask & BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE) + printk(KERN_INFO "New initial S-block (bdev %p, %s)" + " @%llu (%s/%llu/%d)\n", + superblock_bdev, device->name, + (unsigned long long)dev_bytenr, + dev_state->name, + (unsigned long long)dev_bytenr, + superblock_mirror_num); + list_add(&superblock_tmp->all_blocks_node, + &state->all_blocks_list); + btrfsic_block_hashtable_add(superblock_tmp, + &state->block_hashtable); + } + + /* select the one with the highest generation field */ + if (btrfs_super_generation(super_tmp) > + state->max_superblock_generation || + 0 == state->max_superblock_generation) { + memcpy(selected_super, super_tmp, sizeof(*selected_super)); + *selected_dev_state = dev_state; + state->max_superblock_generation = + btrfs_super_generation(super_tmp); + state->latest_superblock = superblock_tmp; + } + + for (pass = 0; pass < 3; pass++) { + u64 next_bytenr; + int num_copies; + int mirror_num; + const char *additional_string = NULL; + struct btrfs_disk_key tmp_disk_key; + + tmp_disk_key.type = BTRFS_ROOT_ITEM_KEY; + tmp_disk_key.offset = 0; + switch (pass) { + case 0: + tmp_disk_key.objectid = + cpu_to_le64(BTRFS_ROOT_TREE_OBJECTID); + additional_string = "initial root "; + next_bytenr = btrfs_super_root(super_tmp); + break; + case 1: + tmp_disk_key.objectid = + cpu_to_le64(BTRFS_CHUNK_TREE_OBJECTID); + additional_string = "initial chunk "; + next_bytenr = btrfs_super_chunk_root(super_tmp); + break; + case 2: + tmp_disk_key.objectid = + cpu_to_le64(BTRFS_TREE_LOG_OBJECTID); + additional_string = "initial log "; + next_bytenr = btrfs_super_log_root(super_tmp); + if (0 == next_bytenr) + continue; + break; + } + + num_copies = + btrfs_num_copies(&state->root->fs_info->mapping_tree, + next_bytenr, PAGE_SIZE); + if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) + printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", + (unsigned long long)next_bytenr, num_copies); + for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { + struct btrfsic_block *next_block; + struct btrfsic_block_data_ctx tmp_next_block_ctx; + struct btrfsic_block_link *l; + + if (btrfsic_map_block(state, next_bytenr, PAGE_SIZE, + &tmp_next_block_ctx, + mirror_num)) { + printk(KERN_INFO "btrfsic: btrfsic_map_block(" + "bytenr @%llu, mirror %d) failed!\n", + (unsigned long long)next_bytenr, + mirror_num); + brelse(bh); + return -1; + } + + next_block = btrfsic_block_lookup_or_add( + state, &tmp_next_block_ctx, + additional_string, 1, 1, 0, + mirror_num, NULL); + if (NULL == next_block) { + btrfsic_release_block_ctx(&tmp_next_block_ctx); + brelse(bh); + return -1; + } + + next_block->disk_key = tmp_disk_key; + next_block->generation = BTRFSIC_GENERATION_UNKNOWN; + l = btrfsic_block_link_lookup_or_add( + state, &tmp_next_block_ctx, + next_block, superblock_tmp, + BTRFSIC_GENERATION_UNKNOWN); + btrfsic_release_block_ctx(&tmp_next_block_ctx); + if (NULL == l) { + brelse(bh); + return -1; + } + } + } + if (state->print_mask & BTRFSIC_PRINT_MASK_INITIAL_ALL_TREES) + btrfsic_dump_tree_sub(state, superblock_tmp, 0); + + brelse(bh); + return 0; +} + +static struct btrfsic_stack_frame *btrfsic_stack_frame_alloc(void) +{ + struct btrfsic_stack_frame *sf; + + sf = kzalloc(sizeof(*sf), GFP_NOFS); + if (NULL == sf) + printk(KERN_INFO "btrfsic: alloc memory failed!\n"); + else + sf->magic = BTRFSIC_BLOCK_STACK_FRAME_MAGIC_NUMBER; + return sf; +} + +static void btrfsic_stack_frame_free(struct btrfsic_stack_frame *sf) +{ + BUG_ON(!(NULL == sf || + BTRFSIC_BLOCK_STACK_FRAME_MAGIC_NUMBER == sf->magic)); + kfree(sf); +} + +static int btrfsic_process_metablock( + struct btrfsic_state *state, + struct btrfsic_block *const first_block, + struct btrfsic_block_data_ctx *const first_block_ctx, + struct btrfs_header *const first_hdr, + int first_limit_nesting, int force_iodone_flag) +{ + struct btrfsic_stack_frame initial_stack_frame = { 0 }; + struct btrfsic_stack_frame *sf; + struct btrfsic_stack_frame *next_stack; + + sf = &initial_stack_frame; + sf->error = 0; + sf->i = -1; + sf->limit_nesting = first_limit_nesting; + sf->block = first_block; + sf->block_ctx = first_block_ctx; + sf->next_block = NULL; + sf->hdr = first_hdr; + sf->prev = NULL; + +continue_with_new_stack_frame: + sf->block->generation = le64_to_cpu(sf->hdr->generation); + if (0 == sf->hdr->level) { + struct btrfs_leaf *const leafhdr = + (struct btrfs_leaf *)sf->hdr; + + if (-1 == sf->i) { + sf->nr = le32_to_cpu(leafhdr->header.nritems); + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "leaf %llu items %d generation %llu" + " owner %llu\n", + (unsigned long long) + sf->block_ctx->start, + sf->nr, + (unsigned long long) + le64_to_cpu(leafhdr->header.generation), + (unsigned long long) + le64_to_cpu(leafhdr->header.owner)); + } + +continue_with_current_leaf_stack_frame: + if (0 == sf->num_copies || sf->mirror_num > sf->num_copies) { + sf->i++; + sf->num_copies = 0; + } + + if (sf->i < sf->nr) { + struct btrfs_item *disk_item = leafhdr->items + sf->i; + struct btrfs_disk_key *disk_key = &disk_item->key; + u8 type; + const u32 item_offset = le32_to_cpu(disk_item->offset); + + type = disk_key->type; + + if (BTRFS_ROOT_ITEM_KEY == type) { + const struct btrfs_root_item *const root_item = + (struct btrfs_root_item *) + (sf->block_ctx->data + + offsetof(struct btrfs_leaf, items) + + item_offset); + const u64 next_bytenr = + le64_to_cpu(root_item->bytenr); + + sf->error = + btrfsic_create_link_to_next_block( + state, + sf->block, + sf->block_ctx, + next_bytenr, + sf->limit_nesting, + &sf->next_block_ctx, + &sf->next_block, + force_iodone_flag, + &sf->num_copies, + &sf->mirror_num, + disk_key, + le64_to_cpu(root_item-> + generation)); + if (sf->error) + goto one_stack_frame_backwards; + + if (NULL != sf->next_block) { + struct btrfs_header *const next_hdr = + (struct btrfs_header *) + sf->next_block_ctx.data; + + next_stack = + btrfsic_stack_frame_alloc(); + if (NULL == next_stack) { + btrfsic_release_block_ctx( + &sf-> + next_block_ctx); + goto one_stack_frame_backwards; + } + + next_stack->i = -1; + next_stack->block = sf->next_block; + next_stack->block_ctx = + &sf->next_block_ctx; + next_stack->next_block = NULL; + next_stack->hdr = next_hdr; + next_stack->limit_nesting = + sf->limit_nesting - 1; + next_stack->prev = sf; + sf = next_stack; + goto continue_with_new_stack_frame; + } + } else if (BTRFS_EXTENT_DATA_KEY == type && + state->include_extent_data) { + sf->error = btrfsic_handle_extent_data( + state, + sf->block, + sf->block_ctx, + item_offset, + force_iodone_flag); + if (sf->error) + goto one_stack_frame_backwards; + } + + goto continue_with_current_leaf_stack_frame; + } + } else { + struct btrfs_node *const nodehdr = (struct btrfs_node *)sf->hdr; + + if (-1 == sf->i) { + sf->nr = le32_to_cpu(nodehdr->header.nritems); + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO "node %llu level %d items %d" + " generation %llu owner %llu\n", + (unsigned long long) + sf->block_ctx->start, + nodehdr->header.level, sf->nr, + (unsigned long long) + le64_to_cpu(nodehdr->header.generation), + (unsigned long long) + le64_to_cpu(nodehdr->header.owner)); + } + +continue_with_current_node_stack_frame: + if (0 == sf->num_copies || sf->mirror_num > sf->num_copies) { + sf->i++; + sf->num_copies = 0; + } + + if (sf->i < sf->nr) { + struct btrfs_key_ptr *disk_key_ptr = + nodehdr->ptrs + sf->i; + const u64 next_bytenr = + le64_to_cpu(disk_key_ptr->blockptr); + + sf->error = btrfsic_create_link_to_next_block( + state, + sf->block, + sf->block_ctx, + next_bytenr, + sf->limit_nesting, + &sf->next_block_ctx, + &sf->next_block, + force_iodone_flag, + &sf->num_copies, + &sf->mirror_num, + &disk_key_ptr->key, + le64_to_cpu(disk_key_ptr->generation)); + if (sf->error) + goto one_stack_frame_backwards; + + if (NULL != sf->next_block) { + struct btrfs_header *const next_hdr = + (struct btrfs_header *) + sf->next_block_ctx.data; + + next_stack = btrfsic_stack_frame_alloc(); + if (NULL == next_stack) + goto one_stack_frame_backwards; + + next_stack->i = -1; + next_stack->block = sf->next_block; + next_stack->block_ctx = &sf->next_block_ctx; + next_stack->next_block = NULL; + next_stack->hdr = next_hdr; + next_stack->limit_nesting = + sf->limit_nesting - 1; + next_stack->prev = sf; + sf = next_stack; + goto continue_with_new_stack_frame; + } + + goto continue_with_current_node_stack_frame; + } + } + +one_stack_frame_backwards: + if (NULL != sf->prev) { + struct btrfsic_stack_frame *const prev = sf->prev; + + /* the one for the initial block is freed in the caller */ + btrfsic_release_block_ctx(sf->block_ctx); + + if (sf->error) { + prev->error = sf->error; + btrfsic_stack_frame_free(sf); + sf = prev; + goto one_stack_frame_backwards; + } + + btrfsic_stack_frame_free(sf); + sf = prev; + goto continue_with_new_stack_frame; + } else { + BUG_ON(&initial_stack_frame != sf); + } + + return sf->error; +} + +static int btrfsic_create_link_to_next_block( + struct btrfsic_state *state, + struct btrfsic_block *block, + struct btrfsic_block_data_ctx *block_ctx, + u64 next_bytenr, + int limit_nesting, + struct btrfsic_block_data_ctx *next_block_ctx, + struct btrfsic_block **next_blockp, + int force_iodone_flag, + int *num_copiesp, int *mirror_nump, + struct btrfs_disk_key *disk_key, + u64 parent_generation) +{ + struct btrfsic_block *next_block = NULL; + int ret; + struct btrfsic_block_link *l; + int did_alloc_block_link; + int block_was_created; + + *next_blockp = NULL; + if (0 == *num_copiesp) { + *num_copiesp = + btrfs_num_copies(&state->root->fs_info->mapping_tree, + next_bytenr, PAGE_SIZE); + if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) + printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", + (unsigned long long)next_bytenr, *num_copiesp); + *mirror_nump = 1; + } + + if (*mirror_nump > *num_copiesp) + return 0; + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "btrfsic_create_link_to_next_block(mirror_num=%d)\n", + *mirror_nump); + ret = btrfsic_map_block(state, next_bytenr, + BTRFSIC_BLOCK_SIZE, + next_block_ctx, *mirror_nump); + if (ret) { + printk(KERN_INFO + "btrfsic: btrfsic_map_block(@%llu, mirror=%d) failed!\n", + (unsigned long long)next_bytenr, *mirror_nump); + btrfsic_release_block_ctx(next_block_ctx); + *next_blockp = NULL; + return -1; + } + + next_block = btrfsic_block_lookup_or_add(state, + next_block_ctx, "referenced ", + 1, force_iodone_flag, + !force_iodone_flag, + *mirror_nump, + &block_was_created); + if (NULL == next_block) { + btrfsic_release_block_ctx(next_block_ctx); + *next_blockp = NULL; + return -1; + } + if (block_was_created) { + l = NULL; + next_block->generation = BTRFSIC_GENERATION_UNKNOWN; + } else { + if (next_block->logical_bytenr != next_bytenr && + !(!next_block->is_metadata && + 0 == next_block->logical_bytenr)) { + printk(KERN_INFO + "Referenced block @%llu (%s/%llu/%d)" + " found in hash table, %c," + " bytenr mismatch (!= stored %llu).\n", + (unsigned long long)next_bytenr, + next_block_ctx->dev->name, + (unsigned long long)next_block_ctx->dev_bytenr, + *mirror_nump, + btrfsic_get_block_type(state, next_block), + (unsigned long long)next_block->logical_bytenr); + } else if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "Referenced block @%llu (%s/%llu/%d)" + " found in hash table, %c.\n", + (unsigned long long)next_bytenr, + next_block_ctx->dev->name, + (unsigned long long)next_block_ctx->dev_bytenr, + *mirror_nump, + btrfsic_get_block_type(state, next_block)); + next_block->logical_bytenr = next_bytenr; + + next_block->mirror_num = *mirror_nump; + l = btrfsic_block_link_hashtable_lookup( + next_block_ctx->dev->bdev, + next_block_ctx->dev_bytenr, + block_ctx->dev->bdev, + block_ctx->dev_bytenr, + &state->block_link_hashtable); + } + + next_block->disk_key = *disk_key; + if (NULL == l) { + l = btrfsic_block_link_alloc(); + if (NULL == l) { + printk(KERN_INFO "btrfsic: error, kmalloc failed!\n"); + btrfsic_release_block_ctx(next_block_ctx); + *next_blockp = NULL; + return -1; + } + + did_alloc_block_link = 1; + l->block_ref_to = next_block; + l->block_ref_from = block; + l->ref_cnt = 1; + l->parent_generation = parent_generation; + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + btrfsic_print_add_link(state, l); + + list_add(&l->node_ref_to, &block->ref_to_list); + list_add(&l->node_ref_from, &next_block->ref_from_list); + + btrfsic_block_link_hashtable_add(l, + &state->block_link_hashtable); + } else { + did_alloc_block_link = 0; + if (0 == limit_nesting) { + l->ref_cnt++; + l->parent_generation = parent_generation; + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + btrfsic_print_add_link(state, l); + } + } + + if (limit_nesting > 0 && did_alloc_block_link) { + ret = btrfsic_read_block(state, next_block_ctx); + if (ret < (int)BTRFSIC_BLOCK_SIZE) { + printk(KERN_INFO + "btrfsic: read block @logical %llu failed!\n", + (unsigned long long)next_bytenr); + btrfsic_release_block_ctx(next_block_ctx); + *next_blockp = NULL; + return -1; + } + + *next_blockp = next_block; + } else { + *next_blockp = NULL; + } + (*mirror_nump)++; + + return 0; +} + +static int btrfsic_handle_extent_data( + struct btrfsic_state *state, + struct btrfsic_block *block, + struct btrfsic_block_data_ctx *block_ctx, + u32 item_offset, int force_iodone_flag) +{ + int ret; + struct btrfs_file_extent_item *file_extent_item = + (struct btrfs_file_extent_item *)(block_ctx->data + + offsetof(struct btrfs_leaf, + items) + item_offset); + u64 next_bytenr = + le64_to_cpu(file_extent_item->disk_bytenr) + + le64_to_cpu(file_extent_item->offset); + u64 num_bytes = le64_to_cpu(file_extent_item->num_bytes); + u64 generation = le64_to_cpu(file_extent_item->generation); + struct btrfsic_block_link *l; + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE) + printk(KERN_INFO "extent_data: type %u, disk_bytenr = %llu," + " offset = %llu, num_bytes = %llu\n", + file_extent_item->type, + (unsigned long long) + le64_to_cpu(file_extent_item->disk_bytenr), + (unsigned long long) + le64_to_cpu(file_extent_item->offset), + (unsigned long long) + le64_to_cpu(file_extent_item->num_bytes)); + if (BTRFS_FILE_EXTENT_REG != file_extent_item->type || + ((u64)0) == le64_to_cpu(file_extent_item->disk_bytenr)) + return 0; + while (num_bytes > 0) { + u32 chunk_len; + int num_copies; + int mirror_num; + + if (num_bytes > BTRFSIC_BLOCK_SIZE) + chunk_len = BTRFSIC_BLOCK_SIZE; + else + chunk_len = num_bytes; + + num_copies = + btrfs_num_copies(&state->root->fs_info->mapping_tree, + next_bytenr, PAGE_SIZE); + if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) + printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", + (unsigned long long)next_bytenr, num_copies); + for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { + struct btrfsic_block_data_ctx next_block_ctx; + struct btrfsic_block *next_block; + int block_was_created; + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO "btrfsic_handle_extent_data(" + "mirror_num=%d)\n", mirror_num); + if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE) + printk(KERN_INFO + "\tdisk_bytenr = %llu, num_bytes %u\n", + (unsigned long long)next_bytenr, + chunk_len); + ret = btrfsic_map_block(state, next_bytenr, + chunk_len, &next_block_ctx, + mirror_num); + if (ret) { + printk(KERN_INFO + "btrfsic: btrfsic_map_block(@%llu," + " mirror=%d) failed!\n", + (unsigned long long)next_bytenr, + mirror_num); + return -1; + } + + next_block = btrfsic_block_lookup_or_add( + state, + &next_block_ctx, + "referenced ", + 0, + force_iodone_flag, + !force_iodone_flag, + mirror_num, + &block_was_created); + if (NULL == next_block) { + printk(KERN_INFO + "btrfsic: error, kmalloc failed!\n"); + btrfsic_release_block_ctx(&next_block_ctx); + return -1; + } + if (!block_was_created) { + if (next_block->logical_bytenr != next_bytenr && + !(!next_block->is_metadata && + 0 == next_block->logical_bytenr)) { + printk(KERN_INFO + "Referenced block" + " @%llu (%s/%llu/%d)" + " found in hash table, D," + " bytenr mismatch" + " (!= stored %llu).\n", + (unsigned long long)next_bytenr, + next_block_ctx.dev->name, + (unsigned long long) + next_block_ctx.dev_bytenr, + mirror_num, + (unsigned long long) + next_block->logical_bytenr); + } + next_block->logical_bytenr = next_bytenr; + next_block->mirror_num = mirror_num; + } + + l = btrfsic_block_link_lookup_or_add(state, + &next_block_ctx, + next_block, block, + generation); + btrfsic_release_block_ctx(&next_block_ctx); + if (NULL == l) + return -1; + } + + next_bytenr += chunk_len; + num_bytes -= chunk_len; + } + + return 0; +} + +static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len, + struct btrfsic_block_data_ctx *block_ctx_out, + int mirror_num) +{ + int ret; + u64 length; + struct btrfs_bio *multi = NULL; + struct btrfs_device *device; + + length = len; + ret = btrfs_map_block(&state->root->fs_info->mapping_tree, READ, + bytenr, &length, &multi, mirror_num); + + device = multi->stripes[0].dev; + block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev); + block_ctx_out->dev_bytenr = multi->stripes[0].physical; + block_ctx_out->start = bytenr; + block_ctx_out->len = len; + block_ctx_out->data = NULL; + block_ctx_out->bh = NULL; + + if (0 == ret) + kfree(multi); + if (NULL == block_ctx_out->dev) { + ret = -ENXIO; + printk(KERN_INFO "btrfsic: error, cannot lookup dev (#1)!\n"); + } + + return ret; +} + +static int btrfsic_map_superblock(struct btrfsic_state *state, u64 bytenr, + u32 len, struct block_device *bdev, + struct btrfsic_block_data_ctx *block_ctx_out) +{ + block_ctx_out->dev = btrfsic_dev_state_lookup(bdev); + block_ctx_out->dev_bytenr = bytenr; + block_ctx_out->start = bytenr; + block_ctx_out->len = len; + block_ctx_out->data = NULL; + block_ctx_out->bh = NULL; + if (NULL != block_ctx_out->dev) { + return 0; + } else { + printk(KERN_INFO "btrfsic: error, cannot lookup dev (#2)!\n"); + return -ENXIO; + } +} + +static void btrfsic_release_block_ctx(struct btrfsic_block_data_ctx *block_ctx) +{ + if (NULL != block_ctx->bh) { + brelse(block_ctx->bh); + block_ctx->bh = NULL; + } +} + +static int btrfsic_read_block(struct btrfsic_state *state, + struct btrfsic_block_data_ctx *block_ctx) +{ + block_ctx->bh = NULL; + if (block_ctx->dev_bytenr & 4095) { + printk(KERN_INFO + "btrfsic: read_block() with unaligned bytenr %llu\n", + (unsigned long long)block_ctx->dev_bytenr); + return -1; + } + if (block_ctx->len > 4096) { + printk(KERN_INFO + "btrfsic: read_block() with too huge size %d\n", + block_ctx->len); + return -1; + } + + block_ctx->bh = __bread(block_ctx->dev->bdev, + block_ctx->dev_bytenr >> 12, 4096); + if (NULL == block_ctx->bh) + return -1; + block_ctx->data = block_ctx->bh->b_data; + + return block_ctx->len; +} + +static void btrfsic_dump_database(struct btrfsic_state *state) +{ + struct list_head *elem_all; + + BUG_ON(NULL == state); + + printk(KERN_INFO "all_blocks_list:\n"); + list_for_each(elem_all, &state->all_blocks_list) { + const struct btrfsic_block *const b_all = + list_entry(elem_all, struct btrfsic_block, + all_blocks_node); + struct list_head *elem_ref_to; + struct list_head *elem_ref_from; + + printk(KERN_INFO "%c-block @%llu (%s/%llu/%d)\n", + btrfsic_get_block_type(state, b_all), + (unsigned long long)b_all->logical_bytenr, + b_all->dev_state->name, + (unsigned long long)b_all->dev_bytenr, + b_all->mirror_num); + + list_for_each(elem_ref_to, &b_all->ref_to_list) { + const struct btrfsic_block_link *const l = + list_entry(elem_ref_to, + struct btrfsic_block_link, + node_ref_to); + + printk(KERN_INFO " %c @%llu (%s/%llu/%d)" + " refers %u* to" + " %c @%llu (%s/%llu/%d)\n", + btrfsic_get_block_type(state, b_all), + (unsigned long long)b_all->logical_bytenr, + b_all->dev_state->name, + (unsigned long long)b_all->dev_bytenr, + b_all->mirror_num, + l->ref_cnt, + btrfsic_get_block_type(state, l->block_ref_to), + (unsigned long long) + l->block_ref_to->logical_bytenr, + l->block_ref_to->dev_state->name, + (unsigned long long)l->block_ref_to->dev_bytenr, + l->block_ref_to->mirror_num); + } + + list_for_each(elem_ref_from, &b_all->ref_from_list) { + const struct btrfsic_block_link *const l = + list_entry(elem_ref_from, + struct btrfsic_block_link, + node_ref_from); + + printk(KERN_INFO " %c @%llu (%s/%llu/%d)" + " is ref %u* from" + " %c @%llu (%s/%llu/%d)\n", + btrfsic_get_block_type(state, b_all), + (unsigned long long)b_all->logical_bytenr, + b_all->dev_state->name, + (unsigned long long)b_all->dev_bytenr, + b_all->mirror_num, + l->ref_cnt, + btrfsic_get_block_type(state, l->block_ref_from), + (unsigned long long) + l->block_ref_from->logical_bytenr, + l->block_ref_from->dev_state->name, + (unsigned long long) + l->block_ref_from->dev_bytenr, + l->block_ref_from->mirror_num); + } + + printk(KERN_INFO "\n"); + } +} + +/* + * Test whether the disk block contains a tree block (leaf or node) + * (note that this test fails for the super block) + */ +static int btrfsic_test_for_metadata(struct btrfsic_state *state, + const u8 *data, unsigned int size) +{ + struct btrfs_header *h; + u8 csum[BTRFS_CSUM_SIZE]; + u32 crc = ~(u32)0; + int fail = 0; + int crc_fail = 0; + + h = (struct btrfs_header *)data; + + if (memcmp(h->fsid, state->root->fs_info->fsid, BTRFS_UUID_SIZE)) + fail++; + + crc = crc32c(crc, data + BTRFS_CSUM_SIZE, PAGE_SIZE - BTRFS_CSUM_SIZE); + btrfs_csum_final(crc, csum); + if (memcmp(csum, h->csum, state->csum_size)) + crc_fail++; + + return fail || crc_fail; +} + +static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state, + u64 dev_bytenr, + u8 *mapped_data, unsigned int len, + struct bio *bio, + int *bio_is_patched, + struct buffer_head *bh, + int submit_bio_bh_rw) +{ + int is_metadata; + struct btrfsic_block *block; + struct btrfsic_block_data_ctx block_ctx; + int ret; + struct btrfsic_state *state = dev_state->state; + struct block_device *bdev = dev_state->bdev; + + WARN_ON(len > PAGE_SIZE); + is_metadata = (0 == btrfsic_test_for_metadata(state, mapped_data, len)); + if (NULL != bio_is_patched) + *bio_is_patched = 0; + + block = btrfsic_block_hashtable_lookup(bdev, dev_bytenr, + &state->block_hashtable); + if (NULL != block) { + u64 bytenr; + struct list_head *elem_ref_to; + struct list_head *tmp_ref_to; + + if (block->is_superblock) { + bytenr = le64_to_cpu(((struct btrfs_super_block *) + mapped_data)->bytenr); + is_metadata = 1; + if (state->print_mask & + BTRFSIC_PRINT_MASK_TREE_BEFORE_SB_WRITE) { + printk(KERN_INFO + "[before new superblock is written]:\n"); + btrfsic_dump_tree_sub(state, block, 0); + } + } + if (is_metadata) { + if (!block->is_superblock) { + bytenr = le64_to_cpu(((struct btrfs_header *) + mapped_data)->bytenr); + btrfsic_cmp_log_and_dev_bytenr(state, bytenr, + dev_state, + dev_bytenr, + mapped_data); + } + if (block->logical_bytenr != bytenr) { + printk(KERN_INFO + "Written block @%llu (%s/%llu/%d)" + " found in hash table, %c," + " bytenr mismatch" + " (!= stored %llu).\n", + (unsigned long long)bytenr, + dev_state->name, + (unsigned long long)dev_bytenr, + block->mirror_num, + btrfsic_get_block_type(state, block), + (unsigned long long) + block->logical_bytenr); + block->logical_bytenr = bytenr; + } else if (state->print_mask & + BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "Written block @%llu (%s/%llu/%d)" + " found in hash table, %c.\n", + (unsigned long long)bytenr, + dev_state->name, + (unsigned long long)dev_bytenr, + block->mirror_num, + btrfsic_get_block_type(state, block)); + } else { + bytenr = block->logical_bytenr; + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "Written block @%llu (%s/%llu/%d)" + " found in hash table, %c.\n", + (unsigned long long)bytenr, + dev_state->name, + (unsigned long long)dev_bytenr, + block->mirror_num, + btrfsic_get_block_type(state, block)); + } + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "ref_to_list: %cE, ref_from_list: %cE\n", + list_empty(&block->ref_to_list) ? ' ' : '!', + list_empty(&block->ref_from_list) ? ' ' : '!'); + if (btrfsic_is_block_ref_by_superblock(state, block, 0)) { + printk(KERN_INFO "btrfs: attempt to overwrite %c-block" + " @%llu (%s/%llu/%d), old(gen=%llu," + " objectid=%llu, type=%d, offset=%llu)," + " new(gen=%llu)," + " which is referenced by most recent superblock" + " (superblockgen=%llu)!\n", + btrfsic_get_block_type(state, block), + (unsigned long long)bytenr, + dev_state->name, + (unsigned long long)dev_bytenr, + block->mirror_num, + (unsigned long long)block->generation, + (unsigned long long) + le64_to_cpu(block->disk_key.objectid), + block->disk_key.type, + (unsigned long long) + le64_to_cpu(block->disk_key.offset), + (unsigned long long) + le64_to_cpu(((struct btrfs_header *) + mapped_data)->generation), + (unsigned long long) + state->max_superblock_generation); + btrfsic_dump_tree(state); + } + + if (!block->is_iodone && !block->never_written) { + printk(KERN_INFO "btrfs: attempt to overwrite %c-block" + " @%llu (%s/%llu/%d), oldgen=%llu, newgen=%llu," + " which is not yet iodone!\n", + btrfsic_get_block_type(state, block), + (unsigned long long)bytenr, + dev_state->name, + (unsigned long long)dev_bytenr, + block->mirror_num, + (unsigned long long)block->generation, + (unsigned long long) + le64_to_cpu(((struct btrfs_header *) + mapped_data)->generation)); + /* it would not be safe to go on */ + btrfsic_dump_tree(state); + return; + } + + /* + * Clear all references of this block. Do not free + * the block itself even if is not referenced anymore + * because it still carries valueable information + * like whether it was ever written and IO completed. + */ + list_for_each_safe(elem_ref_to, tmp_ref_to, + &block->ref_to_list) { + struct btrfsic_block_link *const l = + list_entry(elem_ref_to, + struct btrfsic_block_link, + node_ref_to); + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + btrfsic_print_rem_link(state, l); + l->ref_cnt--; + if (0 == l->ref_cnt) { + list_del(&l->node_ref_to); + list_del(&l->node_ref_from); + btrfsic_block_link_hashtable_remove(l); + btrfsic_block_link_free(l); + } + } + + if (block->is_superblock) + ret = btrfsic_map_superblock(state, bytenr, len, + bdev, &block_ctx); + else + ret = btrfsic_map_block(state, bytenr, len, + &block_ctx, 0); + if (ret) { + printk(KERN_INFO + "btrfsic: btrfsic_map_block(root @%llu)" + " failed!\n", (unsigned long long)bytenr); + return; + } + block_ctx.data = mapped_data; + /* the following is required in case of writes to mirrors, + * use the same that was used for the lookup */ + block_ctx.dev = dev_state; + block_ctx.dev_bytenr = dev_bytenr; + + if (is_metadata || state->include_extent_data) { + block->never_written = 0; + block->iodone_w_error = 0; + if (NULL != bio) { + block->is_iodone = 0; + BUG_ON(NULL == bio_is_patched); + if (!*bio_is_patched) { + block->orig_bio_bh_private = + bio->bi_private; + block->orig_bio_bh_end_io.bio = + bio->bi_end_io; + block->next_in_same_bio = NULL; + bio->bi_private = block; + bio->bi_end_io = btrfsic_bio_end_io; + *bio_is_patched = 1; + } else { + struct btrfsic_block *chained_block = + (struct btrfsic_block *) + bio->bi_private; + + BUG_ON(NULL == chained_block); + block->orig_bio_bh_private = + chained_block->orig_bio_bh_private; + block->orig_bio_bh_end_io.bio = + chained_block->orig_bio_bh_end_io. + bio; + block->next_in_same_bio = chained_block; + bio->bi_private = block; + } + } else if (NULL != bh) { + block->is_iodone = 0; + block->orig_bio_bh_private = bh->b_private; + block->orig_bio_bh_end_io.bh = bh->b_end_io; + block->next_in_same_bio = NULL; + bh->b_private = block; + bh->b_end_io = btrfsic_bh_end_io; + } else { + block->is_iodone = 1; + block->orig_bio_bh_private = NULL; + block->orig_bio_bh_end_io.bio = NULL; + block->next_in_same_bio = NULL; + } + } + + block->flush_gen = dev_state->last_flush_gen + 1; + block->submit_bio_bh_rw = submit_bio_bh_rw; + if (is_metadata) { + block->logical_bytenr = bytenr; + block->is_metadata = 1; + if (block->is_superblock) { + ret = btrfsic_process_written_superblock( + state, + block, + (struct btrfs_super_block *) + mapped_data); + if (state->print_mask & + BTRFSIC_PRINT_MASK_TREE_AFTER_SB_WRITE) { + printk(KERN_INFO + "[after new superblock is written]:\n"); + btrfsic_dump_tree_sub(state, block, 0); + } + } else { + block->mirror_num = 0; /* unknown */ + ret = btrfsic_process_metablock( + state, + block, + &block_ctx, + (struct btrfs_header *) + block_ctx.data, + 0, 0); + } + if (ret) + printk(KERN_INFO + "btrfsic: btrfsic_process_metablock" + "(root @%llu) failed!\n", + (unsigned long long)dev_bytenr); + } else { + block->is_metadata = 0; + block->mirror_num = 0; /* unknown */ + block->generation = BTRFSIC_GENERATION_UNKNOWN; + if (!state->include_extent_data + && list_empty(&block->ref_from_list)) { + /* + * disk block is overwritten with extent + * data (not meta data) and we are configured + * to not include extent data: take the + * chance and free the block's memory + */ + btrfsic_block_hashtable_remove(block); + list_del(&block->all_blocks_node); + btrfsic_block_free(block); + } + } + btrfsic_release_block_ctx(&block_ctx); + } else { + /* block has not been found in hash table */ + u64 bytenr; + + if (!is_metadata) { + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO "Written block (%s/%llu/?)" + " !found in hash table, D.\n", + dev_state->name, + (unsigned long long)dev_bytenr); + if (!state->include_extent_data) + return; /* ignore that written D block */ + + /* this is getting ugly for the + * include_extent_data case... */ + bytenr = 0; /* unknown */ + block_ctx.start = bytenr; + block_ctx.len = len; + block_ctx.bh = NULL; + } else { + bytenr = le64_to_cpu(((struct btrfs_header *) + mapped_data)->bytenr); + btrfsic_cmp_log_and_dev_bytenr(state, bytenr, dev_state, + dev_bytenr, + mapped_data); + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "Written block @%llu (%s/%llu/?)" + " !found in hash table, M.\n", + (unsigned long long)bytenr, + dev_state->name, + (unsigned long long)dev_bytenr); + + ret = btrfsic_map_block(state, bytenr, len, &block_ctx, + 0); + if (ret) { + printk(KERN_INFO + "btrfsic: btrfsic_map_block(root @%llu)" + " failed!\n", + (unsigned long long)dev_bytenr); + return; + } + } + block_ctx.data = mapped_data; + /* the following is required in case of writes to mirrors, + * use the same that was used for the lookup */ + block_ctx.dev = dev_state; + block_ctx.dev_bytenr = dev_bytenr; + + block = btrfsic_block_alloc(); + if (NULL == block) { + printk(KERN_INFO "btrfsic: error, kmalloc failed!\n"); + btrfsic_release_block_ctx(&block_ctx); + return; + } + block->dev_state = dev_state; + block->dev_bytenr = dev_bytenr; + block->logical_bytenr = bytenr; + block->is_metadata = is_metadata; + block->never_written = 0; + block->iodone_w_error = 0; + block->mirror_num = 0; /* unknown */ + block->flush_gen = dev_state->last_flush_gen + 1; + block->submit_bio_bh_rw = submit_bio_bh_rw; + if (NULL != bio) { + block->is_iodone = 0; + BUG_ON(NULL == bio_is_patched); + if (!*bio_is_patched) { + block->orig_bio_bh_private = bio->bi_private; + block->orig_bio_bh_end_io.bio = bio->bi_end_io; + block->next_in_same_bio = NULL; + bio->bi_private = block; + bio->bi_end_io = btrfsic_bio_end_io; + *bio_is_patched = 1; + } else { + struct btrfsic_block *chained_block = + (struct btrfsic_block *) + bio->bi_private; + + BUG_ON(NULL == chained_block); + block->orig_bio_bh_private = + chained_block->orig_bio_bh_private; + block->orig_bio_bh_end_io.bio = + chained_block->orig_bio_bh_end_io.bio; + block->next_in_same_bio = chained_block; + bio->bi_private = block; + } + } else if (NULL != bh) { + block->is_iodone = 0; + block->orig_bio_bh_private = bh->b_private; + block->orig_bio_bh_end_io.bh = bh->b_end_io; + block->next_in_same_bio = NULL; + bh->b_private = block; + bh->b_end_io = btrfsic_bh_end_io; + } else { + block->is_iodone = 1; + block->orig_bio_bh_private = NULL; + block->orig_bio_bh_end_io.bio = NULL; + block->next_in_same_bio = NULL; + } + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "New written %c-block @%llu (%s/%llu/%d)\n", + is_metadata ? 'M' : 'D', + (unsigned long long)block->logical_bytenr, + block->dev_state->name, + (unsigned long long)block->dev_bytenr, + block->mirror_num); + list_add(&block->all_blocks_node, &state->all_blocks_list); + btrfsic_block_hashtable_add(block, &state->block_hashtable); + + if (is_metadata) { + ret = btrfsic_process_metablock(state, block, + &block_ctx, + (struct btrfs_header *) + block_ctx.data, 0, 0); + if (ret) + printk(KERN_INFO + "btrfsic: process_metablock(root @%llu)" + " failed!\n", + (unsigned long long)dev_bytenr); + } + btrfsic_release_block_ctx(&block_ctx); + } +} + +static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) +{ + struct btrfsic_block *block = (struct btrfsic_block *)bp->bi_private; + int iodone_w_error; + + /* mutex is not held! This is not save if IO is not yet completed + * on umount */ + iodone_w_error = 0; + if (bio_error_status) + iodone_w_error = 1; + + BUG_ON(NULL == block); + bp->bi_private = block->orig_bio_bh_private; + bp->bi_end_io = block->orig_bio_bh_end_io.bio; + + do { + struct btrfsic_block *next_block; + struct btrfsic_dev_state *const dev_state = block->dev_state; + + if ((dev_state->state->print_mask & + BTRFSIC_PRINT_MASK_END_IO_BIO_BH)) + printk(KERN_INFO + "bio_end_io(err=%d) for %c @%llu (%s/%llu/%d)\n", + bio_error_status, + btrfsic_get_block_type(dev_state->state, block), + (unsigned long long)block->logical_bytenr, + dev_state->name, + (unsigned long long)block->dev_bytenr, + block->mirror_num); + next_block = block->next_in_same_bio; + block->iodone_w_error = iodone_w_error; + if (block->submit_bio_bh_rw & REQ_FLUSH) { + dev_state->last_flush_gen++; + if ((dev_state->state->print_mask & + BTRFSIC_PRINT_MASK_END_IO_BIO_BH)) + printk(KERN_INFO + "bio_end_io() new %s flush_gen=%llu\n", + dev_state->name, + (unsigned long long) + dev_state->last_flush_gen); + } + if (block->submit_bio_bh_rw & REQ_FUA) + block->flush_gen = 0; /* FUA completed means block is + * on disk */ + block->is_iodone = 1; /* for FLUSH, this releases the block */ + block = next_block; + } while (NULL != block); + + bp->bi_end_io(bp, bio_error_status); +} + +static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate) +{ + struct btrfsic_block *block = (struct btrfsic_block *)bh->b_private; + int iodone_w_error = !uptodate; + struct btrfsic_dev_state *dev_state; + + BUG_ON(NULL == block); + dev_state = block->dev_state; + if ((dev_state->state->print_mask & BTRFSIC_PRINT_MASK_END_IO_BIO_BH)) + printk(KERN_INFO + "bh_end_io(error=%d) for %c @%llu (%s/%llu/%d)\n", + iodone_w_error, + btrfsic_get_block_type(dev_state->state, block), + (unsigned long long)block->logical_bytenr, + block->dev_state->name, + (unsigned long long)block->dev_bytenr, + block->mirror_num); + + block->iodone_w_error = iodone_w_error; + if (block->submit_bio_bh_rw & REQ_FLUSH) { + dev_state->last_flush_gen++; + if ((dev_state->state->print_mask & + BTRFSIC_PRINT_MASK_END_IO_BIO_BH)) + printk(KERN_INFO + "bh_end_io() new %s flush_gen=%llu\n", + dev_state->name, + (unsigned long long)dev_state->last_flush_gen); + } + if (block->submit_bio_bh_rw & REQ_FUA) + block->flush_gen = 0; /* FUA completed means block is on disk */ + + bh->b_private = block->orig_bio_bh_private; + bh->b_end_io = block->orig_bio_bh_end_io.bh; + block->is_iodone = 1; /* for FLUSH, this releases the block */ + bh->b_end_io(bh, uptodate); +} + +static int btrfsic_process_written_superblock( + struct btrfsic_state *state, + struct btrfsic_block *const superblock, + struct btrfs_super_block *const super_hdr) +{ + int pass; + + superblock->generation = btrfs_super_generation(super_hdr); + if (!(superblock->generation > state->max_superblock_generation || + 0 == state->max_superblock_generation)) { + if (state->print_mask & BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE) + printk(KERN_INFO + "btrfsic: superblock @%llu (%s/%llu/%d)" + " with old gen %llu <= %llu\n", + (unsigned long long)superblock->logical_bytenr, + superblock->dev_state->name, + (unsigned long long)superblock->dev_bytenr, + superblock->mirror_num, + (unsigned long long) + btrfs_super_generation(super_hdr), + (unsigned long long) + state->max_superblock_generation); + } else { + if (state->print_mask & BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE) + printk(KERN_INFO + "btrfsic: got new superblock @%llu (%s/%llu/%d)" + " with new gen %llu > %llu\n", + (unsigned long long)superblock->logical_bytenr, + superblock->dev_state->name, + (unsigned long long)superblock->dev_bytenr, + superblock->mirror_num, + (unsigned long long) + btrfs_super_generation(super_hdr), + (unsigned long long) + state->max_superblock_generation); + + state->max_superblock_generation = + btrfs_super_generation(super_hdr); + state->latest_superblock = superblock; + } + + for (pass = 0; pass < 3; pass++) { + int ret; + u64 next_bytenr; + struct btrfsic_block *next_block; + struct btrfsic_block_data_ctx tmp_next_block_ctx; + struct btrfsic_block_link *l; + int num_copies; + int mirror_num; + const char *additional_string = NULL; + struct btrfs_disk_key tmp_disk_key; + + tmp_disk_key.type = BTRFS_ROOT_ITEM_KEY; + tmp_disk_key.offset = 0; + + switch (pass) { + case 0: + tmp_disk_key.objectid = + cpu_to_le64(BTRFS_ROOT_TREE_OBJECTID); + additional_string = "root "; + next_bytenr = btrfs_super_root(super_hdr); + if (state->print_mask & + BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION) + printk(KERN_INFO "root@%llu\n", + (unsigned long long)next_bytenr); + break; + case 1: + tmp_disk_key.objectid = + cpu_to_le64(BTRFS_CHUNK_TREE_OBJECTID); + additional_string = "chunk "; + next_bytenr = btrfs_super_chunk_root(super_hdr); + if (state->print_mask & + BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION) + printk(KERN_INFO "chunk@%llu\n", + (unsigned long long)next_bytenr); + break; + case 2: + tmp_disk_key.objectid = + cpu_to_le64(BTRFS_TREE_LOG_OBJECTID); + additional_string = "log "; + next_bytenr = btrfs_super_log_root(super_hdr); + if (0 == next_bytenr) + continue; + if (state->print_mask & + BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION) + printk(KERN_INFO "log@%llu\n", + (unsigned long long)next_bytenr); + break; + } + + num_copies = + btrfs_num_copies(&state->root->fs_info->mapping_tree, + next_bytenr, PAGE_SIZE); + if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES) + printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n", + (unsigned long long)next_bytenr, num_copies); + for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { + int was_created; + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "btrfsic_process_written_superblock(" + "mirror_num=%d)\n", mirror_num); + ret = btrfsic_map_block(state, next_bytenr, PAGE_SIZE, + &tmp_next_block_ctx, + mirror_num); + if (ret) { + printk(KERN_INFO + "btrfsic: btrfsic_map_block(@%llu," + " mirror=%d) failed!\n", + (unsigned long long)next_bytenr, + mirror_num); + return -1; + } + + next_block = btrfsic_block_lookup_or_add( + state, + &tmp_next_block_ctx, + additional_string, + 1, 0, 1, + mirror_num, + &was_created); + if (NULL == next_block) { + printk(KERN_INFO + "btrfsic: error, kmalloc failed!\n"); + btrfsic_release_block_ctx(&tmp_next_block_ctx); + return -1; + } + + next_block->disk_key = tmp_disk_key; + if (was_created) + next_block->generation = + BTRFSIC_GENERATION_UNKNOWN; + l = btrfsic_block_link_lookup_or_add( + state, + &tmp_next_block_ctx, + next_block, + superblock, + BTRFSIC_GENERATION_UNKNOWN); + btrfsic_release_block_ctx(&tmp_next_block_ctx); + if (NULL == l) + return -1; + } + } + + if (-1 == btrfsic_check_all_ref_blocks(state, superblock, 0)) { + WARN_ON(1); + btrfsic_dump_tree(state); + } + + return 0; +} + +static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state, + struct btrfsic_block *const block, + int recursion_level) +{ + struct list_head *elem_ref_to; + int ret = 0; + + if (recursion_level >= 3 + BTRFS_MAX_LEVEL) { + /* + * Note that this situation can happen and does not + * indicate an error in regular cases. It happens + * when disk blocks are freed and later reused. + * The check-integrity module is not aware of any + * block free operations, it just recognizes block + * write operations. Therefore it keeps the linkage + * information for a block until a block is + * rewritten. This can temporarily cause incorrect + * and even circular linkage informations. This + * causes no harm unless such blocks are referenced + * by the most recent super block. + */ + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "btrfsic: abort cyclic linkage (case 1).\n"); + + return ret; + } + + /* + * This algorithm is recursive because the amount of used stack + * space is very small and the max recursion depth is limited. + */ + list_for_each(elem_ref_to, &block->ref_to_list) { + const struct btrfsic_block_link *const l = + list_entry(elem_ref_to, struct btrfsic_block_link, + node_ref_to); + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "rl=%d, %c @%llu (%s/%llu/%d)" + " %u* refers to %c @%llu (%s/%llu/%d)\n", + recursion_level, + btrfsic_get_block_type(state, block), + (unsigned long long)block->logical_bytenr, + block->dev_state->name, + (unsigned long long)block->dev_bytenr, + block->mirror_num, + l->ref_cnt, + btrfsic_get_block_type(state, l->block_ref_to), + (unsigned long long) + l->block_ref_to->logical_bytenr, + l->block_ref_to->dev_state->name, + (unsigned long long)l->block_ref_to->dev_bytenr, + l->block_ref_to->mirror_num); + if (l->block_ref_to->never_written) { + printk(KERN_INFO "btrfs: attempt to write superblock" + " which references block %c @%llu (%s/%llu/%d)" + " which is never written!\n", + btrfsic_get_block_type(state, l->block_ref_to), + (unsigned long long) + l->block_ref_to->logical_bytenr, + l->block_ref_to->dev_state->name, + (unsigned long long)l->block_ref_to->dev_bytenr, + l->block_ref_to->mirror_num); + ret = -1; + } else if (!l->block_ref_to->is_iodone) { + printk(KERN_INFO "btrfs: attempt to write superblock" + " which references block %c @%llu (%s/%llu/%d)" + " which is not yet iodone!\n", + btrfsic_get_block_type(state, l->block_ref_to), + (unsigned long long) + l->block_ref_to->logical_bytenr, + l->block_ref_to->dev_state->name, + (unsigned long long)l->block_ref_to->dev_bytenr, + l->block_ref_to->mirror_num); + ret = -1; + } else if (l->parent_generation != + l->block_ref_to->generation && + BTRFSIC_GENERATION_UNKNOWN != + l->parent_generation && + BTRFSIC_GENERATION_UNKNOWN != + l->block_ref_to->generation) { + printk(KERN_INFO "btrfs: attempt to write superblock" + " which references block %c @%llu (%s/%llu/%d)" + " with generation %llu !=" + " parent generation %llu!\n", + btrfsic_get_block_type(state, l->block_ref_to), + (unsigned long long) + l->block_ref_to->logical_bytenr, + l->block_ref_to->dev_state->name, + (unsigned long long)l->block_ref_to->dev_bytenr, + l->block_ref_to->mirror_num, + (unsigned long long)l->block_ref_to->generation, + (unsigned long long)l->parent_generation); + ret = -1; + } else if (l->block_ref_to->flush_gen > + l->block_ref_to->dev_state->last_flush_gen) { + printk(KERN_INFO "btrfs: attempt to write superblock" + " which references block %c @%llu (%s/%llu/%d)" + " which is not flushed out of disk's write cache" + " (block flush_gen=%llu," + " dev->flush_gen=%llu)!\n", + btrfsic_get_block_type(state, l->block_ref_to), + (unsigned long long) + l->block_ref_to->logical_bytenr, + l->block_ref_to->dev_state->name, + (unsigned long long)l->block_ref_to->dev_bytenr, + l->block_ref_to->mirror_num, + (unsigned long long)block->flush_gen, + (unsigned long long) + l->block_ref_to->dev_state->last_flush_gen); + ret = -1; + } else if (-1 == btrfsic_check_all_ref_blocks(state, + l->block_ref_to, + recursion_level + + 1)) { + ret = -1; + } + } + + return ret; +} + +static int btrfsic_is_block_ref_by_superblock( + const struct btrfsic_state *state, + const struct btrfsic_block *block, + int recursion_level) +{ + struct list_head *elem_ref_from; + + if (recursion_level >= 3 + BTRFS_MAX_LEVEL) { + /* refer to comment at "abort cyclic linkage (case 1)" */ + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "btrfsic: abort cyclic linkage (case 2).\n"); + + return 0; + } + + /* + * This algorithm is recursive because the amount of used stack space + * is very small and the max recursion depth is limited. + */ + list_for_each(elem_ref_from, &block->ref_from_list) { + const struct btrfsic_block_link *const l = + list_entry(elem_ref_from, struct btrfsic_block_link, + node_ref_from); + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "rl=%d, %c @%llu (%s/%llu/%d)" + " is ref %u* from %c @%llu (%s/%llu/%d)\n", + recursion_level, + btrfsic_get_block_type(state, block), + (unsigned long long)block->logical_bytenr, + block->dev_state->name, + (unsigned long long)block->dev_bytenr, + block->mirror_num, + l->ref_cnt, + btrfsic_get_block_type(state, l->block_ref_from), + (unsigned long long) + l->block_ref_from->logical_bytenr, + l->block_ref_from->dev_state->name, + (unsigned long long) + l->block_ref_from->dev_bytenr, + l->block_ref_from->mirror_num); + if (l->block_ref_from->is_superblock && + state->latest_superblock->dev_bytenr == + l->block_ref_from->dev_bytenr && + state->latest_superblock->dev_state->bdev == + l->block_ref_from->dev_state->bdev) + return 1; + else if (btrfsic_is_block_ref_by_superblock(state, + l->block_ref_from, + recursion_level + + 1)) + return 1; + } + + return 0; +} + +static void btrfsic_print_add_link(const struct btrfsic_state *state, + const struct btrfsic_block_link *l) +{ + printk(KERN_INFO + "Add %u* link from %c @%llu (%s/%llu/%d)" + " to %c @%llu (%s/%llu/%d).\n", + l->ref_cnt, + btrfsic_get_block_type(state, l->block_ref_from), + (unsigned long long)l->block_ref_from->logical_bytenr, + l->block_ref_from->dev_state->name, + (unsigned long long)l->block_ref_from->dev_bytenr, + l->block_ref_from->mirror_num, + btrfsic_get_block_type(state, l->block_ref_to), + (unsigned long long)l->block_ref_to->logical_bytenr, + l->block_ref_to->dev_state->name, + (unsigned long long)l->block_ref_to->dev_bytenr, + l->block_ref_to->mirror_num); +} + +static void btrfsic_print_rem_link(const struct btrfsic_state *state, + const struct btrfsic_block_link *l) +{ + printk(KERN_INFO + "Rem %u* link from %c @%llu (%s/%llu/%d)" + " to %c @%llu (%s/%llu/%d).\n", + l->ref_cnt, + btrfsic_get_block_type(state, l->block_ref_from), + (unsigned long long)l->block_ref_from->logical_bytenr, + l->block_ref_from->dev_state->name, + (unsigned long long)l->block_ref_from->dev_bytenr, + l->block_ref_from->mirror_num, + btrfsic_get_block_type(state, l->block_ref_to), + (unsigned long long)l->block_ref_to->logical_bytenr, + l->block_ref_to->dev_state->name, + (unsigned long long)l->block_ref_to->dev_bytenr, + l->block_ref_to->mirror_num); +} + +static char btrfsic_get_block_type(const struct btrfsic_state *state, + const struct btrfsic_block *block) +{ + if (block->is_superblock && + state->latest_superblock->dev_bytenr == block->dev_bytenr && + state->latest_superblock->dev_state->bdev == block->dev_state->bdev) + return 'S'; + else if (block->is_superblock) + return 's'; + else if (block->is_metadata) + return 'M'; + else + return 'D'; +} + +static void btrfsic_dump_tree(const struct btrfsic_state *state) +{ + btrfsic_dump_tree_sub(state, state->latest_superblock, 0); +} + +static void btrfsic_dump_tree_sub(const struct btrfsic_state *state, + const struct btrfsic_block *block, + int indent_level) +{ + struct list_head *elem_ref_to; + int indent_add; + static char buf[80]; + int cursor_position; + + /* + * Should better fill an on-stack buffer with a complete line and + * dump it at once when it is time to print a newline character. + */ + + /* + * This algorithm is recursive because the amount of used stack space + * is very small and the max recursion depth is limited. + */ + indent_add = sprintf(buf, "%c-%llu(%s/%llu/%d)", + btrfsic_get_block_type(state, block), + (unsigned long long)block->logical_bytenr, + block->dev_state->name, + (unsigned long long)block->dev_bytenr, + block->mirror_num); + if (indent_level + indent_add > BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL) { + printk("[...]\n"); + return; + } + printk(buf); + indent_level += indent_add; + if (list_empty(&block->ref_to_list)) { + printk("\n"); + return; + } + if (block->mirror_num > 1 && + !(state->print_mask & BTRFSIC_PRINT_MASK_TREE_WITH_ALL_MIRRORS)) { + printk(" [...]\n"); + return; + } + + cursor_position = indent_level; + list_for_each(elem_ref_to, &block->ref_to_list) { + const struct btrfsic_block_link *const l = + list_entry(elem_ref_to, struct btrfsic_block_link, + node_ref_to); + + while (cursor_position < indent_level) { + printk(" "); + cursor_position++; + } + if (l->ref_cnt > 1) + indent_add = sprintf(buf, " %d*--> ", l->ref_cnt); + else + indent_add = sprintf(buf, " --> "); + if (indent_level + indent_add > + BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL) { + printk("[...]\n"); + cursor_position = 0; + continue; + } + + printk(buf); + + btrfsic_dump_tree_sub(state, l->block_ref_to, + indent_level + indent_add); + cursor_position = 0; + } +} + +static struct btrfsic_block_link *btrfsic_block_link_lookup_or_add( + struct btrfsic_state *state, + struct btrfsic_block_data_ctx *next_block_ctx, + struct btrfsic_block *next_block, + struct btrfsic_block *from_block, + u64 parent_generation) +{ + struct btrfsic_block_link *l; + + l = btrfsic_block_link_hashtable_lookup(next_block_ctx->dev->bdev, + next_block_ctx->dev_bytenr, + from_block->dev_state->bdev, + from_block->dev_bytenr, + &state->block_link_hashtable); + if (NULL == l) { + l = btrfsic_block_link_alloc(); + if (NULL == l) { + printk(KERN_INFO + "btrfsic: error, kmalloc" " failed!\n"); + return NULL; + } + + l->block_ref_to = next_block; + l->block_ref_from = from_block; + l->ref_cnt = 1; + l->parent_generation = parent_generation; + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + btrfsic_print_add_link(state, l); + + list_add(&l->node_ref_to, &from_block->ref_to_list); + list_add(&l->node_ref_from, &next_block->ref_from_list); + + btrfsic_block_link_hashtable_add(l, + &state->block_link_hashtable); + } else { + l->ref_cnt++; + l->parent_generation = parent_generation; + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + btrfsic_print_add_link(state, l); + } + + return l; +} + +static struct btrfsic_block *btrfsic_block_lookup_or_add( + struct btrfsic_state *state, + struct btrfsic_block_data_ctx *block_ctx, + const char *additional_string, + int is_metadata, + int is_iodone, + int never_written, + int mirror_num, + int *was_created) +{ + struct btrfsic_block *block; + + block = btrfsic_block_hashtable_lookup(block_ctx->dev->bdev, + block_ctx->dev_bytenr, + &state->block_hashtable); + if (NULL == block) { + struct btrfsic_dev_state *dev_state; + + block = btrfsic_block_alloc(); + if (NULL == block) { + printk(KERN_INFO "btrfsic: error, kmalloc failed!\n"); + return NULL; + } + dev_state = btrfsic_dev_state_lookup(block_ctx->dev->bdev); + if (NULL == dev_state) { + printk(KERN_INFO + "btrfsic: error, lookup dev_state failed!\n"); + btrfsic_block_free(block); + return NULL; + } + block->dev_state = dev_state; + block->dev_bytenr = block_ctx->dev_bytenr; + block->logical_bytenr = block_ctx->start; + block->is_metadata = is_metadata; + block->is_iodone = is_iodone; + block->never_written = never_written; + block->mirror_num = mirror_num; + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + printk(KERN_INFO + "New %s%c-block @%llu (%s/%llu/%d)\n", + additional_string, + btrfsic_get_block_type(state, block), + (unsigned long long)block->logical_bytenr, + dev_state->name, + (unsigned long long)block->dev_bytenr, + mirror_num); + list_add(&block->all_blocks_node, &state->all_blocks_list); + btrfsic_block_hashtable_add(block, &state->block_hashtable); + if (NULL != was_created) + *was_created = 1; + } else { + if (NULL != was_created) + *was_created = 0; + } + + return block; +} + +static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state, + u64 bytenr, + struct btrfsic_dev_state *dev_state, + u64 dev_bytenr, char *data) +{ + int num_copies; + int mirror_num; + int ret; + struct btrfsic_block_data_ctx block_ctx; + int match = 0; + + num_copies = btrfs_num_copies(&state->root->fs_info->mapping_tree, + bytenr, PAGE_SIZE); + + for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { + ret = btrfsic_map_block(state, bytenr, PAGE_SIZE, + &block_ctx, mirror_num); + if (ret) { + printk(KERN_INFO "btrfsic:" + " btrfsic_map_block(logical @%llu," + " mirror %d) failed!\n", + (unsigned long long)bytenr, mirror_num); + continue; + } + + if (dev_state->bdev == block_ctx.dev->bdev && + dev_bytenr == block_ctx.dev_bytenr) { + match++; + btrfsic_release_block_ctx(&block_ctx); + break; + } + btrfsic_release_block_ctx(&block_ctx); + } + + if (!match) { + printk(KERN_INFO "btrfs: attempt to write M-block which contains logical bytenr that doesn't map to dev+physical bytenr of submit_bio," + " buffer->log_bytenr=%llu, submit_bio(bdev=%s," + " phys_bytenr=%llu)!\n", + (unsigned long long)bytenr, dev_state->name, + (unsigned long long)dev_bytenr); + for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) { + ret = btrfsic_map_block(state, bytenr, PAGE_SIZE, + &block_ctx, mirror_num); + if (ret) + continue; + + printk(KERN_INFO "Read logical bytenr @%llu maps to" + " (%s/%llu/%d)\n", + (unsigned long long)bytenr, + block_ctx.dev->name, + (unsigned long long)block_ctx.dev_bytenr, + mirror_num); + } + WARN_ON(1); + } +} + +static struct btrfsic_dev_state *btrfsic_dev_state_lookup( + struct block_device *bdev) +{ + struct btrfsic_dev_state *ds; + + ds = btrfsic_dev_state_hashtable_lookup(bdev, + &btrfsic_dev_state_hashtable); + return ds; +} + +int btrfsic_submit_bh(int rw, struct buffer_head *bh) +{ + struct btrfsic_dev_state *dev_state; + + if (!btrfsic_is_initialized) + return submit_bh(rw, bh); + + mutex_lock(&btrfsic_mutex); + /* since btrfsic_submit_bh() might also be called before + * btrfsic_mount(), this might return NULL */ + dev_state = btrfsic_dev_state_lookup(bh->b_bdev); + + /* Only called to write the superblock (incl. FLUSH/FUA) */ + if (NULL != dev_state && + (rw & WRITE) && bh->b_size > 0) { + u64 dev_bytenr; + + dev_bytenr = 4096 * bh->b_blocknr; + if (dev_state->state->print_mask & + BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) + printk(KERN_INFO + "submit_bh(rw=0x%x, blocknr=%lu (bytenr %llu)," + " size=%lu, data=%p, bdev=%p)\n", + rw, bh->b_blocknr, + (unsigned long long)dev_bytenr, bh->b_size, + bh->b_data, bh->b_bdev); + btrfsic_process_written_block(dev_state, dev_bytenr, + bh->b_data, bh->b_size, NULL, + NULL, bh, rw); + } else if (NULL != dev_state && (rw & REQ_FLUSH)) { + if (dev_state->state->print_mask & + BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) + printk(KERN_INFO + "submit_bh(rw=0x%x) FLUSH, bdev=%p)\n", + rw, bh->b_bdev); + if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) { + if ((dev_state->state->print_mask & + (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | + BTRFSIC_PRINT_MASK_VERBOSE))) + printk(KERN_INFO + "btrfsic_submit_bh(%s) with FLUSH" + " but dummy block already in use" + " (ignored)!\n", + dev_state->name); + } else { + struct btrfsic_block *const block = + &dev_state->dummy_block_for_bio_bh_flush; + + block->is_iodone = 0; + block->never_written = 0; + block->iodone_w_error = 0; + block->flush_gen = dev_state->last_flush_gen + 1; + block->submit_bio_bh_rw = rw; + block->orig_bio_bh_private = bh->b_private; + block->orig_bio_bh_end_io.bh = bh->b_end_io; + block->next_in_same_bio = NULL; + bh->b_private = block; + bh->b_end_io = btrfsic_bh_end_io; + } + } + mutex_unlock(&btrfsic_mutex); + return submit_bh(rw, bh); +} + +void btrfsic_submit_bio(int rw, struct bio *bio) +{ + struct btrfsic_dev_state *dev_state; + + if (!btrfsic_is_initialized) { + submit_bio(rw, bio); + return; + } + + mutex_lock(&btrfsic_mutex); + /* since btrfsic_submit_bio() is also called before + * btrfsic_mount(), this might return NULL */ + dev_state = btrfsic_dev_state_lookup(bio->bi_bdev); + if (NULL != dev_state && + (rw & WRITE) && NULL != bio->bi_io_vec) { + unsigned int i; + u64 dev_bytenr; + int bio_is_patched; + + dev_bytenr = 512 * bio->bi_sector; + bio_is_patched = 0; + if (dev_state->state->print_mask & + BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) + printk(KERN_INFO + "submit_bio(rw=0x%x, bi_vcnt=%u," + " bi_sector=%lu (bytenr %llu), bi_bdev=%p)\n", + rw, bio->bi_vcnt, bio->bi_sector, + (unsigned long long)dev_bytenr, + bio->bi_bdev); + + for (i = 0; i < bio->bi_vcnt; i++) { + u8 *mapped_data; + + mapped_data = kmap(bio->bi_io_vec[i].bv_page); + if ((BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | + BTRFSIC_PRINT_MASK_VERBOSE) == + (dev_state->state->print_mask & + (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | + BTRFSIC_PRINT_MASK_VERBOSE))) + printk(KERN_INFO + "#%u: page=%p, mapped=%p, len=%u," + " offset=%u\n", + i, bio->bi_io_vec[i].bv_page, + mapped_data, + bio->bi_io_vec[i].bv_len, + bio->bi_io_vec[i].bv_offset); + btrfsic_process_written_block(dev_state, dev_bytenr, + mapped_data, + bio->bi_io_vec[i].bv_len, + bio, &bio_is_patched, + NULL, rw); + kunmap(bio->bi_io_vec[i].bv_page); + dev_bytenr += bio->bi_io_vec[i].bv_len; + } + } else if (NULL != dev_state && (rw & REQ_FLUSH)) { + if (dev_state->state->print_mask & + BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) + printk(KERN_INFO + "submit_bio(rw=0x%x) FLUSH, bdev=%p)\n", + rw, bio->bi_bdev); + if (!dev_state->dummy_block_for_bio_bh_flush.is_iodone) { + if ((dev_state->state->print_mask & + (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | + BTRFSIC_PRINT_MASK_VERBOSE))) + printk(KERN_INFO + "btrfsic_submit_bio(%s) with FLUSH" + " but dummy block already in use" + " (ignored)!\n", + dev_state->name); + } else { + struct btrfsic_block *const block = + &dev_state->dummy_block_for_bio_bh_flush; + + block->is_iodone = 0; + block->never_written = 0; + block->iodone_w_error = 0; + block->flush_gen = dev_state->last_flush_gen + 1; + block->submit_bio_bh_rw = rw; + block->orig_bio_bh_private = bio->bi_private; + block->orig_bio_bh_end_io.bio = bio->bi_end_io; + block->next_in_same_bio = NULL; + bio->bi_private = block; + bio->bi_end_io = btrfsic_bio_end_io; + } + } + mutex_unlock(&btrfsic_mutex); + + submit_bio(rw, bio); +} + +int btrfsic_mount(struct btrfs_root *root, + struct btrfs_fs_devices *fs_devices, + int including_extent_data, u32 print_mask) +{ + int ret; + struct btrfsic_state *state; + struct list_head *dev_head = &fs_devices->devices; + struct btrfs_device *device; + + state = kzalloc(sizeof(*state), GFP_NOFS); + if (NULL == state) { + printk(KERN_INFO "btrfs check-integrity: kmalloc() failed!\n"); + return -1; + } + + if (!btrfsic_is_initialized) { + mutex_init(&btrfsic_mutex); + btrfsic_dev_state_hashtable_init(&btrfsic_dev_state_hashtable); + btrfsic_is_initialized = 1; + } + mutex_lock(&btrfsic_mutex); + state->root = root; + state->print_mask = print_mask; + state->include_extent_data = including_extent_data; + state->csum_size = 0; + INIT_LIST_HEAD(&state->all_blocks_list); + btrfsic_block_hashtable_init(&state->block_hashtable); + btrfsic_block_link_hashtable_init(&state->block_link_hashtable); + state->max_superblock_generation = 0; + state->latest_superblock = NULL; + + list_for_each_entry(device, dev_head, dev_list) { + struct btrfsic_dev_state *ds; + char *p; + + if (!device->bdev || !device->name) + continue; + + ds = btrfsic_dev_state_alloc(); + if (NULL == ds) { + printk(KERN_INFO + "btrfs check-integrity: kmalloc() failed!\n"); + mutex_unlock(&btrfsic_mutex); + return -1; + } + ds->bdev = device->bdev; + ds->state = state; + bdevname(ds->bdev, ds->name); + ds->name[BDEVNAME_SIZE - 1] = '\0'; + for (p = ds->name; *p != '\0'; p++); + while (p > ds->name && *p != '/') + p--; + if (*p == '/') + p++; + strlcpy(ds->name, p, sizeof(ds->name)); + btrfsic_dev_state_hashtable_add(ds, + &btrfsic_dev_state_hashtable); + } + + ret = btrfsic_process_superblock(state, fs_devices); + if (0 != ret) { + mutex_unlock(&btrfsic_mutex); + btrfsic_unmount(root, fs_devices); + return ret; + } + + if (state->print_mask & BTRFSIC_PRINT_MASK_INITIAL_DATABASE) + btrfsic_dump_database(state); + if (state->print_mask & BTRFSIC_PRINT_MASK_INITIAL_TREE) + btrfsic_dump_tree(state); + + mutex_unlock(&btrfsic_mutex); + return 0; +} + +void btrfsic_unmount(struct btrfs_root *root, + struct btrfs_fs_devices *fs_devices) +{ + struct list_head *elem_all; + struct list_head *tmp_all; + struct btrfsic_state *state; + struct list_head *dev_head = &fs_devices->devices; + struct btrfs_device *device; + + if (!btrfsic_is_initialized) + return; + + mutex_lock(&btrfsic_mutex); + + state = NULL; + list_for_each_entry(device, dev_head, dev_list) { + struct btrfsic_dev_state *ds; + + if (!device->bdev || !device->name) + continue; + + ds = btrfsic_dev_state_hashtable_lookup( + device->bdev, + &btrfsic_dev_state_hashtable); + if (NULL != ds) { + state = ds->state; + btrfsic_dev_state_hashtable_remove(ds); + btrfsic_dev_state_free(ds); + } + } + + if (NULL == state) { + printk(KERN_INFO + "btrfsic: error, cannot find state information" + " on umount!\n"); + mutex_unlock(&btrfsic_mutex); + return; + } + + /* + * Don't care about keeping the lists' state up to date, + * just free all memory that was allocated dynamically. + * Free the blocks and the block_links. + */ + list_for_each_safe(elem_all, tmp_all, &state->all_blocks_list) { + struct btrfsic_block *const b_all = + list_entry(elem_all, struct btrfsic_block, + all_blocks_node); + struct list_head *elem_ref_to; + struct list_head *tmp_ref_to; + + list_for_each_safe(elem_ref_to, tmp_ref_to, + &b_all->ref_to_list) { + struct btrfsic_block_link *const l = + list_entry(elem_ref_to, + struct btrfsic_block_link, + node_ref_to); + + if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE) + btrfsic_print_rem_link(state, l); + + l->ref_cnt--; + if (0 == l->ref_cnt) + btrfsic_block_link_free(l); + } + + if (b_all->is_iodone) + btrfsic_block_free(b_all); + else + printk(KERN_INFO "btrfs: attempt to free %c-block" + " @%llu (%s/%llu/%d) on umount which is" + " not yet iodone!\n", + btrfsic_get_block_type(state, b_all), + (unsigned long long)b_all->logical_bytenr, + b_all->dev_state->name, + (unsigned long long)b_all->dev_bytenr, + b_all->mirror_num); + } + + mutex_unlock(&btrfsic_mutex); + + kfree(state); +} diff --git a/fs/btrfs/check-integrity.h b/fs/btrfs/check-integrity.h new file mode 100644 index 000000000000..8b59175cc502 --- /dev/null +++ b/fs/btrfs/check-integrity.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) STRATO AG 2011. 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 v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#if !defined(__BTRFS_CHECK_INTEGRITY__) +#define __BTRFS_CHECK_INTEGRITY__ + +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY +int btrfsic_submit_bh(int rw, struct buffer_head *bh); +void btrfsic_submit_bio(int rw, struct bio *bio); +#else +#define btrfsic_submit_bh submit_bh +#define btrfsic_submit_bio submit_bio +#endif + +int btrfsic_mount(struct btrfs_root *root, + struct btrfs_fs_devices *fs_devices, + int including_extent_data, u32 print_mask); +void btrfsic_unmount(struct btrfs_root *root, + struct btrfs_fs_devices *fs_devices); + +#endif diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index dede441bdeee..0639a555e16e 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -240,7 +240,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, cow = btrfs_alloc_free_block(trans, root, buf->len, 0, new_root_objectid, &disk_key, level, - buf->start, 0); + buf->start, 0, 1); if (IS_ERR(cow)) return PTR_ERR(cow); @@ -261,9 +261,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, WARN_ON(btrfs_header_generation(buf) > trans->transid); if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID) - ret = btrfs_inc_ref(trans, root, cow, 1); + ret = btrfs_inc_ref(trans, root, cow, 1, 1); else - ret = btrfs_inc_ref(trans, root, cow, 0); + ret = btrfs_inc_ref(trans, root, cow, 0, 1); if (ret) return ret; @@ -350,14 +350,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, if ((owner == root->root_key.objectid || root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { - ret = btrfs_inc_ref(trans, root, buf, 1); + ret = btrfs_inc_ref(trans, root, buf, 1, 1); BUG_ON(ret); if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { - ret = btrfs_dec_ref(trans, root, buf, 0); + ret = btrfs_dec_ref(trans, root, buf, 0, 1); BUG_ON(ret); - ret = btrfs_inc_ref(trans, root, cow, 1); + ret = btrfs_inc_ref(trans, root, cow, 1, 1); BUG_ON(ret); } new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; @@ -365,9 +365,9 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) - ret = btrfs_inc_ref(trans, root, cow, 1); + ret = btrfs_inc_ref(trans, root, cow, 1, 1); else - ret = btrfs_inc_ref(trans, root, cow, 0); + ret = btrfs_inc_ref(trans, root, cow, 0, 1); BUG_ON(ret); } if (new_flags != 0) { @@ -381,11 +381,11 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) { if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) - ret = btrfs_inc_ref(trans, root, cow, 1); + ret = btrfs_inc_ref(trans, root, cow, 1, 1); else - ret = btrfs_inc_ref(trans, root, cow, 0); + ret = btrfs_inc_ref(trans, root, cow, 0, 1); BUG_ON(ret); - ret = btrfs_dec_ref(trans, root, buf, 1); + ret = btrfs_dec_ref(trans, root, buf, 1, 1); BUG_ON(ret); } clean_tree_block(trans, root, buf); @@ -446,7 +446,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, cow = btrfs_alloc_free_block(trans, root, buf->len, parent_start, root->root_key.objectid, &disk_key, - level, search_start, empty_size); + level, search_start, empty_size, 1); if (IS_ERR(cow)) return PTR_ERR(cow); @@ -484,7 +484,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, rcu_assign_pointer(root->node, cow); btrfs_free_tree_block(trans, root, buf, parent_start, - last_ref); + last_ref, 1); free_extent_buffer(buf); add_root_to_dirty_list(root); } else { @@ -500,7 +500,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, trans->transid); btrfs_mark_buffer_dirty(parent); btrfs_free_tree_block(trans, root, buf, parent_start, - last_ref); + last_ref, 1); } if (unlock_orig) btrfs_tree_unlock(buf); @@ -957,7 +957,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, free_extent_buffer(mid); root_sub_used(root, mid->len); - btrfs_free_tree_block(trans, root, mid, 0, 1); + btrfs_free_tree_block(trans, root, mid, 0, 1, 0); /* once for the root ptr */ free_extent_buffer(mid); return 0; @@ -1015,7 +1015,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, if (wret) ret = wret; root_sub_used(root, right->len); - btrfs_free_tree_block(trans, root, right, 0, 1); + btrfs_free_tree_block(trans, root, right, 0, 1, 0); free_extent_buffer(right); right = NULL; } else { @@ -1055,7 +1055,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, if (wret) ret = wret; root_sub_used(root, mid->len); - btrfs_free_tree_block(trans, root, mid, 0, 1); + btrfs_free_tree_block(trans, root, mid, 0, 1, 0); free_extent_buffer(mid); mid = NULL; } else { @@ -2089,7 +2089,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, c = btrfs_alloc_free_block(trans, root, root->nodesize, 0, root->root_key.objectid, &lower_key, - level, root->node->start, 0); + level, root->node->start, 0, 0); if (IS_ERR(c)) return PTR_ERR(c); @@ -2216,7 +2216,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans, split = btrfs_alloc_free_block(trans, root, root->nodesize, 0, root->root_key.objectid, - &disk_key, level, c->start, 0); + &disk_key, level, c->start, 0, 0); if (IS_ERR(split)) return PTR_ERR(split); @@ -2970,7 +2970,7 @@ again: right = btrfs_alloc_free_block(trans, root, root->leafsize, 0, root->root_key.objectid, - &disk_key, 0, l->start, 0); + &disk_key, 0, l->start, 0, 0); if (IS_ERR(right)) return PTR_ERR(right); @@ -3781,7 +3781,7 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans, root_sub_used(root, leaf->len); - btrfs_free_tree_block(trans, root, leaf, 0, 1); + btrfs_free_tree_block(trans, root, leaf, 0, 1, 0); return 0; } /* diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 67385033323d..27ebe61d3ccc 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -86,6 +86,9 @@ struct btrfs_ordered_sum; /* holds checksums of all the data extents */ #define BTRFS_CSUM_TREE_OBJECTID 7ULL +/* for storing balance parameters in the root tree */ +#define BTRFS_BALANCE_OBJECTID -4ULL + /* orhpan objectid for tracking unlinked/truncated files */ #define BTRFS_ORPHAN_OBJECTID -5ULL @@ -692,6 +695,54 @@ struct btrfs_root_ref { __le16 name_len; } __attribute__ ((__packed__)); +struct btrfs_disk_balance_args { + /* + * profiles to operate on, single is denoted by + * BTRFS_AVAIL_ALLOC_BIT_SINGLE + */ + __le64 profiles; + + /* usage filter */ + __le64 usage; + + /* devid filter */ + __le64 devid; + + /* devid subset filter [pstart..pend) */ + __le64 pstart; + __le64 pend; + + /* btrfs virtual address space subset filter [vstart..vend) */ + __le64 vstart; + __le64 vend; + + /* + * profile to convert to, single is denoted by + * BTRFS_AVAIL_ALLOC_BIT_SINGLE + */ + __le64 target; + + /* BTRFS_BALANCE_ARGS_* */ + __le64 flags; + + __le64 unused[8]; +} __attribute__ ((__packed__)); + +/* + * store balance parameters to disk so that balance can be properly + * resumed after crash or unmount + */ +struct btrfs_balance_item { + /* BTRFS_BALANCE_* */ + __le64 flags; + + struct btrfs_disk_balance_args data; + struct btrfs_disk_balance_args meta; + struct btrfs_disk_balance_args sys; + + __le64 unused[4]; +} __attribute__ ((__packed__)); + #define BTRFS_FILE_EXTENT_INLINE 0 #define BTRFS_FILE_EXTENT_REG 1 #define BTRFS_FILE_EXTENT_PREALLOC 2 @@ -751,14 +802,32 @@ struct btrfs_csum_item { } __attribute__ ((__packed__)); /* different types of block groups (and chunks) */ -#define BTRFS_BLOCK_GROUP_DATA (1 << 0) -#define BTRFS_BLOCK_GROUP_SYSTEM (1 << 1) -#define BTRFS_BLOCK_GROUP_METADATA (1 << 2) -#define BTRFS_BLOCK_GROUP_RAID0 (1 << 3) -#define BTRFS_BLOCK_GROUP_RAID1 (1 << 4) -#define BTRFS_BLOCK_GROUP_DUP (1 << 5) -#define BTRFS_BLOCK_GROUP_RAID10 (1 << 6) -#define BTRFS_NR_RAID_TYPES 5 +#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) +#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) +#define BTRFS_BLOCK_GROUP_METADATA (1ULL << 2) +#define BTRFS_BLOCK_GROUP_RAID0 (1ULL << 3) +#define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4) +#define BTRFS_BLOCK_GROUP_DUP (1ULL << 5) +#define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6) +#define BTRFS_BLOCK_GROUP_RESERVED BTRFS_AVAIL_ALLOC_BIT_SINGLE +#define BTRFS_NR_RAID_TYPES 5 + +#define BTRFS_BLOCK_GROUP_TYPE_MASK (BTRFS_BLOCK_GROUP_DATA | \ + BTRFS_BLOCK_GROUP_SYSTEM | \ + BTRFS_BLOCK_GROUP_METADATA) + +#define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \ + BTRFS_BLOCK_GROUP_RAID1 | \ + BTRFS_BLOCK_GROUP_DUP | \ + BTRFS_BLOCK_GROUP_RAID10) +/* + * We need a bit for restriper to be able to tell when chunks of type + * SINGLE are available. This "extended" profile format is used in + * fs_info->avail_*_alloc_bits (in-memory) and balance item fields + * (on-disk). The corresponding on-disk bit in chunk.type is reserved + * to avoid remappings between two formats in future. + */ +#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) struct btrfs_block_group_item { __le64 used; @@ -916,6 +985,7 @@ struct btrfs_block_group_cache { struct reloc_control; struct btrfs_device; struct btrfs_fs_devices; +struct btrfs_balance_control; struct btrfs_delayed_root; struct btrfs_fs_info { u8 fsid[BTRFS_FSID_SIZE]; @@ -971,7 +1041,7 @@ struct btrfs_fs_info { * is required instead of the faster short fsync log commits */ u64 last_trans_log_full_commit; - unsigned long mount_opt:20; + unsigned long mount_opt:21; unsigned long compress_type:4; u64 max_inline; u64 alloc_start; @@ -1132,12 +1202,23 @@ struct btrfs_fs_info { spinlock_t ref_cache_lock; u64 total_ref_cache_size; + /* + * these three are in extended format (availability of single + * chunks is denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other + * types are denoted by corresponding BTRFS_BLOCK_GROUP_* bits) + */ u64 avail_data_alloc_bits; u64 avail_metadata_alloc_bits; u64 avail_system_alloc_bits; - u64 data_alloc_profile; - u64 metadata_alloc_profile; - u64 system_alloc_profile; + + /* restriper state */ + spinlock_t balance_lock; + struct mutex balance_mutex; + atomic_t balance_running; + atomic_t balance_pause_req; + atomic_t balance_cancel_req; + struct btrfs_balance_control *balance_ctl; + wait_queue_head_t balance_wait_q; unsigned data_chunk_allocations; unsigned metadata_ratio; @@ -1155,6 +1236,10 @@ struct btrfs_fs_info { int scrub_workers_refcnt; struct btrfs_workers scrub_workers; +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY + u32 check_integrity_print_mask; +#endif + /* filesystem state */ u64 fs_state; @@ -1383,6 +1468,8 @@ struct btrfs_ioctl_defrag_range_args { #define BTRFS_DEV_ITEM_KEY 216 #define BTRFS_CHUNK_ITEM_KEY 228 +#define BTRFS_BALANCE_ITEM_KEY 248 + /* * string items are for debugging. They just store a short string of * data in the FS @@ -1413,6 +1500,9 @@ struct btrfs_ioctl_defrag_range_args { #define BTRFS_MOUNT_AUTO_DEFRAG (1 << 16) #define BTRFS_MOUNT_INODE_MAP_CACHE (1 << 17) #define BTRFS_MOUNT_RECOVERY (1 << 18) +#define BTRFS_MOUNT_SKIP_BALANCE (1 << 19) +#define BTRFS_MOUNT_CHECK_INTEGRITY (1 << 20) +#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21) #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) @@ -2077,8 +2167,86 @@ BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup, BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup, num_devices, 64); -/* struct btrfs_super_block */ +/* struct btrfs_balance_item */ +BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64); +static inline void btrfs_balance_data(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + read_eb_member(eb, bi, struct btrfs_balance_item, data, ba); +} + +static inline void btrfs_set_balance_data(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + write_eb_member(eb, bi, struct btrfs_balance_item, data, ba); +} + +static inline void btrfs_balance_meta(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba); +} + +static inline void btrfs_set_balance_meta(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba); +} + +static inline void btrfs_balance_sys(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba); +} + +static inline void btrfs_set_balance_sys(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba); +} + +static inline void +btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu, + struct btrfs_disk_balance_args *disk) +{ + memset(cpu, 0, sizeof(*cpu)); + + cpu->profiles = le64_to_cpu(disk->profiles); + cpu->usage = le64_to_cpu(disk->usage); + cpu->devid = le64_to_cpu(disk->devid); + cpu->pstart = le64_to_cpu(disk->pstart); + cpu->pend = le64_to_cpu(disk->pend); + cpu->vstart = le64_to_cpu(disk->vstart); + cpu->vend = le64_to_cpu(disk->vend); + cpu->target = le64_to_cpu(disk->target); + cpu->flags = le64_to_cpu(disk->flags); +} + +static inline void +btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk, + struct btrfs_balance_args *cpu) +{ + memset(disk, 0, sizeof(*disk)); + + disk->profiles = cpu_to_le64(cpu->profiles); + disk->usage = cpu_to_le64(cpu->usage); + disk->devid = cpu_to_le64(cpu->devid); + disk->pstart = cpu_to_le64(cpu->pstart); + disk->pend = cpu_to_le64(cpu->pend); + disk->vstart = cpu_to_le64(cpu->vstart); + disk->vend = cpu_to_le64(cpu->vend); + disk->target = cpu_to_le64(cpu->target); + disk->flags = cpu_to_le64(cpu->flags); +} + +/* struct btrfs_super_block */ BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64); BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block, @@ -2196,7 +2364,7 @@ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb, return btrfs_item_size(eb, e) - offset; } -static inline struct btrfs_root *btrfs_sb(struct super_block *sb) +static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb) { return sb->s_fs_info; } @@ -2277,11 +2445,11 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u32 blocksize, u64 parent, u64 root_objectid, struct btrfs_disk_key *key, int level, - u64 hint, u64 empty_size); + u64 hint, u64 empty_size, int for_cow); void btrfs_free_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, - u64 parent, int last_ref); + u64 parent, int last_ref, int for_cow); struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u32 blocksize, @@ -2301,17 +2469,17 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, u64 search_end, struct btrfs_key *ins, u64 data); int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct extent_buffer *buf, int full_backref); + struct extent_buffer *buf, int full_backref, int for_cow); int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct extent_buffer *buf, int full_backref); + struct extent_buffer *buf, int full_backref, int for_cow); int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 flags, int is_data); int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, - u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, u64 offset); + u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, + u64 owner, u64 offset, int for_cow); int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root, @@ -2323,7 +2491,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, u64 offset); + u64 root_objectid, u64 owner, u64 offset, int for_cow); int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, struct btrfs_root *root); @@ -2482,10 +2650,18 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, } int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); +static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) +{ + ++p->slots[0]; + if (p->slots[0] >= btrfs_header_nritems(p->nodes[0])) + return btrfs_next_leaf(root, p); + return 0; +} int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); void btrfs_drop_snapshot(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, int update_ref); + struct btrfs_block_rsv *block_rsv, int update_ref, + int for_reloc); int btrfs_drop_subtree(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *node, @@ -2500,6 +2676,7 @@ static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info) } static inline void free_fs_info(struct btrfs_fs_info *fs_info) { + kfree(fs_info->balance_ctl); kfree(fs_info->delayed_root); kfree(fs_info->extent_root); kfree(fs_info->tree_root); @@ -2510,6 +2687,24 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info) kfree(fs_info->super_for_commit); kfree(fs_info); } +/** + * profile_is_valid - tests whether a given profile is valid and reduced + * @flags: profile to validate + * @extended: if true @flags is treated as an extended profile + */ +static inline int profile_is_valid(u64 flags, int extended) +{ + u64 mask = ~BTRFS_BLOCK_GROUP_PROFILE_MASK; + + flags &= ~BTRFS_BLOCK_GROUP_TYPE_MASK; + if (extended) + mask &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE; + + if (flags & mask) + return 0; + /* true if zero or exactly one bit set */ + return (flags & (~flags + 1)) == flags; +} /* root-item.c */ int btrfs_find_root_ref(struct btrfs_root *tree_root, diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 9c1eccc2c503..fe4cd0f1cef1 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -595,8 +595,12 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans, num_bytes = btrfs_calc_trans_metadata_size(root, 1); ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes); - if (!ret) + if (!ret) { + trace_btrfs_space_reservation(root->fs_info, "delayed_item", + item->key.objectid, + num_bytes, 1); item->bytes_reserved = num_bytes; + } return ret; } @@ -610,6 +614,9 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root, return; rsv = &root->fs_info->delayed_block_rsv; + trace_btrfs_space_reservation(root->fs_info, "delayed_item", + item->key.objectid, item->bytes_reserved, + 0); btrfs_block_rsv_release(root, rsv, item->bytes_reserved); } @@ -624,7 +631,7 @@ static int btrfs_delayed_inode_reserve_metadata( struct btrfs_block_rsv *dst_rsv; u64 num_bytes; int ret; - int release = false; + bool release = false; src_rsv = trans->block_rsv; dst_rsv = &root->fs_info->delayed_block_rsv; @@ -651,8 +658,13 @@ static int btrfs_delayed_inode_reserve_metadata( */ if (ret == -EAGAIN) ret = -ENOSPC; - if (!ret) + if (!ret) { node->bytes_reserved = num_bytes; + trace_btrfs_space_reservation(root->fs_info, + "delayed_inode", + btrfs_ino(inode), + num_bytes, 1); + } return ret; } else if (src_rsv == &root->fs_info->delalloc_block_rsv) { spin_lock(&BTRFS_I(inode)->lock); @@ -707,11 +719,17 @@ out: * reservation here. I think it may be time for a documentation page on * how block rsvs. work. */ - if (!ret) + if (!ret) { + trace_btrfs_space_reservation(root->fs_info, "delayed_inode", + btrfs_ino(inode), num_bytes, 1); node->bytes_reserved = num_bytes; + } - if (release) + if (release) { + trace_btrfs_space_reservation(root->fs_info, "delalloc", + btrfs_ino(inode), num_bytes, 0); btrfs_block_rsv_release(root, src_rsv, num_bytes); + } return ret; } @@ -725,6 +743,8 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root, return; rsv = &root->fs_info->delayed_block_rsv; + trace_btrfs_space_reservation(root->fs_info, "delayed_inode", + node->inode_id, node->bytes_reserved, 0); btrfs_block_rsv_release(root, rsv, node->bytes_reserved); node->bytes_reserved = 0; @@ -1372,13 +1392,6 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, goto release_node; } - ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item); - /* - * we have reserved enough space when we start a new transaction, - * so reserving metadata failure is impossible - */ - BUG_ON(ret); - delayed_item->key.objectid = btrfs_ino(dir); btrfs_set_key_type(&delayed_item->key, BTRFS_DIR_INDEX_KEY); delayed_item->key.offset = index; @@ -1391,6 +1404,14 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, dir_item->type = type; memcpy((char *)(dir_item + 1), name, name_len); + ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item); + /* + * we have reserved enough space when we start a new transaction, + * so reserving metadata failure is impossible + */ + BUG_ON(ret); + + mutex_lock(&delayed_node->mutex); ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item); if (unlikely(ret)) { diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 125cf76fcd08..66e4f29505a3 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -101,6 +101,11 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref2, return -1; if (ref1->type > ref2->type) return 1; + /* merging of sequenced refs is not allowed */ + if (ref1->seq < ref2->seq) + return -1; + if (ref1->seq > ref2->seq) + return 1; if (ref1->type == BTRFS_TREE_BLOCK_REF_KEY || ref1->type == BTRFS_SHARED_BLOCK_REF_KEY) { return comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref2), @@ -150,16 +155,22 @@ static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root, /* * find an head entry based on bytenr. This returns the delayed ref - * head if it was able to find one, or NULL if nothing was in that spot + * head if it was able to find one, or NULL if nothing was in that spot. + * If return_bigger is given, the next bigger entry is returned if no exact + * match is found. */ static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root, u64 bytenr, - struct btrfs_delayed_ref_node **last) + struct btrfs_delayed_ref_node **last, + int return_bigger) { - struct rb_node *n = root->rb_node; + struct rb_node *n; struct btrfs_delayed_ref_node *entry; - int cmp; + int cmp = 0; +again: + n = root->rb_node; + entry = NULL; while (n) { entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node); WARN_ON(!entry->in_tree); @@ -182,6 +193,19 @@ static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root, else return entry; } + if (entry && return_bigger) { + if (cmp > 0) { + n = rb_next(&entry->rb_node); + if (!n) + n = rb_first(root); + entry = rb_entry(n, struct btrfs_delayed_ref_node, + rb_node); + bytenr = entry->bytenr; + return_bigger = 0; + goto again; + } + return entry; + } return NULL; } @@ -209,6 +233,24 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, return 0; } +int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs, + u64 seq) +{ + struct seq_list *elem; + + assert_spin_locked(&delayed_refs->lock); + if (list_empty(&delayed_refs->seq_head)) + return 0; + + elem = list_first_entry(&delayed_refs->seq_head, struct seq_list, list); + if (seq >= elem->seq) { + pr_debug("holding back delayed_ref %llu, lowest is %llu (%p)\n", + seq, elem->seq, delayed_refs); + return 1; + } + return 0; +} + int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans, struct list_head *cluster, u64 start) { @@ -223,20 +265,8 @@ int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans, node = rb_first(&delayed_refs->root); } else { ref = NULL; - find_ref_head(&delayed_refs->root, start, &ref); + find_ref_head(&delayed_refs->root, start + 1, &ref, 1); if (ref) { - struct btrfs_delayed_ref_node *tmp; - - node = rb_prev(&ref->rb_node); - while (node) { - tmp = rb_entry(node, - struct btrfs_delayed_ref_node, - rb_node); - if (tmp->bytenr < start) - break; - ref = tmp; - node = rb_prev(&ref->rb_node); - } node = &ref->rb_node; } else node = rb_first(&delayed_refs->root); @@ -390,7 +420,8 @@ update_existing_head_ref(struct btrfs_delayed_ref_node *existing, * this does all the dirty work in terms of maintaining the correct * overall modification count. */ -static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans, +static noinline int add_delayed_ref_head(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_node *ref, u64 bytenr, u64 num_bytes, int action, int is_data) @@ -437,6 +468,7 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans, ref->action = 0; ref->is_head = 1; ref->in_tree = 1; + ref->seq = 0; head_ref = btrfs_delayed_node_to_head(ref); head_ref->must_insert_reserved = must_insert_reserved; @@ -468,14 +500,17 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans, /* * helper to insert a delayed tree ref into the rbtree. */ -static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans, +static noinline int add_delayed_tree_ref(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_node *ref, u64 bytenr, u64 num_bytes, u64 parent, - u64 ref_root, int level, int action) + u64 ref_root, int level, int action, + int for_cow) { struct btrfs_delayed_ref_node *existing; struct btrfs_delayed_tree_ref *full_ref; struct btrfs_delayed_ref_root *delayed_refs; + u64 seq = 0; if (action == BTRFS_ADD_DELAYED_EXTENT) action = BTRFS_ADD_DELAYED_REF; @@ -491,14 +526,17 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans, ref->is_head = 0; ref->in_tree = 1; + if (need_ref_seq(for_cow, ref_root)) + seq = inc_delayed_seq(delayed_refs); + ref->seq = seq; + full_ref = btrfs_delayed_node_to_tree_ref(ref); - if (parent) { - full_ref->parent = parent; + full_ref->parent = parent; + full_ref->root = ref_root; + if (parent) ref->type = BTRFS_SHARED_BLOCK_REF_KEY; - } else { - full_ref->root = ref_root; + else ref->type = BTRFS_TREE_BLOCK_REF_KEY; - } full_ref->level = level; trace_btrfs_delayed_tree_ref(ref, full_ref, action); @@ -522,15 +560,17 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans, /* * helper to insert a delayed data ref into the rbtree. */ -static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans, +static noinline int add_delayed_data_ref(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_node *ref, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, u64 owner, u64 offset, - int action) + int action, int for_cow) { struct btrfs_delayed_ref_node *existing; struct btrfs_delayed_data_ref *full_ref; struct btrfs_delayed_ref_root *delayed_refs; + u64 seq = 0; if (action == BTRFS_ADD_DELAYED_EXTENT) action = BTRFS_ADD_DELAYED_REF; @@ -546,14 +586,18 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans, ref->is_head = 0; ref->in_tree = 1; + if (need_ref_seq(for_cow, ref_root)) + seq = inc_delayed_seq(delayed_refs); + ref->seq = seq; + full_ref = btrfs_delayed_node_to_data_ref(ref); - if (parent) { - full_ref->parent = parent; + full_ref->parent = parent; + full_ref->root = ref_root; + if (parent) ref->type = BTRFS_SHARED_DATA_REF_KEY; - } else { - full_ref->root = ref_root; + else ref->type = BTRFS_EXTENT_DATA_REF_KEY; - } + full_ref->objectid = owner; full_ref->offset = offset; @@ -580,10 +624,12 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans, * to make sure the delayed ref is eventually processed before this * transaction commits. */ -int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, +int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, int level, int action, - struct btrfs_delayed_extent_op *extent_op) + struct btrfs_delayed_extent_op *extent_op, + int for_cow) { struct btrfs_delayed_tree_ref *ref; struct btrfs_delayed_ref_head *head_ref; @@ -610,13 +656,17 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, * insert both the head node and the new ref without dropping * the spin lock */ - ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, num_bytes, - action, 0); + ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr, + num_bytes, action, 0); BUG_ON(ret); - ret = add_delayed_tree_ref(trans, &ref->node, bytenr, num_bytes, - parent, ref_root, level, action); + ret = add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr, + num_bytes, parent, ref_root, level, action, + for_cow); BUG_ON(ret); + if (!need_ref_seq(for_cow, ref_root) && + waitqueue_active(&delayed_refs->seq_wait)) + wake_up(&delayed_refs->seq_wait); spin_unlock(&delayed_refs->lock); return 0; } @@ -624,11 +674,13 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, /* * add a delayed data ref. it's similar to btrfs_add_delayed_tree_ref. */ -int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, +int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, u64 owner, u64 offset, int action, - struct btrfs_delayed_extent_op *extent_op) + struct btrfs_delayed_extent_op *extent_op, + int for_cow) { struct btrfs_delayed_data_ref *ref; struct btrfs_delayed_ref_head *head_ref; @@ -655,18 +707,23 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, * insert both the head node and the new ref without dropping * the spin lock */ - ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, num_bytes, - action, 1); + ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr, + num_bytes, action, 1); BUG_ON(ret); - ret = add_delayed_data_ref(trans, &ref->node, bytenr, num_bytes, - parent, ref_root, owner, offset, action); + ret = add_delayed_data_ref(fs_info, trans, &ref->node, bytenr, + num_bytes, parent, ref_root, owner, offset, + action, for_cow); BUG_ON(ret); + if (!need_ref_seq(for_cow, ref_root) && + waitqueue_active(&delayed_refs->seq_wait)) + wake_up(&delayed_refs->seq_wait); spin_unlock(&delayed_refs->lock); return 0; } -int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans, +int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, struct btrfs_delayed_extent_op *extent_op) { @@ -683,11 +740,13 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans, delayed_refs = &trans->transaction->delayed_refs; spin_lock(&delayed_refs->lock); - ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, + ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr, num_bytes, BTRFS_UPDATE_DELAYED_HEAD, extent_op->is_data); BUG_ON(ret); + if (waitqueue_active(&delayed_refs->seq_wait)) + wake_up(&delayed_refs->seq_wait); spin_unlock(&delayed_refs->lock); return 0; } @@ -704,7 +763,7 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr) struct btrfs_delayed_ref_root *delayed_refs; delayed_refs = &trans->transaction->delayed_refs; - ref = find_ref_head(&delayed_refs->root, bytenr, NULL); + ref = find_ref_head(&delayed_refs->root, bytenr, NULL, 0); if (ref) return btrfs_delayed_node_to_head(ref); return NULL; diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index e287e3b0eab0..d8f244d94925 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -33,6 +33,9 @@ struct btrfs_delayed_ref_node { /* the size of the extent */ u64 num_bytes; + /* seq number to keep track of insertion order */ + u64 seq; + /* ref count on this data structure */ atomic_t refs; @@ -98,19 +101,15 @@ struct btrfs_delayed_ref_head { struct btrfs_delayed_tree_ref { struct btrfs_delayed_ref_node node; - union { - u64 root; - u64 parent; - }; + u64 root; + u64 parent; int level; }; struct btrfs_delayed_data_ref { struct btrfs_delayed_ref_node node; - union { - u64 root; - u64 parent; - }; + u64 root; + u64 parent; u64 objectid; u64 offset; }; @@ -140,6 +139,26 @@ struct btrfs_delayed_ref_root { int flushing; u64 run_delayed_start; + + /* + * seq number of delayed refs. We need to know if a backref was being + * added before the currently processed ref or afterwards. + */ + u64 seq; + + /* + * seq_list holds a list of all seq numbers that are currently being + * added to the list. While walking backrefs (btrfs_find_all_roots, + * qgroups), which might take some time, no newer ref must be processed, + * as it might influence the outcome of the walk. + */ + struct list_head seq_head; + + /* + * when the only refs we have in the list must not be processed, we want + * to wait for more refs to show up or for the end of backref walking. + */ + wait_queue_head_t seq_wait; }; static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) @@ -151,16 +170,21 @@ static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) } } -int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans, +int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, int level, int action, - struct btrfs_delayed_extent_op *extent_op); -int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans, + struct btrfs_delayed_extent_op *extent_op, + int for_cow); +int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root, u64 owner, u64 offset, int action, - struct btrfs_delayed_extent_op *extent_op); -int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans, + struct btrfs_delayed_extent_op *extent_op, + int for_cow); +int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, + struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, struct btrfs_delayed_extent_op *extent_op); @@ -170,6 +194,60 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_head *head); int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans, struct list_head *cluster, u64 search_start); + +struct seq_list { + struct list_head list; + u64 seq; +}; + +static inline u64 inc_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs) +{ + assert_spin_locked(&delayed_refs->lock); + ++delayed_refs->seq; + return delayed_refs->seq; +} + +static inline void +btrfs_get_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs, + struct seq_list *elem) +{ + assert_spin_locked(&delayed_refs->lock); + elem->seq = delayed_refs->seq; + list_add_tail(&elem->list, &delayed_refs->seq_head); +} + +static inline void +btrfs_put_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs, + struct seq_list *elem) +{ + spin_lock(&delayed_refs->lock); + list_del(&elem->list); + wake_up(&delayed_refs->seq_wait); + spin_unlock(&delayed_refs->lock); +} + +int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs, + u64 seq); + +/* + * delayed refs with a ref_seq > 0 must be held back during backref walking. + * this only applies to items in one of the fs-trees. for_cow items never need + * to be held back, so they won't get a ref_seq number. + */ +static inline int need_ref_seq(int for_cow, u64 rootid) +{ + if (for_cow) + return 0; + + if (rootid == BTRFS_FS_TREE_OBJECTID) + return 1; + + if ((s64)rootid >= (s64)BTRFS_FIRST_FREE_OBJECTID) + return 1; + + return 0; +} + /* * a node might live in a head or a regular ref, this lets you * test for the proper type to use. diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index d8525662ca7a..7aa9cd36bf1b 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -43,6 +43,7 @@ #include "tree-log.h" #include "free-space-cache.h" #include "inode-map.h" +#include "check-integrity.h" static struct extent_io_ops btree_extent_io_ops; static void end_workqueue_fn(struct btrfs_work *work); @@ -1143,7 +1144,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, root->orphan_item_inserted = 0; root->orphan_cleanup_state = 0; - root->fs_info = fs_info; root->objectid = objectid; root->last_trans = 0; root->highest_objectid = 0; @@ -1217,6 +1217,14 @@ static int find_and_setup_root(struct btrfs_root *tree_root, return 0; } +static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info) +{ + struct btrfs_root *root = kzalloc(sizeof(*root), GFP_NOFS); + if (root) + root->fs_info = fs_info; + return root; +} + static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { @@ -1224,7 +1232,7 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root = fs_info->tree_root; struct extent_buffer *leaf; - root = kzalloc(sizeof(*root), GFP_NOFS); + root = btrfs_alloc_root(fs_info); if (!root) return ERR_PTR(-ENOMEM); @@ -1244,7 +1252,8 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, root->ref_cows = 0; leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, - BTRFS_TREE_LOG_OBJECTID, NULL, 0, 0, 0); + BTRFS_TREE_LOG_OBJECTID, NULL, + 0, 0, 0, 0); if (IS_ERR(leaf)) { kfree(root); return ERR_CAST(leaf); @@ -1318,7 +1327,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, u32 blocksize; int ret = 0; - root = kzalloc(sizeof(*root), GFP_NOFS); + root = btrfs_alloc_root(fs_info); if (!root) return ERR_PTR(-ENOMEM); if (location->offset == (u64)-1) { @@ -1874,9 +1883,9 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root) } -struct btrfs_root *open_ctree(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - char *options) +int open_ctree(struct super_block *sb, + struct btrfs_fs_devices *fs_devices, + char *options) { u32 sectorsize; u32 nodesize; @@ -1888,8 +1897,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, struct btrfs_key location; struct buffer_head *bh; struct btrfs_super_block *disk_super; - struct btrfs_root *tree_root = btrfs_sb(sb); - struct btrfs_fs_info *fs_info = tree_root->fs_info; + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + struct btrfs_root *tree_root; struct btrfs_root *extent_root; struct btrfs_root *csum_root; struct btrfs_root *chunk_root; @@ -1900,16 +1909,14 @@ struct btrfs_root *open_ctree(struct super_block *sb, int num_backups_tried = 0; int backup_index = 0; - extent_root = fs_info->extent_root = - kzalloc(sizeof(struct btrfs_root), GFP_NOFS); - csum_root = fs_info->csum_root = - kzalloc(sizeof(struct btrfs_root), GFP_NOFS); - chunk_root = fs_info->chunk_root = - kzalloc(sizeof(struct btrfs_root), GFP_NOFS); - dev_root = fs_info->dev_root = - kzalloc(sizeof(struct btrfs_root), GFP_NOFS); + tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info); + extent_root = fs_info->extent_root = btrfs_alloc_root(fs_info); + csum_root = fs_info->csum_root = btrfs_alloc_root(fs_info); + chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info); + dev_root = fs_info->dev_root = btrfs_alloc_root(fs_info); - if (!extent_root || !csum_root || !chunk_root || !dev_root) { + if (!tree_root || !extent_root || !csum_root || + !chunk_root || !dev_root) { err = -ENOMEM; goto fail; } @@ -1998,6 +2005,17 @@ struct btrfs_root *open_ctree(struct super_block *sb, init_waitqueue_head(&fs_info->scrub_pause_wait); init_rwsem(&fs_info->scrub_super_lock); fs_info->scrub_workers_refcnt = 0; +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY + fs_info->check_integrity_print_mask = 0; +#endif + + spin_lock_init(&fs_info->balance_lock); + mutex_init(&fs_info->balance_mutex); + atomic_set(&fs_info->balance_running, 0); + atomic_set(&fs_info->balance_pause_req, 0); + atomic_set(&fs_info->balance_cancel_req, 0); + fs_info->balance_ctl = NULL; + init_waitqueue_head(&fs_info->balance_wait_q); sb->s_blocksize = 4096; sb->s_blocksize_bits = blksize_bits(4096); @@ -2267,9 +2285,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node), BTRFS_UUID_SIZE); - mutex_lock(&fs_info->chunk_mutex); ret = btrfs_read_chunk_tree(chunk_root); - mutex_unlock(&fs_info->chunk_mutex); if (ret) { printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n", sb->s_id); @@ -2318,9 +2334,6 @@ retry_root_backup: fs_info->generation = generation; fs_info->last_trans_committed = generation; - fs_info->data_alloc_profile = (u64)-1; - fs_info->metadata_alloc_profile = (u64)-1; - fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; ret = btrfs_init_space_info(fs_info); if (ret) { @@ -2353,6 +2366,19 @@ retry_root_backup: btrfs_set_opt(fs_info->mount_opt, SSD); } +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY + if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) { + ret = btrfsic_mount(tree_root, fs_devices, + btrfs_test_opt(tree_root, + CHECK_INTEGRITY_INCLUDING_EXTENT_DATA) ? + 1 : 0, + fs_info->check_integrity_print_mask); + if (ret) + printk(KERN_WARNING "btrfs: failed to initialize" + " integrity check module %s\n", sb->s_id); + } +#endif + /* do not make disk changes in broken FS */ if (btrfs_super_log_root(disk_super) != 0 && !(fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)) { @@ -2368,7 +2394,7 @@ retry_root_backup: btrfs_level_size(tree_root, btrfs_super_log_root_level(disk_super)); - log_tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); + log_tree_root = btrfs_alloc_root(fs_info); if (!log_tree_root) { err = -ENOMEM; goto fail_trans_kthread; @@ -2423,13 +2449,17 @@ retry_root_backup: if (!err) err = btrfs_orphan_cleanup(fs_info->tree_root); up_read(&fs_info->cleanup_work_sem); + + if (!err) + err = btrfs_recover_balance(fs_info->tree_root); + if (err) { close_ctree(tree_root); - return ERR_PTR(err); + return err; } } - return tree_root; + return 0; fail_trans_kthread: kthread_stop(fs_info->transaction_kthread); @@ -2475,8 +2505,7 @@ fail_srcu: cleanup_srcu_struct(&fs_info->subvol_srcu); fail: btrfs_close_devices(fs_info->fs_devices); - free_fs_info(fs_info); - return ERR_PTR(err); + return err; recovery_tree_root: if (!btrfs_test_opt(tree_root, RECOVERY)) @@ -2631,7 +2660,7 @@ static int write_dev_supers(struct btrfs_device *device, * we fua the first super. The others we allow * to go down lazy. */ - ret = submit_bh(WRITE_FUA, bh); + ret = btrfsic_submit_bh(WRITE_FUA, bh); if (ret) errors++; } @@ -2708,7 +2737,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait) device->flush_bio = bio; bio_get(bio); - submit_bio(WRITE_FLUSH, bio); + btrfsic_submit_bio(WRITE_FLUSH, bio); return 0; } @@ -2972,6 +3001,9 @@ int close_ctree(struct btrfs_root *root) fs_info->closing = 1; smp_mb(); + /* pause restriper - we want to resume on mount */ + btrfs_pause_balance(root->fs_info); + btrfs_scrub_cancel(root); /* wait for any defraggers to finish */ @@ -2979,7 +3011,7 @@ int close_ctree(struct btrfs_root *root) (atomic_read(&fs_info->defrag_running) == 0)); /* clear out the rbtree of defraggable inodes */ - btrfs_run_defrag_inodes(root->fs_info); + btrfs_run_defrag_inodes(fs_info); /* * Here come 2 situations when btrfs is broken to flip readonly: @@ -3008,8 +3040,8 @@ int close_ctree(struct btrfs_root *root) btrfs_put_block_group_cache(fs_info); - kthread_stop(root->fs_info->transaction_kthread); - kthread_stop(root->fs_info->cleaner_kthread); + kthread_stop(fs_info->transaction_kthread); + kthread_stop(fs_info->cleaner_kthread); fs_info->closing = 2; smp_mb(); @@ -3027,14 +3059,14 @@ int close_ctree(struct btrfs_root *root) free_extent_buffer(fs_info->extent_root->commit_root); free_extent_buffer(fs_info->tree_root->node); free_extent_buffer(fs_info->tree_root->commit_root); - free_extent_buffer(root->fs_info->chunk_root->node); - free_extent_buffer(root->fs_info->chunk_root->commit_root); - free_extent_buffer(root->fs_info->dev_root->node); - free_extent_buffer(root->fs_info->dev_root->commit_root); - free_extent_buffer(root->fs_info->csum_root->node); - free_extent_buffer(root->fs_info->csum_root->commit_root); + free_extent_buffer(fs_info->chunk_root->node); + free_extent_buffer(fs_info->chunk_root->commit_root); + free_extent_buffer(fs_info->dev_root->node); + free_extent_buffer(fs_info->dev_root->commit_root); + free_extent_buffer(fs_info->csum_root->node); + free_extent_buffer(fs_info->csum_root->commit_root); - btrfs_free_block_groups(root->fs_info); + btrfs_free_block_groups(fs_info); del_fs_roots(fs_info); @@ -3054,14 +3086,17 @@ int close_ctree(struct btrfs_root *root) btrfs_stop_workers(&fs_info->caching_workers); btrfs_stop_workers(&fs_info->readahead_workers); +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY + if (btrfs_test_opt(root, CHECK_INTEGRITY)) + btrfsic_unmount(root, fs_info->fs_devices); +#endif + btrfs_close_devices(fs_info->fs_devices); btrfs_mapping_tree_free(&fs_info->mapping_tree); bdi_destroy(&fs_info->bdi); cleanup_srcu_struct(&fs_info->subvol_srcu); - free_fs_info(fs_info); - return 0; } diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index c99d0a8f13fa..e4bc4741319b 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -46,9 +46,9 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize); int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf); -struct btrfs_root *open_ctree(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - char *options); +int open_ctree(struct super_block *sb, + struct btrfs_fs_devices *fs_devices, + char *options); int close_ctree(struct btrfs_root *root); int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, int max_mirrors); diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index 1b8dc33778f9..5f77166fd01c 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c @@ -67,7 +67,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, u64 root_objectid, u32 generation, int check_generation) { - struct btrfs_fs_info *fs_info = btrfs_sb(sb)->fs_info; + struct btrfs_fs_info *fs_info = btrfs_sb(sb); struct btrfs_root *root; struct inode *inode; struct btrfs_key key; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index f5fbe576d2ba..700879ed64cf 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -618,8 +618,7 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, struct list_head *head = &info->space_info; struct btrfs_space_info *found; - flags &= BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_SYSTEM | - BTRFS_BLOCK_GROUP_METADATA; + flags &= BTRFS_BLOCK_GROUP_TYPE_MASK; rcu_read_lock(); list_for_each_entry_rcu(found, head, list) { @@ -1872,20 +1871,24 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, u64 offset) + u64 root_objectid, u64 owner, u64 offset, int for_cow) { int ret; + struct btrfs_fs_info *fs_info = root->fs_info; + BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID && root_objectid == BTRFS_TREE_LOG_OBJECTID); if (owner < BTRFS_FIRST_FREE_OBJECTID) { - ret = btrfs_add_delayed_tree_ref(trans, bytenr, num_bytes, + ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr, + num_bytes, parent, root_objectid, (int)owner, - BTRFS_ADD_DELAYED_REF, NULL); + BTRFS_ADD_DELAYED_REF, NULL, for_cow); } else { - ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes, + ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr, + num_bytes, parent, root_objectid, owner, offset, - BTRFS_ADD_DELAYED_REF, NULL); + BTRFS_ADD_DELAYED_REF, NULL, for_cow); } return ret; } @@ -2233,6 +2236,28 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, } /* + * locked_ref is the head node, so we have to go one + * node back for any delayed ref updates + */ + ref = select_delayed_ref(locked_ref); + + if (ref && ref->seq && + btrfs_check_delayed_seq(delayed_refs, ref->seq)) { + /* + * there are still refs with lower seq numbers in the + * process of being added. Don't run this ref yet. + */ + list_del_init(&locked_ref->cluster); + mutex_unlock(&locked_ref->mutex); + locked_ref = NULL; + delayed_refs->num_heads_ready++; + spin_unlock(&delayed_refs->lock); + cond_resched(); + spin_lock(&delayed_refs->lock); + continue; + } + + /* * record the must insert reserved flag before we * drop the spin lock. */ @@ -2242,11 +2267,6 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, extent_op = locked_ref->extent_op; locked_ref->extent_op = NULL; - /* - * locked_ref is the head node, so we have to go one - * node back for any delayed ref updates - */ - ref = select_delayed_ref(locked_ref); if (!ref) { /* All delayed refs have been processed, Go ahead * and send the head node to run_one_delayed_ref, @@ -2267,9 +2287,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, BUG_ON(ret); kfree(extent_op); - cond_resched(); - spin_lock(&delayed_refs->lock); - continue; + goto next; } list_del_init(&locked_ref->cluster); @@ -2279,7 +2297,12 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, ref->in_tree = 0; rb_erase(&ref->rb_node, &delayed_refs->root); delayed_refs->num_entries--; - + /* + * we modified num_entries, but as we're currently running + * delayed refs, skip + * wake_up(&delayed_refs->seq_wait); + * here. + */ spin_unlock(&delayed_refs->lock); ret = run_one_delayed_ref(trans, root, ref, extent_op, @@ -2289,13 +2312,34 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, btrfs_put_delayed_ref(ref); kfree(extent_op); count++; - +next: + do_chunk_alloc(trans, root->fs_info->extent_root, + 2 * 1024 * 1024, + btrfs_get_alloc_profile(root, 0), + CHUNK_ALLOC_NO_FORCE); cond_resched(); spin_lock(&delayed_refs->lock); } return count; } + +static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs, + unsigned long num_refs) +{ + struct list_head *first_seq = delayed_refs->seq_head.next; + + spin_unlock(&delayed_refs->lock); + pr_debug("waiting for more refs (num %ld, first %p)\n", + num_refs, first_seq); + wait_event(delayed_refs->seq_wait, + num_refs != delayed_refs->num_entries || + delayed_refs->seq_head.next != first_seq); + pr_debug("done waiting for more refs (num %ld, first %p)\n", + delayed_refs->num_entries, delayed_refs->seq_head.next); + spin_lock(&delayed_refs->lock); +} + /* * this starts processing the delayed reference count updates and * extent insertions we have queued up so far. count can be @@ -2311,15 +2355,23 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_node *ref; struct list_head cluster; int ret; + u64 delayed_start; int run_all = count == (unsigned long)-1; int run_most = 0; + unsigned long num_refs = 0; + int consider_waiting; if (root == root->fs_info->extent_root) root = root->fs_info->tree_root; + do_chunk_alloc(trans, root->fs_info->extent_root, + 2 * 1024 * 1024, btrfs_get_alloc_profile(root, 0), + CHUNK_ALLOC_NO_FORCE); + delayed_refs = &trans->transaction->delayed_refs; INIT_LIST_HEAD(&cluster); again: + consider_waiting = 0; spin_lock(&delayed_refs->lock); if (count == 0) { count = delayed_refs->num_entries * 2; @@ -2336,11 +2388,35 @@ again: * of refs to process starting at the first one we are able to * lock */ + delayed_start = delayed_refs->run_delayed_start; ret = btrfs_find_ref_cluster(trans, &cluster, delayed_refs->run_delayed_start); if (ret) break; + if (delayed_start >= delayed_refs->run_delayed_start) { + if (consider_waiting == 0) { + /* + * btrfs_find_ref_cluster looped. let's do one + * more cycle. if we don't run any delayed ref + * during that cycle (because we can't because + * all of them are blocked) and if the number of + * refs doesn't change, we avoid busy waiting. + */ + consider_waiting = 1; + num_refs = delayed_refs->num_entries; + } else { + wait_for_more_refs(delayed_refs, num_refs); + /* + * after waiting, things have changed. we + * dropped the lock and someone else might have + * run some refs, built new clusters and so on. + * therefore, we restart staleness detection. + */ + consider_waiting = 0; + } + } + ret = run_clustered_refs(trans, root, &cluster); BUG_ON(ret < 0); @@ -2348,6 +2424,11 @@ again: if (count == 0) break; + + if (ret || delayed_refs->run_delayed_start == 0) { + /* refs were run, let's reset staleness detection */ + consider_waiting = 0; + } } if (run_all) { @@ -2405,7 +2486,8 @@ int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans, extent_op->update_key = 0; extent_op->is_data = is_data ? 1 : 0; - ret = btrfs_add_delayed_extent_op(trans, bytenr, num_bytes, extent_op); + ret = btrfs_add_delayed_extent_op(root->fs_info, trans, bytenr, + num_bytes, extent_op); if (ret) kfree(extent_op); return ret; @@ -2590,7 +2672,7 @@ out: static int __btrfs_mod_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, - int full_backref, int inc) + int full_backref, int inc, int for_cow) { u64 bytenr; u64 num_bytes; @@ -2603,7 +2685,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans, int level; int ret = 0; int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *, - u64, u64, u64, u64, u64, u64); + u64, u64, u64, u64, u64, u64, int); ref_root = btrfs_header_owner(buf); nritems = btrfs_header_nritems(buf); @@ -2640,14 +2722,15 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans, key.offset -= btrfs_file_extent_offset(buf, fi); ret = process_func(trans, root, bytenr, num_bytes, parent, ref_root, key.objectid, - key.offset); + key.offset, for_cow); if (ret) goto fail; } else { bytenr = btrfs_node_blockptr(buf, i); num_bytes = btrfs_level_size(root, level - 1); ret = process_func(trans, root, bytenr, num_bytes, - parent, ref_root, level - 1, 0); + parent, ref_root, level - 1, 0, + for_cow); if (ret) goto fail; } @@ -2659,15 +2742,15 @@ fail: } int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct extent_buffer *buf, int full_backref) + struct extent_buffer *buf, int full_backref, int for_cow) { - return __btrfs_mod_ref(trans, root, buf, full_backref, 1); + return __btrfs_mod_ref(trans, root, buf, full_backref, 1, for_cow); } int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct extent_buffer *buf, int full_backref) + struct extent_buffer *buf, int full_backref, int for_cow) { - return __btrfs_mod_ref(trans, root, buf, full_backref, 0); + return __btrfs_mod_ref(trans, root, buf, full_backref, 0, for_cow); } static int write_one_cache_group(struct btrfs_trans_handle *trans, @@ -2993,9 +3076,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, INIT_LIST_HEAD(&found->block_groups[i]); init_rwsem(&found->groups_sem); spin_lock_init(&found->lock); - found->flags = flags & (BTRFS_BLOCK_GROUP_DATA | - BTRFS_BLOCK_GROUP_SYSTEM | - BTRFS_BLOCK_GROUP_METADATA); + found->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK; found->total_bytes = total_bytes; found->disk_total = total_bytes * factor; found->bytes_used = bytes_used; @@ -3016,20 +3097,27 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) { - u64 extra_flags = flags & (BTRFS_BLOCK_GROUP_RAID0 | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_DUP); - if (extra_flags) { - if (flags & BTRFS_BLOCK_GROUP_DATA) - fs_info->avail_data_alloc_bits |= extra_flags; - if (flags & BTRFS_BLOCK_GROUP_METADATA) - fs_info->avail_metadata_alloc_bits |= extra_flags; - if (flags & BTRFS_BLOCK_GROUP_SYSTEM) - fs_info->avail_system_alloc_bits |= extra_flags; - } + u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; + + /* chunk -> extended profile */ + if (extra_flags == 0) + extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE; + + if (flags & BTRFS_BLOCK_GROUP_DATA) + fs_info->avail_data_alloc_bits |= extra_flags; + if (flags & BTRFS_BLOCK_GROUP_METADATA) + fs_info->avail_metadata_alloc_bits |= extra_flags; + if (flags & BTRFS_BLOCK_GROUP_SYSTEM) + fs_info->avail_system_alloc_bits |= extra_flags; } +/* + * @flags: available profiles in extended format (see ctree.h) + * + * Returns reduced profile in chunk format. If profile changing is in + * progress (either running or paused) picks the target profile (if it's + * already available), otherwise falls back to plain reducing. + */ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) { /* @@ -3040,6 +3128,34 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) u64 num_devices = root->fs_info->fs_devices->rw_devices + root->fs_info->fs_devices->missing_devices; + /* pick restriper's target profile if it's available */ + spin_lock(&root->fs_info->balance_lock); + if (root->fs_info->balance_ctl) { + struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; + u64 tgt = 0; + + if ((flags & BTRFS_BLOCK_GROUP_DATA) && + (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) && + (flags & bctl->data.target)) { + tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target; + } else if ((flags & BTRFS_BLOCK_GROUP_SYSTEM) && + (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) && + (flags & bctl->sys.target)) { + tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target; + } else if ((flags & BTRFS_BLOCK_GROUP_METADATA) && + (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) && + (flags & bctl->meta.target)) { + tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target; + } + + if (tgt) { + spin_unlock(&root->fs_info->balance_lock); + flags = tgt; + goto out; + } + } + spin_unlock(&root->fs_info->balance_lock); + if (num_devices == 1) flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0); if (num_devices < 4) @@ -3059,22 +3175,25 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) if ((flags & BTRFS_BLOCK_GROUP_RAID0) && ((flags & BTRFS_BLOCK_GROUP_RAID1) | (flags & BTRFS_BLOCK_GROUP_RAID10) | - (flags & BTRFS_BLOCK_GROUP_DUP))) + (flags & BTRFS_BLOCK_GROUP_DUP))) { flags &= ~BTRFS_BLOCK_GROUP_RAID0; + } + +out: + /* extended -> chunk profile */ + flags &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE; return flags; } static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) { if (flags & BTRFS_BLOCK_GROUP_DATA) - flags |= root->fs_info->avail_data_alloc_bits & - root->fs_info->data_alloc_profile; + flags |= root->fs_info->avail_data_alloc_bits; else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) - flags |= root->fs_info->avail_system_alloc_bits & - root->fs_info->system_alloc_profile; + flags |= root->fs_info->avail_system_alloc_bits; else if (flags & BTRFS_BLOCK_GROUP_METADATA) - flags |= root->fs_info->avail_metadata_alloc_bits & - root->fs_info->metadata_alloc_profile; + flags |= root->fs_info->avail_metadata_alloc_bits; + return btrfs_reduce_alloc_profile(root, flags); } @@ -3191,6 +3310,8 @@ commit_trans: return -ENOSPC; } data_sinfo->bytes_may_use += bytes; + trace_btrfs_space_reservation(root->fs_info, "space_info", + (u64)data_sinfo, bytes, 1); spin_unlock(&data_sinfo->lock); return 0; @@ -3210,6 +3331,8 @@ void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes) data_sinfo = BTRFS_I(inode)->space_info; spin_lock(&data_sinfo->lock); data_sinfo->bytes_may_use -= bytes; + trace_btrfs_space_reservation(root->fs_info, "space_info", + (u64)data_sinfo, bytes, 0); spin_unlock(&data_sinfo->lock); } @@ -3257,27 +3380,15 @@ static int should_alloc_chunk(struct btrfs_root *root, if (num_bytes - num_allocated < thresh) return 1; } - - /* - * we have two similar checks here, one based on percentage - * and once based on a hard number of 256MB. The idea - * is that if we have a good amount of free - * room, don't allocate a chunk. A good mount is - * less than 80% utilized of the chunks we have allocated, - * or more than 256MB free - */ - if (num_allocated + alloc_bytes + 256 * 1024 * 1024 < num_bytes) - return 0; - - if (num_allocated + alloc_bytes < div_factor(num_bytes, 8)) - return 0; - thresh = btrfs_super_total_bytes(root->fs_info->super_copy); - /* 256MB or 5% of the FS */ - thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 5)); + /* 256MB or 2% of the FS */ + thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 2)); + /* system chunks need a much small threshold */ + if (sinfo->flags & BTRFS_BLOCK_GROUP_SYSTEM) + thresh = 32 * 1024 * 1024; - if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 3)) + if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 8)) return 0; return 1; } @@ -3291,7 +3402,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, int wait_for_alloc = 0; int ret = 0; - flags = btrfs_reduce_alloc_profile(extent_root, flags); + BUG_ON(!profile_is_valid(flags, 0)); space_info = __find_space_info(extent_root->fs_info, flags); if (!space_info) { @@ -3582,6 +3693,10 @@ again: if (used <= space_info->total_bytes) { if (used + orig_bytes <= space_info->total_bytes) { space_info->bytes_may_use += orig_bytes; + trace_btrfs_space_reservation(root->fs_info, + "space_info", + (u64)space_info, + orig_bytes, 1); ret = 0; } else { /* @@ -3649,6 +3764,10 @@ again: if (used + num_bytes < space_info->total_bytes + avail) { space_info->bytes_may_use += orig_bytes; + trace_btrfs_space_reservation(root->fs_info, + "space_info", + (u64)space_info, + orig_bytes, 1); ret = 0; } else { wait_ordered = true; @@ -3755,7 +3874,8 @@ static void block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv, spin_unlock(&block_rsv->lock); } -static void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv, +static void block_rsv_release_bytes(struct btrfs_fs_info *fs_info, + struct btrfs_block_rsv *block_rsv, struct btrfs_block_rsv *dest, u64 num_bytes) { struct btrfs_space_info *space_info = block_rsv->space_info; @@ -3791,6 +3911,9 @@ static void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv, if (num_bytes) { spin_lock(&space_info->lock); space_info->bytes_may_use -= num_bytes; + trace_btrfs_space_reservation(fs_info, "space_info", + (u64)space_info, + num_bytes, 0); space_info->reservation_progress++; spin_unlock(&space_info->lock); } @@ -3947,7 +4070,8 @@ void btrfs_block_rsv_release(struct btrfs_root *root, if (global_rsv->full || global_rsv == block_rsv || block_rsv->space_info != global_rsv->space_info) global_rsv = NULL; - block_rsv_release_bytes(block_rsv, global_rsv, num_bytes); + block_rsv_release_bytes(root->fs_info, block_rsv, global_rsv, + num_bytes); } /* @@ -4006,11 +4130,15 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info) num_bytes = sinfo->total_bytes - num_bytes; block_rsv->reserved += num_bytes; sinfo->bytes_may_use += num_bytes; + trace_btrfs_space_reservation(fs_info, "space_info", + (u64)sinfo, num_bytes, 1); } if (block_rsv->reserved >= block_rsv->size) { num_bytes = block_rsv->reserved - block_rsv->size; sinfo->bytes_may_use -= num_bytes; + trace_btrfs_space_reservation(fs_info, "space_info", + (u64)sinfo, num_bytes, 0); sinfo->reservation_progress++; block_rsv->reserved = block_rsv->size; block_rsv->full = 1; @@ -4045,7 +4173,8 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info) static void release_global_block_rsv(struct btrfs_fs_info *fs_info) { - block_rsv_release_bytes(&fs_info->global_block_rsv, NULL, (u64)-1); + block_rsv_release_bytes(fs_info, &fs_info->global_block_rsv, NULL, + (u64)-1); WARN_ON(fs_info->delalloc_block_rsv.size > 0); WARN_ON(fs_info->delalloc_block_rsv.reserved > 0); WARN_ON(fs_info->trans_block_rsv.size > 0); @@ -4062,6 +4191,8 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, if (!trans->bytes_reserved) return; + trace_btrfs_space_reservation(root->fs_info, "transaction", (u64)trans, + trans->bytes_reserved, 0); btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved); trans->bytes_reserved = 0; } @@ -4079,6 +4210,8 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, * when we are truly done with the orphan item. */ u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1); + trace_btrfs_space_reservation(root->fs_info, "orphan", + btrfs_ino(inode), num_bytes, 1); return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes); } @@ -4086,6 +4219,8 @@ void btrfs_orphan_release_metadata(struct inode *inode) { struct btrfs_root *root = BTRFS_I(inode)->root; u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1); + trace_btrfs_space_reservation(root->fs_info, "orphan", + btrfs_ino(inode), num_bytes, 0); btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes); } @@ -4213,12 +4348,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) /* Need to be holding the i_mutex here if we aren't free space cache */ if (btrfs_is_free_space_inode(root, inode)) flush = 0; - else - WARN_ON(!mutex_is_locked(&inode->i_mutex)); if (flush && btrfs_transaction_in_commit(root->fs_info)) schedule_timeout(1); + mutex_lock(&BTRFS_I(inode)->delalloc_mutex); num_bytes = ALIGN(num_bytes, root->sectorsize); spin_lock(&BTRFS_I(inode)->lock); @@ -4266,8 +4400,14 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) if (dropped) to_free += btrfs_calc_trans_metadata_size(root, dropped); - if (to_free) + if (to_free) { btrfs_block_rsv_release(root, block_rsv, to_free); + trace_btrfs_space_reservation(root->fs_info, + "delalloc", + btrfs_ino(inode), + to_free, 0); + } + mutex_unlock(&BTRFS_I(inode)->delalloc_mutex); return ret; } @@ -4278,7 +4418,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) } BTRFS_I(inode)->reserved_extents += nr_extents; spin_unlock(&BTRFS_I(inode)->lock); + mutex_unlock(&BTRFS_I(inode)->delalloc_mutex); + if (to_reserve) + trace_btrfs_space_reservation(root->fs_info,"delalloc", + btrfs_ino(inode), to_reserve, 1); block_rsv_add_bytes(block_rsv, to_reserve, 1); return 0; @@ -4308,6 +4452,8 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes) if (dropped > 0) to_free += btrfs_calc_trans_metadata_size(root, dropped); + trace_btrfs_space_reservation(root->fs_info, "delalloc", + btrfs_ino(inode), to_free, 0); btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv, to_free); } @@ -4562,7 +4708,10 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache, cache->reserved += num_bytes; space_info->bytes_reserved += num_bytes; if (reserve == RESERVE_ALLOC) { - BUG_ON(space_info->bytes_may_use < num_bytes); + trace_btrfs_space_reservation(cache->fs_info, + "space_info", + (u64)space_info, + num_bytes, 0); space_info->bytes_may_use -= num_bytes; } } @@ -4928,6 +5077,8 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, rb_erase(&head->node.rb_node, &delayed_refs->root); delayed_refs->num_entries--; + if (waitqueue_active(&delayed_refs->seq_wait)) + wake_up(&delayed_refs->seq_wait); /* * we don't take a ref on the node because we're removing it from the @@ -4955,16 +5106,17 @@ out: void btrfs_free_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, - u64 parent, int last_ref) + u64 parent, int last_ref, int for_cow) { struct btrfs_block_group_cache *cache = NULL; int ret; if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { - ret = btrfs_add_delayed_tree_ref(trans, buf->start, buf->len, - parent, root->root_key.objectid, - btrfs_header_level(buf), - BTRFS_DROP_DELAYED_REF, NULL); + ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, + buf->start, buf->len, + parent, root->root_key.objectid, + btrfs_header_level(buf), + BTRFS_DROP_DELAYED_REF, NULL, for_cow); BUG_ON(ret); } @@ -4999,12 +5151,12 @@ out: btrfs_put_block_group(cache); } -int btrfs_free_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, u64 offset) +int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, + u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, + u64 owner, u64 offset, int for_cow) { int ret; + struct btrfs_fs_info *fs_info = root->fs_info; /* * tree log blocks never actually go into the extent allocation @@ -5016,14 +5168,17 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, btrfs_pin_extent(root, bytenr, num_bytes, 1); ret = 0; } else if (owner < BTRFS_FIRST_FREE_OBJECTID) { - ret = btrfs_add_delayed_tree_ref(trans, bytenr, num_bytes, + ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr, + num_bytes, parent, root_objectid, (int)owner, - BTRFS_DROP_DELAYED_REF, NULL); + BTRFS_DROP_DELAYED_REF, NULL, for_cow); BUG_ON(ret); } else { - ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes, - parent, root_objectid, owner, - offset, BTRFS_DROP_DELAYED_REF, NULL); + ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr, + num_bytes, + parent, root_objectid, owner, + offset, BTRFS_DROP_DELAYED_REF, + NULL, for_cow); BUG_ON(ret); } return ret; @@ -5146,6 +5301,8 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ins->objectid = 0; ins->offset = 0; + trace_find_free_extent(orig_root, num_bytes, empty_size, data); + space_info = __find_space_info(root->fs_info, data); if (!space_info) { printk(KERN_ERR "No space info for %llu\n", data); @@ -5295,15 +5452,6 @@ alloc: if (unlikely(block_group->ro)) goto loop; - spin_lock(&block_group->free_space_ctl->tree_lock); - if (cached && - block_group->free_space_ctl->free_space < - num_bytes + empty_cluster + empty_size) { - spin_unlock(&block_group->free_space_ctl->tree_lock); - goto loop; - } - spin_unlock(&block_group->free_space_ctl->tree_lock); - /* * Ok we want to try and use the cluster allocator, so * lets look there @@ -5331,6 +5479,8 @@ alloc: if (offset) { /* we have a block, we're done */ spin_unlock(&last_ptr->refill_lock); + trace_btrfs_reserve_extent_cluster(root, + block_group, search_start, num_bytes); goto checks; } @@ -5349,8 +5499,15 @@ refill_cluster: * plenty of times and not have found * anything, so we are likely way too * fragmented for the clustering stuff to find - * anything. */ - if (loop >= LOOP_NO_EMPTY_SIZE) { + * anything. + * + * However, if the cluster is taken from the + * current block group, release the cluster + * first, so that we stand a better chance of + * succeeding in the unclustered + * allocation. */ + if (loop >= LOOP_NO_EMPTY_SIZE && + last_ptr->block_group != block_group) { spin_unlock(&last_ptr->refill_lock); goto unclustered_alloc; } @@ -5361,6 +5518,11 @@ refill_cluster: */ btrfs_return_cluster_to_free_space(NULL, last_ptr); + if (loop >= LOOP_NO_EMPTY_SIZE) { + spin_unlock(&last_ptr->refill_lock); + goto unclustered_alloc; + } + /* allocate a cluster in this block group */ ret = btrfs_find_space_cluster(trans, root, block_group, last_ptr, @@ -5377,6 +5539,9 @@ refill_cluster: if (offset) { /* we found one, proceed */ spin_unlock(&last_ptr->refill_lock); + trace_btrfs_reserve_extent_cluster(root, + block_group, search_start, + num_bytes); goto checks; } } else if (!cached && loop > LOOP_CACHING_NOWAIT @@ -5401,6 +5566,15 @@ refill_cluster: } unclustered_alloc: + spin_lock(&block_group->free_space_ctl->tree_lock); + if (cached && + block_group->free_space_ctl->free_space < + num_bytes + empty_cluster + empty_size) { + spin_unlock(&block_group->free_space_ctl->tree_lock); + goto loop; + } + spin_unlock(&block_group->free_space_ctl->tree_lock); + offset = btrfs_find_space_for_alloc(block_group, search_start, num_bytes, empty_size); /* @@ -5438,9 +5612,6 @@ checks: goto loop; } - ins->objectid = search_start; - ins->offset = num_bytes; - if (offset < search_start) btrfs_add_free_space(used_block_group, offset, search_start - offset); @@ -5457,6 +5628,8 @@ checks: ins->objectid = search_start; ins->offset = num_bytes; + trace_btrfs_reserve_extent(orig_root, block_group, + search_start, num_bytes); if (offset < search_start) btrfs_add_free_space(used_block_group, offset, search_start - offset); @@ -5842,9 +6015,10 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, BUG_ON(root_objectid == BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_add_delayed_data_ref(trans, ins->objectid, ins->offset, - 0, root_objectid, owner, offset, - BTRFS_ADD_DELAYED_EXTENT, NULL); + ret = btrfs_add_delayed_data_ref(root->fs_info, trans, ins->objectid, + ins->offset, 0, + root_objectid, owner, offset, + BTRFS_ADD_DELAYED_EXTENT, NULL, 0); return ret; } @@ -5997,10 +6171,11 @@ use_block_rsv(struct btrfs_trans_handle *trans, return ERR_PTR(-ENOSPC); } -static void unuse_block_rsv(struct btrfs_block_rsv *block_rsv, u32 blocksize) +static void unuse_block_rsv(struct btrfs_fs_info *fs_info, + struct btrfs_block_rsv *block_rsv, u32 blocksize) { block_rsv_add_bytes(block_rsv, blocksize, 0); - block_rsv_release_bytes(block_rsv, NULL, 0); + block_rsv_release_bytes(fs_info, block_rsv, NULL, 0); } /* @@ -6014,7 +6189,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u32 blocksize, u64 parent, u64 root_objectid, struct btrfs_disk_key *key, int level, - u64 hint, u64 empty_size) + u64 hint, u64 empty_size, int for_cow) { struct btrfs_key ins; struct btrfs_block_rsv *block_rsv; @@ -6030,7 +6205,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ret = btrfs_reserve_extent(trans, root, blocksize, blocksize, empty_size, hint, (u64)-1, &ins, 0); if (ret) { - unuse_block_rsv(block_rsv, blocksize); + unuse_block_rsv(root->fs_info, block_rsv, blocksize); return ERR_PTR(ret); } @@ -6058,10 +6233,11 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, extent_op->update_flags = 1; extent_op->is_data = 0; - ret = btrfs_add_delayed_tree_ref(trans, ins.objectid, + ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, + ins.objectid, ins.offset, parent, root_objectid, level, BTRFS_ADD_DELAYED_EXTENT, - extent_op); + extent_op, for_cow); BUG_ON(ret); } return buf; @@ -6078,6 +6254,7 @@ struct walk_control { int keep_locks; int reada_slot; int reada_count; + int for_reloc; }; #define DROP_REFERENCE 1 @@ -6216,9 +6393,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans, /* wc->stage == UPDATE_BACKREF */ if (!(wc->flags[level] & flag)) { BUG_ON(!path->locks[level]); - ret = btrfs_inc_ref(trans, root, eb, 1); + ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc); BUG_ON(ret); - ret = btrfs_dec_ref(trans, root, eb, 0); + ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc); BUG_ON(ret); ret = btrfs_set_disk_extent_flags(trans, root, eb->start, eb->len, flag, 0); @@ -6362,7 +6539,7 @@ skip: } ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent, - root->root_key.objectid, level - 1, 0); + root->root_key.objectid, level - 1, 0, 0); BUG_ON(ret); } btrfs_tree_unlock(next); @@ -6436,9 +6613,11 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, if (wc->refs[level] == 1) { if (level == 0) { if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) - ret = btrfs_dec_ref(trans, root, eb, 1); + ret = btrfs_dec_ref(trans, root, eb, 1, + wc->for_reloc); else - ret = btrfs_dec_ref(trans, root, eb, 0); + ret = btrfs_dec_ref(trans, root, eb, 0, + wc->for_reloc); BUG_ON(ret); } /* make block locked assertion in clean_tree_block happy */ @@ -6465,7 +6644,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, btrfs_header_owner(path->nodes[level + 1])); } - btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1); + btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1, 0); out: wc->refs[level] = 0; wc->flags[level] = 0; @@ -6549,7 +6728,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans, * blocks are properly updated. */ void btrfs_drop_snapshot(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, int update_ref) + struct btrfs_block_rsv *block_rsv, int update_ref, + int for_reloc) { struct btrfs_path *path; struct btrfs_trans_handle *trans; @@ -6637,6 +6817,7 @@ void btrfs_drop_snapshot(struct btrfs_root *root, wc->stage = DROP_REFERENCE; wc->update_ref = update_ref; wc->keep_locks = 0; + wc->for_reloc = for_reloc; wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); while (1) { @@ -6721,6 +6902,7 @@ out: * drop subtree rooted at tree block 'node'. * * NOTE: this function will unlock and release tree block 'node' + * only used by relocation code */ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -6765,6 +6947,7 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, wc->stage = DROP_REFERENCE; wc->update_ref = 0; wc->keep_locks = 1; + wc->for_reloc = 1; wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); while (1) { @@ -6792,6 +6975,29 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) u64 stripped = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; + if (root->fs_info->balance_ctl) { + struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; + u64 tgt = 0; + + /* pick restriper's target profile and return */ + if (flags & BTRFS_BLOCK_GROUP_DATA && + bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) { + tgt = BTRFS_BLOCK_GROUP_DATA | bctl->data.target; + } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM && + bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { + tgt = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target; + } else if (flags & BTRFS_BLOCK_GROUP_METADATA && + bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) { + tgt = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target; + } + + if (tgt) { + /* extended -> chunk profile */ + tgt &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE; + return tgt; + } + } + /* * we add in the count of missing devices because we want * to make sure that any RAID levels on a degraded FS @@ -7085,7 +7291,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) * space to fit our block group in. */ if (device->total_bytes > device->bytes_used + min_free) { - ret = find_free_dev_extent(NULL, device, min_free, + ret = find_free_dev_extent(device, min_free, &dev_offset, NULL); if (!ret) dev_nr++; @@ -7447,6 +7653,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, ret = update_space_info(root->fs_info, cache->flags, size, bytes_used, &cache->space_info); BUG_ON(ret); + update_global_block_rsv(root->fs_info); spin_lock(&cache->space_info->lock); cache->space_info->bytes_readonly += cache->bytes_super; @@ -7466,6 +7673,22 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, return 0; } +static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) +{ + u64 extra_flags = flags & BTRFS_BLOCK_GROUP_PROFILE_MASK; + + /* chunk -> extended profile */ + if (extra_flags == 0) + extra_flags = BTRFS_AVAIL_ALLOC_BIT_SINGLE; + + if (flags & BTRFS_BLOCK_GROUP_DATA) + fs_info->avail_data_alloc_bits &= ~extra_flags; + if (flags & BTRFS_BLOCK_GROUP_METADATA) + fs_info->avail_metadata_alloc_bits &= ~extra_flags; + if (flags & BTRFS_BLOCK_GROUP_SYSTEM) + fs_info->avail_system_alloc_bits &= ~extra_flags; +} + int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 group_start) { @@ -7476,6 +7699,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_key key; struct inode *inode; int ret; + int index; int factor; root = root->fs_info->extent_root; @@ -7491,6 +7715,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, free_excluded_extents(root, block_group); memcpy(&key, &block_group->key, sizeof(key)); + index = get_block_group_index(block_group); if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)) @@ -7565,6 +7790,8 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, * are still on the list after taking the semaphore */ list_del_init(&block_group->list); + if (list_empty(&block_group->space_info->block_groups[index])) + clear_avail_alloc_bits(root->fs_info, block_group->flags); up_write(&block_group->space_info->groups_sem); if (block_group->cached == BTRFS_CACHE_STARTED) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 49f3c9dc09f4..9d09a4f81875 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -18,6 +18,7 @@ #include "ctree.h" #include "btrfs_inode.h" #include "volumes.h" +#include "check-integrity.h" static struct kmem_cache *extent_state_cache; static struct kmem_cache *extent_buffer_cache; @@ -1895,7 +1896,7 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start, } bio->bi_bdev = dev->bdev; bio_add_page(bio, page, length, start-page_offset(page)); - submit_bio(WRITE_SYNC, bio); + btrfsic_submit_bio(WRITE_SYNC, bio); wait_for_completion(&compl); if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { @@ -2393,7 +2394,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num, ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio, mirror_num, bio_flags, start); else - submit_bio(rw, bio); + btrfsic_submit_bio(rw, bio); if (bio_flagged(bio, BIO_EOPNOTSUPP)) ret = -EOPNOTSUPP; @@ -3579,6 +3580,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, atomic_set(&eb->blocking_writers, 0); atomic_set(&eb->spinning_readers, 0); atomic_set(&eb->spinning_writers, 0); + eb->lock_nested = 0; init_waitqueue_head(&eb->write_lock_wq); init_waitqueue_head(&eb->read_lock_wq); diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 7604c3001322..bc6a042cb6fc 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -129,6 +129,7 @@ struct extent_buffer { struct list_head leak_list; struct rcu_head rcu_head; atomic_t refs; + pid_t lock_owner; /* count of read lock holders on the extent buffer */ atomic_t write_locks; @@ -137,6 +138,7 @@ struct extent_buffer { atomic_t blocking_readers; atomic_t spinning_readers; atomic_t spinning_writers; + int lock_nested; /* protects write locks */ rwlock_t lock; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 034d98503229..859ba2dd8890 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -678,7 +678,7 @@ next_slot: disk_bytenr, num_bytes, 0, root->root_key.objectid, new_key.objectid, - start - extent_offset); + start - extent_offset, 0); BUG_ON(ret); *hint_byte = disk_bytenr; } @@ -753,7 +753,7 @@ next_slot: disk_bytenr, num_bytes, 0, root->root_key.objectid, key.objectid, key.offset - - extent_offset); + extent_offset, 0); BUG_ON(ret); inode_sub_bytes(inode, extent_end - key.offset); @@ -962,7 +962,7 @@ again: ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, root->root_key.objectid, - ino, orig_offset); + ino, orig_offset, 0); BUG_ON(ret); if (split == start) { @@ -989,7 +989,7 @@ again: del_nr++; ret = btrfs_free_extent(trans, root, bytenr, num_bytes, 0, root->root_key.objectid, - ino, orig_offset); + ino, orig_offset, 0); BUG_ON(ret); } other_start = 0; @@ -1006,7 +1006,7 @@ again: del_nr++; ret = btrfs_free_extent(trans, root, bytenr, num_bytes, 0, root->root_key.objectid, - ino, orig_offset); + ino, orig_offset, 0); BUG_ON(ret); } if (del_nr == 0) { @@ -1274,7 +1274,6 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file, dirty_pages); if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1) btrfs_btree_balance_dirty(root, 1); - btrfs_throttle(root); pos += copied; num_written += copied; diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 9a897bf79538..d20ff87ca603 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -319,9 +319,11 @@ static void io_ctl_drop_pages(struct io_ctl *io_ctl) io_ctl_unmap_page(io_ctl); for (i = 0; i < io_ctl->num_pages; i++) { - ClearPageChecked(io_ctl->pages[i]); - unlock_page(io_ctl->pages[i]); - page_cache_release(io_ctl->pages[i]); + if (io_ctl->pages[i]) { + ClearPageChecked(io_ctl->pages[i]); + unlock_page(io_ctl->pages[i]); + page_cache_release(io_ctl->pages[i]); + } } } @@ -635,7 +637,10 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, if (!num_entries) return 0; - io_ctl_init(&io_ctl, inode, root); + ret = io_ctl_init(&io_ctl, inode, root); + if (ret) + return ret; + ret = readahead_cache(inode); if (ret) goto out; @@ -838,7 +843,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, struct io_ctl io_ctl; struct list_head bitmap_list; struct btrfs_key key; - u64 start, end, len; + u64 start, extent_start, extent_end, len; int entries = 0; int bitmaps = 0; int ret; @@ -849,7 +854,9 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, if (!i_size_read(inode)) return -1; - io_ctl_init(&io_ctl, inode, root); + ret = io_ctl_init(&io_ctl, inode, root); + if (ret) + return -1; /* Get the cluster for this block_group if it exists */ if (block_group && !list_empty(&block_group->cluster_list)) @@ -857,25 +864,12 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, struct btrfs_free_cluster, block_group_list); - /* - * We shouldn't have switched the pinned extents yet so this is the - * right one - */ - unpin = root->fs_info->pinned_extents; - /* Lock all pages first so we can lock the extent safely. */ io_ctl_prepare_pages(&io_ctl, inode, 0); lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, 0, &cached_state, GFP_NOFS); - /* - * When searching for pinned extents, we need to start at our start - * offset. - */ - if (block_group) - start = block_group->key.objectid; - node = rb_first(&ctl->free_space_offset); if (!node && cluster) { node = rb_first(&cluster->root); @@ -918,9 +912,20 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, * We want to add any pinned extents to our free space cache * so we don't leak the space */ + + /* + * We shouldn't have switched the pinned extents yet so this is the + * right one + */ + unpin = root->fs_info->pinned_extents; + + if (block_group) + start = block_group->key.objectid; + while (block_group && (start < block_group->key.objectid + block_group->key.offset)) { - ret = find_first_extent_bit(unpin, start, &start, &end, + ret = find_first_extent_bit(unpin, start, + &extent_start, &extent_end, EXTENT_DIRTY); if (ret) { ret = 0; @@ -928,20 +933,21 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, } /* This pinned extent is out of our range */ - if (start >= block_group->key.objectid + + if (extent_start >= block_group->key.objectid + block_group->key.offset) break; - len = block_group->key.objectid + - block_group->key.offset - start; - len = min(len, end + 1 - start); + extent_start = max(extent_start, start); + extent_end = min(block_group->key.objectid + + block_group->key.offset, extent_end + 1); + len = extent_end - extent_start; entries++; - ret = io_ctl_add_entry(&io_ctl, start, len, NULL); + ret = io_ctl_add_entry(&io_ctl, extent_start, len, NULL); if (ret) goto out_nospc; - start = end + 1; + start = extent_end; } /* Write out the bitmaps */ @@ -2283,23 +2289,23 @@ out: static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group, struct btrfs_free_space *entry, struct btrfs_free_cluster *cluster, - u64 offset, u64 bytes, u64 min_bytes) + u64 offset, u64 bytes, + u64 cont1_bytes, u64 min_bytes) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; unsigned long next_zero; unsigned long i; - unsigned long search_bits; - unsigned long total_bits; + unsigned long want_bits; + unsigned long min_bits; unsigned long found_bits; unsigned long start = 0; unsigned long total_found = 0; int ret; - bool found = false; i = offset_to_bit(entry->offset, block_group->sectorsize, max_t(u64, offset, entry->offset)); - search_bits = bytes_to_bits(bytes, block_group->sectorsize); - total_bits = bytes_to_bits(min_bytes, block_group->sectorsize); + want_bits = bytes_to_bits(bytes, block_group->sectorsize); + min_bits = bytes_to_bits(min_bytes, block_group->sectorsize); again: found_bits = 0; @@ -2308,7 +2314,7 @@ again: i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i + 1)) { next_zero = find_next_zero_bit(entry->bitmap, BITS_PER_BITMAP, i); - if (next_zero - i >= search_bits) { + if (next_zero - i >= min_bits) { found_bits = next_zero - i; break; } @@ -2318,10 +2324,9 @@ again: if (!found_bits) return -ENOSPC; - if (!found) { + if (!total_found) { start = i; cluster->max_size = 0; - found = true; } total_found += found_bits; @@ -2329,13 +2334,8 @@ again: if (cluster->max_size < found_bits * block_group->sectorsize) cluster->max_size = found_bits * block_group->sectorsize; - if (total_found < total_bits) { - i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, next_zero); - if (i - start > total_bits * 2) { - total_found = 0; - cluster->max_size = 0; - found = false; - } + if (total_found < want_bits || cluster->max_size < cont1_bytes) { + i = next_zero + 1; goto again; } @@ -2346,28 +2346,31 @@ again: &entry->offset_index, 1); BUG_ON(ret); + trace_btrfs_setup_cluster(block_group, cluster, + total_found * block_group->sectorsize, 1); return 0; } /* * This searches the block group for just extents to fill the cluster with. + * Try to find a cluster with at least bytes total bytes, at least one + * extent of cont1_bytes, and other clusters of at least min_bytes. */ static noinline int setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group, struct btrfs_free_cluster *cluster, struct list_head *bitmaps, u64 offset, u64 bytes, - u64 min_bytes) + u64 cont1_bytes, u64 min_bytes) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *first = NULL; struct btrfs_free_space *entry = NULL; - struct btrfs_free_space *prev = NULL; struct btrfs_free_space *last; struct rb_node *node; u64 window_start; u64 window_free; u64 max_extent; - u64 max_gap = 128 * 1024; + u64 total_size = 0; entry = tree_search_offset(ctl, offset, 0, 1); if (!entry) @@ -2377,8 +2380,8 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group, * We don't want bitmaps, so just move along until we find a normal * extent entry. */ - while (entry->bitmap) { - if (list_empty(&entry->list)) + while (entry->bitmap || entry->bytes < min_bytes) { + if (entry->bitmap && list_empty(&entry->list)) list_add_tail(&entry->list, bitmaps); node = rb_next(&entry->offset_index); if (!node) @@ -2391,12 +2394,9 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group, max_extent = entry->bytes; first = entry; last = entry; - prev = entry; - while (window_free <= min_bytes) { - node = rb_next(&entry->offset_index); - if (!node) - return -ENOSPC; + for (node = rb_next(&entry->offset_index); node; + node = rb_next(&entry->offset_index)) { entry = rb_entry(node, struct btrfs_free_space, offset_index); if (entry->bitmap) { @@ -2405,26 +2405,18 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group, continue; } - /* - * we haven't filled the empty size and the window is - * very large. reset and try again - */ - if (entry->offset - (prev->offset + prev->bytes) > max_gap || - entry->offset - window_start > (min_bytes * 2)) { - first = entry; - window_start = entry->offset; - window_free = entry->bytes; - last = entry; + if (entry->bytes < min_bytes) + continue; + + last = entry; + window_free += entry->bytes; + if (entry->bytes > max_extent) max_extent = entry->bytes; - } else { - last = entry; - window_free += entry->bytes; - if (entry->bytes > max_extent) - max_extent = entry->bytes; - } - prev = entry; } + if (window_free < bytes || max_extent < cont1_bytes) + return -ENOSPC; + cluster->window_start = first->offset; node = &first->offset_index; @@ -2438,17 +2430,18 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group, entry = rb_entry(node, struct btrfs_free_space, offset_index); node = rb_next(&entry->offset_index); - if (entry->bitmap) + if (entry->bitmap || entry->bytes < min_bytes) continue; rb_erase(&entry->offset_index, &ctl->free_space_offset); ret = tree_insert_offset(&cluster->root, entry->offset, &entry->offset_index, 0); + total_size += entry->bytes; BUG_ON(ret); } while (node && entry != last); cluster->max_size = max_extent; - + trace_btrfs_setup_cluster(block_group, cluster, total_size, 0); return 0; } @@ -2460,7 +2453,7 @@ static noinline int setup_cluster_bitmap(struct btrfs_block_group_cache *block_group, struct btrfs_free_cluster *cluster, struct list_head *bitmaps, u64 offset, u64 bytes, - u64 min_bytes) + u64 cont1_bytes, u64 min_bytes) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *entry; @@ -2485,7 +2478,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group, if (entry->bytes < min_bytes) continue; ret = btrfs_bitmap_cluster(block_group, entry, cluster, offset, - bytes, min_bytes); + bytes, cont1_bytes, min_bytes); if (!ret) return 0; } @@ -2499,7 +2492,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group, /* * here we try to find a cluster of blocks in a block group. The goal - * is to find at least bytes free and up to empty_size + bytes free. + * is to find at least bytes+empty_size. * We might not find them all in one contiguous area. * * returns zero and sets up cluster if things worked out, otherwise @@ -2515,23 +2508,24 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, struct btrfs_free_space *entry, *tmp; LIST_HEAD(bitmaps); u64 min_bytes; + u64 cont1_bytes; int ret; - /* for metadata, allow allocates with more holes */ + /* + * Choose the minimum extent size we'll require for this + * cluster. For SSD_SPREAD, don't allow any fragmentation. + * For metadata, allow allocates with smaller extents. For + * data, keep it dense. + */ if (btrfs_test_opt(root, SSD_SPREAD)) { - min_bytes = bytes + empty_size; + cont1_bytes = min_bytes = bytes + empty_size; } else if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) { - /* - * we want to do larger allocations when we are - * flushing out the delayed refs, it helps prevent - * making more work as we go along. - */ - if (trans->transaction->delayed_refs.flushing) - min_bytes = max(bytes, (bytes + empty_size) >> 1); - else - min_bytes = max(bytes, (bytes + empty_size) >> 4); - } else - min_bytes = max(bytes, (bytes + empty_size) >> 2); + cont1_bytes = bytes; + min_bytes = block_group->sectorsize; + } else { + cont1_bytes = max(bytes, (bytes + empty_size) >> 2); + min_bytes = block_group->sectorsize; + } spin_lock(&ctl->tree_lock); @@ -2539,7 +2533,7 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, * If we know we don't have enough space to make a cluster don't even * bother doing all the work to try and find one. */ - if (ctl->free_space < min_bytes) { + if (ctl->free_space < bytes) { spin_unlock(&ctl->tree_lock); return -ENOSPC; } @@ -2552,11 +2546,17 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, goto out; } + trace_btrfs_find_cluster(block_group, offset, bytes, empty_size, + min_bytes); + + INIT_LIST_HEAD(&bitmaps); ret = setup_cluster_no_bitmap(block_group, cluster, &bitmaps, offset, - bytes, min_bytes); + bytes + empty_size, + cont1_bytes, min_bytes); if (ret) ret = setup_cluster_bitmap(block_group, cluster, &bitmaps, - offset, bytes, min_bytes); + offset, bytes + empty_size, + cont1_bytes, min_bytes); /* Clear our temporary list */ list_for_each_entry_safe(entry, tmp, &bitmaps, list) @@ -2567,6 +2567,8 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, list_add_tail(&cluster->block_group_list, &block_group->cluster_list); cluster->block_group = block_group; + } else { + trace_btrfs_failed_cluster_setup(block_group); } out: spin_unlock(&cluster->lock); @@ -2588,17 +2590,57 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster) cluster->block_group = NULL; } -int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, - u64 *trimmed, u64 start, u64 end, u64 minlen) +static int do_trimming(struct btrfs_block_group_cache *block_group, + u64 *total_trimmed, u64 start, u64 bytes, + u64 reserved_start, u64 reserved_bytes) { - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *entry = NULL; + struct btrfs_space_info *space_info = block_group->space_info; struct btrfs_fs_info *fs_info = block_group->fs_info; - u64 bytes = 0; - u64 actually_trimmed; - int ret = 0; + int ret; + int update = 0; + u64 trimmed = 0; - *trimmed = 0; + spin_lock(&space_info->lock); + spin_lock(&block_group->lock); + if (!block_group->ro) { + block_group->reserved += reserved_bytes; + space_info->bytes_reserved += reserved_bytes; + update = 1; + } + spin_unlock(&block_group->lock); + spin_unlock(&space_info->lock); + + ret = btrfs_error_discard_extent(fs_info->extent_root, + start, bytes, &trimmed); + if (!ret) + *total_trimmed += trimmed; + + btrfs_add_free_space(block_group, reserved_start, reserved_bytes); + + if (update) { + spin_lock(&space_info->lock); + spin_lock(&block_group->lock); + if (block_group->ro) + space_info->bytes_readonly += reserved_bytes; + block_group->reserved -= reserved_bytes; + space_info->bytes_reserved -= reserved_bytes; + spin_unlock(&space_info->lock); + spin_unlock(&block_group->lock); + } + + return ret; +} + +static int trim_no_bitmap(struct btrfs_block_group_cache *block_group, + u64 *total_trimmed, u64 start, u64 end, u64 minlen) +{ + struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; + struct btrfs_free_space *entry; + struct rb_node *node; + int ret = 0; + u64 extent_start; + u64 extent_bytes; + u64 bytes; while (start < end) { spin_lock(&ctl->tree_lock); @@ -2609,81 +2651,118 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, } entry = tree_search_offset(ctl, start, 0, 1); - if (!entry) - entry = tree_search_offset(ctl, - offset_to_bitmap(ctl, start), - 1, 1); - - if (!entry || entry->offset >= end) { + if (!entry) { spin_unlock(&ctl->tree_lock); break; } - if (entry->bitmap) { - ret = search_bitmap(ctl, entry, &start, &bytes); - if (!ret) { - if (start >= end) { - spin_unlock(&ctl->tree_lock); - break; - } - bytes = min(bytes, end - start); - bitmap_clear_bits(ctl, entry, start, bytes); - if (entry->bytes == 0) - free_bitmap(ctl, entry); - } else { - start = entry->offset + BITS_PER_BITMAP * - block_group->sectorsize; + /* skip bitmaps */ + while (entry->bitmap) { + node = rb_next(&entry->offset_index); + if (!node) { spin_unlock(&ctl->tree_lock); - ret = 0; - continue; + goto out; } - } else { - start = entry->offset; - bytes = min(entry->bytes, end - start); - unlink_free_space(ctl, entry); - kmem_cache_free(btrfs_free_space_cachep, entry); + entry = rb_entry(node, struct btrfs_free_space, + offset_index); } + if (entry->offset >= end) { + spin_unlock(&ctl->tree_lock); + break; + } + + extent_start = entry->offset; + extent_bytes = entry->bytes; + start = max(start, extent_start); + bytes = min(extent_start + extent_bytes, end) - start; + if (bytes < minlen) { + spin_unlock(&ctl->tree_lock); + goto next; + } + + unlink_free_space(ctl, entry); + kmem_cache_free(btrfs_free_space_cachep, entry); + spin_unlock(&ctl->tree_lock); - if (bytes >= minlen) { - struct btrfs_space_info *space_info; - int update = 0; - - space_info = block_group->space_info; - spin_lock(&space_info->lock); - spin_lock(&block_group->lock); - if (!block_group->ro) { - block_group->reserved += bytes; - space_info->bytes_reserved += bytes; - update = 1; - } - spin_unlock(&block_group->lock); - spin_unlock(&space_info->lock); - - ret = btrfs_error_discard_extent(fs_info->extent_root, - start, - bytes, - &actually_trimmed); - - btrfs_add_free_space(block_group, start, bytes); - if (update) { - spin_lock(&space_info->lock); - spin_lock(&block_group->lock); - if (block_group->ro) - space_info->bytes_readonly += bytes; - block_group->reserved -= bytes; - space_info->bytes_reserved -= bytes; - spin_unlock(&space_info->lock); - spin_unlock(&block_group->lock); - } + ret = do_trimming(block_group, total_trimmed, start, bytes, + extent_start, extent_bytes); + if (ret) + break; +next: + start += bytes; - if (ret) - break; - *trimmed += actually_trimmed; + if (fatal_signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + cond_resched(); + } +out: + return ret; +} + +static int trim_bitmaps(struct btrfs_block_group_cache *block_group, + u64 *total_trimmed, u64 start, u64 end, u64 minlen) +{ + struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; + struct btrfs_free_space *entry; + int ret = 0; + int ret2; + u64 bytes; + u64 offset = offset_to_bitmap(ctl, start); + + while (offset < end) { + bool next_bitmap = false; + + spin_lock(&ctl->tree_lock); + + if (ctl->free_space < minlen) { + spin_unlock(&ctl->tree_lock); + break; + } + + entry = tree_search_offset(ctl, offset, 1, 0); + if (!entry) { + spin_unlock(&ctl->tree_lock); + next_bitmap = true; + goto next; + } + + bytes = minlen; + ret2 = search_bitmap(ctl, entry, &start, &bytes); + if (ret2 || start >= end) { + spin_unlock(&ctl->tree_lock); + next_bitmap = true; + goto next; + } + + bytes = min(bytes, end - start); + if (bytes < minlen) { + spin_unlock(&ctl->tree_lock); + goto next; + } + + bitmap_clear_bits(ctl, entry, start, bytes); + if (entry->bytes == 0) + free_bitmap(ctl, entry); + + spin_unlock(&ctl->tree_lock); + + ret = do_trimming(block_group, total_trimmed, start, bytes, + start, bytes); + if (ret) + break; +next: + if (next_bitmap) { + offset += BITS_PER_BITMAP * ctl->unit; + } else { + start += bytes; + if (start >= offset + BITS_PER_BITMAP * ctl->unit) + offset += BITS_PER_BITMAP * ctl->unit; } - start += bytes; - bytes = 0; if (fatal_signal_pending(current)) { ret = -ERESTARTSYS; @@ -2696,6 +2775,22 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, return ret; } +int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, + u64 *trimmed, u64 start, u64 end, u64 minlen) +{ + int ret; + + *trimmed = 0; + + ret = trim_no_bitmap(block_group, trimmed, start, end, minlen); + if (ret) + return ret; + + ret = trim_bitmaps(block_group, trimmed, start, end, minlen); + + return ret; +} + /* * Find the left-most item in the cache tree, and then return the * smallest inode number in the item. diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index f8962a957d65..213ffa86ce1b 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -438,6 +438,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root, trans->bytes_reserved); if (ret) goto out; + trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans, + trans->bytes_reserved, 1); again: inode = lookup_free_ino_inode(root, path); if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) { @@ -498,6 +500,8 @@ again: out_put: iput(inode); out_release: + trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans, + trans->bytes_reserved, 0); btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved); out: trans->block_rsv = rsv; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 81b235a61f8c..0da19a0ea00d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1951,12 +1951,28 @@ enum btrfs_orphan_cleanup_state { void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans, struct btrfs_root *root) { + struct btrfs_block_rsv *block_rsv; int ret; if (!list_empty(&root->orphan_list) || root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE) return; + spin_lock(&root->orphan_lock); + if (!list_empty(&root->orphan_list)) { + spin_unlock(&root->orphan_lock); + return; + } + + if (root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE) { + spin_unlock(&root->orphan_lock); + return; + } + + block_rsv = root->orphan_block_rsv; + root->orphan_block_rsv = NULL; + spin_unlock(&root->orphan_lock); + if (root->orphan_item_inserted && btrfs_root_refs(&root->root_item) > 0) { ret = btrfs_del_orphan_item(trans, root->fs_info->tree_root, @@ -1965,10 +1981,9 @@ void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans, root->orphan_item_inserted = 0; } - if (root->orphan_block_rsv) { - WARN_ON(root->orphan_block_rsv->size > 0); - btrfs_free_block_rsv(root, root->orphan_block_rsv); - root->orphan_block_rsv = NULL; + if (block_rsv) { + WARN_ON(block_rsv->size > 0); + btrfs_free_block_rsv(root, block_rsv); } } @@ -2224,14 +2239,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) continue; } nr_truncate++; - /* - * Need to hold the imutex for reservation purposes, not - * a huge deal here but I have a WARN_ON in - * btrfs_delalloc_reserve_space to catch offenders. - */ - mutex_lock(&inode->i_mutex); ret = btrfs_truncate(inode); - mutex_unlock(&inode->i_mutex); } else { nr_unlink++; } @@ -2845,7 +2853,7 @@ static void __unlink_end_trans(struct btrfs_trans_handle *trans, BUG_ON(!root->fs_info->enospc_unlink); root->fs_info->enospc_unlink = 0; } - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); } static int btrfs_unlink(struct inode *dir, struct dentry *dentry) @@ -3009,7 +3017,6 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, int pending_del_nr = 0; int pending_del_slot = 0; int extent_type = -1; - int encoding; int ret; int err = 0; u64 ino = btrfs_ino(inode); @@ -3059,7 +3066,6 @@ search_again: leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); found_type = btrfs_key_type(&found_key); - encoding = 0; if (found_key.objectid != ino) break; @@ -3072,10 +3078,6 @@ search_again: fi = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); extent_type = btrfs_file_extent_type(leaf, fi); - encoding = btrfs_file_extent_compression(leaf, fi); - encoding |= btrfs_file_extent_encryption(leaf, fi); - encoding |= btrfs_file_extent_other_encoding(leaf, fi); - if (extent_type != BTRFS_FILE_EXTENT_INLINE) { item_end += btrfs_file_extent_num_bytes(leaf, fi); @@ -3103,7 +3105,7 @@ search_again: if (extent_type != BTRFS_FILE_EXTENT_INLINE) { u64 num_dec; extent_start = btrfs_file_extent_disk_bytenr(leaf, fi); - if (!del_item && !encoding) { + if (!del_item) { u64 orig_num_bytes = btrfs_file_extent_num_bytes(leaf, fi); extent_num_bytes = new_size - @@ -3179,7 +3181,7 @@ delete: ret = btrfs_free_extent(trans, root, extent_start, extent_num_bytes, 0, btrfs_header_owner(leaf), - ino, extent_offset); + ino, extent_offset, 0); BUG_ON(ret); } @@ -3434,7 +3436,7 @@ static int btrfs_setsize(struct inode *inode, loff_t newsize) i_size_write(inode, newsize); btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL); ret = btrfs_update_inode(trans, root, inode); - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); } else { /* @@ -4655,7 +4657,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, } out_unlock: nr = trans->blocks_used; - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); btrfs_btree_balance_dirty(root, nr); if (drop_inode) { inode_dec_link_count(inode); @@ -4723,7 +4725,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, } out_unlock: nr = trans->blocks_used; - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); if (drop_inode) { inode_dec_link_count(inode); iput(inode); @@ -4782,7 +4784,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, } nr = trans->blocks_used; - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); fail: if (drop_inode) { inode_dec_link_count(inode); @@ -4848,7 +4850,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) out_fail: nr = trans->blocks_used; - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); if (drop_on_err) iput(inode); btrfs_btree_balance_dirty(root, nr); @@ -5121,7 +5123,7 @@ again: } flush_dcache_page(page); } else if (create && PageUptodate(page)) { - WARN_ON(1); + BUG(); if (!trans) { kunmap(page); free_extent_map(em); @@ -6402,10 +6404,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) u64 page_start; u64 page_end; - /* Need this to keep space reservations serialized */ - mutex_lock(&inode->i_mutex); ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE); - mutex_unlock(&inode->i_mutex); if (!ret) ret = btrfs_update_time(vma->vm_file); if (ret) { @@ -6494,8 +6493,8 @@ out_unlock: if (!ret) return VM_FAULT_LOCKED; unlock_page(page); - btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE); out: + btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE); return ret; } @@ -6668,7 +6667,7 @@ end_trans: err = ret; nr = trans->blocks_used; - ret = btrfs_end_transaction_throttle(trans, root); + ret = btrfs_end_transaction(trans, root); btrfs_btree_balance_dirty(root, nr); } @@ -6749,6 +6748,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) extent_io_tree_init(&ei->io_tree, &inode->i_data); extent_io_tree_init(&ei->io_failure_tree, &inode->i_data); mutex_init(&ei->log_mutex); + mutex_init(&ei->delalloc_mutex); btrfs_ordered_inode_tree_init(&ei->ordered_tree); INIT_LIST_HEAD(&ei->i_orphan); INIT_LIST_HEAD(&ei->delalloc_inodes); @@ -7074,7 +7074,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, btrfs_end_log_trans(root); } out_fail: - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); out_notrans: if (old_ino == BTRFS_FIRST_FREE_OBJECTID) up_read(&root->fs_info->subvol_sem); @@ -7246,7 +7246,7 @@ out_unlock: if (!err) d_instantiate(dentry, inode); nr = trans->blocks_used; - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); if (drop_inode) { inode_dec_link_count(inode); iput(inode); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 5441ff1480fd..ab620014bcc3 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -176,6 +176,8 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) struct btrfs_trans_handle *trans; unsigned int flags, oldflags; int ret; + u64 ip_oldflags; + unsigned int i_oldflags; if (btrfs_root_readonly(root)) return -EROFS; @@ -192,6 +194,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) mutex_lock(&inode->i_mutex); + ip_oldflags = ip->flags; + i_oldflags = inode->i_flags; + flags = btrfs_mask_flags(inode->i_mode, flags); oldflags = btrfs_flags_to_ioctl(ip->flags); if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { @@ -249,19 +254,24 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); } - trans = btrfs_join_transaction(root); - BUG_ON(IS_ERR(trans)); + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out_drop; + } btrfs_update_iflags(inode); inode->i_ctime = CURRENT_TIME; ret = btrfs_update_inode(trans, root, inode); - BUG_ON(ret); btrfs_end_transaction(trans, root); + out_drop: + if (ret) { + ip->flags = ip_oldflags; + inode->i_flags = i_oldflags; + } mnt_drop_write_file(file); - - ret = 0; out_unlock: mutex_unlock(&inode->i_mutex); return ret; @@ -276,14 +286,13 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg) static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) { - struct btrfs_root *root = fdentry(file)->d_sb->s_fs_info; - struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_fs_info *fs_info = btrfs_sb(fdentry(file)->d_sb); struct btrfs_device *device; struct request_queue *q; struct fstrim_range range; u64 minlen = ULLONG_MAX; u64 num_devices = 0; - u64 total_bytes = btrfs_super_total_bytes(root->fs_info->super_copy); + u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy); int ret; if (!capable(CAP_SYS_ADMIN)) @@ -312,7 +321,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) range.len = min(range.len, total_bytes - range.start); range.minlen = max(range.minlen, minlen); - ret = btrfs_trim_fs(root, &range); + ret = btrfs_trim_fs(fs_info->tree_root, &range); if (ret < 0) return ret; @@ -358,7 +367,7 @@ static noinline int create_subvol(struct btrfs_root *root, return PTR_ERR(trans); leaf = btrfs_alloc_free_block(trans, root, root->leafsize, - 0, objectid, NULL, 0, 0, 0); + 0, objectid, NULL, 0, 0, 0, 0); if (IS_ERR(leaf)) { ret = PTR_ERR(leaf); goto fail; @@ -858,10 +867,8 @@ static int cluster_pages_for_defrag(struct inode *inode, return 0; file_end = (isize - 1) >> PAGE_CACHE_SHIFT; - mutex_lock(&inode->i_mutex); ret = btrfs_delalloc_reserve_space(inode, num_pages << PAGE_CACHE_SHIFT); - mutex_unlock(&inode->i_mutex); if (ret) return ret; again: @@ -1203,13 +1210,21 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, if (!capable(CAP_SYS_ADMIN)) return -EPERM; + mutex_lock(&root->fs_info->volume_mutex); + if (root->fs_info->balance_ctl) { + printk(KERN_INFO "btrfs: balance in progress\n"); + ret = -EINVAL; + goto out; + } + vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) - return PTR_ERR(vol_args); + if (IS_ERR(vol_args)) { + ret = PTR_ERR(vol_args); + goto out; + } vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; - mutex_lock(&root->fs_info->volume_mutex); sizestr = vol_args->name; devstr = strchr(sizestr, ':'); if (devstr) { @@ -1226,7 +1241,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", (unsigned long long)devid); ret = -EINVAL; - goto out_unlock; + goto out_free; } if (!strcmp(sizestr, "max")) new_size = device->bdev->bd_inode->i_size; @@ -1241,7 +1256,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, new_size = memparse(sizestr, NULL); if (new_size == 0) { ret = -EINVAL; - goto out_unlock; + goto out_free; } } @@ -1250,7 +1265,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, if (mod < 0) { if (new_size > old_size) { ret = -EINVAL; - goto out_unlock; + goto out_free; } new_size = old_size - new_size; } else if (mod > 0) { @@ -1259,11 +1274,11 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, if (new_size < 256 * 1024 * 1024) { ret = -EINVAL; - goto out_unlock; + goto out_free; } if (new_size > device->bdev->bd_inode->i_size) { ret = -EFBIG; - goto out_unlock; + goto out_free; } do_div(new_size, root->sectorsize); @@ -1276,7 +1291,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { ret = PTR_ERR(trans); - goto out_unlock; + goto out_free; } ret = btrfs_grow_device(trans, device, new_size); btrfs_commit_transaction(trans, root); @@ -1284,9 +1299,10 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, ret = btrfs_shrink_device(device, new_size); } -out_unlock: - mutex_unlock(&root->fs_info->volume_mutex); +out_free: kfree(vol_args); +out: + mutex_unlock(&root->fs_info->volume_mutex); return ret; } @@ -2052,14 +2068,25 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) if (!capable(CAP_SYS_ADMIN)) return -EPERM; + mutex_lock(&root->fs_info->volume_mutex); + if (root->fs_info->balance_ctl) { + printk(KERN_INFO "btrfs: balance in progress\n"); + ret = -EINVAL; + goto out; + } + vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) - return PTR_ERR(vol_args); + if (IS_ERR(vol_args)) { + ret = PTR_ERR(vol_args); + goto out; + } vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; ret = btrfs_init_new_device(root, vol_args->name); kfree(vol_args); +out: + mutex_unlock(&root->fs_info->volume_mutex); return ret; } @@ -2074,14 +2101,25 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) if (root->fs_info->sb->s_flags & MS_RDONLY) return -EROFS; + mutex_lock(&root->fs_info->volume_mutex); + if (root->fs_info->balance_ctl) { + printk(KERN_INFO "btrfs: balance in progress\n"); + ret = -EINVAL; + goto out; + } + vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) - return PTR_ERR(vol_args); + if (IS_ERR(vol_args)) { + ret = PTR_ERR(vol_args); + goto out; + } vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; ret = btrfs_rm_device(root, vol_args->name); kfree(vol_args); +out: + mutex_unlock(&root->fs_info->volume_mutex); return ret; } @@ -2427,7 +2465,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, disko, diskl, 0, root->root_key.objectid, btrfs_ino(inode), - new_key.offset - datao); + new_key.offset - datao, + 0); BUG_ON(ret); } } else if (type == BTRFS_FILE_EXTENT_INLINE) { @@ -2977,7 +3016,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, { int ret = 0; int size; - u64 extent_offset; + u64 extent_item_pos; struct btrfs_ioctl_logical_ino_args *loi; struct btrfs_data_container *inodes = NULL; struct btrfs_path *path = NULL; @@ -3008,15 +3047,17 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, } ret = extent_from_logical(root->fs_info, loi->logical, path, &key); + btrfs_release_path(path); if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) ret = -ENOENT; if (ret < 0) goto out; - extent_offset = loi->logical - key.objectid; + extent_item_pos = loi->logical - key.objectid; ret = iterate_extent_inodes(root->fs_info, path, key.objectid, - extent_offset, build_ino_list, inodes); + extent_item_pos, build_ino_list, + inodes); if (ret < 0) goto out; @@ -3034,6 +3075,163 @@ out: return ret; } +void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, + struct btrfs_ioctl_balance_args *bargs) +{ + struct btrfs_balance_control *bctl = fs_info->balance_ctl; + + bargs->flags = bctl->flags; + + if (atomic_read(&fs_info->balance_running)) + bargs->state |= BTRFS_BALANCE_STATE_RUNNING; + if (atomic_read(&fs_info->balance_pause_req)) + bargs->state |= BTRFS_BALANCE_STATE_PAUSE_REQ; + if (atomic_read(&fs_info->balance_cancel_req)) + bargs->state |= BTRFS_BALANCE_STATE_CANCEL_REQ; + + memcpy(&bargs->data, &bctl->data, sizeof(bargs->data)); + memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta)); + memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys)); + + if (lock) { + spin_lock(&fs_info->balance_lock); + memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); + spin_unlock(&fs_info->balance_lock); + } else { + memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); + } +} + +static long btrfs_ioctl_balance(struct btrfs_root *root, void __user *arg) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ioctl_balance_args *bargs; + struct btrfs_balance_control *bctl; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (fs_info->sb->s_flags & MS_RDONLY) + return -EROFS; + + mutex_lock(&fs_info->volume_mutex); + mutex_lock(&fs_info->balance_mutex); + + if (arg) { + bargs = memdup_user(arg, sizeof(*bargs)); + if (IS_ERR(bargs)) { + ret = PTR_ERR(bargs); + goto out; + } + + if (bargs->flags & BTRFS_BALANCE_RESUME) { + if (!fs_info->balance_ctl) { + ret = -ENOTCONN; + goto out_bargs; + } + + bctl = fs_info->balance_ctl; + spin_lock(&fs_info->balance_lock); + bctl->flags |= BTRFS_BALANCE_RESUME; + spin_unlock(&fs_info->balance_lock); + + goto do_balance; + } + } else { + bargs = NULL; + } + + if (fs_info->balance_ctl) { + ret = -EINPROGRESS; + goto out_bargs; + } + + bctl = kzalloc(sizeof(*bctl), GFP_NOFS); + if (!bctl) { + ret = -ENOMEM; + goto out_bargs; + } + + bctl->fs_info = fs_info; + if (arg) { + memcpy(&bctl->data, &bargs->data, sizeof(bctl->data)); + memcpy(&bctl->meta, &bargs->meta, sizeof(bctl->meta)); + memcpy(&bctl->sys, &bargs->sys, sizeof(bctl->sys)); + + bctl->flags = bargs->flags; + } else { + /* balance everything - no filters */ + bctl->flags |= BTRFS_BALANCE_TYPE_MASK; + } + +do_balance: + ret = btrfs_balance(bctl, bargs); + /* + * bctl is freed in __cancel_balance or in free_fs_info if + * restriper was paused all the way until unmount + */ + if (arg) { + if (copy_to_user(arg, bargs, sizeof(*bargs))) + ret = -EFAULT; + } + +out_bargs: + kfree(bargs); +out: + mutex_unlock(&fs_info->balance_mutex); + mutex_unlock(&fs_info->volume_mutex); + return ret; +} + +static long btrfs_ioctl_balance_ctl(struct btrfs_root *root, int cmd) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch (cmd) { + case BTRFS_BALANCE_CTL_PAUSE: + return btrfs_pause_balance(root->fs_info); + case BTRFS_BALANCE_CTL_CANCEL: + return btrfs_cancel_balance(root->fs_info); + } + + return -EINVAL; +} + +static long btrfs_ioctl_balance_progress(struct btrfs_root *root, + void __user *arg) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + struct btrfs_ioctl_balance_args *bargs; + int ret = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + mutex_lock(&fs_info->balance_mutex); + if (!fs_info->balance_ctl) { + ret = -ENOTCONN; + goto out; + } + + bargs = kzalloc(sizeof(*bargs), GFP_NOFS); + if (!bargs) { + ret = -ENOMEM; + goto out; + } + + update_ioctl_balance_args(fs_info, 1, bargs); + + if (copy_to_user(arg, bargs, sizeof(*bargs))) + ret = -EFAULT; + + kfree(bargs); +out: + mutex_unlock(&fs_info->balance_mutex); + return ret; +} + long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -3078,7 +3276,7 @@ long btrfs_ioctl(struct file *file, unsigned int case BTRFS_IOC_DEV_INFO: return btrfs_ioctl_dev_info(root, argp); case BTRFS_IOC_BALANCE: - return btrfs_balance(root->fs_info->dev_root); + return btrfs_ioctl_balance(root, NULL); case BTRFS_IOC_CLONE: return btrfs_ioctl_clone(file, arg, 0, 0, 0); case BTRFS_IOC_CLONE_RANGE: @@ -3110,6 +3308,12 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_scrub_cancel(root, argp); case BTRFS_IOC_SCRUB_PROGRESS: return btrfs_ioctl_scrub_progress(root, argp); + case BTRFS_IOC_BALANCE_V2: + return btrfs_ioctl_balance(root, argp); + case BTRFS_IOC_BALANCE_CTL: + return btrfs_ioctl_balance_ctl(root, arg); + case BTRFS_IOC_BALANCE_PROGRESS: + return btrfs_ioctl_balance_progress(root, argp); } return -ENOTTY; diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 252ae9915de8..4f69028a68c4 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h @@ -109,6 +109,55 @@ struct btrfs_ioctl_fs_info_args { __u64 reserved[124]; /* pad to 1k */ }; +/* balance control ioctl modes */ +#define BTRFS_BALANCE_CTL_PAUSE 1 +#define BTRFS_BALANCE_CTL_CANCEL 2 + +/* + * this is packed, because it should be exactly the same as its disk + * byte order counterpart (struct btrfs_disk_balance_args) + */ +struct btrfs_balance_args { + __u64 profiles; + __u64 usage; + __u64 devid; + __u64 pstart; + __u64 pend; + __u64 vstart; + __u64 vend; + + __u64 target; + + __u64 flags; + + __u64 unused[8]; +} __attribute__ ((__packed__)); + +/* report balance progress to userspace */ +struct btrfs_balance_progress { + __u64 expected; /* estimated # of chunks that will be + * relocated to fulfill the request */ + __u64 considered; /* # of chunks we have considered so far */ + __u64 completed; /* # of chunks relocated so far */ +}; + +#define BTRFS_BALANCE_STATE_RUNNING (1ULL << 0) +#define BTRFS_BALANCE_STATE_PAUSE_REQ (1ULL << 1) +#define BTRFS_BALANCE_STATE_CANCEL_REQ (1ULL << 2) + +struct btrfs_ioctl_balance_args { + __u64 flags; /* in/out */ + __u64 state; /* out */ + + struct btrfs_balance_args data; /* in/out */ + struct btrfs_balance_args meta; /* in/out */ + struct btrfs_balance_args sys; /* in/out */ + + struct btrfs_balance_progress stat; /* out */ + + __u64 unused[72]; /* pad to 1k */ +}; + #define BTRFS_INO_LOOKUP_PATH_MAX 4080 struct btrfs_ioctl_ino_lookup_args { __u64 treeid; @@ -272,6 +321,11 @@ struct btrfs_ioctl_logical_ino_args { struct btrfs_ioctl_dev_info_args) #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ struct btrfs_ioctl_fs_info_args) +#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \ + struct btrfs_ioctl_balance_args) +#define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int) +#define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \ + struct btrfs_ioctl_balance_args) #define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \ struct btrfs_ioctl_ino_path_args) #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c index d77b67c4b275..5e178d8f7167 100644 --- a/fs/btrfs/locking.c +++ b/fs/btrfs/locking.c @@ -33,6 +33,14 @@ void btrfs_assert_tree_read_locked(struct extent_buffer *eb); */ void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw) { + if (eb->lock_nested) { + read_lock(&eb->lock); + if (eb->lock_nested && current->pid == eb->lock_owner) { + read_unlock(&eb->lock); + return; + } + read_unlock(&eb->lock); + } if (rw == BTRFS_WRITE_LOCK) { if (atomic_read(&eb->blocking_writers) == 0) { WARN_ON(atomic_read(&eb->spinning_writers) != 1); @@ -57,6 +65,14 @@ void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw) */ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw) { + if (eb->lock_nested) { + read_lock(&eb->lock); + if (&eb->lock_nested && current->pid == eb->lock_owner) { + read_unlock(&eb->lock); + return; + } + read_unlock(&eb->lock); + } if (rw == BTRFS_WRITE_LOCK_BLOCKING) { BUG_ON(atomic_read(&eb->blocking_writers) != 1); write_lock(&eb->lock); @@ -81,12 +97,25 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw) void btrfs_tree_read_lock(struct extent_buffer *eb) { again: + read_lock(&eb->lock); + if (atomic_read(&eb->blocking_writers) && + current->pid == eb->lock_owner) { + /* + * This extent is already write-locked by our thread. We allow + * an additional read lock to be added because it's for the same + * thread. btrfs_find_all_roots() depends on this as it may be + * called on a partly (write-)locked tree. + */ + BUG_ON(eb->lock_nested); + eb->lock_nested = 1; + read_unlock(&eb->lock); + return; + } + read_unlock(&eb->lock); wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers) == 0); read_lock(&eb->lock); if (atomic_read(&eb->blocking_writers)) { read_unlock(&eb->lock); - wait_event(eb->write_lock_wq, - atomic_read(&eb->blocking_writers) == 0); goto again; } atomic_inc(&eb->read_locks); @@ -129,6 +158,7 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb) } atomic_inc(&eb->write_locks); atomic_inc(&eb->spinning_writers); + eb->lock_owner = current->pid; return 1; } @@ -137,6 +167,15 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb) */ void btrfs_tree_read_unlock(struct extent_buffer *eb) { + if (eb->lock_nested) { + read_lock(&eb->lock); + if (eb->lock_nested && current->pid == eb->lock_owner) { + eb->lock_nested = 0; + read_unlock(&eb->lock); + return; + } + read_unlock(&eb->lock); + } btrfs_assert_tree_read_locked(eb); WARN_ON(atomic_read(&eb->spinning_readers) == 0); atomic_dec(&eb->spinning_readers); @@ -149,6 +188,15 @@ void btrfs_tree_read_unlock(struct extent_buffer *eb) */ void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb) { + if (eb->lock_nested) { + read_lock(&eb->lock); + if (eb->lock_nested && current->pid == eb->lock_owner) { + eb->lock_nested = 0; + read_unlock(&eb->lock); + return; + } + read_unlock(&eb->lock); + } btrfs_assert_tree_read_locked(eb); WARN_ON(atomic_read(&eb->blocking_readers) == 0); if (atomic_dec_and_test(&eb->blocking_readers)) @@ -181,6 +229,7 @@ again: WARN_ON(atomic_read(&eb->spinning_writers)); atomic_inc(&eb->spinning_writers); atomic_inc(&eb->write_locks); + eb->lock_owner = current->pid; return 0; } diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index cfb55434a469..8c1aae2c845d 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -1604,12 +1604,12 @@ int replace_file_extents(struct btrfs_trans_handle *trans, ret = btrfs_inc_extent_ref(trans, root, new_bytenr, num_bytes, parent, btrfs_header_owner(leaf), - key.objectid, key.offset); + key.objectid, key.offset, 1); BUG_ON(ret); ret = btrfs_free_extent(trans, root, bytenr, num_bytes, parent, btrfs_header_owner(leaf), - key.objectid, key.offset); + key.objectid, key.offset, 1); BUG_ON(ret); } if (dirty) @@ -1778,21 +1778,23 @@ again: ret = btrfs_inc_extent_ref(trans, src, old_bytenr, blocksize, path->nodes[level]->start, - src->root_key.objectid, level - 1, 0); + src->root_key.objectid, level - 1, 0, + 1); BUG_ON(ret); ret = btrfs_inc_extent_ref(trans, dest, new_bytenr, blocksize, 0, dest->root_key.objectid, level - 1, - 0); + 0, 1); BUG_ON(ret); ret = btrfs_free_extent(trans, src, new_bytenr, blocksize, path->nodes[level]->start, - src->root_key.objectid, level - 1, 0); + src->root_key.objectid, level - 1, 0, + 1); BUG_ON(ret); ret = btrfs_free_extent(trans, dest, old_bytenr, blocksize, 0, dest->root_key.objectid, level - 1, - 0); + 0, 1); BUG_ON(ret); btrfs_unlock_up_safe(path, 0); @@ -2244,7 +2246,7 @@ again: } else { list_del_init(&reloc_root->root_list); } - btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0); + btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1); } if (found) { @@ -2558,7 +2560,7 @@ static int do_relocation(struct btrfs_trans_handle *trans, node->eb->start, blocksize, upper->eb->start, btrfs_header_owner(upper->eb), - node->level, 0); + node->level, 0, 1); BUG_ON(ret); ret = btrfs_drop_subtree(trans, root, eb, upper->eb); @@ -2947,9 +2949,7 @@ static int relocate_file_extent_cluster(struct inode *inode, index = (cluster->start - offset) >> PAGE_CACHE_SHIFT; last_index = (cluster->end - offset) >> PAGE_CACHE_SHIFT; while (index <= last_index) { - mutex_lock(&inode->i_mutex); ret = btrfs_delalloc_reserve_metadata(inode, PAGE_CACHE_SIZE); - mutex_unlock(&inode->i_mutex); if (ret) goto out; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index ddf2c90d3fc0..9770cc5bfb76 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -25,6 +25,7 @@ #include "transaction.h" #include "backref.h" #include "extent_io.h" +#include "check-integrity.h" /* * This is only the first step towards a full-features scrub. It reads all @@ -309,7 +310,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio, u8 ref_level; unsigned long ptr = 0; const int bufsize = 4096; - u64 extent_offset; + u64 extent_item_pos; path = btrfs_alloc_path(); @@ -329,12 +330,13 @@ static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio, if (ret < 0) goto out; - extent_offset = swarn.logical - found_key.objectid; + extent_item_pos = swarn.logical - found_key.objectid; swarn.extent_item_size = found_key.offset; eb = path->nodes[0]; ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); item_size = btrfs_item_size_nr(eb, path->slots[0]); + btrfs_release_path(path); if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) { do { @@ -351,7 +353,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio, } else { swarn.path = path; iterate_extent_inodes(fs_info, path, found_key.objectid, - extent_offset, + extent_item_pos, scrub_print_warning_inode, &swarn); } @@ -732,7 +734,7 @@ static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector, bio_add_page(bio, page, PAGE_SIZE, 0); bio->bi_end_io = scrub_fixup_end_io; bio->bi_private = &complete; - submit_bio(rw, bio); + btrfsic_submit_bio(rw, bio); /* this will also unplug the queue */ wait_for_completion(&complete); @@ -958,7 +960,7 @@ static int scrub_submit(struct scrub_dev *sdev) sdev->curr = -1; atomic_inc(&sdev->in_flight); - submit_bio(READ, sbio->bio); + btrfsic_submit_bio(READ, sbio->bio); return 0; } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ae488aa1966a..3ce97b217cbe 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -147,13 +147,13 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function, static void btrfs_put_super(struct super_block *sb) { - struct btrfs_root *root = btrfs_sb(sb); - int ret; - - ret = close_ctree(root); - sb->s_fs_info = NULL; - - (void)ret; /* FIXME: need to fix VFS to return error? */ + (void)close_ctree(btrfs_sb(sb)->tree_root); + /* FIXME: need to fix VFS to return error? */ + /* AV: return it _where_? ->put_super() can be triggered by any number + * of async events, up to and including delivery of SIGKILL to the + * last process that kept it busy. Or segfault in the aforementioned + * process... Whom would you report that to? + */ } enum { @@ -163,8 +163,11 @@ enum { Opt_compress_type, Opt_compress_force, Opt_compress_force_type, Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, - Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, - Opt_inode_cache, Opt_no_space_cache, Opt_recovery, Opt_err, + Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_inode_cache, + Opt_no_space_cache, Opt_recovery, Opt_skip_balance, + Opt_check_integrity, Opt_check_integrity_including_extent_data, + Opt_check_integrity_print_mask, + Opt_err, }; static match_table_t tokens = { @@ -199,6 +202,10 @@ static match_table_t tokens = { {Opt_inode_cache, "inode_cache"}, {Opt_no_space_cache, "nospace_cache"}, {Opt_recovery, "recovery"}, + {Opt_skip_balance, "skip_balance"}, + {Opt_check_integrity, "check_int"}, + {Opt_check_integrity_including_extent_data, "check_int_data"}, + {Opt_check_integrity_print_mask, "check_int_print_mask=%d"}, {Opt_err, NULL}, }; @@ -397,6 +404,40 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) printk(KERN_INFO "btrfs: enabling auto recovery"); btrfs_set_opt(info->mount_opt, RECOVERY); break; + case Opt_skip_balance: + btrfs_set_opt(info->mount_opt, SKIP_BALANCE); + break; +#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY + case Opt_check_integrity_including_extent_data: + printk(KERN_INFO "btrfs: enabling check integrity" + " including extent data\n"); + btrfs_set_opt(info->mount_opt, + CHECK_INTEGRITY_INCLUDING_EXTENT_DATA); + btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY); + break; + case Opt_check_integrity: + printk(KERN_INFO "btrfs: enabling check integrity\n"); + btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY); + break; + case Opt_check_integrity_print_mask: + intarg = 0; + match_int(&args[0], &intarg); + if (intarg) { + info->check_integrity_print_mask = intarg; + printk(KERN_INFO "btrfs:" + " check_integrity_print_mask 0x%x\n", + info->check_integrity_print_mask); + } + break; +#else + case Opt_check_integrity_including_extent_data: + case Opt_check_integrity: + case Opt_check_integrity_print_mask: + printk(KERN_ERR "btrfs: support for check_integrity*" + " not compiled in!\n"); + ret = -EINVAL; + goto out; +#endif case Opt_err: printk(KERN_INFO "btrfs: unrecognized mount option " "'%s'\n", p); @@ -500,7 +541,8 @@ out: static struct dentry *get_default_root(struct super_block *sb, u64 subvol_objectid) { - struct btrfs_root *root = sb->s_fs_info; + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + struct btrfs_root *root = fs_info->tree_root; struct btrfs_root *new_root; struct btrfs_dir_item *di; struct btrfs_path *path; @@ -530,7 +572,7 @@ static struct dentry *get_default_root(struct super_block *sb, * will mount by default if we haven't been given a specific subvolume * to mount. */ - dir_id = btrfs_super_root_dir(root->fs_info->super_copy); + dir_id = btrfs_super_root_dir(fs_info->super_copy); di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0); if (IS_ERR(di)) { btrfs_free_path(path); @@ -544,7 +586,7 @@ static struct dentry *get_default_root(struct super_block *sb, */ btrfs_free_path(path); dir_id = BTRFS_FIRST_FREE_OBJECTID; - new_root = root->fs_info->fs_root; + new_root = fs_info->fs_root; goto setup_root; } @@ -552,7 +594,7 @@ static struct dentry *get_default_root(struct super_block *sb, btrfs_free_path(path); find_root: - new_root = btrfs_read_fs_root_no_name(root->fs_info, &location); + new_root = btrfs_read_fs_root_no_name(fs_info, &location); if (IS_ERR(new_root)) return ERR_CAST(new_root); @@ -588,7 +630,7 @@ static int btrfs_fill_super(struct super_block *sb, { struct inode *inode; struct dentry *root_dentry; - struct btrfs_root *tree_root; + struct btrfs_fs_info *fs_info = btrfs_sb(sb); struct btrfs_key key; int err; @@ -603,18 +645,16 @@ static int btrfs_fill_super(struct super_block *sb, sb->s_flags |= MS_POSIXACL; #endif - tree_root = open_ctree(sb, fs_devices, (char *)data); - - if (IS_ERR(tree_root)) { + err = open_ctree(sb, fs_devices, (char *)data); + if (err) { printk("btrfs: open_ctree failed\n"); - return PTR_ERR(tree_root); + return err; } - sb->s_fs_info = tree_root; key.objectid = BTRFS_FIRST_FREE_OBJECTID; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; - inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root, NULL); + inode = btrfs_iget(sb, &key, fs_info->fs_root, NULL); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto fail_close; @@ -631,23 +671,25 @@ static int btrfs_fill_super(struct super_block *sb, save_mount_options(sb, data); cleancache_init_fs(sb); + sb->s_flags |= MS_ACTIVE; return 0; fail_close: - close_ctree(tree_root); + close_ctree(fs_info->tree_root); return err; } int btrfs_sync_fs(struct super_block *sb, int wait) { struct btrfs_trans_handle *trans; - struct btrfs_root *root = btrfs_sb(sb); + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + struct btrfs_root *root = fs_info->tree_root; int ret; trace_btrfs_sync_fs(wait); if (!wait) { - filemap_flush(root->fs_info->btree_inode->i_mapping); + filemap_flush(fs_info->btree_inode->i_mapping); return 0; } @@ -663,8 +705,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait) static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) { - struct btrfs_root *root = btrfs_sb(dentry->d_sb); - struct btrfs_fs_info *info = root->fs_info; + struct btrfs_fs_info *info = btrfs_sb(dentry->d_sb); + struct btrfs_root *root = info->tree_root; char *compress_type; if (btrfs_test_opt(root, DEGRADED)) @@ -722,28 +764,25 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) seq_puts(seq, ",autodefrag"); if (btrfs_test_opt(root, INODE_MAP_CACHE)) seq_puts(seq, ",inode_cache"); + if (btrfs_test_opt(root, SKIP_BALANCE)) + seq_puts(seq, ",skip_balance"); return 0; } static int btrfs_test_super(struct super_block *s, void *data) { - struct btrfs_root *test_root = data; - struct btrfs_root *root = btrfs_sb(s); + struct btrfs_fs_info *p = data; + struct btrfs_fs_info *fs_info = btrfs_sb(s); - /* - * If this super block is going away, return false as it - * can't match as an existing super block. - */ - if (!atomic_read(&s->s_active)) - return 0; - return root->fs_info->fs_devices == test_root->fs_info->fs_devices; + return fs_info->fs_devices == p->fs_devices; } static int btrfs_set_super(struct super_block *s, void *data) { - s->s_fs_info = data; - - return set_anon_super(s, data); + int err = set_anon_super(s, data); + if (!err) + s->s_fs_info = data; + return err; } /* @@ -903,12 +942,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, if (!fs_info) return ERR_PTR(-ENOMEM); - fs_info->tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); - if (!fs_info->tree_root) { - error = -ENOMEM; - goto error_fs_info; - } - fs_info->tree_root->fs_info = fs_info; fs_info->fs_devices = fs_devices; fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); @@ -928,43 +961,30 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, } bdev = fs_devices->latest_bdev; - s = sget(fs_type, btrfs_test_super, btrfs_set_super, - fs_info->tree_root); + s = sget(fs_type, btrfs_test_super, btrfs_set_super, fs_info); if (IS_ERR(s)) { error = PTR_ERR(s); goto error_close_devices; } if (s->s_root) { - if ((flags ^ s->s_flags) & MS_RDONLY) { - deactivate_locked_super(s); - error = -EBUSY; - goto error_close_devices; - } - btrfs_close_devices(fs_devices); free_fs_info(fs_info); + if ((flags ^ s->s_flags) & MS_RDONLY) + error = -EBUSY; } else { char b[BDEVNAME_SIZE]; s->s_flags = flags | MS_NOSEC; strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); - btrfs_sb(s)->fs_info->bdev_holder = fs_type; + btrfs_sb(s)->bdev_holder = fs_type; error = btrfs_fill_super(s, fs_devices, data, flags & MS_SILENT ? 1 : 0); - if (error) { - deactivate_locked_super(s); - return ERR_PTR(error); - } - - s->s_flags |= MS_ACTIVE; } - root = get_default_root(s, subvol_objectid); - if (IS_ERR(root)) { + root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error); + if (IS_ERR(root)) deactivate_locked_super(s); - return root; - } return root; @@ -977,7 +997,8 @@ error_fs_info: static int btrfs_remount(struct super_block *sb, int *flags, char *data) { - struct btrfs_root *root = btrfs_sb(sb); + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + struct btrfs_root *root = fs_info->tree_root; int ret; ret = btrfs_parse_options(root, data); @@ -993,13 +1014,13 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) ret = btrfs_commit_super(root); WARN_ON(ret); } else { - if (root->fs_info->fs_devices->rw_devices == 0) + if (fs_info->fs_devices->rw_devices == 0) return -EACCES; - if (btrfs_super_log_root(root->fs_info->super_copy) != 0) + if (btrfs_super_log_root(fs_info->super_copy) != 0) return -EINVAL; - ret = btrfs_cleanup_fs_roots(root->fs_info); + ret = btrfs_cleanup_fs_roots(fs_info); WARN_ON(ret); /* recover relocation */ @@ -1168,18 +1189,18 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes) static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct btrfs_root *root = btrfs_sb(dentry->d_sb); - struct btrfs_super_block *disk_super = root->fs_info->super_copy; - struct list_head *head = &root->fs_info->space_info; + struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb); + struct btrfs_super_block *disk_super = fs_info->super_copy; + struct list_head *head = &fs_info->space_info; struct btrfs_space_info *found; u64 total_used = 0; u64 total_free_data = 0; int bits = dentry->d_sb->s_blocksize_bits; - __be32 *fsid = (__be32 *)root->fs_info->fsid; + __be32 *fsid = (__be32 *)fs_info->fsid; int ret; /* holding chunk_muext to avoid allocating new chunks */ - mutex_lock(&root->fs_info->chunk_mutex); + mutex_lock(&fs_info->chunk_mutex); rcu_read_lock(); list_for_each_entry_rcu(found, head, list) { if (found->flags & BTRFS_BLOCK_GROUP_DATA) { @@ -1198,14 +1219,14 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bsize = dentry->d_sb->s_blocksize; buf->f_type = BTRFS_SUPER_MAGIC; buf->f_bavail = total_free_data; - ret = btrfs_calc_avail_data_space(root, &total_free_data); + ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data); if (ret) { - mutex_unlock(&root->fs_info->chunk_mutex); + mutex_unlock(&fs_info->chunk_mutex); return ret; } buf->f_bavail += total_free_data; buf->f_bavail = buf->f_bavail >> bits; - mutex_unlock(&root->fs_info->chunk_mutex); + mutex_unlock(&fs_info->chunk_mutex); /* We treat it as constant endianness (it doesn't matter _which_) because we want the fsid to come out the same whether mounted @@ -1219,11 +1240,18 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } +static void btrfs_kill_super(struct super_block *sb) +{ + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + kill_anon_super(sb); + free_fs_info(fs_info); +} + static struct file_system_type btrfs_fs_type = { .owner = THIS_MODULE, .name = "btrfs", .mount = btrfs_mount, - .kill_sb = kill_anon_super, + .kill_sb = btrfs_kill_super, .fs_flags = FS_REQUIRES_DEV, }; @@ -1257,17 +1285,17 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd, static int btrfs_freeze(struct super_block *sb) { - struct btrfs_root *root = btrfs_sb(sb); - mutex_lock(&root->fs_info->transaction_kthread_mutex); - mutex_lock(&root->fs_info->cleaner_mutex); + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + mutex_lock(&fs_info->transaction_kthread_mutex); + mutex_lock(&fs_info->cleaner_mutex); return 0; } static int btrfs_unfreeze(struct super_block *sb) { - struct btrfs_root *root = btrfs_sb(sb); - mutex_unlock(&root->fs_info->cleaner_mutex); - mutex_unlock(&root->fs_info->transaction_kthread_mutex); + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + mutex_unlock(&fs_info->cleaner_mutex); + mutex_unlock(&fs_info->transaction_kthread_mutex); return 0; } diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 81376d94cd3c..287a6728b1ad 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -36,6 +36,8 @@ static noinline void put_transaction(struct btrfs_transaction *transaction) WARN_ON(atomic_read(&transaction->use_count) == 0); if (atomic_dec_and_test(&transaction->use_count)) { BUG_ON(!list_empty(&transaction->list)); + WARN_ON(transaction->delayed_refs.root.rb_node); + WARN_ON(!list_empty(&transaction->delayed_refs.seq_head)); memset(transaction, 0, sizeof(*transaction)); kmem_cache_free(btrfs_transaction_cachep, transaction); } @@ -108,8 +110,11 @@ loop: cur_trans->delayed_refs.num_heads = 0; cur_trans->delayed_refs.flushing = 0; cur_trans->delayed_refs.run_delayed_start = 0; + cur_trans->delayed_refs.seq = 1; + init_waitqueue_head(&cur_trans->delayed_refs.seq_wait); spin_lock_init(&cur_trans->commit_lock); spin_lock_init(&cur_trans->delayed_refs.lock); + INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head); INIT_LIST_HEAD(&cur_trans->pending_snapshots); list_add_tail(&cur_trans->list, &root->fs_info->trans_list); @@ -321,6 +326,8 @@ again: } if (num_bytes) { + trace_btrfs_space_reservation(root->fs_info, "transaction", + (u64)h, num_bytes, 1); h->block_rsv = &root->fs_info->trans_block_rsv; h->bytes_reserved = num_bytes; } @@ -467,19 +474,12 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, btrfs_trans_release_metadata(trans, root); trans->block_rsv = NULL; - while (count < 4) { + while (count < 2) { unsigned long cur = trans->delayed_ref_updates; trans->delayed_ref_updates = 0; if (cur && trans->transaction->delayed_refs.num_heads_ready > 64) { trans->delayed_ref_updates = 0; - - /* - * do a full flush if the transaction is trying - * to close - */ - if (trans->transaction->delayed_refs.flushing) - cur = 0; btrfs_run_delayed_refs(trans, root, cur); } else { break; @@ -1393,9 +1393,9 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root) if (btrfs_header_backref_rev(root->node) < BTRFS_MIXED_BACKREF_REV) - btrfs_drop_snapshot(root, NULL, 0); + btrfs_drop_snapshot(root, NULL, 0, 0); else - btrfs_drop_snapshot(root, NULL, 1); + btrfs_drop_snapshot(root, NULL, 1, 0); } return 0; } diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 3568374d419d..cb877e0886a7 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -589,7 +589,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, ret = btrfs_inc_extent_ref(trans, root, ins.objectid, ins.offset, 0, root->root_key.objectid, - key->objectid, offset); + key->objectid, offset, 0); BUG_ON(ret); } else { /* diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c new file mode 100644 index 000000000000..12f5147bd2b1 --- /dev/null +++ b/fs/btrfs/ulist.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2011 STRATO AG + * written by Arne Jansen <sensille@gmx.net> + * Distributed under the GNU GPL license version 2. + */ + +#include <linux/slab.h> +#include <linux/module.h> +#include "ulist.h" + +/* + * ulist is a generic data structure to hold a collection of unique u64 + * values. The only operations it supports is adding to the list and + * enumerating it. + * It is possible to store an auxiliary value along with the key. + * + * The implementation is preliminary and can probably be sped up + * significantly. A first step would be to store the values in an rbtree + * as soon as ULIST_SIZE is exceeded. + * + * A sample usage for ulists is the enumeration of directed graphs without + * visiting a node twice. The pseudo-code could look like this: + * + * ulist = ulist_alloc(); + * ulist_add(ulist, root); + * elem = NULL; + * + * while ((elem = ulist_next(ulist, elem)) { + * for (all child nodes n in elem) + * ulist_add(ulist, n); + * do something useful with the node; + * } + * ulist_free(ulist); + * + * This assumes the graph nodes are adressable by u64. This stems from the + * usage for tree enumeration in btrfs, where the logical addresses are + * 64 bit. + * + * It is also useful for tree enumeration which could be done elegantly + * recursively, but is not possible due to kernel stack limitations. The + * loop would be similar to the above. + */ + +/** + * ulist_init - freshly initialize a ulist + * @ulist: the ulist to initialize + * + * Note: don't use this function to init an already used ulist, use + * ulist_reinit instead. + */ +void ulist_init(struct ulist *ulist) +{ + ulist->nnodes = 0; + ulist->nodes = ulist->int_nodes; + ulist->nodes_alloced = ULIST_SIZE; +} +EXPORT_SYMBOL(ulist_init); + +/** + * ulist_fini - free up additionally allocated memory for the ulist + * @ulist: the ulist from which to free the additional memory + * + * This is useful in cases where the base 'struct ulist' has been statically + * allocated. + */ +void ulist_fini(struct ulist *ulist) +{ + /* + * The first ULIST_SIZE elements are stored inline in struct ulist. + * Only if more elements are alocated they need to be freed. + */ + if (ulist->nodes_alloced > ULIST_SIZE) + kfree(ulist->nodes); + ulist->nodes_alloced = 0; /* in case ulist_fini is called twice */ +} +EXPORT_SYMBOL(ulist_fini); + +/** + * ulist_reinit - prepare a ulist for reuse + * @ulist: ulist to be reused + * + * Free up all additional memory allocated for the list elements and reinit + * the ulist. + */ +void ulist_reinit(struct ulist *ulist) +{ + ulist_fini(ulist); + ulist_init(ulist); +} +EXPORT_SYMBOL(ulist_reinit); + +/** + * ulist_alloc - dynamically allocate a ulist + * @gfp_mask: allocation flags to for base allocation + * + * The allocated ulist will be returned in an initialized state. + */ +struct ulist *ulist_alloc(unsigned long gfp_mask) +{ + struct ulist *ulist = kmalloc(sizeof(*ulist), gfp_mask); + + if (!ulist) + return NULL; + + ulist_init(ulist); + + return ulist; +} +EXPORT_SYMBOL(ulist_alloc); + +/** + * ulist_free - free dynamically allocated ulist + * @ulist: ulist to free + * + * It is not necessary to call ulist_fini before. + */ +void ulist_free(struct ulist *ulist) +{ + if (!ulist) + return; + ulist_fini(ulist); + kfree(ulist); +} +EXPORT_SYMBOL(ulist_free); + +/** + * ulist_add - add an element to the ulist + * @ulist: ulist to add the element to + * @val: value to add to ulist + * @aux: auxiliary value to store along with val + * @gfp_mask: flags to use for allocation + * + * Note: locking must be provided by the caller. In case of rwlocks write + * locking is needed + * + * Add an element to a ulist. The @val will only be added if it doesn't + * already exist. If it is added, the auxiliary value @aux is stored along with + * it. In case @val already exists in the ulist, @aux is ignored, even if + * it differs from the already stored value. + * + * ulist_add returns 0 if @val already exists in ulist and 1 if @val has been + * inserted. + * In case of allocation failure -ENOMEM is returned and the ulist stays + * unaltered. + */ +int ulist_add(struct ulist *ulist, u64 val, unsigned long aux, + unsigned long gfp_mask) +{ + int i; + + for (i = 0; i < ulist->nnodes; ++i) { + if (ulist->nodes[i].val == val) + return 0; + } + + if (ulist->nnodes >= ulist->nodes_alloced) { + u64 new_alloced = ulist->nodes_alloced + 128; + struct ulist_node *new_nodes; + void *old = NULL; + + /* + * if nodes_alloced == ULIST_SIZE no memory has been allocated + * yet, so pass NULL to krealloc + */ + if (ulist->nodes_alloced > ULIST_SIZE) + old = ulist->nodes; + + new_nodes = krealloc(old, sizeof(*new_nodes) * new_alloced, + gfp_mask); + if (!new_nodes) + return -ENOMEM; + + if (!old) + memcpy(new_nodes, ulist->int_nodes, + sizeof(ulist->int_nodes)); + + ulist->nodes = new_nodes; + ulist->nodes_alloced = new_alloced; + } + ulist->nodes[ulist->nnodes].val = val; + ulist->nodes[ulist->nnodes].aux = aux; + ++ulist->nnodes; + + return 1; +} +EXPORT_SYMBOL(ulist_add); + +/** + * ulist_next - iterate ulist + * @ulist: ulist to iterate + * @prev: previously returned element or %NULL to start iteration + * + * Note: locking must be provided by the caller. In case of rwlocks only read + * locking is needed + * + * This function is used to iterate an ulist. The iteration is started with + * @prev = %NULL. It returns the next element from the ulist or %NULL when the + * end is reached. No guarantee is made with respect to the order in which + * the elements are returned. They might neither be returned in order of + * addition nor in ascending order. + * It is allowed to call ulist_add during an enumeration. Newly added items + * are guaranteed to show up in the running enumeration. + */ +struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_node *prev) +{ + int next; + + if (ulist->nnodes == 0) + return NULL; + + if (!prev) + return &ulist->nodes[0]; + + next = (prev - ulist->nodes) + 1; + if (next < 0 || next >= ulist->nnodes) + return NULL; + + return &ulist->nodes[next]; +} +EXPORT_SYMBOL(ulist_next); diff --git a/fs/btrfs/ulist.h b/fs/btrfs/ulist.h new file mode 100644 index 000000000000..2e25dec58ec0 --- /dev/null +++ b/fs/btrfs/ulist.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 STRATO AG + * written by Arne Jansen <sensille@gmx.net> + * Distributed under the GNU GPL license version 2. + * + */ + +#ifndef __ULIST__ +#define __ULIST__ + +/* + * ulist is a generic data structure to hold a collection of unique u64 + * values. The only operations it supports is adding to the list and + * enumerating it. + * It is possible to store an auxiliary value along with the key. + * + * The implementation is preliminary and can probably be sped up + * significantly. A first step would be to store the values in an rbtree + * as soon as ULIST_SIZE is exceeded. + */ + +/* + * number of elements statically allocated inside struct ulist + */ +#define ULIST_SIZE 16 + +/* + * element of the list + */ +struct ulist_node { + u64 val; /* value to store */ + unsigned long aux; /* auxiliary value saved along with the val */ +}; + +struct ulist { + /* + * number of elements stored in list + */ + unsigned long nnodes; + + /* + * number of nodes we already have room for + */ + unsigned long nodes_alloced; + + /* + * pointer to the array storing the elements. The first ULIST_SIZE + * elements are stored inline. In this case the it points to int_nodes. + * After exceeding ULIST_SIZE, dynamic memory is allocated. + */ + struct ulist_node *nodes; + + /* + * inline storage space for the first ULIST_SIZE entries + */ + struct ulist_node int_nodes[ULIST_SIZE]; +}; + +void ulist_init(struct ulist *ulist); +void ulist_fini(struct ulist *ulist); +void ulist_reinit(struct ulist *ulist); +struct ulist *ulist_alloc(unsigned long gfp_mask); +void ulist_free(struct ulist *ulist); +int ulist_add(struct ulist *ulist, u64 val, unsigned long aux, + unsigned long gfp_mask); +struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_node *prev); + +#endif diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index f4b839fd3c9d..0b4e2af7954d 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -23,6 +23,7 @@ #include <linux/random.h> #include <linux/iocontext.h> #include <linux/capability.h> +#include <linux/kthread.h> #include <asm/div64.h> #include "compat.h" #include "ctree.h" @@ -32,6 +33,7 @@ #include "print-tree.h" #include "volumes.h" #include "async-thread.h" +#include "check-integrity.h" static int init_first_rw_device(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -246,7 +248,7 @@ loop_lock: sync_pending = 0; } - submit_bio(cur->bi_rw, cur); + btrfsic_submit_bio(cur->bi_rw, cur); num_run++; batch_run++; if (need_resched()) @@ -706,8 +708,6 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, u64 devid; u64 transid; - mutex_lock(&uuid_mutex); - flags |= FMODE_EXCL; bdev = blkdev_get_by_path(path, flags, holder); @@ -716,6 +716,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, goto error; } + mutex_lock(&uuid_mutex); ret = set_blocksize(bdev, 4096); if (ret) goto error_close; @@ -737,9 +738,9 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, brelse(bh); error_close: + mutex_unlock(&uuid_mutex); blkdev_put(bdev, flags); error: - mutex_unlock(&uuid_mutex); return ret; } @@ -829,7 +830,6 @@ out: /* * find_free_dev_extent - find free space in the specified device - * @trans: transaction handler * @device: the device which we search the free space in * @num_bytes: the size of the free space that we need * @start: store the start of the free space. @@ -848,8 +848,7 @@ out: * But if we don't find suitable free space, it is used to store the size of * the max free space. */ -int find_free_dev_extent(struct btrfs_trans_handle *trans, - struct btrfs_device *device, u64 num_bytes, +int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, u64 *start, u64 *len) { struct btrfs_key key; @@ -893,7 +892,7 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans, key.offset = search_start; key.type = BTRFS_DEV_EXTENT_KEY; - ret = btrfs_search_slot(trans, root, &key, path, 0, 0); + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; if (ret > 0) { @@ -1282,7 +1281,6 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) bool clear_super = false; mutex_lock(&uuid_mutex); - mutex_lock(&root->fs_info->volume_mutex); all_avail = root->fs_info->avail_data_alloc_bits | root->fs_info->avail_system_alloc_bits | @@ -1452,7 +1450,6 @@ error_close: if (bdev) blkdev_put(bdev, FMODE_READ | FMODE_EXCL); out: - mutex_unlock(&root->fs_info->volume_mutex); mutex_unlock(&uuid_mutex); return ret; error_undo: @@ -1469,8 +1466,7 @@ error_undo: /* * does all the dirty work required for changing file system's UUID. */ -static int btrfs_prepare_sprout(struct btrfs_trans_handle *trans, - struct btrfs_root *root) +static int btrfs_prepare_sprout(struct btrfs_root *root) { struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; struct btrfs_fs_devices *old_devices; @@ -1629,7 +1625,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) } filemap_write_and_wait(bdev->bd_inode->i_mapping); - mutex_lock(&root->fs_info->volume_mutex); devices = &root->fs_info->fs_devices->devices; /* @@ -1695,7 +1690,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) if (seeding_dev) { sb->s_flags &= ~MS_RDONLY; - ret = btrfs_prepare_sprout(trans, root); + ret = btrfs_prepare_sprout(root); BUG_ON(ret); } @@ -1757,8 +1752,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) ret = btrfs_relocate_sys_chunks(root); BUG_ON(ret); } -out: - mutex_unlock(&root->fs_info->volume_mutex); + return ret; error: blkdev_put(bdev, FMODE_EXCL); @@ -1766,7 +1760,7 @@ error: mutex_unlock(&uuid_mutex); up_write(&sb->s_umount); } - goto out; + return ret; } static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, @@ -2077,6 +2071,362 @@ error: return ret; } +static int insert_balance_item(struct btrfs_root *root, + struct btrfs_balance_control *bctl) +{ + struct btrfs_trans_handle *trans; + struct btrfs_balance_item *item; + struct btrfs_disk_balance_args disk_bargs; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_key key; + int ret, err; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + btrfs_free_path(path); + return PTR_ERR(trans); + } + + key.objectid = BTRFS_BALANCE_OBJECTID; + key.type = BTRFS_BALANCE_ITEM_KEY; + key.offset = 0; + + ret = btrfs_insert_empty_item(trans, root, path, &key, + sizeof(*item)); + if (ret) + goto out; + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item); + + memset_extent_buffer(leaf, 0, (unsigned long)item, sizeof(*item)); + + btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->data); + btrfs_set_balance_data(leaf, item, &disk_bargs); + btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->meta); + btrfs_set_balance_meta(leaf, item, &disk_bargs); + btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->sys); + btrfs_set_balance_sys(leaf, item, &disk_bargs); + + btrfs_set_balance_flags(leaf, item, bctl->flags); + + btrfs_mark_buffer_dirty(leaf); +out: + btrfs_free_path(path); + err = btrfs_commit_transaction(trans, root); + if (err && !ret) + ret = err; + return ret; +} + +static int del_balance_item(struct btrfs_root *root) +{ + struct btrfs_trans_handle *trans; + struct btrfs_path *path; + struct btrfs_key key; + int ret, err; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + trans = btrfs_start_transaction(root, 0); + if (IS_ERR(trans)) { + btrfs_free_path(path); + return PTR_ERR(trans); + } + + key.objectid = BTRFS_BALANCE_OBJECTID; + key.type = BTRFS_BALANCE_ITEM_KEY; + key.offset = 0; + + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); + if (ret < 0) + goto out; + if (ret > 0) { + ret = -ENOENT; + goto out; + } + + ret = btrfs_del_item(trans, root, path); +out: + btrfs_free_path(path); + err = btrfs_commit_transaction(trans, root); + if (err && !ret) + ret = err; + return ret; +} + +/* + * This is a heuristic used to reduce the number of chunks balanced on + * resume after balance was interrupted. + */ +static void update_balance_args(struct btrfs_balance_control *bctl) +{ + /* + * Turn on soft mode for chunk types that were being converted. + */ + if (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) + bctl->data.flags |= BTRFS_BALANCE_ARGS_SOFT; + if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) + bctl->sys.flags |= BTRFS_BALANCE_ARGS_SOFT; + if (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) + bctl->meta.flags |= BTRFS_BALANCE_ARGS_SOFT; + + /* + * Turn on usage filter if is not already used. The idea is + * that chunks that we have already balanced should be + * reasonably full. Don't do it for chunks that are being + * converted - that will keep us from relocating unconverted + * (albeit full) chunks. + */ + if (!(bctl->data.flags & BTRFS_BALANCE_ARGS_USAGE) && + !(bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT)) { + bctl->data.flags |= BTRFS_BALANCE_ARGS_USAGE; + bctl->data.usage = 90; + } + if (!(bctl->sys.flags & BTRFS_BALANCE_ARGS_USAGE) && + !(bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT)) { + bctl->sys.flags |= BTRFS_BALANCE_ARGS_USAGE; + bctl->sys.usage = 90; + } + if (!(bctl->meta.flags & BTRFS_BALANCE_ARGS_USAGE) && + !(bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT)) { + bctl->meta.flags |= BTRFS_BALANCE_ARGS_USAGE; + bctl->meta.usage = 90; + } +} + +/* + * Should be called with both balance and volume mutexes held to + * serialize other volume operations (add_dev/rm_dev/resize) with + * restriper. Same goes for unset_balance_control. + */ +static void set_balance_control(struct btrfs_balance_control *bctl) +{ + struct btrfs_fs_info *fs_info = bctl->fs_info; + + BUG_ON(fs_info->balance_ctl); + + spin_lock(&fs_info->balance_lock); + fs_info->balance_ctl = bctl; + spin_unlock(&fs_info->balance_lock); +} + +static void unset_balance_control(struct btrfs_fs_info *fs_info) +{ + struct btrfs_balance_control *bctl = fs_info->balance_ctl; + + BUG_ON(!fs_info->balance_ctl); + + spin_lock(&fs_info->balance_lock); + fs_info->balance_ctl = NULL; + spin_unlock(&fs_info->balance_lock); + + kfree(bctl); +} + +/* + * Balance filters. Return 1 if chunk should be filtered out + * (should not be balanced). + */ +static int chunk_profiles_filter(u64 chunk_profile, + struct btrfs_balance_args *bargs) +{ + chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; + + if (chunk_profile == 0) + chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE; + + if (bargs->profiles & chunk_profile) + return 0; + + return 1; +} + +static u64 div_factor_fine(u64 num, int factor) +{ + if (factor <= 0) + return 0; + if (factor >= 100) + return num; + + num *= factor; + do_div(num, 100); + return num; +} + +static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, + struct btrfs_balance_args *bargs) +{ + struct btrfs_block_group_cache *cache; + u64 chunk_used, user_thresh; + int ret = 1; + + cache = btrfs_lookup_block_group(fs_info, chunk_offset); + chunk_used = btrfs_block_group_used(&cache->item); + + user_thresh = div_factor_fine(cache->key.offset, bargs->usage); + if (chunk_used < user_thresh) + ret = 0; + + btrfs_put_block_group(cache); + return ret; +} + +static int chunk_devid_filter(struct extent_buffer *leaf, + struct btrfs_chunk *chunk, + struct btrfs_balance_args *bargs) +{ + struct btrfs_stripe *stripe; + int num_stripes = btrfs_chunk_num_stripes(leaf, chunk); + int i; + + for (i = 0; i < num_stripes; i++) { + stripe = btrfs_stripe_nr(chunk, i); + if (btrfs_stripe_devid(leaf, stripe) == bargs->devid) + return 0; + } + + return 1; +} + +/* [pstart, pend) */ +static int chunk_drange_filter(struct extent_buffer *leaf, + struct btrfs_chunk *chunk, + u64 chunk_offset, + struct btrfs_balance_args *bargs) +{ + struct btrfs_stripe *stripe; + int num_stripes = btrfs_chunk_num_stripes(leaf, chunk); + u64 stripe_offset; + u64 stripe_length; + int factor; + int i; + + if (!(bargs->flags & BTRFS_BALANCE_ARGS_DEVID)) + return 0; + + if (btrfs_chunk_type(leaf, chunk) & (BTRFS_BLOCK_GROUP_DUP | + BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)) + factor = 2; + else + factor = 1; + factor = num_stripes / factor; + + for (i = 0; i < num_stripes; i++) { + stripe = btrfs_stripe_nr(chunk, i); + if (btrfs_stripe_devid(leaf, stripe) != bargs->devid) + continue; + + stripe_offset = btrfs_stripe_offset(leaf, stripe); + stripe_length = btrfs_chunk_length(leaf, chunk); + do_div(stripe_length, factor); + + if (stripe_offset < bargs->pend && + stripe_offset + stripe_length > bargs->pstart) + return 0; + } + + return 1; +} + +/* [vstart, vend) */ +static int chunk_vrange_filter(struct extent_buffer *leaf, + struct btrfs_chunk *chunk, + u64 chunk_offset, + struct btrfs_balance_args *bargs) +{ + if (chunk_offset < bargs->vend && + chunk_offset + btrfs_chunk_length(leaf, chunk) > bargs->vstart) + /* at least part of the chunk is inside this vrange */ + return 0; + + return 1; +} + +static int chunk_soft_convert_filter(u64 chunk_profile, + struct btrfs_balance_args *bargs) +{ + if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT)) + return 0; + + chunk_profile &= BTRFS_BLOCK_GROUP_PROFILE_MASK; + + if (chunk_profile == 0) + chunk_profile = BTRFS_AVAIL_ALLOC_BIT_SINGLE; + + if (bargs->target & chunk_profile) + return 1; + + return 0; +} + +static int should_balance_chunk(struct btrfs_root *root, + struct extent_buffer *leaf, + struct btrfs_chunk *chunk, u64 chunk_offset) +{ + struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; + struct btrfs_balance_args *bargs = NULL; + u64 chunk_type = btrfs_chunk_type(leaf, chunk); + + /* type filter */ + if (!((chunk_type & BTRFS_BLOCK_GROUP_TYPE_MASK) & + (bctl->flags & BTRFS_BALANCE_TYPE_MASK))) { + return 0; + } + + if (chunk_type & BTRFS_BLOCK_GROUP_DATA) + bargs = &bctl->data; + else if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) + bargs = &bctl->sys; + else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA) + bargs = &bctl->meta; + + /* profiles filter */ + if ((bargs->flags & BTRFS_BALANCE_ARGS_PROFILES) && + chunk_profiles_filter(chunk_type, bargs)) { + return 0; + } + + /* usage filter */ + if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE) && + chunk_usage_filter(bctl->fs_info, chunk_offset, bargs)) { + return 0; + } + + /* devid filter */ + if ((bargs->flags & BTRFS_BALANCE_ARGS_DEVID) && + chunk_devid_filter(leaf, chunk, bargs)) { + return 0; + } + + /* drange filter, makes sense only with devid filter */ + if ((bargs->flags & BTRFS_BALANCE_ARGS_DRANGE) && + chunk_drange_filter(leaf, chunk, chunk_offset, bargs)) { + return 0; + } + + /* vrange filter */ + if ((bargs->flags & BTRFS_BALANCE_ARGS_VRANGE) && + chunk_vrange_filter(leaf, chunk, chunk_offset, bargs)) { + return 0; + } + + /* soft profile changing mode */ + if ((bargs->flags & BTRFS_BALANCE_ARGS_SOFT) && + chunk_soft_convert_filter(chunk_type, bargs)) { + return 0; + } + + return 1; +} + static u64 div_factor(u64 num, int factor) { if (factor == 10) @@ -2086,29 +2436,28 @@ static u64 div_factor(u64 num, int factor) return num; } -int btrfs_balance(struct btrfs_root *dev_root) +static int __btrfs_balance(struct btrfs_fs_info *fs_info) { - int ret; - struct list_head *devices = &dev_root->fs_info->fs_devices->devices; + struct btrfs_balance_control *bctl = fs_info->balance_ctl; + struct btrfs_root *chunk_root = fs_info->chunk_root; + struct btrfs_root *dev_root = fs_info->dev_root; + struct list_head *devices; struct btrfs_device *device; u64 old_size; u64 size_to_free; + struct btrfs_chunk *chunk; struct btrfs_path *path; struct btrfs_key key; - struct btrfs_root *chunk_root = dev_root->fs_info->chunk_root; - struct btrfs_trans_handle *trans; struct btrfs_key found_key; - - if (dev_root->fs_info->sb->s_flags & MS_RDONLY) - return -EROFS; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - mutex_lock(&dev_root->fs_info->volume_mutex); - dev_root = dev_root->fs_info->dev_root; + struct btrfs_trans_handle *trans; + struct extent_buffer *leaf; + int slot; + int ret; + int enospc_errors = 0; + bool counting = true; /* step one make some room on all the devices */ + devices = &fs_info->fs_devices->devices; list_for_each_entry(device, devices, dev_list) { old_size = device->total_bytes; size_to_free = div_factor(old_size, 1); @@ -2137,11 +2486,23 @@ int btrfs_balance(struct btrfs_root *dev_root) ret = -ENOMEM; goto error; } + + /* zero out stat counters */ + spin_lock(&fs_info->balance_lock); + memset(&bctl->stat, 0, sizeof(bctl->stat)); + spin_unlock(&fs_info->balance_lock); +again: key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; key.offset = (u64)-1; key.type = BTRFS_CHUNK_ITEM_KEY; while (1) { + if ((!counting && atomic_read(&fs_info->balance_pause_req)) || + atomic_read(&fs_info->balance_cancel_req)) { + ret = -ECANCELED; + goto error; + } + ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); if (ret < 0) goto error; @@ -2151,15 +2512,19 @@ int btrfs_balance(struct btrfs_root *dev_root) * failed */ if (ret == 0) - break; + BUG(); /* FIXME break ? */ ret = btrfs_previous_item(chunk_root, path, 0, BTRFS_CHUNK_ITEM_KEY); - if (ret) + if (ret) { + ret = 0; break; + } + + leaf = path->nodes[0]; + slot = path->slots[0]; + btrfs_item_key_to_cpu(leaf, &found_key, slot); - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); if (found_key.objectid != key.objectid) break; @@ -2167,22 +2532,375 @@ int btrfs_balance(struct btrfs_root *dev_root) if (found_key.offset == 0) break; + chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); + + if (!counting) { + spin_lock(&fs_info->balance_lock); + bctl->stat.considered++; + spin_unlock(&fs_info->balance_lock); + } + + ret = should_balance_chunk(chunk_root, leaf, chunk, + found_key.offset); btrfs_release_path(path); + if (!ret) + goto loop; + + if (counting) { + spin_lock(&fs_info->balance_lock); + bctl->stat.expected++; + spin_unlock(&fs_info->balance_lock); + goto loop; + } + ret = btrfs_relocate_chunk(chunk_root, chunk_root->root_key.objectid, found_key.objectid, found_key.offset); if (ret && ret != -ENOSPC) goto error; + if (ret == -ENOSPC) { + enospc_errors++; + } else { + spin_lock(&fs_info->balance_lock); + bctl->stat.completed++; + spin_unlock(&fs_info->balance_lock); + } +loop: key.offset = found_key.offset - 1; } - ret = 0; + + if (counting) { + btrfs_release_path(path); + counting = false; + goto again; + } error: btrfs_free_path(path); - mutex_unlock(&dev_root->fs_info->volume_mutex); + if (enospc_errors) { + printk(KERN_INFO "btrfs: %d enospc errors during balance\n", + enospc_errors); + if (!ret) + ret = -ENOSPC; + } + return ret; } +static inline int balance_need_close(struct btrfs_fs_info *fs_info) +{ + /* cancel requested || normal exit path */ + return atomic_read(&fs_info->balance_cancel_req) || + (atomic_read(&fs_info->balance_pause_req) == 0 && + atomic_read(&fs_info->balance_cancel_req) == 0); +} + +static void __cancel_balance(struct btrfs_fs_info *fs_info) +{ + int ret; + + unset_balance_control(fs_info); + ret = del_balance_item(fs_info->tree_root); + BUG_ON(ret); +} + +void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, + struct btrfs_ioctl_balance_args *bargs); + +/* + * Should be called with both balance and volume mutexes held + */ +int btrfs_balance(struct btrfs_balance_control *bctl, + struct btrfs_ioctl_balance_args *bargs) +{ + struct btrfs_fs_info *fs_info = bctl->fs_info; + u64 allowed; + int ret; + + if (btrfs_fs_closing(fs_info) || + atomic_read(&fs_info->balance_pause_req) || + atomic_read(&fs_info->balance_cancel_req)) { + ret = -EINVAL; + goto out; + } + + /* + * In case of mixed groups both data and meta should be picked, + * and identical options should be given for both of them. + */ + allowed = btrfs_super_incompat_flags(fs_info->super_copy); + if ((allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) && + (bctl->flags & (BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA))) { + if (!(bctl->flags & BTRFS_BALANCE_DATA) || + !(bctl->flags & BTRFS_BALANCE_METADATA) || + memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) { + printk(KERN_ERR "btrfs: with mixed groups data and " + "metadata balance options must be the same\n"); + ret = -EINVAL; + goto out; + } + } + + /* + * Profile changing sanity checks. Skip them if a simple + * balance is requested. + */ + if (!((bctl->data.flags | bctl->sys.flags | bctl->meta.flags) & + BTRFS_BALANCE_ARGS_CONVERT)) + goto do_balance; + + allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE; + if (fs_info->fs_devices->num_devices == 1) + allowed |= BTRFS_BLOCK_GROUP_DUP; + else if (fs_info->fs_devices->num_devices < 4) + allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1); + else + allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID10); + + if (!profile_is_valid(bctl->data.target, 1) || + bctl->data.target & ~allowed) { + printk(KERN_ERR "btrfs: unable to start balance with target " + "data profile %llu\n", + (unsigned long long)bctl->data.target); + ret = -EINVAL; + goto out; + } + if (!profile_is_valid(bctl->meta.target, 1) || + bctl->meta.target & ~allowed) { + printk(KERN_ERR "btrfs: unable to start balance with target " + "metadata profile %llu\n", + (unsigned long long)bctl->meta.target); + ret = -EINVAL; + goto out; + } + if (!profile_is_valid(bctl->sys.target, 1) || + bctl->sys.target & ~allowed) { + printk(KERN_ERR "btrfs: unable to start balance with target " + "system profile %llu\n", + (unsigned long long)bctl->sys.target); + ret = -EINVAL; + goto out; + } + + if (bctl->data.target & BTRFS_BLOCK_GROUP_DUP) { + printk(KERN_ERR "btrfs: dup for data is not allowed\n"); + ret = -EINVAL; + goto out; + } + + /* allow to reduce meta or sys integrity only if force set */ + allowed = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID10; + if (((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) && + (fs_info->avail_system_alloc_bits & allowed) && + !(bctl->sys.target & allowed)) || + ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) && + (fs_info->avail_metadata_alloc_bits & allowed) && + !(bctl->meta.target & allowed))) { + if (bctl->flags & BTRFS_BALANCE_FORCE) { + printk(KERN_INFO "btrfs: force reducing metadata " + "integrity\n"); + } else { + printk(KERN_ERR "btrfs: balance will reduce metadata " + "integrity, use force if you want this\n"); + ret = -EINVAL; + goto out; + } + } + +do_balance: + ret = insert_balance_item(fs_info->tree_root, bctl); + if (ret && ret != -EEXIST) + goto out; + + if (!(bctl->flags & BTRFS_BALANCE_RESUME)) { + BUG_ON(ret == -EEXIST); + set_balance_control(bctl); + } else { + BUG_ON(ret != -EEXIST); + spin_lock(&fs_info->balance_lock); + update_balance_args(bctl); + spin_unlock(&fs_info->balance_lock); + } + + atomic_inc(&fs_info->balance_running); + mutex_unlock(&fs_info->balance_mutex); + + ret = __btrfs_balance(fs_info); + + mutex_lock(&fs_info->balance_mutex); + atomic_dec(&fs_info->balance_running); + + if (bargs) { + memset(bargs, 0, sizeof(*bargs)); + update_ioctl_balance_args(fs_info, 0, bargs); + } + + if ((ret && ret != -ECANCELED && ret != -ENOSPC) || + balance_need_close(fs_info)) { + __cancel_balance(fs_info); + } + + wake_up(&fs_info->balance_wait_q); + + return ret; +out: + if (bctl->flags & BTRFS_BALANCE_RESUME) + __cancel_balance(fs_info); + else + kfree(bctl); + return ret; +} + +static int balance_kthread(void *data) +{ + struct btrfs_balance_control *bctl = + (struct btrfs_balance_control *)data; + struct btrfs_fs_info *fs_info = bctl->fs_info; + int ret = 0; + + mutex_lock(&fs_info->volume_mutex); + mutex_lock(&fs_info->balance_mutex); + + set_balance_control(bctl); + + if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) { + printk(KERN_INFO "btrfs: force skipping balance\n"); + } else { + printk(KERN_INFO "btrfs: continuing balance\n"); + ret = btrfs_balance(bctl, NULL); + } + + mutex_unlock(&fs_info->balance_mutex); + mutex_unlock(&fs_info->volume_mutex); + return ret; +} + +int btrfs_recover_balance(struct btrfs_root *tree_root) +{ + struct task_struct *tsk; + struct btrfs_balance_control *bctl; + struct btrfs_balance_item *item; + struct btrfs_disk_balance_args disk_bargs; + struct btrfs_path *path; + struct extent_buffer *leaf; + struct btrfs_key key; + int ret; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + bctl = kzalloc(sizeof(*bctl), GFP_NOFS); + if (!bctl) { + ret = -ENOMEM; + goto out; + } + + key.objectid = BTRFS_BALANCE_OBJECTID; + key.type = BTRFS_BALANCE_ITEM_KEY; + key.offset = 0; + + ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0); + if (ret < 0) + goto out_bctl; + if (ret > 0) { /* ret = -ENOENT; */ + ret = 0; + goto out_bctl; + } + + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item); + + bctl->fs_info = tree_root->fs_info; + bctl->flags = btrfs_balance_flags(leaf, item) | BTRFS_BALANCE_RESUME; + + btrfs_balance_data(leaf, item, &disk_bargs); + btrfs_disk_balance_args_to_cpu(&bctl->data, &disk_bargs); + btrfs_balance_meta(leaf, item, &disk_bargs); + btrfs_disk_balance_args_to_cpu(&bctl->meta, &disk_bargs); + btrfs_balance_sys(leaf, item, &disk_bargs); + btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs); + + tsk = kthread_run(balance_kthread, bctl, "btrfs-balance"); + if (IS_ERR(tsk)) + ret = PTR_ERR(tsk); + else + goto out; + +out_bctl: + kfree(bctl); +out: + btrfs_free_path(path); + return ret; +} + +int btrfs_pause_balance(struct btrfs_fs_info *fs_info) +{ + int ret = 0; + + mutex_lock(&fs_info->balance_mutex); + if (!fs_info->balance_ctl) { + mutex_unlock(&fs_info->balance_mutex); + return -ENOTCONN; + } + + if (atomic_read(&fs_info->balance_running)) { + atomic_inc(&fs_info->balance_pause_req); + mutex_unlock(&fs_info->balance_mutex); + + wait_event(fs_info->balance_wait_q, + atomic_read(&fs_info->balance_running) == 0); + + mutex_lock(&fs_info->balance_mutex); + /* we are good with balance_ctl ripped off from under us */ + BUG_ON(atomic_read(&fs_info->balance_running)); + atomic_dec(&fs_info->balance_pause_req); + } else { + ret = -ENOTCONN; + } + + mutex_unlock(&fs_info->balance_mutex); + return ret; +} + +int btrfs_cancel_balance(struct btrfs_fs_info *fs_info) +{ + mutex_lock(&fs_info->balance_mutex); + if (!fs_info->balance_ctl) { + mutex_unlock(&fs_info->balance_mutex); + return -ENOTCONN; + } + + atomic_inc(&fs_info->balance_cancel_req); + /* + * if we are running just wait and return, balance item is + * deleted in btrfs_balance in this case + */ + if (atomic_read(&fs_info->balance_running)) { + mutex_unlock(&fs_info->balance_mutex); + wait_event(fs_info->balance_wait_q, + atomic_read(&fs_info->balance_running) == 0); + mutex_lock(&fs_info->balance_mutex); + } else { + /* __cancel_balance needs volume_mutex */ + mutex_unlock(&fs_info->balance_mutex); + mutex_lock(&fs_info->volume_mutex); + mutex_lock(&fs_info->balance_mutex); + + if (fs_info->balance_ctl) + __cancel_balance(fs_info); + + mutex_unlock(&fs_info->volume_mutex); + } + + BUG_ON(fs_info->balance_ctl || atomic_read(&fs_info->balance_running)); + atomic_dec(&fs_info->balance_cancel_req); + mutex_unlock(&fs_info->balance_mutex); + return 0; +} + /* * shrinking a device means finding all of the device extents past * the new size, and then following the back refs to the chunks. @@ -2323,8 +3041,7 @@ done: return ret; } -static int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *root, +static int btrfs_add_system_chunk(struct btrfs_root *root, struct btrfs_key *key, struct btrfs_chunk *chunk, int item_size) { @@ -2441,10 +3158,14 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, max_stripe_size = 1024 * 1024 * 1024; max_chunk_size = 10 * max_stripe_size; } else if (type & BTRFS_BLOCK_GROUP_METADATA) { - max_stripe_size = 256 * 1024 * 1024; + /* for larger filesystems, use larger metadata chunks */ + if (fs_devices->total_rw_bytes > 50ULL * 1024 * 1024 * 1024) + max_stripe_size = 1024 * 1024 * 1024; + else + max_stripe_size = 256 * 1024 * 1024; max_chunk_size = max_stripe_size; } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) { - max_stripe_size = 8 * 1024 * 1024; + max_stripe_size = 32 * 1024 * 1024; max_chunk_size = 2 * max_stripe_size; } else { printk(KERN_ERR "btrfs: invalid chunk type 0x%llx requested\n", @@ -2496,7 +3217,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, if (total_avail == 0) continue; - ret = find_free_dev_extent(trans, device, + ret = find_free_dev_extent(device, max_stripe_size * dev_stripes, &dev_offset, &max_avail); if (ret && ret != -ENOSPC) @@ -2687,7 +3408,7 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, BUG_ON(ret); if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { - ret = btrfs_add_system_chunk(trans, chunk_root, &key, chunk, + ret = btrfs_add_system_chunk(chunk_root, &key, chunk, item_size); BUG_ON(ret); } @@ -2752,8 +3473,7 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, return ret; alloc_profile = BTRFS_BLOCK_GROUP_METADATA | - (fs_info->metadata_alloc_profile & - fs_info->avail_metadata_alloc_bits); + fs_info->avail_metadata_alloc_bits; alloc_profile = btrfs_reduce_alloc_profile(root, alloc_profile); ret = __btrfs_alloc_chunk(trans, extent_root, &map, &chunk_size, @@ -2763,8 +3483,7 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, sys_chunk_offset = chunk_offset + chunk_size; alloc_profile = BTRFS_BLOCK_GROUP_SYSTEM | - (fs_info->system_alloc_profile & - fs_info->avail_system_alloc_bits); + fs_info->avail_system_alloc_bits; alloc_profile = btrfs_reduce_alloc_profile(root, alloc_profile); ret = __btrfs_alloc_chunk(trans, extent_root, &sys_map, @@ -2901,26 +3620,13 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 stripe_nr; u64 stripe_nr_orig; u64 stripe_nr_end; - int stripes_allocated = 8; - int stripes_required = 1; int stripe_index; int i; + int ret = 0; int num_stripes; int max_errors = 0; struct btrfs_bio *bbio = NULL; - if (bbio_ret && !(rw & (REQ_WRITE | REQ_DISCARD))) - stripes_allocated = 1; -again: - if (bbio_ret) { - bbio = kzalloc(btrfs_bio_size(stripes_allocated), - GFP_NOFS); - if (!bbio) - return -ENOMEM; - - atomic_set(&bbio->error, 0); - } - read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, logical, *length); read_unlock(&em_tree->lock); @@ -2939,32 +3645,6 @@ again: if (mirror_num > map->num_stripes) mirror_num = 0; - /* if our btrfs_bio struct is too small, back off and try again */ - if (rw & REQ_WRITE) { - if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_DUP)) { - stripes_required = map->num_stripes; - max_errors = 1; - } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { - stripes_required = map->sub_stripes; - max_errors = 1; - } - } - if (rw & REQ_DISCARD) { - if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID10)) { - stripes_required = map->num_stripes; - } - } - if (bbio_ret && (rw & (REQ_WRITE | REQ_DISCARD)) && - stripes_allocated < stripes_required) { - stripes_allocated = map->num_stripes; - free_extent_map(em); - kfree(bbio); - goto again; - } stripe_nr = offset; /* * stripe_nr counts the total number of stripes we have to stride @@ -2980,10 +3660,7 @@ again: if (rw & REQ_DISCARD) *length = min_t(u64, em->len - offset, *length); - else if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_DUP)) { + else if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { /* we limit the length of each bio to what fits in a stripe */ *length = min_t(u64, em->len - offset, map->stripe_len - stripe_offset); @@ -3059,81 +3736,55 @@ again: } BUG_ON(stripe_index >= map->num_stripes); + bbio = kzalloc(btrfs_bio_size(num_stripes), GFP_NOFS); + if (!bbio) { + ret = -ENOMEM; + goto out; + } + atomic_set(&bbio->error, 0); + if (rw & REQ_DISCARD) { + int factor = 0; + int sub_stripes = 0; + u64 stripes_per_dev = 0; + u32 remaining_stripes = 0; + + if (map->type & + (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { + if (map->type & BTRFS_BLOCK_GROUP_RAID0) + sub_stripes = 1; + else + sub_stripes = map->sub_stripes; + + factor = map->num_stripes / sub_stripes; + stripes_per_dev = div_u64_rem(stripe_nr_end - + stripe_nr_orig, + factor, + &remaining_stripes); + } + for (i = 0; i < num_stripes; i++) { bbio->stripes[i].physical = map->stripes[stripe_index].physical + stripe_offset + stripe_nr * map->stripe_len; bbio->stripes[i].dev = map->stripes[stripe_index].dev; - if (map->type & BTRFS_BLOCK_GROUP_RAID0) { - u64 stripes; - u32 last_stripe = 0; - int j; - - div_u64_rem(stripe_nr_end - 1, - map->num_stripes, - &last_stripe); - - for (j = 0; j < map->num_stripes; j++) { - u32 test; - - div_u64_rem(stripe_nr_end - 1 - j, - map->num_stripes, &test); - if (test == stripe_index) - break; - } - stripes = stripe_nr_end - 1 - j; - do_div(stripes, map->num_stripes); - bbio->stripes[i].length = map->stripe_len * - (stripes - stripe_nr + 1); - - if (i == 0) { - bbio->stripes[i].length -= - stripe_offset; - stripe_offset = 0; - } - if (stripe_index == last_stripe) - bbio->stripes[i].length -= - stripe_end_offset; - } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { - u64 stripes; - int j; - int factor = map->num_stripes / - map->sub_stripes; - u32 last_stripe = 0; - - div_u64_rem(stripe_nr_end - 1, - factor, &last_stripe); - last_stripe *= map->sub_stripes; - - for (j = 0; j < factor; j++) { - u32 test; - - div_u64_rem(stripe_nr_end - 1 - j, - factor, &test); - - if (test == - stripe_index / map->sub_stripes) - break; - } - stripes = stripe_nr_end - 1 - j; - do_div(stripes, factor); - bbio->stripes[i].length = map->stripe_len * - (stripes - stripe_nr + 1); - - if (i < map->sub_stripes) { + if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | + BTRFS_BLOCK_GROUP_RAID10)) { + bbio->stripes[i].length = stripes_per_dev * + map->stripe_len; + if (i / sub_stripes < remaining_stripes) + bbio->stripes[i].length += + map->stripe_len; + if (i < sub_stripes) bbio->stripes[i].length -= stripe_offset; - if (i == map->sub_stripes - 1) - stripe_offset = 0; - } - if (stripe_index >= last_stripe && - stripe_index <= (last_stripe + - map->sub_stripes - 1)) { + if ((i / sub_stripes + 1) % + sub_stripes == remaining_stripes) bbio->stripes[i].length -= stripe_end_offset; - } + if (i == sub_stripes - 1) + stripe_offset = 0; } else bbio->stripes[i].length = *length; @@ -3155,15 +3806,22 @@ again: stripe_index++; } } - if (bbio_ret) { - *bbio_ret = bbio; - bbio->num_stripes = num_stripes; - bbio->max_errors = max_errors; - bbio->mirror_num = mirror_num; + + if (rw & REQ_WRITE) { + if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID10 | + BTRFS_BLOCK_GROUP_DUP)) { + max_errors = 1; + } } + + *bbio_ret = bbio; + bbio->num_stripes = num_stripes; + bbio->max_errors = max_errors; + bbio->mirror_num = mirror_num; out: free_extent_map(em); - return 0; + return ret; } int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, @@ -3304,7 +3962,7 @@ static noinline int schedule_bio(struct btrfs_root *root, /* don't bother with additional async steps for reads, right now */ if (!(rw & REQ_WRITE)) { bio_get(bio); - submit_bio(rw, bio); + btrfsic_submit_bio(rw, bio); bio_put(bio); return 0; } @@ -3399,7 +4057,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, if (async_submit) schedule_bio(root, dev, rw, bio); else - submit_bio(rw, bio); + btrfsic_submit_bio(rw, bio); } else { bio->bi_bdev = root->fs_info->fs_devices->latest_bdev; bio->bi_sector = logical >> 9; @@ -3568,7 +4226,7 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid) struct btrfs_fs_devices *fs_devices; int ret; - mutex_lock(&uuid_mutex); + BUG_ON(!mutex_is_locked(&uuid_mutex)); fs_devices = root->fs_info->fs_devices->seed; while (fs_devices) { @@ -3606,7 +4264,6 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid) fs_devices->seed = root->fs_info->fs_devices->seed; root->fs_info->fs_devices->seed = fs_devices; out: - mutex_unlock(&uuid_mutex); return ret; } @@ -3749,6 +4406,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) if (!path) return -ENOMEM; + mutex_lock(&uuid_mutex); + lock_chunks(root); + /* first we search for all of the device items, and then we * read in all of the chunk items. This way we can create chunk * mappings that reference all of the devices that are afound @@ -3799,6 +4459,9 @@ again: } ret = 0; error: + unlock_chunks(root); + mutex_unlock(&uuid_mutex); + btrfs_free_path(path); return ret; } diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 78f2d4d4f37f..19ac95048b88 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -186,6 +186,51 @@ struct map_lookup { #define map_lookup_size(n) (sizeof(struct map_lookup) + \ (sizeof(struct btrfs_bio_stripe) * (n))) +/* + * Restriper's general type filter + */ +#define BTRFS_BALANCE_DATA (1ULL << 0) +#define BTRFS_BALANCE_SYSTEM (1ULL << 1) +#define BTRFS_BALANCE_METADATA (1ULL << 2) + +#define BTRFS_BALANCE_TYPE_MASK (BTRFS_BALANCE_DATA | \ + BTRFS_BALANCE_SYSTEM | \ + BTRFS_BALANCE_METADATA) + +#define BTRFS_BALANCE_FORCE (1ULL << 3) +#define BTRFS_BALANCE_RESUME (1ULL << 4) + +/* + * Balance filters + */ +#define BTRFS_BALANCE_ARGS_PROFILES (1ULL << 0) +#define BTRFS_BALANCE_ARGS_USAGE (1ULL << 1) +#define BTRFS_BALANCE_ARGS_DEVID (1ULL << 2) +#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3) +#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4) + +/* + * Profile changing flags. When SOFT is set we won't relocate chunk if + * it already has the target profile (even though it may be + * half-filled). + */ +#define BTRFS_BALANCE_ARGS_CONVERT (1ULL << 8) +#define BTRFS_BALANCE_ARGS_SOFT (1ULL << 9) + +struct btrfs_balance_args; +struct btrfs_balance_progress; +struct btrfs_balance_control { + struct btrfs_fs_info *fs_info; + + struct btrfs_balance_args data; + struct btrfs_balance_args meta; + struct btrfs_balance_args sys; + + u64 flags; + + struct btrfs_balance_progress stat; +}; + int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, u64 end, u64 *length); @@ -228,9 +273,12 @@ struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, u8 *uuid, u8 *fsid); int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); int btrfs_init_new_device(struct btrfs_root *root, char *path); -int btrfs_balance(struct btrfs_root *dev_root); +int btrfs_balance(struct btrfs_balance_control *bctl, + struct btrfs_ioctl_balance_args *bargs); +int btrfs_recover_balance(struct btrfs_root *tree_root); +int btrfs_pause_balance(struct btrfs_fs_info *fs_info); +int btrfs_cancel_balance(struct btrfs_fs_info *fs_info); int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); -int find_free_dev_extent(struct btrfs_trans_handle *trans, - struct btrfs_device *device, u64 num_bytes, +int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, u64 *start, u64 *max_avail); #endif diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 3848b04e310e..e7a5659087e6 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -200,7 +200,7 @@ int __btrfs_setxattr(struct btrfs_trans_handle *trans, ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); out: - btrfs_end_transaction_throttle(trans, root); + btrfs_end_transaction(trans, root); return ret; } diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 74fd74719dc2..618246bc2196 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -973,7 +973,7 @@ static int dentry_lease_is_valid(struct dentry *dentry) spin_lock(&dentry->d_lock); di = ceph_dentry(dentry); - if (di && di->lease_session) { + if (di->lease_session) { s = di->lease_session; spin_lock(&s->s_cap_lock); gen = s->s_cap_gen; @@ -1072,13 +1072,11 @@ static void ceph_d_release(struct dentry *dentry) struct ceph_dentry_info *di = ceph_dentry(dentry); dout("d_release %p\n", dentry); - if (di) { - ceph_dentry_lru_del(dentry); - if (di->lease_session) - ceph_put_mds_session(di->lease_session); - kmem_cache_free(ceph_dentry_cachep, di); - dentry->d_fsdata = NULL; - } + ceph_dentry_lru_del(dentry); + if (di->lease_session) + ceph_put_mds_session(di->lease_session); + kmem_cache_free(ceph_dentry_cachep, di); + dentry->d_fsdata = NULL; } static int ceph_snapdir_d_revalidate(struct dentry *dentry, @@ -1096,17 +1094,36 @@ static int ceph_snapdir_d_revalidate(struct dentry *dentry, */ void ceph_dir_set_complete(struct inode *inode) { - /* not yet implemented */ + struct dentry *dentry = d_find_any_alias(inode); + + if (dentry && ceph_dentry(dentry) && + ceph_test_mount_opt(ceph_sb_to_client(dentry->d_sb), DCACHE)) { + dout(" marking %p (%p) complete\n", inode, dentry); + set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); + } + dput(dentry); } void ceph_dir_clear_complete(struct inode *inode) { - /* not yet implemented */ + struct dentry *dentry = d_find_any_alias(inode); + + if (dentry && ceph_dentry(dentry)) { + dout(" marking %p (%p) complete\n", inode, dentry); + set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); + } + dput(dentry); } bool ceph_dir_test_complete(struct inode *inode) { - /* not yet implemented */ + struct dentry *dentry = d_find_any_alias(inode); + + if (dentry && ceph_dentry(dentry)) { + dout(" marking %p (%p) NOT complete\n", inode, dentry); + clear_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); + } + dput(dentry); return false; } @@ -1220,6 +1237,7 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, do { ceph_mdsc_get_request(req); spin_unlock(&ci->i_unsafe_lock); + dout("dir_fsync %p wait on tid %llu (until %llu)\n", inode, req->r_tid, last_tid); if (req->r_timeout) { @@ -1232,9 +1250,9 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, } else { wait_for_completion(&req->r_safe_completion); } - spin_lock(&ci->i_unsafe_lock); ceph_mdsc_put_request(req); + spin_lock(&ci->i_unsafe_lock); if (ret || list_empty(head)) break; req = list_entry(head->next, @@ -1259,13 +1277,11 @@ void ceph_dentry_lru_add(struct dentry *dn) dout("dentry_lru_add %p %p '%.*s'\n", di, dn, dn->d_name.len, dn->d_name.name); - if (di) { - mdsc = ceph_sb_to_client(dn->d_sb)->mdsc; - spin_lock(&mdsc->dentry_lru_lock); - list_add_tail(&di->lru, &mdsc->dentry_lru); - mdsc->num_dentry++; - spin_unlock(&mdsc->dentry_lru_lock); - } + mdsc = ceph_sb_to_client(dn->d_sb)->mdsc; + spin_lock(&mdsc->dentry_lru_lock); + list_add_tail(&di->lru, &mdsc->dentry_lru); + mdsc->num_dentry++; + spin_unlock(&mdsc->dentry_lru_lock); } void ceph_dentry_lru_touch(struct dentry *dn) @@ -1275,12 +1291,10 @@ void ceph_dentry_lru_touch(struct dentry *dn) dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn, dn->d_name.len, dn->d_name.name, di->offset); - if (di) { - mdsc = ceph_sb_to_client(dn->d_sb)->mdsc; - spin_lock(&mdsc->dentry_lru_lock); - list_move_tail(&di->lru, &mdsc->dentry_lru); - spin_unlock(&mdsc->dentry_lru_lock); - } + mdsc = ceph_sb_to_client(dn->d_sb)->mdsc; + spin_lock(&mdsc->dentry_lru_lock); + list_move_tail(&di->lru, &mdsc->dentry_lru); + spin_unlock(&mdsc->dentry_lru_lock); } void ceph_dentry_lru_del(struct dentry *dn) @@ -1290,13 +1304,11 @@ void ceph_dentry_lru_del(struct dentry *dn) dout("dentry_lru_del %p %p '%.*s'\n", di, dn, dn->d_name.len, dn->d_name.name); - if (di) { - mdsc = ceph_sb_to_client(dn->d_sb)->mdsc; - spin_lock(&mdsc->dentry_lru_lock); - list_del_init(&di->lru); - mdsc->num_dentry--; - spin_unlock(&mdsc->dentry_lru_lock); - } + mdsc = ceph_sb_to_client(dn->d_sb)->mdsc; + spin_lock(&mdsc->dentry_lru_lock); + list_del_init(&di->lru); + mdsc->num_dentry--; + spin_unlock(&mdsc->dentry_lru_lock); } /* diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 9fbcdecaaccd..fbb2a643ef10 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -56,9 +56,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len, return -EINVAL; spin_lock(&dentry->d_lock); - parent = dget(dentry->d_parent); - spin_unlock(&dentry->d_lock); - + parent = dentry->d_parent; if (*max_len >= connected_handle_length) { dout("encode_fh %p connectable\n", dentry); cfh->ino = ceph_ino(dentry->d_inode); @@ -81,7 +79,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len, *max_len = handle_length; type = 255; } - dput(parent); + spin_unlock(&dentry->d_lock); return type; } diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 25283e7a37f8..2c489378b4cd 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -850,11 +850,12 @@ static void ceph_set_dentry_offset(struct dentry *dn) { struct dentry *dir = dn->d_parent; struct inode *inode = dir->d_inode; - struct ceph_inode_info *ci = ceph_inode(inode); + struct ceph_inode_info *ci; struct ceph_dentry_info *di; BUG_ON(!inode); + ci = ceph_inode(inode); di = ceph_dentry(dn); spin_lock(&ci->i_ceph_lock); diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 6203d805eb45..23ab6a3f1825 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2772,7 +2772,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, di = ceph_dentry(dentry); switch (h->action) { case CEPH_MDS_LEASE_REVOKE: - if (di && di->lease_session == session) { + if (di->lease_session == session) { if (ceph_seq_cmp(di->lease_seq, seq) > 0) h->seq = cpu_to_le32(di->lease_seq); __ceph_mdsc_drop_dentry_lease(dentry); @@ -2781,7 +2781,7 @@ static void handle_lease(struct ceph_mds_client *mdsc, break; case CEPH_MDS_LEASE_RENEW: - if (di && di->lease_session == session && + if (di->lease_session == session && di->lease_gen == session->s_cap_gen && di->lease_renew_from && di->lease_renew_after == 0) { diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 48f61a12af66..00de2c9568cd 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -131,6 +131,8 @@ enum { Opt_rbytes, Opt_norbytes, Opt_noasyncreaddir, + Opt_dcache, + Opt_nodcache, Opt_ino32, }; @@ -152,6 +154,8 @@ static match_table_t fsopt_tokens = { {Opt_rbytes, "rbytes"}, {Opt_norbytes, "norbytes"}, {Opt_noasyncreaddir, "noasyncreaddir"}, + {Opt_dcache, "dcache"}, + {Opt_nodcache, "nodcache"}, {Opt_ino32, "ino32"}, {-1, NULL} }; @@ -231,6 +235,12 @@ static int parse_fsopt_token(char *c, void *private) case Opt_noasyncreaddir: fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR; break; + case Opt_dcache: + fsopt->flags |= CEPH_MOUNT_OPT_DCACHE; + break; + case Opt_nodcache: + fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE; + break; case Opt_ino32: fsopt->flags |= CEPH_MOUNT_OPT_INO32; break; @@ -377,6 +387,10 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) seq_puts(m, ",norbytes"); if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR) seq_puts(m, ",noasyncreaddir"); + if (fsopt->flags & CEPH_MOUNT_OPT_DCACHE) + seq_puts(m, ",dcache"); + else + seq_puts(m, ",nodcache"); if (fsopt->wsize) seq_printf(m, ",wsize=%d", fsopt->wsize); @@ -647,10 +661,10 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, root = ERR_PTR(-ENOMEM); goto out; } - ceph_init_dentry(root); } else { root = d_obtain_alias(inode); } + ceph_init_dentry(root); dout("open_root_inode success, root dentry is %p\n", root); } else { root = ERR_PTR(err); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index cb3652b37271..1421f3d875a2 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -28,6 +28,7 @@ #define CEPH_MOUNT_OPT_RBYTES (1<<5) /* dir st_bytes = rbytes */ #define CEPH_MOUNT_OPT_NOASYNCREADDIR (1<<7) /* no dcache readdir */ #define CEPH_MOUNT_OPT_INO32 (1<<8) /* 32 bit inos */ +#define CEPH_MOUNT_OPT_DCACHE (1<<9) /* use dcache for readdir etc */ #define CEPH_MOUNT_OPT_DEFAULT (CEPH_MOUNT_OPT_RBYTES) diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index a5e36e4488a7..857214ae8c08 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -818,6 +818,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name) struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode); int issued; int err; + int required_blob_size; int dirty; if (ceph_snap(inode) != CEPH_NOSNAP) @@ -833,14 +834,34 @@ int ceph_removexattr(struct dentry *dentry, const char *name) return -EOPNOTSUPP; } + err = -ENOMEM; spin_lock(&ci->i_ceph_lock); __build_xattrs(inode); +retry: issued = __ceph_caps_issued(ci, NULL); dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued)); if (!(issued & CEPH_CAP_XATTR_EXCL)) goto do_sync; + required_blob_size = __get_required_blob_size(ci, 0, 0); + + if (!ci->i_xattrs.prealloc_blob || + required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) { + struct ceph_buffer *blob; + + spin_unlock(&ci->i_ceph_lock); + dout(" preaallocating new blob size=%d\n", required_blob_size); + blob = ceph_buffer_new(required_blob_size, GFP_NOFS); + if (!blob) + goto out; + spin_lock(&ci->i_ceph_lock); + if (ci->i_xattrs.prealloc_blob) + ceph_buffer_put(ci->i_xattrs.prealloc_blob); + ci->i_xattrs.prealloc_blob = blob; + goto retry; + } + err = __remove_xattr_by_name(ceph_inode(inode), name); dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); ci->i_xattrs.dirty = true; @@ -853,6 +874,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name) do_sync: spin_unlock(&ci->i_ceph_lock); err = ceph_send_removexattr(dentry, name); +out: return err; } diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index f66cc1625150..0554b00a7b33 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -140,7 +140,6 @@ config CIFS_DFS_UPCALL config CIFS_FSCACHE bool "Provide CIFS client caching support (EXPERIMENTAL)" - depends on EXPERIMENTAL depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y help Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data @@ -149,7 +148,7 @@ config CIFS_FSCACHE config CIFS_ACL bool "Provide CIFS ACL support (EXPERIMENTAL)" - depends on EXPERIMENTAL && CIFS_XATTR && KEYS + depends on CIFS_XATTR && KEYS help Allows to fetch CIFS/NTFS ACL from the server. The DACL blob is handed over to the application/caller. diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 84e8c0724704..24b3dfc05282 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -676,14 +676,23 @@ static ssize_t cifs_multiuser_mount_proc_write(struct file *file, { char c; int rc; + static bool warned; rc = get_user(c, buffer); if (rc) return rc; if (c == '0' || c == 'n' || c == 'N') multiuser_mount = 0; - else if (c == '1' || c == 'y' || c == 'Y') + else if (c == '1' || c == 'y' || c == 'Y') { multiuser_mount = 1; + if (!warned) { + warned = true; + printk(KERN_WARNING "CIFS VFS: The legacy multiuser " + "mount code is scheduled to be deprecated in " + "3.5. Please switch to using the multiuser " + "mount option."); + } + } return count; } diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 2272fd5fe5b7..e622863b292f 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -113,9 +113,11 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo) MAX_MECH_STR_LEN + UID_KEY_LEN + (sizeof(uid_t) * 2) + CREDUID_KEY_LEN + (sizeof(uid_t) * 2) + - USER_KEY_LEN + strlen(sesInfo->user_name) + PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; + if (sesInfo->user_name) + desc_len += USER_KEY_LEN + strlen(sesInfo->user_name); + spnego_key = ERR_PTR(-ENOMEM); description = kzalloc(desc_len, GFP_KERNEL); if (description == NULL) @@ -152,8 +154,10 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo) dp = description + strlen(description); sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); - dp = description + strlen(description); - sprintf(dp, ";user=%s", sesInfo->user_name); + if (sesInfo->user_name) { + dp = description + strlen(description); + sprintf(dp, ";user=%s", sesInfo->user_name); + } dp = description + strlen(description); sprintf(dp, ";pid=0x%x", current->pid); diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 1b2e180b018d..fbb9da951843 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -27,17 +27,17 @@ #include "cifs_debug.h" /* - * cifs_ucs2_bytes - how long will a string be after conversion? - * @ucs - pointer to input string + * cifs_utf16_bytes - how long will a string be after conversion? + * @utf16 - pointer to input string * @maxbytes - don't go past this many bytes of input string * @codepage - destination codepage * - * Walk a ucs2le string and return the number of bytes that the string will + * Walk a utf16le string and return the number of bytes that the string will * be after being converted to the given charset, not including any null * termination required. Don't walk past maxbytes in the source buffer. */ int -cifs_ucs2_bytes(const __le16 *from, int maxbytes, +cifs_utf16_bytes(const __le16 *from, int maxbytes, const struct nls_table *codepage) { int i; @@ -122,7 +122,7 @@ cp_convert: } /* - * cifs_from_ucs2 - convert utf16le string to local charset + * cifs_from_utf16 - convert utf16le string to local charset * @to - destination buffer * @from - source buffer * @tolen - destination buffer size (in bytes) @@ -130,7 +130,7 @@ cp_convert: * @codepage - codepage to which characters should be converted * @mapchar - should characters be remapped according to the mapchars option? * - * Convert a little-endian ucs2le string (as sent by the server) to a string + * Convert a little-endian utf16le string (as sent by the server) to a string * in the provided codepage. The tolen and fromlen parameters are to ensure * that the code doesn't walk off of the end of the buffer (which is always * a danger if the alignment of the source buffer is off). The destination @@ -139,12 +139,12 @@ cp_convert: * null terminator). * * Note that some windows versions actually send multiword UTF-16 characters - * instead of straight UCS-2. The linux nls routines however aren't able to + * instead of straight UTF16-2. The linux nls routines however aren't able to * deal with those characters properly. In the event that we get some of * those characters, they won't be translated properly. */ int -cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, +cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, const struct nls_table *codepage, bool mapchar) { int i, charlen, safelen; @@ -190,13 +190,13 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, } /* - * NAME: cifs_strtoUCS() + * NAME: cifs_strtoUTF16() * * FUNCTION: Convert character string to unicode string * */ int -cifs_strtoUCS(__le16 *to, const char *from, int len, +cifs_strtoUTF16(__le16 *to, const char *from, int len, const struct nls_table *codepage) { int charlen; @@ -206,7 +206,7 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, for (i = 0; len && *from; i++, from += charlen, len -= charlen) { charlen = codepage->char2uni(from, len, &wchar_to); if (charlen < 1) { - cERROR(1, "strtoUCS: char2uni of 0x%x returned %d", + cERROR(1, "strtoUTF16: char2uni of 0x%x returned %d", *from, charlen); /* A question mark */ wchar_to = 0x003f; @@ -220,7 +220,8 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, } /* - * cifs_strndup_from_ucs - copy a string from wire format to the local codepage + * cifs_strndup_from_utf16 - copy a string from wire format to the local + * codepage * @src - source string * @maxlen - don't walk past this many bytes in the source string * @is_unicode - is this a unicode string? @@ -231,19 +232,19 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, * error. */ char * -cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, - const struct nls_table *codepage) +cifs_strndup_from_utf16(const char *src, const int maxlen, + const bool is_unicode, const struct nls_table *codepage) { int len; char *dst; if (is_unicode) { - len = cifs_ucs2_bytes((__le16 *) src, maxlen, codepage); + len = cifs_utf16_bytes((__le16 *) src, maxlen, codepage); len += nls_nullsize(codepage); dst = kmalloc(len, GFP_KERNEL); if (!dst) return NULL; - cifs_from_ucs2(dst, (__le16 *) src, len, maxlen, codepage, + cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage, false); } else { len = strnlen(src, maxlen); @@ -264,7 +265,7 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, * names are little endian 16 bit Unicode on the wire */ int -cifsConvertToUCS(__le16 *target, const char *source, int srclen, +cifsConvertToUTF16(__le16 *target, const char *source, int srclen, const struct nls_table *cp, int mapChars) { int i, j, charlen; @@ -273,7 +274,7 @@ cifsConvertToUCS(__le16 *target, const char *source, int srclen, wchar_t tmp; if (!mapChars) - return cifs_strtoUCS(target, source, PATH_MAX, cp); + return cifs_strtoUTF16(target, source, PATH_MAX, cp); for (i = 0, j = 0; i < srclen; j++) { src_char = source[i]; @@ -281,7 +282,7 @@ cifsConvertToUCS(__le16 *target, const char *source, int srclen, switch (src_char) { case 0: put_unaligned(0, &target[j]); - goto ctoUCS_out; + goto ctoUTF16_out; case ':': dst_char = cpu_to_le16(UNI_COLON); break; @@ -326,7 +327,7 @@ cifsConvertToUCS(__le16 *target, const char *source, int srclen, put_unaligned(dst_char, &target[j]); } -ctoUCS_out: +ctoUTF16_out: return i; } diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 6d02fd560566..a513a546700b 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -74,16 +74,16 @@ extern const struct UniCaseRange CifsUniLowerRange[]; #endif /* UNIUPR_NOLOWER */ #ifdef __KERNEL__ -int cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, - const struct nls_table *codepage, bool mapchar); -int cifs_ucs2_bytes(const __le16 *from, int maxbytes, - const struct nls_table *codepage); -int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); -char *cifs_strndup_from_ucs(const char *src, const int maxlen, - const bool is_unicode, - const struct nls_table *codepage); -extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, - const struct nls_table *cp, int mapChars); +int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, + const struct nls_table *codepage, bool mapchar); +int cifs_utf16_bytes(const __le16 *from, int maxbytes, + const struct nls_table *codepage); +int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *); +char *cifs_strndup_from_utf16(const char *src, const int maxlen, + const bool is_unicode, + const struct nls_table *codepage); +extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen, + const struct nls_table *cp, int mapChars); #endif diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 72ddf23ef6f7..c1b254487388 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -909,6 +909,8 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, umode_t group_mask = S_IRWXG; umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; + if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *)) + return; ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), GFP_KERNEL); if (!ppace) { diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 5d9b9acc5fce..63c460e503b6 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -327,7 +327,7 @@ build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp) attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); attrptr->length = cpu_to_le16(2 * dlen); blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); - cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp); + cifs_strtoUTF16((__le16 *)blobptr, ses->domainName, dlen, nls_cp); return 0; } @@ -376,7 +376,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) kmalloc(attrsize + 1, GFP_KERNEL); if (!ses->domainName) return -ENOMEM; - cifs_from_ucs2(ses->domainName, + cifs_from_utf16(ses->domainName, (__le16 *)blobptr, attrsize, attrsize, nls_cp, false); break; @@ -420,15 +420,20 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, } /* convert ses->user_name to unicode and uppercase */ - len = strlen(ses->user_name); + len = ses->user_name ? strlen(ses->user_name) : 0; user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) { cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); rc = -ENOMEM; return rc; } - len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp); - UniStrupr(user); + + if (len) { + len = cifs_strtoUTF16((__le16 *)user, ses->user_name, len, nls_cp); + UniStrupr(user); + } else { + memset(user, '\0', 2); + } rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, (char *)user, 2 * len); @@ -448,8 +453,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, rc = -ENOMEM; return rc; } - len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, - nls_cp); + len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len, + nls_cp); rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, (char *)domain, 2 * len); @@ -468,7 +473,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, rc = -ENOMEM; return rc; } - len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, + len = cifs_strtoUTF16((__le16 *)server, ses->serverName, len, nls_cp); rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ba53c1c6c6cc..76e7d8b6da17 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -879,6 +879,8 @@ require use of the stronger protocol */ #define CIFSSEC_MASK 0xB70B7 /* current flags supported if weak */ #endif /* UPCALL */ #else /* do not allow weak pw hash */ +#define CIFSSEC_MUST_LANMAN 0 +#define CIFSSEC_MUST_PLNTXT 0 #ifdef CONFIG_CIFS_UPCALL #define CIFSSEC_MASK 0x8F08F /* flags supported if no weak allowed */ #else diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6600aa2d2ef3..8b7794c31591 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -821,8 +821,8 @@ PsxDelete: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB add path length overrun check */ @@ -893,8 +893,8 @@ DelFileRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ @@ -938,8 +938,8 @@ RmDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ @@ -981,8 +981,8 @@ MkDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ @@ -1030,8 +1030,8 @@ PsxCreat: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, name, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, name, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -1197,8 +1197,8 @@ OldOpenRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { count = 1; /* account for one byte pad to word boundary */ name_len = - cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), - fileName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), + fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve check for buffer overruns BB */ @@ -1304,8 +1304,8 @@ openRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { count = 1; /* account for one byte pad to word boundary */ name_len = - cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), - fileName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1), + fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->NameLength = cpu_to_le16(name_len); @@ -2649,16 +2649,16 @@ renameRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], - toName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -2738,10 +2738,12 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon, /* unicode only call */ if (target_name == NULL) { sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid); - len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, + len_of_str = + cifsConvertToUTF16((__le16 *)rename_info->target_name, dummy_string, 24, nls_codepage, remap); } else { - len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, + len_of_str = + cifsConvertToUTF16((__le16 *)rename_info->target_name, target_name, PATH_MAX, nls_codepage, remap); } @@ -2795,17 +2797,17 @@ copyRetry: pSMB->Flags = cpu_to_le16(flags & COPY_TREE); if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, - fromName, PATH_MAX, nls_codepage, - remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, + fromName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], - toName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -2861,9 +2863,9 @@ createSymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName, + /* find define for this maxpathcomponent */ + PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; @@ -2885,9 +2887,9 @@ createSymLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX - /* find define for this maxpathcomponent */ - , nls_codepage); + cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX + /* find define for this maxpathcomponent */ + , nls_codepage); name_len_target++; /* trailing null */ name_len_target *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -2949,8 +2951,8 @@ createHardLinkRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName, - PATH_MAX, nls_codepage, remap); + name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2972,8 +2974,8 @@ createHardLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX, - nls_codepage, remap); + cifsConvertToUTF16((__le16 *) data_offset, fromName, + PATH_MAX, nls_codepage, remap); name_len_target++; /* trailing null */ name_len_target *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3042,8 +3044,8 @@ winCreateHardLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3051,8 +3053,8 @@ winCreateHardLinkRetry: pSMB->OldFileName[name_len] = 0x04; pSMB->OldFileName[name_len + 1] = 0x00; /* pad */ name_len2 = - cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], - toName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], + toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */ @@ -3108,8 +3110,8 @@ querySymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage); + cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3166,8 +3168,8 @@ querySymLinkRetry: is_unicode = false; /* BB FIXME investigate remapping reserved chars here */ - *symlinkinfo = cifs_strndup_from_ucs(data_start, count, - is_unicode, nls_codepage); + *symlinkinfo = cifs_strndup_from_utf16(data_start, + count, is_unicode, nls_codepage); if (!*symlinkinfo) rc = -ENOMEM; } @@ -3450,8 +3452,9 @@ queryAclRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, + searchName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; pSMB->FileName[name_len] = 0; @@ -3537,8 +3540,8 @@ setAclRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -3948,8 +3951,9 @@ QInfRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, + searchName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; } else { @@ -4086,8 +4090,8 @@ QPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -4255,8 +4259,8 @@ UnixQPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -4344,8 +4348,8 @@ findFirstRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); /* We can not add the asterik earlier in case it got remapped to 0xF03A as if it were part of the directory name instead of a wildcard */ @@ -4656,8 +4660,9 @@ GetInodeNumberRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, + searchName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -4794,9 +4799,9 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, rc = -ENOMEM; goto parse_DFS_referrals_exit; } - cifsConvertToUCS((__le16 *) tmp, searchName, - PATH_MAX, nls_codepage, remap); - node->path_consumed = cifs_ucs2_bytes(tmp, + cifsConvertToUTF16((__le16 *) tmp, searchName, + PATH_MAX, nls_codepage, remap); + node->path_consumed = cifs_utf16_bytes(tmp, le16_to_cpu(pSMBr->PathConsumed), nls_codepage); kfree(tmp); @@ -4809,8 +4814,8 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, /* copy DfsPath */ temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); max_len = data_end - temp; - node->path_name = cifs_strndup_from_ucs(temp, max_len, - is_unicode, nls_codepage); + node->path_name = cifs_strndup_from_utf16(temp, max_len, + is_unicode, nls_codepage); if (!node->path_name) { rc = -ENOMEM; goto parse_DFS_referrals_exit; @@ -4819,8 +4824,8 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, /* copy link target UNC */ temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); max_len = data_end - temp; - node->node_name = cifs_strndup_from_ucs(temp, max_len, - is_unicode, nls_codepage); + node->node_name = cifs_strndup_from_utf16(temp, max_len, + is_unicode, nls_codepage); if (!node->node_name) rc = -ENOMEM; } @@ -4873,8 +4878,9 @@ getDFSRetry: if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; name_len = - cifsConvertToUCS((__le16 *) pSMB->RequestFileName, - searchName, PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->RequestFileName, + searchName, PATH_MAX, nls_codepage, + remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -5506,8 +5512,8 @@ SetEOFRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -5796,8 +5802,8 @@ SetTimesRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -5877,8 +5883,8 @@ SetAttrLgcyRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - ConvertToUCS((__le16 *) pSMB->fileName, fileName, - PATH_MAX, nls_codepage); + ConvertToUTF16((__le16 *) pSMB->fileName, fileName, + PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -6030,8 +6036,8 @@ setPermsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -6123,8 +6129,8 @@ QAllEAsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { list_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, + PATH_MAX, nls_codepage, remap); list_len++; /* trailing null */ list_len *= 2; } else { /* BB improve the check for buffer overruns BB */ @@ -6301,8 +6307,8 @@ SetEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, - PATH_MAX, nls_codepage, remap); + cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName, + PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; } else { /* BB improve the check for buffer overruns BB */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 4666780f315d..986709a8d903 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -38,6 +38,7 @@ #include <asm/processor.h> #include <linux/inet.h> #include <linux/module.h> +#include <keys/user-type.h> #include <net/ipv6.h> #include "cifspdu.h" #include "cifsglob.h" @@ -225,74 +226,90 @@ static int check2ndT2(struct smb_hdr *pSMB) static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) { - struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; + struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)psecond; struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; - char *data_area_of_target; - char *data_area_of_buf2; + char *data_area_of_tgt; + char *data_area_of_src; int remaining; - unsigned int byte_count, total_in_buf; - __u16 total_data_size, total_in_buf2; + unsigned int byte_count, total_in_tgt; + __u16 tgt_total_cnt, src_total_cnt, total_in_src; - total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); + src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount); + tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); - if (total_data_size != - get_unaligned_le16(&pSMB2->t2_rsp.TotalDataCount)) - cFYI(1, "total data size of primary and secondary t2 differ"); + if (tgt_total_cnt != src_total_cnt) + cFYI(1, "total data count of primary and secondary t2 differ " + "source=%hu target=%hu", src_total_cnt, tgt_total_cnt); - total_in_buf = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); + total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); - remaining = total_data_size - total_in_buf; + remaining = tgt_total_cnt - total_in_tgt; - if (remaining < 0) + if (remaining < 0) { + cFYI(1, "Server sent too much data. tgt_total_cnt=%hu " + "total_in_tgt=%hu", tgt_total_cnt, total_in_tgt); return -EPROTO; + } - if (remaining == 0) /* nothing to do, ignore */ + if (remaining == 0) { + /* nothing to do, ignore */ + cFYI(1, "no more data remains"); return 0; + } - total_in_buf2 = get_unaligned_le16(&pSMB2->t2_rsp.DataCount); - if (remaining < total_in_buf2) { + total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount); + if (remaining < total_in_src) cFYI(1, "transact2 2nd response contains too much data"); - } /* find end of first SMB data area */ - data_area_of_target = (char *)&pSMBt->hdr.Protocol + + data_area_of_tgt = (char *)&pSMBt->hdr.Protocol + get_unaligned_le16(&pSMBt->t2_rsp.DataOffset); - /* validate target area */ - data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol + - get_unaligned_le16(&pSMB2->t2_rsp.DataOffset); + /* validate target area */ + data_area_of_src = (char *)&pSMBs->hdr.Protocol + + get_unaligned_le16(&pSMBs->t2_rsp.DataOffset); - data_area_of_target += total_in_buf; + data_area_of_tgt += total_in_tgt; - /* copy second buffer into end of first buffer */ - total_in_buf += total_in_buf2; + total_in_tgt += total_in_src; /* is the result too big for the field? */ - if (total_in_buf > USHRT_MAX) + if (total_in_tgt > USHRT_MAX) { + cFYI(1, "coalesced DataCount too large (%u)", total_in_tgt); return -EPROTO; - put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount); + } + put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount); /* fix up the BCC */ byte_count = get_bcc(pTargetSMB); - byte_count += total_in_buf2; + byte_count += total_in_src; /* is the result too big for the field? */ - if (byte_count > USHRT_MAX) + if (byte_count > USHRT_MAX) { + cFYI(1, "coalesced BCC too large (%u)", byte_count); return -EPROTO; + } put_bcc(byte_count, pTargetSMB); byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); - byte_count += total_in_buf2; + byte_count += total_in_src; /* don't allow buffer to overflow */ - if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) + if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + cFYI(1, "coalesced BCC exceeds buffer size (%u)", byte_count); return -ENOBUFS; + } pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); - memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); + /* copy second buffer into end of first buffer */ + memcpy(data_area_of_tgt, data_area_of_src, total_in_src); - if (remaining == total_in_buf2) { - cFYI(1, "found the last secondary response"); - return 0; /* we are done */ - } else /* more responses to go */ + if (remaining != total_in_src) { + /* more responses to go */ + cFYI(1, "waiting for more secondary responses"); return 1; + } + + /* we are done */ + cFYI(1, "found the last secondary response"); + return 0; } static void @@ -1578,11 +1595,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, } } - if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) { - cERROR(1, "Multiuser mounts currently require krb5 " - "authentication!"); +#ifndef CONFIG_KEYS + /* Muliuser mounts require CONFIG_KEYS support */ + if (vol->multiuser) { + cERROR(1, "Multiuser mounts require kernels with " + "CONFIG_KEYS enabled."); goto cifs_parse_mount_err; } +#endif if (vol->UNCip == NULL) vol->UNCip = &vol->UNC[2]; @@ -1981,10 +2001,16 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol) return 0; break; default: + /* NULL username means anonymous session */ + if (ses->user_name == NULL) { + if (!vol->nullauth) + return 0; + break; + } + /* anything else takes username/password */ - if (ses->user_name == NULL) - return 0; - if (strncmp(ses->user_name, vol->username, + if (strncmp(ses->user_name, + vol->username ? vol->username : "", MAX_USERNAME_SIZE)) return 0; if (strlen(vol->username) != 0 && @@ -2039,6 +2065,132 @@ cifs_put_smb_ses(struct cifs_ses *ses) cifs_put_tcp_session(server); } +#ifdef CONFIG_KEYS + +/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */ +#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1) + +/* Populate username and pw fields from keyring if possible */ +static int +cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses) +{ + int rc = 0; + char *desc, *delim, *payload; + ssize_t len; + struct key *key; + struct TCP_Server_Info *server = ses->server; + struct sockaddr_in *sa; + struct sockaddr_in6 *sa6; + struct user_key_payload *upayload; + + desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL); + if (!desc) + return -ENOMEM; + + /* try to find an address key first */ + switch (server->dstaddr.ss_family) { + case AF_INET: + sa = (struct sockaddr_in *)&server->dstaddr; + sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr); + break; + case AF_INET6: + sa6 = (struct sockaddr_in6 *)&server->dstaddr; + sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr); + break; + default: + cFYI(1, "Bad ss_family (%hu)", server->dstaddr.ss_family); + rc = -EINVAL; + goto out_err; + } + + cFYI(1, "%s: desc=%s", __func__, desc); + key = request_key(&key_type_logon, desc, ""); + if (IS_ERR(key)) { + if (!ses->domainName) { + cFYI(1, "domainName is NULL"); + rc = PTR_ERR(key); + goto out_err; + } + + /* didn't work, try to find a domain key */ + sprintf(desc, "cifs:d:%s", ses->domainName); + cFYI(1, "%s: desc=%s", __func__, desc); + key = request_key(&key_type_logon, desc, ""); + if (IS_ERR(key)) { + rc = PTR_ERR(key); + goto out_err; + } + } + + down_read(&key->sem); + upayload = key->payload.data; + if (IS_ERR_OR_NULL(upayload)) { + rc = PTR_ERR(key); + goto out_key_put; + } + + /* find first : in payload */ + payload = (char *)upayload->data; + delim = strnchr(payload, upayload->datalen, ':'); + cFYI(1, "payload=%s", payload); + if (!delim) { + cFYI(1, "Unable to find ':' in payload (datalen=%d)", + upayload->datalen); + rc = -EINVAL; + goto out_key_put; + } + + len = delim - payload; + if (len > MAX_USERNAME_SIZE || len <= 0) { + cFYI(1, "Bad value from username search (len=%ld)", len); + rc = -EINVAL; + goto out_key_put; + } + + vol->username = kstrndup(payload, len, GFP_KERNEL); + if (!vol->username) { + cFYI(1, "Unable to allocate %ld bytes for username", len); + rc = -ENOMEM; + goto out_key_put; + } + cFYI(1, "%s: username=%s", __func__, vol->username); + + len = key->datalen - (len + 1); + if (len > MAX_PASSWORD_SIZE || len <= 0) { + cFYI(1, "Bad len for password search (len=%ld)", len); + rc = -EINVAL; + kfree(vol->username); + vol->username = NULL; + goto out_key_put; + } + + ++delim; + vol->password = kstrndup(delim, len, GFP_KERNEL); + if (!vol->password) { + cFYI(1, "Unable to allocate %ld bytes for password", len); + rc = -ENOMEM; + kfree(vol->username); + vol->username = NULL; + goto out_key_put; + } + +out_key_put: + up_read(&key->sem); + key_put(key); +out_err: + kfree(desc); + cFYI(1, "%s: returning %d", __func__, rc); + return rc; +} +#else /* ! CONFIG_KEYS */ +static inline int +cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)), + struct cifs_ses *ses __attribute__((unused))) +{ + return -ENOSYS; +} +#endif /* CONFIG_KEYS */ + static bool warned_on_ntlm; /* globals init to false automatically */ static struct cifs_ses * @@ -2914,18 +3066,33 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, #define CIFS_DEFAULT_IOSIZE (1024 * 1024) /* - * Windows only supports a max of 60k reads. Default to that when posix - * extensions aren't in force. + * Windows only supports a max of 60kb reads and 65535 byte writes. Default to + * those values when posix extensions aren't in force. In actuality here, we + * use 65536 to allow for a write that is a multiple of 4k. Most servers seem + * to be ok with the extra byte even though Windows doesn't send writes that + * are that large. + * + * Citation: + * + * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx */ #define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024) +#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536) static unsigned int cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) { __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); struct TCP_Server_Info *server = tcon->ses->server; - unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize : - CIFS_DEFAULT_IOSIZE; + unsigned int wsize; + + /* start with specified wsize, or default */ + if (pvolume_info->wsize) + wsize = pvolume_info->wsize; + else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) + wsize = CIFS_DEFAULT_IOSIZE; + else + wsize = CIFS_DEFAULT_NON_POSIX_WSIZE; /* can server support 24-bit write sizes? (via UNIX extensions) */ if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) @@ -3136,10 +3303,9 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, return -EINVAL; if (volume_info->nullauth) { - cFYI(1, "null user"); - volume_info->username = kzalloc(1, GFP_KERNEL); - if (volume_info->username == NULL) - return -ENOMEM; + cFYI(1, "Anonymous login"); + kfree(volume_info->username); + volume_info->username = NULL; } else if (volume_info->username) { /* BB fixme parse for domain name here */ cFYI(1, "Username: %s", volume_info->username); @@ -3478,7 +3644,7 @@ CIFSTCon(unsigned int xid, struct cifs_ses *ses, if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; length = - cifs_strtoUCS((__le16 *) bcc_ptr, tree, + cifs_strtoUTF16((__le16 *) bcc_ptr, tree, 6 /* max utf8 char length in bytes */ * (/* server len*/ + 256 /* share len */), nls_codepage); bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */ @@ -3533,7 +3699,7 @@ CIFSTCon(unsigned int xid, struct cifs_ses *ses, /* mostly informational -- no need to fail on error here */ kfree(tcon->nativeFileSystem); - tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr, + tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr, bytes_left, is_unicode, nls_codepage); @@ -3657,16 +3823,38 @@ int cifs_setup_session(unsigned int xid, struct cifs_ses *ses, return rc; } +static int +cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses) +{ + switch (ses->server->secType) { + case Kerberos: + vol->secFlg = CIFSSEC_MUST_KRB5; + return 0; + case NTLMv2: + vol->secFlg = CIFSSEC_MUST_NTLMV2; + break; + case NTLM: + vol->secFlg = CIFSSEC_MUST_NTLM; + break; + case RawNTLMSSP: + vol->secFlg = CIFSSEC_MUST_NTLMSSP; + break; + case LANMAN: + vol->secFlg = CIFSSEC_MUST_LANMAN; + break; + } + + return cifs_set_cifscreds(vol, ses); +} + static struct cifs_tcon * cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) { + int rc; struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); struct cifs_ses *ses; struct cifs_tcon *tcon = NULL; struct smb_vol *vol_info; - char username[28]; /* big enough for "krb50x" + hex of ULONG_MAX 6+16 */ - /* We used to have this as MAX_USERNAME which is */ - /* way too big now (256 instead of 32) */ vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); if (vol_info == NULL) { @@ -3674,8 +3862,6 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) goto out; } - snprintf(username, sizeof(username), "krb50x%x", fsuid); - vol_info->username = username; vol_info->local_nls = cifs_sb->local_nls; vol_info->linux_uid = fsuid; vol_info->cred_uid = fsuid; @@ -3685,8 +3871,11 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) vol_info->local_lease = master_tcon->local_lease; vol_info->no_linux_ext = !master_tcon->unix_ext; - /* FIXME: allow for other secFlg settings */ - vol_info->secFlg = CIFSSEC_MUST_KRB5; + rc = cifs_set_vol_auth(vol_info, master_tcon->ses); + if (rc) { + tcon = ERR_PTR(rc); + goto out; + } /* get a reference for the same TCP session */ spin_lock(&cifs_tcp_ses_lock); @@ -3709,6 +3898,8 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) if (ses->capabilities & CAP_UNIX) reset_cifs_unix_caps(0, tcon, NULL, vol_info); out: + kfree(vol_info->username); + kfree(vol_info->password); kfree(vol_info); return tcon; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index a090bbe6ee29..e2bbc683e018 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -647,10 +647,11 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir, name.name = scratch_buf; name.len = - cifs_from_ucs2((char *)name.name, (__le16 *)de.name, - UNICODE_NAME_MAX, - min(de.namelen, (size_t)max_len), nlt, - cifs_sb->mnt_cifs_flags & + cifs_from_utf16((char *)name.name, (__le16 *)de.name, + UNICODE_NAME_MAX, + min_t(size_t, de.namelen, + (size_t)max_len), nlt, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); name.len -= nls_nullsize(nlt); } else { diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 4ec3ee9d72cc..d85efad5765f 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -167,16 +167,16 @@ unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) int bytes_ret = 0; /* Copy OS version */ - bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, - nls_cp); + bytes_ret = cifs_strtoUTF16((__le16 *)bcc_ptr, "Linux version ", 32, + nls_cp); bcc_ptr += 2 * bytes_ret; - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release, - 32, nls_cp); + bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, init_utsname()->release, + 32, nls_cp); bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* trailing null */ - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, - 32, nls_cp); + bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, + 32, nls_cp); bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* trailing null */ @@ -197,8 +197,8 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, *(bcc_ptr+1) = 0; bytes_ret = 0; } else - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, - 256, nls_cp); + bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName, + 256, nls_cp); bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null terminator */ @@ -226,8 +226,8 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, *bcc_ptr = 0; *(bcc_ptr+1) = 0; } else { - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->user_name, - MAX_USERNAME_SIZE, nls_cp); + bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->user_name, + MAX_USERNAME_SIZE, nls_cp); } bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ @@ -287,7 +287,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, cFYI(1, "bleft %d", bleft); kfree(ses->serverOS); - ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); + ses->serverOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp); cFYI(1, "serverOS=%s", ses->serverOS); len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; data += len; @@ -296,7 +296,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, return; kfree(ses->serverNOS); - ses->serverNOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); + ses->serverNOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp); cFYI(1, "serverNOS=%s", ses->serverNOS); len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; data += len; @@ -305,7 +305,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, return; kfree(ses->serverDomain); - ses->serverDomain = cifs_strndup_from_ucs(data, bleft, true, nls_cp); + ses->serverDomain = cifs_strndup_from_utf16(data, bleft, true, nls_cp); cFYI(1, "serverDomain=%s", ses->serverDomain); return; @@ -502,8 +502,8 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, tmp += 2; } else { int len; - len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, - MAX_USERNAME_SIZE, nls_cp); + len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName, + MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->DomainName.Length = cpu_to_le16(len); @@ -518,8 +518,8 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, tmp += 2; } else { int len; - len = cifs_strtoUCS((__le16 *)tmp, ses->user_name, - MAX_USERNAME_SIZE, nls_cp); + len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name, + MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->UserName.Length = cpu_to_le16(len); diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 80d850881938..d5cd9aa7eacc 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -213,7 +213,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16, /* Password cannot be longer than 128 characters */ if (passwd) /* Password must be converted to NT unicode */ - len = cifs_strtoUCS(wpwd, passwd, 128, codepage); + len = cifs_strtoUTF16(wpwd, passwd, 128, codepage); else { len = 0; *wpwd = 0; /* Ensure string is null terminated */ diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index a10e428b32b4..a26bea10e81b 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -105,6 +105,7 @@ #include <linux/hiddev.h> +#define __DVB_CORE__ #include <linux/dvb/audio.h> #include <linux/dvb/dmx.h> #include <linux/dvb/frontend.h> diff --git a/fs/dcache.c b/fs/dcache.c index 616fedff011a..16a53cc2cc02 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1475,7 +1475,14 @@ static struct dentry * __d_find_any_alias(struct inode *inode) return alias; } -static struct dentry * d_find_any_alias(struct inode *inode) +/** + * d_find_any_alias - find any alias for a given inode + * @inode: inode to find an alias for + * + * If any aliases exist for the given inode, take and return a + * reference for one of them. If no aliases exist, return %NULL. + */ +struct dentry *d_find_any_alias(struct inode *inode) { struct dentry *de; @@ -1484,7 +1491,7 @@ static struct dentry * d_find_any_alias(struct inode *inode) spin_unlock(&inode->i_lock); return de; } - +EXPORT_SYMBOL(d_find_any_alias); /** * d_obtain_alias - find or allocate a dentry for a given inode diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index f65d4455c5e5..ef023eef0464 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -540,7 +540,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_blob); * debugfs_print_regs32 - use seq_print to describe a set of registers * @s: the seq_file structure being used to generate output * @regs: an array if struct debugfs_reg32 structures - * @mregs: the length of the above array + * @nregs: the length of the above array * @base: the base address to be used in reading the registers * @prefix: a string to be prefixed to every output line * diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 1089f760c847..2de655f5d625 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -77,10 +77,11 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) flags = flags & EXT2_FL_USER_MODIFIABLE; flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; ei->i_flags = flags; - mutex_unlock(&inode->i_mutex); ext2_set_inode_flags(inode); inode->i_ctime = CURRENT_TIME_SEC; + mutex_unlock(&inode->i_mutex); + mark_inode_dirty(inode); setflags_out: mnt_drop_write_file(filp); @@ -88,20 +89,29 @@ setflags_out: } case EXT2_IOC_GETVERSION: return put_user(inode->i_generation, (int __user *) arg); - case EXT2_IOC_SETVERSION: + case EXT2_IOC_SETVERSION: { + __u32 generation; + if (!inode_owner_or_capable(inode)) return -EPERM; ret = mnt_want_write_file(filp); if (ret) return ret; - if (get_user(inode->i_generation, (int __user *) arg)) { + if (get_user(generation, (int __user *) arg)) { ret = -EFAULT; - } else { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); + goto setversion_out; } + + mutex_lock(&inode->i_mutex); + inode->i_ctime = CURRENT_TIME_SEC; + inode->i_generation = generation; + mutex_unlock(&inode->i_mutex); + + mark_inode_dirty(inode); +setversion_out: mnt_drop_write_file(filp); return ret; + } case EXT2_IOC_GETRSVSZ: if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 88e8a23d0026..376816fcd040 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1353,7 +1353,7 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret) spin_lock(&gl->gl_spin); gl->gl_reply = ret; - if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) { + if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags))) { if (gfs2_should_freeze(gl)) { set_bit(GLF_FROZEN, &gl->gl_flags); spin_unlock(&gl->gl_spin); diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index 2553b858a72e..307ac31df781 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -121,8 +121,11 @@ enum { struct lm_lockops { const char *lm_proto_name; - int (*lm_mount) (struct gfs2_sbd *sdp, const char *fsname); - void (*lm_unmount) (struct gfs2_sbd *sdp); + int (*lm_mount) (struct gfs2_sbd *sdp, const char *table); + void (*lm_first_done) (struct gfs2_sbd *sdp); + void (*lm_recovery_result) (struct gfs2_sbd *sdp, unsigned int jid, + unsigned int result); + void (*lm_unmount) (struct gfs2_sbd *sdp); void (*lm_withdraw) (struct gfs2_sbd *sdp); void (*lm_put_lock) (struct gfs2_glock *gl); int (*lm_lock) (struct gfs2_glock *gl, unsigned int req_state, diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e1d3bb59945c..97742a7ea9cc 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -139,8 +139,45 @@ struct gfs2_bufdata { #define GDLM_STRNAME_BYTES 25 #define GDLM_LVB_SIZE 32 +/* + * ls_recover_flags: + * + * DFL_BLOCK_LOCKS: dlm is in recovery and will grant locks that had been + * held by failed nodes whose journals need recovery. Those locks should + * only be used for journal recovery until the journal recovery is done. + * This is set by the dlm recover_prep callback and cleared by the + * gfs2_control thread when journal recovery is complete. To avoid + * races between recover_prep setting and gfs2_control clearing, recover_spin + * is held while changing this bit and reading/writing recover_block + * and recover_start. + * + * DFL_NO_DLM_OPS: dlm lockspace ops/callbacks are not being used. + * + * DFL_FIRST_MOUNT: this node is the first to mount this fs and is doing + * recovery of all journals before allowing other nodes to mount the fs. + * This is cleared when FIRST_MOUNT_DONE is set. + * + * DFL_FIRST_MOUNT_DONE: this node was the first mounter, and has finished + * recovery of all journals, and now allows other nodes to mount the fs. + * + * DFL_MOUNT_DONE: gdlm_mount has completed successfully and cleared + * BLOCK_LOCKS for the first time. The gfs2_control thread should now + * control clearing BLOCK_LOCKS for further recoveries. + * + * DFL_UNMOUNT: gdlm_unmount sets to keep sdp off gfs2_control_wq. + * + * DFL_DLM_RECOVERY: set while dlm is in recovery, between recover_prep() + * and recover_done(), i.e. set while recover_block == recover_start. + */ + enum { DFL_BLOCK_LOCKS = 0, + DFL_NO_DLM_OPS = 1, + DFL_FIRST_MOUNT = 2, + DFL_FIRST_MOUNT_DONE = 3, + DFL_MOUNT_DONE = 4, + DFL_UNMOUNT = 5, + DFL_DLM_RECOVERY = 6, }; struct lm_lockname { @@ -392,6 +429,7 @@ struct gfs2_jdesc { #define JDF_RECOVERY 1 unsigned int jd_jid; unsigned int jd_blocks; + int jd_recover_error; }; struct gfs2_statfs_change_host { @@ -461,6 +499,7 @@ enum { SDF_NORECOVERY = 4, SDF_DEMOTE = 5, SDF_NOJOURNALID = 6, + SDF_RORECOVERY = 7, /* read only recovery */ }; #define GFS2_FSNAME_LEN 256 @@ -499,14 +538,26 @@ struct gfs2_sb_host { struct lm_lockstruct { int ls_jid; unsigned int ls_first; - unsigned int ls_first_done; unsigned int ls_nodir; const struct lm_lockops *ls_ops; - unsigned long ls_flags; dlm_lockspace_t *ls_dlm; - int ls_recover_jid_done; - int ls_recover_jid_status; + int ls_recover_jid_done; /* These two are deprecated, */ + int ls_recover_jid_status; /* used previously by gfs_controld */ + + struct dlm_lksb ls_mounted_lksb; /* mounted_lock */ + struct dlm_lksb ls_control_lksb; /* control_lock */ + char ls_control_lvb[GDLM_LVB_SIZE]; /* control_lock lvb */ + struct completion ls_sync_wait; /* {control,mounted}_{lock,unlock} */ + + spinlock_t ls_recover_spin; /* protects following fields */ + unsigned long ls_recover_flags; /* DFL_ */ + uint32_t ls_recover_mount; /* gen in first recover_done cb */ + uint32_t ls_recover_start; /* gen in last recover_done cb */ + uint32_t ls_recover_block; /* copy recover_start in last recover_prep */ + uint32_t ls_recover_size; /* size of recover_submit, recover_result */ + uint32_t *ls_recover_submit; /* gen in last recover_slot cb per jid */ + uint32_t *ls_recover_result; /* result of last jid recovery */ }; struct gfs2_sbd { @@ -544,6 +595,7 @@ struct gfs2_sbd { wait_queue_head_t sd_glock_wait; atomic_t sd_glock_disposal; struct completion sd_locking_init; + struct delayed_work sd_control_work; /* Inode Stuff */ diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 017960cf1d7a..a7d611b93f0f 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -599,9 +599,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name, error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto fail_end_trans; - inc_nlink(&ip->i_inode); - if (S_ISDIR(ip->i_inode.i_mode)) - inc_nlink(&ip->i_inode); + set_nlink(&ip->i_inode, S_ISDIR(ip->i_inode.i_mode) ? 2 : 1); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index ce85b62bc0a2..8944d1e32ab5 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -1,6 +1,6 @@ /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. - * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. + * Copyright 2004-2011 Red Hat, Inc. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions @@ -11,12 +11,15 @@ #include <linux/dlm.h> #include <linux/slab.h> #include <linux/types.h> +#include <linux/delay.h> #include <linux/gfs2_ondisk.h> #include "incore.h" #include "glock.h" #include "util.h" +#include "sys.h" +extern struct workqueue_struct *gfs2_control_wq; static void gdlm_ast(void *arg) { @@ -185,34 +188,1002 @@ static void gdlm_cancel(struct gfs2_glock *gl) dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl); } -static int gdlm_mount(struct gfs2_sbd *sdp, const char *fsname) +/* + * dlm/gfs2 recovery coordination using dlm_recover callbacks + * + * 1. dlm_controld sees lockspace members change + * 2. dlm_controld blocks dlm-kernel locking activity + * 3. dlm_controld within dlm-kernel notifies gfs2 (recover_prep) + * 4. dlm_controld starts and finishes its own user level recovery + * 5. dlm_controld starts dlm-kernel dlm_recoverd to do kernel recovery + * 6. dlm_recoverd notifies gfs2 of failed nodes (recover_slot) + * 7. dlm_recoverd does its own lock recovery + * 8. dlm_recoverd unblocks dlm-kernel locking activity + * 9. dlm_recoverd notifies gfs2 when done (recover_done with new generation) + * 10. gfs2_control updates control_lock lvb with new generation and jid bits + * 11. gfs2_control enqueues journals for gfs2_recover to recover (maybe none) + * 12. gfs2_recover dequeues and recovers journals of failed nodes + * 13. gfs2_recover provides recovery results to gfs2_control (recovery_result) + * 14. gfs2_control updates control_lock lvb jid bits for recovered journals + * 15. gfs2_control unblocks normal locking when all journals are recovered + * + * - failures during recovery + * + * recover_prep() may set BLOCK_LOCKS (step 3) again before gfs2_control + * clears BLOCK_LOCKS (step 15), e.g. another node fails while still + * recovering for a prior failure. gfs2_control needs a way to detect + * this so it can leave BLOCK_LOCKS set in step 15. This is managed using + * the recover_block and recover_start values. + * + * recover_done() provides a new lockspace generation number each time it + * is called (step 9). This generation number is saved as recover_start. + * When recover_prep() is called, it sets BLOCK_LOCKS and sets + * recover_block = recover_start. So, while recover_block is equal to + * recover_start, BLOCK_LOCKS should remain set. (recover_spin must + * be held around the BLOCK_LOCKS/recover_block/recover_start logic.) + * + * - more specific gfs2 steps in sequence above + * + * 3. recover_prep sets BLOCK_LOCKS and sets recover_block = recover_start + * 6. recover_slot records any failed jids (maybe none) + * 9. recover_done sets recover_start = new generation number + * 10. gfs2_control sets control_lock lvb = new gen + bits for failed jids + * 12. gfs2_recover does journal recoveries for failed jids identified above + * 14. gfs2_control clears control_lock lvb bits for recovered jids + * 15. gfs2_control checks if recover_block == recover_start (step 3 occured + * again) then do nothing, otherwise if recover_start > recover_block + * then clear BLOCK_LOCKS. + * + * - parallel recovery steps across all nodes + * + * All nodes attempt to update the control_lock lvb with the new generation + * number and jid bits, but only the first to get the control_lock EX will + * do so; others will see that it's already done (lvb already contains new + * generation number.) + * + * . All nodes get the same recover_prep/recover_slot/recover_done callbacks + * . All nodes attempt to set control_lock lvb gen + bits for the new gen + * . One node gets control_lock first and writes the lvb, others see it's done + * . All nodes attempt to recover jids for which they see control_lock bits set + * . One node succeeds for a jid, and that one clears the jid bit in the lvb + * . All nodes will eventually see all lvb bits clear and unblock locks + * + * - is there a problem with clearing an lvb bit that should be set + * and missing a journal recovery? + * + * 1. jid fails + * 2. lvb bit set for step 1 + * 3. jid recovered for step 1 + * 4. jid taken again (new mount) + * 5. jid fails (for step 4) + * 6. lvb bit set for step 5 (will already be set) + * 7. lvb bit cleared for step 3 + * + * This is not a problem because the failure in step 5 does not + * require recovery, because the mount in step 4 could not have + * progressed far enough to unblock locks and access the fs. The + * control_mount() function waits for all recoveries to be complete + * for the latest lockspace generation before ever unblocking locks + * and returning. The mount in step 4 waits until the recovery in + * step 1 is done. + * + * - special case of first mounter: first node to mount the fs + * + * The first node to mount a gfs2 fs needs to check all the journals + * and recover any that need recovery before other nodes are allowed + * to mount the fs. (Others may begin mounting, but they must wait + * for the first mounter to be done before taking locks on the fs + * or accessing the fs.) This has two parts: + * + * 1. The mounted_lock tells a node it's the first to mount the fs. + * Each node holds the mounted_lock in PR while it's mounted. + * Each node tries to acquire the mounted_lock in EX when it mounts. + * If a node is granted the mounted_lock EX it means there are no + * other mounted nodes (no PR locks exist), and it is the first mounter. + * The mounted_lock is demoted to PR when first recovery is done, so + * others will fail to get an EX lock, but will get a PR lock. + * + * 2. The control_lock blocks others in control_mount() while the first + * mounter is doing first mount recovery of all journals. + * A mounting node needs to acquire control_lock in EX mode before + * it can proceed. The first mounter holds control_lock in EX while doing + * the first mount recovery, blocking mounts from other nodes, then demotes + * control_lock to NL when it's done (others_may_mount/first_done), + * allowing other nodes to continue mounting. + * + * first mounter: + * control_lock EX/NOQUEUE success + * mounted_lock EX/NOQUEUE success (no other PR, so no other mounters) + * set first=1 + * do first mounter recovery + * mounted_lock EX->PR + * control_lock EX->NL, write lvb generation + * + * other mounter: + * control_lock EX/NOQUEUE success (if fail -EAGAIN, retry) + * mounted_lock EX/NOQUEUE fail -EAGAIN (expected due to other mounters PR) + * mounted_lock PR/NOQUEUE success + * read lvb generation + * control_lock EX->NL + * set first=0 + * + * - mount during recovery + * + * If a node mounts while others are doing recovery (not first mounter), + * the mounting node will get its initial recover_done() callback without + * having seen any previous failures/callbacks. + * + * It must wait for all recoveries preceding its mount to be finished + * before it unblocks locks. It does this by repeating the "other mounter" + * steps above until the lvb generation number is >= its mount generation + * number (from initial recover_done) and all lvb bits are clear. + * + * - control_lock lvb format + * + * 4 bytes generation number: the latest dlm lockspace generation number + * from recover_done callback. Indicates the jid bitmap has been updated + * to reflect all slot failures through that generation. + * 4 bytes unused. + * GDLM_LVB_SIZE-8 bytes of jid bit map. If bit N is set, it indicates + * that jid N needs recovery. + */ + +#define JID_BITMAP_OFFSET 8 /* 4 byte generation number + 4 byte unused */ + +static void control_lvb_read(struct lm_lockstruct *ls, uint32_t *lvb_gen, + char *lvb_bits) +{ + uint32_t gen; + memcpy(lvb_bits, ls->ls_control_lvb, GDLM_LVB_SIZE); + memcpy(&gen, lvb_bits, sizeof(uint32_t)); + *lvb_gen = le32_to_cpu(gen); +} + +static void control_lvb_write(struct lm_lockstruct *ls, uint32_t lvb_gen, + char *lvb_bits) +{ + uint32_t gen; + memcpy(ls->ls_control_lvb, lvb_bits, GDLM_LVB_SIZE); + gen = cpu_to_le32(lvb_gen); + memcpy(ls->ls_control_lvb, &gen, sizeof(uint32_t)); +} + +static int all_jid_bits_clear(char *lvb) +{ + int i; + for (i = JID_BITMAP_OFFSET; i < GDLM_LVB_SIZE; i++) { + if (lvb[i]) + return 0; + } + return 1; +} + +static void sync_wait_cb(void *arg) +{ + struct lm_lockstruct *ls = arg; + complete(&ls->ls_sync_wait); +} + +static int sync_unlock(struct gfs2_sbd *sdp, struct dlm_lksb *lksb, char *name) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; int error; - if (fsname == NULL) { - fs_info(sdp, "no fsname found\n"); - return -EINVAL; + error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls); + if (error) { + fs_err(sdp, "%s lkid %x error %d\n", + name, lksb->sb_lkid, error); + return error; + } + + wait_for_completion(&ls->ls_sync_wait); + + if (lksb->sb_status != -DLM_EUNLOCK) { + fs_err(sdp, "%s lkid %x status %d\n", + name, lksb->sb_lkid, lksb->sb_status); + return -1; + } + return 0; +} + +static int sync_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags, + unsigned int num, struct dlm_lksb *lksb, char *name) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + char strname[GDLM_STRNAME_BYTES]; + int error, status; + + memset(strname, 0, GDLM_STRNAME_BYTES); + snprintf(strname, GDLM_STRNAME_BYTES, "%8x%16x", LM_TYPE_NONDISK, num); + + error = dlm_lock(ls->ls_dlm, mode, lksb, flags, + strname, GDLM_STRNAME_BYTES - 1, + 0, sync_wait_cb, ls, NULL); + if (error) { + fs_err(sdp, "%s lkid %x flags %x mode %d error %d\n", + name, lksb->sb_lkid, flags, mode, error); + return error; + } + + wait_for_completion(&ls->ls_sync_wait); + + status = lksb->sb_status; + + if (status && status != -EAGAIN) { + fs_err(sdp, "%s lkid %x flags %x mode %d status %d\n", + name, lksb->sb_lkid, flags, mode, status); + } + + return status; +} + +static int mounted_unlock(struct gfs2_sbd *sdp) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sync_unlock(sdp, &ls->ls_mounted_lksb, "mounted_lock"); +} + +static int mounted_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sync_lock(sdp, mode, flags, GFS2_MOUNTED_LOCK, + &ls->ls_mounted_lksb, "mounted_lock"); +} + +static int control_unlock(struct gfs2_sbd *sdp) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sync_unlock(sdp, &ls->ls_control_lksb, "control_lock"); +} + +static int control_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + return sync_lock(sdp, mode, flags, GFS2_CONTROL_LOCK, + &ls->ls_control_lksb, "control_lock"); +} + +static void gfs2_control_func(struct work_struct *work) +{ + struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_control_work.work); + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + char lvb_bits[GDLM_LVB_SIZE]; + uint32_t block_gen, start_gen, lvb_gen, flags; + int recover_set = 0; + int write_lvb = 0; + int recover_size; + int i, error; + + spin_lock(&ls->ls_recover_spin); + /* + * No MOUNT_DONE means we're still mounting; control_mount() + * will set this flag, after which this thread will take over + * all further clearing of BLOCK_LOCKS. + * + * FIRST_MOUNT means this node is doing first mounter recovery, + * for which recovery control is handled by + * control_mount()/control_first_done(), not this thread. + */ + if (!test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) || + test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) { + spin_unlock(&ls->ls_recover_spin); + return; + } + block_gen = ls->ls_recover_block; + start_gen = ls->ls_recover_start; + spin_unlock(&ls->ls_recover_spin); + + /* + * Equal block_gen and start_gen implies we are between + * recover_prep and recover_done callbacks, which means + * dlm recovery is in progress and dlm locking is blocked. + * There's no point trying to do any work until recover_done. + */ + + if (block_gen == start_gen) + return; + + /* + * Propagate recover_submit[] and recover_result[] to lvb: + * dlm_recoverd adds to recover_submit[] jids needing recovery + * gfs2_recover adds to recover_result[] journal recovery results + * + * set lvb bit for jids in recover_submit[] if the lvb has not + * yet been updated for the generation of the failure + * + * clear lvb bit for jids in recover_result[] if the result of + * the journal recovery is SUCCESS + */ + + error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_VALBLK); + if (error) { + fs_err(sdp, "control lock EX error %d\n", error); + return; + } + + control_lvb_read(ls, &lvb_gen, lvb_bits); + + spin_lock(&ls->ls_recover_spin); + if (block_gen != ls->ls_recover_block || + start_gen != ls->ls_recover_start) { + fs_info(sdp, "recover generation %u block1 %u %u\n", + start_gen, block_gen, ls->ls_recover_block); + spin_unlock(&ls->ls_recover_spin); + control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT); + return; + } + + recover_size = ls->ls_recover_size; + + if (lvb_gen <= start_gen) { + /* + * Clear lvb bits for jids we've successfully recovered. + * Because all nodes attempt to recover failed journals, + * a journal can be recovered multiple times successfully + * in succession. Only the first will really do recovery, + * the others find it clean, but still report a successful + * recovery. So, another node may have already recovered + * the jid and cleared the lvb bit for it. + */ + for (i = 0; i < recover_size; i++) { + if (ls->ls_recover_result[i] != LM_RD_SUCCESS) + continue; + + ls->ls_recover_result[i] = 0; + + if (!test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET)) + continue; + + __clear_bit_le(i, lvb_bits + JID_BITMAP_OFFSET); + write_lvb = 1; + } + } + + if (lvb_gen == start_gen) { + /* + * Failed slots before start_gen are already set in lvb. + */ + for (i = 0; i < recover_size; i++) { + if (!ls->ls_recover_submit[i]) + continue; + if (ls->ls_recover_submit[i] < lvb_gen) + ls->ls_recover_submit[i] = 0; + } + } else if (lvb_gen < start_gen) { + /* + * Failed slots before start_gen are not yet set in lvb. + */ + for (i = 0; i < recover_size; i++) { + if (!ls->ls_recover_submit[i]) + continue; + if (ls->ls_recover_submit[i] < start_gen) { + ls->ls_recover_submit[i] = 0; + __set_bit_le(i, lvb_bits + JID_BITMAP_OFFSET); + } + } + /* even if there are no bits to set, we need to write the + latest generation to the lvb */ + write_lvb = 1; + } else { + /* + * we should be getting a recover_done() for lvb_gen soon + */ + } + spin_unlock(&ls->ls_recover_spin); + + if (write_lvb) { + control_lvb_write(ls, start_gen, lvb_bits); + flags = DLM_LKF_CONVERT | DLM_LKF_VALBLK; + } else { + flags = DLM_LKF_CONVERT; + } + + error = control_lock(sdp, DLM_LOCK_NL, flags); + if (error) { + fs_err(sdp, "control lock NL error %d\n", error); + return; + } + + /* + * Everyone will see jid bits set in the lvb, run gfs2_recover_set(), + * and clear a jid bit in the lvb if the recovery is a success. + * Eventually all journals will be recovered, all jid bits will + * be cleared in the lvb, and everyone will clear BLOCK_LOCKS. + */ + + for (i = 0; i < recover_size; i++) { + if (test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET)) { + fs_info(sdp, "recover generation %u jid %d\n", + start_gen, i); + gfs2_recover_set(sdp, i); + recover_set++; + } + } + if (recover_set) + return; + + /* + * No more jid bits set in lvb, all recovery is done, unblock locks + * (unless a new recover_prep callback has occured blocking locks + * again while working above) + */ + + spin_lock(&ls->ls_recover_spin); + if (ls->ls_recover_block == block_gen && + ls->ls_recover_start == start_gen) { + clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); + spin_unlock(&ls->ls_recover_spin); + fs_info(sdp, "recover generation %u done\n", start_gen); + gfs2_glock_thaw(sdp); + } else { + fs_info(sdp, "recover generation %u block2 %u %u\n", + start_gen, block_gen, ls->ls_recover_block); + spin_unlock(&ls->ls_recover_spin); + } +} + +static int control_mount(struct gfs2_sbd *sdp) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + char lvb_bits[GDLM_LVB_SIZE]; + uint32_t start_gen, block_gen, mount_gen, lvb_gen; + int mounted_mode; + int retries = 0; + int error; + + memset(&ls->ls_mounted_lksb, 0, sizeof(struct dlm_lksb)); + memset(&ls->ls_control_lksb, 0, sizeof(struct dlm_lksb)); + memset(&ls->ls_control_lvb, 0, GDLM_LVB_SIZE); + ls->ls_control_lksb.sb_lvbptr = ls->ls_control_lvb; + init_completion(&ls->ls_sync_wait); + + set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); + + error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_VALBLK); + if (error) { + fs_err(sdp, "control_mount control_lock NL error %d\n", error); + return error; + } + + error = mounted_lock(sdp, DLM_LOCK_NL, 0); + if (error) { + fs_err(sdp, "control_mount mounted_lock NL error %d\n", error); + control_unlock(sdp); + return error; + } + mounted_mode = DLM_LOCK_NL; + +restart: + if (retries++ && signal_pending(current)) { + error = -EINTR; + goto fail; + } + + /* + * We always start with both locks in NL. control_lock is + * demoted to NL below so we don't need to do it here. + */ + + if (mounted_mode != DLM_LOCK_NL) { + error = mounted_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT); + if (error) + goto fail; + mounted_mode = DLM_LOCK_NL; + } + + /* + * Other nodes need to do some work in dlm recovery and gfs2_control + * before the recover_done and control_lock will be ready for us below. + * A delay here is not required but often avoids having to retry. + */ + + msleep_interruptible(500); + + /* + * Acquire control_lock in EX and mounted_lock in either EX or PR. + * control_lock lvb keeps track of any pending journal recoveries. + * mounted_lock indicates if any other nodes have the fs mounted. + */ + + error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE|DLM_LKF_VALBLK); + if (error == -EAGAIN) { + goto restart; + } else if (error) { + fs_err(sdp, "control_mount control_lock EX error %d\n", error); + goto fail; + } + + error = mounted_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE); + if (!error) { + mounted_mode = DLM_LOCK_EX; + goto locks_done; + } else if (error != -EAGAIN) { + fs_err(sdp, "control_mount mounted_lock EX error %d\n", error); + goto fail; + } + + error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE); + if (!error) { + mounted_mode = DLM_LOCK_PR; + goto locks_done; + } else { + /* not even -EAGAIN should happen here */ + fs_err(sdp, "control_mount mounted_lock PR error %d\n", error); + goto fail; + } + +locks_done: + /* + * If we got both locks above in EX, then we're the first mounter. + * If not, then we need to wait for the control_lock lvb to be + * updated by other mounted nodes to reflect our mount generation. + * + * In simple first mounter cases, first mounter will see zero lvb_gen, + * but in cases where all existing nodes leave/fail before mounting + * nodes finish control_mount, then all nodes will be mounting and + * lvb_gen will be non-zero. + */ + + control_lvb_read(ls, &lvb_gen, lvb_bits); + + if (lvb_gen == 0xFFFFFFFF) { + /* special value to force mount attempts to fail */ + fs_err(sdp, "control_mount control_lock disabled\n"); + error = -EINVAL; + goto fail; + } + + if (mounted_mode == DLM_LOCK_EX) { + /* first mounter, keep both EX while doing first recovery */ + spin_lock(&ls->ls_recover_spin); + clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); + set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags); + set_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags); + spin_unlock(&ls->ls_recover_spin); + fs_info(sdp, "first mounter control generation %u\n", lvb_gen); + return 0; + } + + error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT); + if (error) + goto fail; + + /* + * We are not first mounter, now we need to wait for the control_lock + * lvb generation to be >= the generation from our first recover_done + * and all lvb bits to be clear (no pending journal recoveries.) + */ + + if (!all_jid_bits_clear(lvb_bits)) { + /* journals need recovery, wait until all are clear */ + fs_info(sdp, "control_mount wait for journal recovery\n"); + goto restart; + } + + spin_lock(&ls->ls_recover_spin); + block_gen = ls->ls_recover_block; + start_gen = ls->ls_recover_start; + mount_gen = ls->ls_recover_mount; + + if (lvb_gen < mount_gen) { + /* wait for mounted nodes to update control_lock lvb to our + generation, which might include new recovery bits set */ + fs_info(sdp, "control_mount wait1 block %u start %u mount %u " + "lvb %u flags %lx\n", block_gen, start_gen, mount_gen, + lvb_gen, ls->ls_recover_flags); + spin_unlock(&ls->ls_recover_spin); + goto restart; + } + + if (lvb_gen != start_gen) { + /* wait for mounted nodes to update control_lock lvb to the + latest recovery generation */ + fs_info(sdp, "control_mount wait2 block %u start %u mount %u " + "lvb %u flags %lx\n", block_gen, start_gen, mount_gen, + lvb_gen, ls->ls_recover_flags); + spin_unlock(&ls->ls_recover_spin); + goto restart; + } + + if (block_gen == start_gen) { + /* dlm recovery in progress, wait for it to finish */ + fs_info(sdp, "control_mount wait3 block %u start %u mount %u " + "lvb %u flags %lx\n", block_gen, start_gen, mount_gen, + lvb_gen, ls->ls_recover_flags); + spin_unlock(&ls->ls_recover_spin); + goto restart; } - error = dlm_new_lockspace(fsname, NULL, - DLM_LSFL_FS | DLM_LSFL_NEWEXCL | - (ls->ls_nodir ? DLM_LSFL_NODIR : 0), - GDLM_LVB_SIZE, NULL, NULL, NULL, &ls->ls_dlm); + clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); + set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags); + memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t)); + memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t)); + spin_unlock(&ls->ls_recover_spin); + return 0; + +fail: + mounted_unlock(sdp); + control_unlock(sdp); + return error; +} + +static int dlm_recovery_wait(void *word) +{ + schedule(); + return 0; +} + +static int control_first_done(struct gfs2_sbd *sdp) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + char lvb_bits[GDLM_LVB_SIZE]; + uint32_t start_gen, block_gen; + int error; + +restart: + spin_lock(&ls->ls_recover_spin); + start_gen = ls->ls_recover_start; + block_gen = ls->ls_recover_block; + + if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags) || + !test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) || + !test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) { + /* sanity check, should not happen */ + fs_err(sdp, "control_first_done start %u block %u flags %lx\n", + start_gen, block_gen, ls->ls_recover_flags); + spin_unlock(&ls->ls_recover_spin); + control_unlock(sdp); + return -1; + } + + if (start_gen == block_gen) { + /* + * Wait for the end of a dlm recovery cycle to switch from + * first mounter recovery. We can ignore any recover_slot + * callbacks between the recover_prep and next recover_done + * because we are still the first mounter and any failed nodes + * have not fully mounted, so they don't need recovery. + */ + spin_unlock(&ls->ls_recover_spin); + fs_info(sdp, "control_first_done wait gen %u\n", start_gen); + + wait_on_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY, + dlm_recovery_wait, TASK_UNINTERRUPTIBLE); + goto restart; + } + + clear_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags); + set_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags); + memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t)); + memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t)); + spin_unlock(&ls->ls_recover_spin); + + memset(lvb_bits, 0, sizeof(lvb_bits)); + control_lvb_write(ls, start_gen, lvb_bits); + + error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT); + if (error) + fs_err(sdp, "control_first_done mounted PR error %d\n", error); + + error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT|DLM_LKF_VALBLK); if (error) - printk(KERN_ERR "dlm_new_lockspace error %d", error); + fs_err(sdp, "control_first_done control NL error %d\n", error); return error; } +/* + * Expand static jid arrays if necessary (by increments of RECOVER_SIZE_INC) + * to accomodate the largest slot number. (NB dlm slot numbers start at 1, + * gfs2 jids start at 0, so jid = slot - 1) + */ + +#define RECOVER_SIZE_INC 16 + +static int set_recover_size(struct gfs2_sbd *sdp, struct dlm_slot *slots, + int num_slots) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + uint32_t *submit = NULL; + uint32_t *result = NULL; + uint32_t old_size, new_size; + int i, max_jid; + + max_jid = 0; + for (i = 0; i < num_slots; i++) { + if (max_jid < slots[i].slot - 1) + max_jid = slots[i].slot - 1; + } + + old_size = ls->ls_recover_size; + + if (old_size >= max_jid + 1) + return 0; + + new_size = old_size + RECOVER_SIZE_INC; + + submit = kzalloc(new_size * sizeof(uint32_t), GFP_NOFS); + result = kzalloc(new_size * sizeof(uint32_t), GFP_NOFS); + if (!submit || !result) { + kfree(submit); + kfree(result); + return -ENOMEM; + } + + spin_lock(&ls->ls_recover_spin); + memcpy(submit, ls->ls_recover_submit, old_size * sizeof(uint32_t)); + memcpy(result, ls->ls_recover_result, old_size * sizeof(uint32_t)); + kfree(ls->ls_recover_submit); + kfree(ls->ls_recover_result); + ls->ls_recover_submit = submit; + ls->ls_recover_result = result; + ls->ls_recover_size = new_size; + spin_unlock(&ls->ls_recover_spin); + return 0; +} + +static void free_recover_size(struct lm_lockstruct *ls) +{ + kfree(ls->ls_recover_submit); + kfree(ls->ls_recover_result); + ls->ls_recover_submit = NULL; + ls->ls_recover_result = NULL; + ls->ls_recover_size = 0; +} + +/* dlm calls before it does lock recovery */ + +static void gdlm_recover_prep(void *arg) +{ + struct gfs2_sbd *sdp = arg; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + + spin_lock(&ls->ls_recover_spin); + ls->ls_recover_block = ls->ls_recover_start; + set_bit(DFL_DLM_RECOVERY, &ls->ls_recover_flags); + + if (!test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) || + test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) { + spin_unlock(&ls->ls_recover_spin); + return; + } + set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); + spin_unlock(&ls->ls_recover_spin); +} + +/* dlm calls after recover_prep has been completed on all lockspace members; + identifies slot/jid of failed member */ + +static void gdlm_recover_slot(void *arg, struct dlm_slot *slot) +{ + struct gfs2_sbd *sdp = arg; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + int jid = slot->slot - 1; + + spin_lock(&ls->ls_recover_spin); + if (ls->ls_recover_size < jid + 1) { + fs_err(sdp, "recover_slot jid %d gen %u short size %d", + jid, ls->ls_recover_block, ls->ls_recover_size); + spin_unlock(&ls->ls_recover_spin); + return; + } + + if (ls->ls_recover_submit[jid]) { + fs_info(sdp, "recover_slot jid %d gen %u prev %u", + jid, ls->ls_recover_block, ls->ls_recover_submit[jid]); + } + ls->ls_recover_submit[jid] = ls->ls_recover_block; + spin_unlock(&ls->ls_recover_spin); +} + +/* dlm calls after recover_slot and after it completes lock recovery */ + +static void gdlm_recover_done(void *arg, struct dlm_slot *slots, int num_slots, + int our_slot, uint32_t generation) +{ + struct gfs2_sbd *sdp = arg; + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + + /* ensure the ls jid arrays are large enough */ + set_recover_size(sdp, slots, num_slots); + + spin_lock(&ls->ls_recover_spin); + ls->ls_recover_start = generation; + + if (!ls->ls_recover_mount) { + ls->ls_recover_mount = generation; + ls->ls_jid = our_slot - 1; + } + + if (!test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) + queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work, 0); + + clear_bit(DFL_DLM_RECOVERY, &ls->ls_recover_flags); + smp_mb__after_clear_bit(); + wake_up_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY); + spin_unlock(&ls->ls_recover_spin); +} + +/* gfs2_recover thread has a journal recovery result */ + +static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid, + unsigned int result) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + + if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags)) + return; + + /* don't care about the recovery of own journal during mount */ + if (jid == ls->ls_jid) + return; + + spin_lock(&ls->ls_recover_spin); + if (test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) { + spin_unlock(&ls->ls_recover_spin); + return; + } + if (ls->ls_recover_size < jid + 1) { + fs_err(sdp, "recovery_result jid %d short size %d", + jid, ls->ls_recover_size); + spin_unlock(&ls->ls_recover_spin); + return; + } + + fs_info(sdp, "recover jid %d result %s\n", jid, + result == LM_RD_GAVEUP ? "busy" : "success"); + + ls->ls_recover_result[jid] = result; + + /* GAVEUP means another node is recovering the journal; delay our + next attempt to recover it, to give the other node a chance to + finish before trying again */ + + if (!test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) + queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work, + result == LM_RD_GAVEUP ? HZ : 0); + spin_unlock(&ls->ls_recover_spin); +} + +const struct dlm_lockspace_ops gdlm_lockspace_ops = { + .recover_prep = gdlm_recover_prep, + .recover_slot = gdlm_recover_slot, + .recover_done = gdlm_recover_done, +}; + +static int gdlm_mount(struct gfs2_sbd *sdp, const char *table) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + char cluster[GFS2_LOCKNAME_LEN]; + const char *fsname; + uint32_t flags; + int error, ops_result; + + /* + * initialize everything + */ + + INIT_DELAYED_WORK(&sdp->sd_control_work, gfs2_control_func); + spin_lock_init(&ls->ls_recover_spin); + ls->ls_recover_flags = 0; + ls->ls_recover_mount = 0; + ls->ls_recover_start = 0; + ls->ls_recover_block = 0; + ls->ls_recover_size = 0; + ls->ls_recover_submit = NULL; + ls->ls_recover_result = NULL; + + error = set_recover_size(sdp, NULL, 0); + if (error) + goto fail; + + /* + * prepare dlm_new_lockspace args + */ + + fsname = strchr(table, ':'); + if (!fsname) { + fs_info(sdp, "no fsname found\n"); + error = -EINVAL; + goto fail_free; + } + memset(cluster, 0, sizeof(cluster)); + memcpy(cluster, table, strlen(table) - strlen(fsname)); + fsname++; + + flags = DLM_LSFL_FS | DLM_LSFL_NEWEXCL; + if (ls->ls_nodir) + flags |= DLM_LSFL_NODIR; + + /* + * create/join lockspace + */ + + error = dlm_new_lockspace(fsname, cluster, flags, GDLM_LVB_SIZE, + &gdlm_lockspace_ops, sdp, &ops_result, + &ls->ls_dlm); + if (error) { + fs_err(sdp, "dlm_new_lockspace error %d\n", error); + goto fail_free; + } + + if (ops_result < 0) { + /* + * dlm does not support ops callbacks, + * old dlm_controld/gfs_controld are used, try without ops. + */ + fs_info(sdp, "dlm lockspace ops not used\n"); + free_recover_size(ls); + set_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags); + return 0; + } + + if (!test_bit(SDF_NOJOURNALID, &sdp->sd_flags)) { + fs_err(sdp, "dlm lockspace ops disallow jid preset\n"); + error = -EINVAL; + goto fail_release; + } + + /* + * control_mount() uses control_lock to determine first mounter, + * and for later mounts, waits for any recoveries to be cleared. + */ + + error = control_mount(sdp); + if (error) { + fs_err(sdp, "mount control error %d\n", error); + goto fail_release; + } + + ls->ls_first = !!test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags); + clear_bit(SDF_NOJOURNALID, &sdp->sd_flags); + smp_mb__after_clear_bit(); + wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID); + return 0; + +fail_release: + dlm_release_lockspace(ls->ls_dlm, 2); +fail_free: + free_recover_size(ls); +fail: + return error; +} + +static void gdlm_first_done(struct gfs2_sbd *sdp) +{ + struct lm_lockstruct *ls = &sdp->sd_lockstruct; + int error; + + if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags)) + return; + + error = control_first_done(sdp); + if (error) + fs_err(sdp, "mount first_done error %d\n", error); +} + static void gdlm_unmount(struct gfs2_sbd *sdp) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; + if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags)) + goto release; + + /* wait for gfs2_control_wq to be done with this mount */ + + spin_lock(&ls->ls_recover_spin); + set_bit(DFL_UNMOUNT, &ls->ls_recover_flags); + spin_unlock(&ls->ls_recover_spin); + flush_delayed_work_sync(&sdp->sd_control_work); + + /* mounted_lock and control_lock will be purged in dlm recovery */ +release: if (ls->ls_dlm) { dlm_release_lockspace(ls->ls_dlm, 2); ls->ls_dlm = NULL; } + + free_recover_size(ls); } static const match_table_t dlm_tokens = { @@ -226,6 +1197,8 @@ static const match_table_t dlm_tokens = { const struct lm_lockops gfs2_dlm_ops = { .lm_proto_name = "lock_dlm", .lm_mount = gdlm_mount, + .lm_first_done = gdlm_first_done, + .lm_recovery_result = gdlm_recovery_result, .lm_unmount = gdlm_unmount, .lm_put_lock = gdlm_put_lock, .lm_lock = gdlm_lock, diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index c150298e2d8e..a8d9bcd0e19c 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -28,6 +28,8 @@ #include "recovery.h" #include "dir.h" +struct workqueue_struct *gfs2_control_wq; + static struct shrinker qd_shrinker = { .shrink = gfs2_shrink_qd_memory, .seeks = DEFAULT_SEEKS, @@ -146,12 +148,19 @@ static int __init init_gfs2_fs(void) if (!gfs_recovery_wq) goto fail_wq; + gfs2_control_wq = alloc_workqueue("gfs2_control", + WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0); + if (!gfs2_control_wq) + goto fail_control; + gfs2_register_debugfs(); printk("GFS2 installed\n"); return 0; +fail_control: + destroy_workqueue(gfs_recovery_wq); fail_wq: unregister_filesystem(&gfs2meta_fs_type); fail_unregister: @@ -195,6 +204,7 @@ static void __exit exit_gfs2_fs(void) unregister_filesystem(&gfs2_fs_type); unregister_filesystem(&gfs2meta_fs_type); destroy_workqueue(gfs_recovery_wq); + destroy_workqueue(gfs2_control_wq); rcu_barrier(); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index fe72e79e6ff9..6aacf3f230a2 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -562,8 +562,12 @@ static void gfs2_others_may_mount(struct gfs2_sbd *sdp) { char *message = "FIRSTMOUNT=Done"; char *envp[] = { message, NULL }; - struct lm_lockstruct *ls = &sdp->sd_lockstruct; - ls->ls_first_done = 1; + + fs_info(sdp, "first mount done, others may mount\n"); + + if (sdp->sd_lockstruct.ls_ops->lm_first_done) + sdp->sd_lockstruct.ls_ops->lm_first_done(sdp); + kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); } @@ -944,7 +948,6 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) struct gfs2_args *args = &sdp->sd_args; const char *proto = sdp->sd_proto_name; const char *table = sdp->sd_table_name; - const char *fsname; char *o, *options; int ret; @@ -1004,21 +1007,12 @@ hostdata_error: } } - if (sdp->sd_args.ar_spectator) - snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table); - else - snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table, - sdp->sd_lockstruct.ls_jid); - - fsname = strchr(table, ':'); - if (fsname) - fsname++; if (lm->lm_mount == NULL) { fs_info(sdp, "Now mounting FS...\n"); complete_all(&sdp->sd_locking_init); return 0; } - ret = lm->lm_mount(sdp, fsname); + ret = lm->lm_mount(sdp, table); if (ret == 0) fs_info(sdp, "Joined cluster. Now mounting FS...\n"); complete_all(&sdp->sd_locking_init); @@ -1084,7 +1078,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent if (sdp->sd_args.ar_spectator) { sb->s_flags |= MS_RDONLY; - set_bit(SDF_NORECOVERY, &sdp->sd_flags); + set_bit(SDF_RORECOVERY, &sdp->sd_flags); } if (sdp->sd_args.ar_posix_acl) sb->s_flags |= MS_POSIXACL; @@ -1124,6 +1118,8 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent if (error) goto fail; + snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s", sdp->sd_table_name); + gfs2_create_debugfs_file(sdp); error = gfs2_sys_fs_add(sdp); @@ -1160,6 +1156,13 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent goto fail_sb; } + if (sdp->sd_args.ar_spectator) + snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", + sdp->sd_table_name); + else + snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", + sdp->sd_table_name, sdp->sd_lockstruct.ls_jid); + error = init_inodes(sdp, DO); if (error) goto fail_sb; diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c index f2a02edcac8f..963b2d75200c 100644 --- a/fs/gfs2/recovery.c +++ b/fs/gfs2/recovery.c @@ -436,12 +436,16 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid, char env_status[20]; char *envp[] = { env_jid, env_status, NULL }; struct lm_lockstruct *ls = &sdp->sd_lockstruct; + ls->ls_recover_jid_done = jid; ls->ls_recover_jid_status = message; sprintf(env_jid, "JID=%d", jid); sprintf(env_status, "RECOVERY=%s", message == LM_RD_SUCCESS ? "Done" : "Failed"); kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp); + + if (sdp->sd_lockstruct.ls_ops->lm_recovery_result) + sdp->sd_lockstruct.ls_ops->lm_recovery_result(sdp, jid, message); } void gfs2_recover_func(struct work_struct *work) @@ -512,7 +516,9 @@ void gfs2_recover_func(struct work_struct *work) if (error) goto fail_gunlock_ji; - if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) { + if (test_bit(SDF_RORECOVERY, &sdp->sd_flags)) { + ro = 1; + } else if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) { if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) ro = 1; } else { @@ -577,6 +583,7 @@ fail_gunlock_j: fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done"); fail: + jd->jd_recover_error = error; gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP); done: clear_bit(JDF_RECOVERY, &jd->jd_flags); @@ -605,6 +612,6 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait) wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait, TASK_UNINTERRUPTIBLE); - return 0; + return wait ? jd->jd_recover_error : 0; } diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 22234627f684..981bfa32121a 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1108,9 +1108,9 @@ void gfs2_inplace_release(struct gfs2_inode *ip) { struct gfs2_blkreserv *rs = ip->i_res; - gfs2_blkrsv_put(ip); if (rs->rs_rgd_gh.gh_gl) gfs2_glock_dq_uninit(&rs->rs_rgd_gh); + gfs2_blkrsv_put(ip); } /** diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 443cabcfcd23..d33172c291ba 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -298,7 +298,7 @@ static ssize_t block_show(struct gfs2_sbd *sdp, char *buf) ssize_t ret; int val = 0; - if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags)) + if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags)) val = 1; ret = sprintf(buf, "%d\n", val); return ret; @@ -313,9 +313,9 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len) val = simple_strtol(buf, NULL, 0); if (val == 1) - set_bit(DFL_BLOCK_LOCKS, &ls->ls_flags); + set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); else if (val == 0) { - clear_bit(DFL_BLOCK_LOCKS, &ls->ls_flags); + clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); smp_mb__after_clear_bit(); gfs2_glock_thaw(sdp); } else { @@ -350,8 +350,8 @@ static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len) goto out; if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) goto out; - sdp->sd_lockstruct.ls_first = first; - rv = 0; + sdp->sd_lockstruct.ls_first = first; + rv = 0; out: spin_unlock(&sdp->sd_jindex_spin); return rv ? rv : len; @@ -360,19 +360,14 @@ out: static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; - return sprintf(buf, "%d\n", ls->ls_first_done); + return sprintf(buf, "%d\n", !!test_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags)); } -static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid) { - unsigned jid; struct gfs2_jdesc *jd; int rv; - rv = sscanf(buf, "%u", &jid); - if (rv != 1) - return -EINVAL; - rv = -ESHUTDOWN; spin_lock(&sdp->sd_jindex_spin); if (test_bit(SDF_NORECOVERY, &sdp->sd_flags)) @@ -389,6 +384,20 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) } out: spin_unlock(&sdp->sd_jindex_spin); + return rv; +} + +static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ + unsigned jid; + int rv; + + rv = sscanf(buf, "%u", &jid); + if (rv != 1) + return -EINVAL; + + rv = gfs2_recover_set(sdp, jid); + return rv ? rv : len; } diff --git a/fs/gfs2/sys.h b/fs/gfs2/sys.h index e94560e836d7..79182d6ad6ac 100644 --- a/fs/gfs2/sys.h +++ b/fs/gfs2/sys.h @@ -19,5 +19,7 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp); int gfs2_sys_init(void); void gfs2_sys_uninit(void); +int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid); + #endif /* __SYS_DOT_H__ */ diff --git a/fs/inode.c b/fs/inode.c index 4fa4f0916af9..fb10d86ffad7 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -322,9 +322,6 @@ EXPORT_SYMBOL(clear_nlink); void set_nlink(struct inode *inode, unsigned int nlink) { if (!nlink) { - printk_ratelimited(KERN_INFO - "set_nlink() clearing i_nlink on %s inode %li\n", - inode->i_sb->s_type->name, inode->i_ino); clear_nlink(inode); } else { /* Yes, some filesystems do change nlink from zero to one */ diff --git a/fs/ioprio.c b/fs/ioprio.c index f79dab83e17b..f84b380d65e5 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -48,28 +48,12 @@ int set_task_ioprio(struct task_struct *task, int ioprio) if (err) return err; - task_lock(task); - do { - ioc = task->io_context; - /* see wmb() in current_io_context() */ - smp_read_barrier_depends(); - if (ioc) - break; - - ioc = alloc_io_context(GFP_ATOMIC, -1); - if (!ioc) { - err = -ENOMEM; - break; - } - task->io_context = ioc; - } while (1); - - if (!err) { - ioc->ioprio = ioprio; - ioc->ioprio_changed = 1; + ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE); + if (ioc) { + ioc_ioprio_changed(ioc, ioprio); + put_io_context(ioc, NULL); } - task_unlock(task); return err; } EXPORT_SYMBOL_GPL(set_task_ioprio); diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 5d1a00a5041b..05f0754f2b46 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -453,8 +453,6 @@ out: * * Return <0 on error, 0 on success, 1 if there was nothing to clean up. * - * Called with the journal lock held. - * * This is the only part of the journaling code which really needs to be * aware of transaction aborts. Checkpointing involves writing to the * main filesystem area rather than to the journal, so it can proceed @@ -472,13 +470,14 @@ int cleanup_journal_tail(journal_t *journal) if (is_journal_aborted(journal)) return 1; - /* OK, work out the oldest transaction remaining in the log, and + /* + * OK, work out the oldest transaction remaining in the log, and * the log block it starts at. * * If the log is now empty, we need to work out which is the * next transaction ID we will write, and where it will - * start. */ - + * start. + */ spin_lock(&journal->j_state_lock); spin_lock(&journal->j_list_lock); transaction = journal->j_checkpoint_transactions; @@ -504,7 +503,25 @@ int cleanup_journal_tail(journal_t *journal) spin_unlock(&journal->j_state_lock); return 1; } + spin_unlock(&journal->j_state_lock); + + /* + * We need to make sure that any blocks that were recently written out + * --- perhaps by log_do_checkpoint() --- are flushed out before we + * drop the transactions from the journal. It's unlikely this will be + * necessary, especially with an appropriately sized journal, but we + * need this to guarantee correctness. Fortunately + * cleanup_journal_tail() doesn't get called all that often. + */ + if (journal->j_flags & JFS_BARRIER) + blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); + spin_lock(&journal->j_state_lock); + if (!tid_gt(first_tid, journal->j_tail_sequence)) { + spin_unlock(&journal->j_state_lock); + /* Someone else cleaned up journal so return 0 */ + return 0; + } /* OK, update the superblock to recover the freed space. * Physical blocks come first: have we wrapped beyond the end of * the log? */ diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 5b43e96788e6..008bf062fd26 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -20,6 +20,7 @@ #include <linux/fs.h> #include <linux/jbd.h> #include <linux/errno.h> +#include <linux/blkdev.h> #endif /* @@ -263,6 +264,9 @@ int journal_recover(journal_t *journal) err2 = sync_blockdev(journal->j_fs_dev); if (!err) err = err2; + /* Flush disk caches to get replayed data on the permanent storage */ + if (journal->j_flags & JFS_BARRIER) + blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); return err; } diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 23d7451b2938..65ba36b80a9e 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -55,7 +55,7 @@ static DEFINE_SPINLOCK(nsm_lock); * Local NSM state */ u32 __read_mostly nsm_local_state; -int __read_mostly nsm_use_hostnames; +bool __read_mostly nsm_use_hostnames; static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) { diff --git a/fs/mpage.c b/fs/mpage.c index fdfae9fa98cd..643e9f55ef29 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -371,9 +371,6 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages, sector_t last_block_in_bio = 0; struct buffer_head map_bh; unsigned long first_logical_block = 0; - struct blk_plug plug; - - blk_start_plug(&plug); map_bh.b_state = 0; map_bh.b_size = 0; @@ -395,7 +392,6 @@ mpage_readpages(struct address_space *mapping, struct list_head *pages, BUG_ON(!list_empty(pages)); if (bio) mpage_bio_submit(READ, bio); - blk_finish_plug(&plug); return 0; } EXPORT_SYMBOL(mpage_readpages); diff --git a/fs/namei.c b/fs/namei.c index c283a1ec008e..208c6aa4a989 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -140,21 +140,19 @@ static int do_getname(const char __user *filename, char *page) static char *getname_flags(const char __user *filename, int flags, int *empty) { - char *tmp, *result; - - result = ERR_PTR(-ENOMEM); - tmp = __getname(); - if (tmp) { - int retval = do_getname(filename, tmp); - - result = tmp; - if (retval < 0) { - if (retval == -ENOENT && empty) - *empty = 1; - if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { - __putname(tmp); - result = ERR_PTR(retval); - } + char *result = __getname(); + int retval; + + if (!result) + return ERR_PTR(-ENOMEM); + + retval = do_getname(filename, result); + if (retval < 0) { + if (retval == -ENOENT && empty) + *empty = 1; + if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { + __putname(result); + return ERR_PTR(retval); } } audit_getname(result); diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 281ae95932c9..48cfac31f64c 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -90,9 +90,9 @@ static int is_writable(struct pnfs_block_extent *be, sector_t isect) */ struct parallel_io { struct kref refcnt; - struct rpc_call_ops call_ops; - void (*pnfs_callback) (void *data); + void (*pnfs_callback) (void *data, int num_se); void *data; + int bse_count; }; static inline struct parallel_io *alloc_parallel(void *data) @@ -103,6 +103,7 @@ static inline struct parallel_io *alloc_parallel(void *data) if (rv) { rv->data = data; kref_init(&rv->refcnt); + rv->bse_count = 0; } return rv; } @@ -117,7 +118,7 @@ static void destroy_parallel(struct kref *kref) struct parallel_io *p = container_of(kref, struct parallel_io, refcnt); dprintk("%s enter\n", __func__); - p->pnfs_callback(p->data); + p->pnfs_callback(p->data, p->bse_count); kfree(p); } @@ -146,14 +147,19 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect, { struct bio *bio; + npg = min(npg, BIO_MAX_PAGES); bio = bio_alloc(GFP_NOIO, npg); - if (!bio) - return NULL; + if (!bio && (current->flags & PF_MEMALLOC)) { + while (!bio && (npg /= 2)) + bio = bio_alloc(GFP_NOIO, npg); + } - bio->bi_sector = isect - be->be_f_offset + be->be_v_offset; - bio->bi_bdev = be->be_mdev; - bio->bi_end_io = end_io; - bio->bi_private = par; + if (bio) { + bio->bi_sector = isect - be->be_f_offset + be->be_v_offset; + bio->bi_bdev = be->be_mdev; + bio->bi_end_io = end_io; + bio->bi_private = par; + } return bio; } @@ -212,22 +218,15 @@ static void bl_read_cleanup(struct work_struct *work) } static void -bl_end_par_io_read(void *data) +bl_end_par_io_read(void *data, int unused) { struct nfs_read_data *rdata = data; + rdata->task.tk_status = rdata->pnfs_error; INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup); schedule_work(&rdata->task.u.tk_work); } -/* We don't want normal .rpc_call_done callback used, so we replace it - * with this stub. - */ -static void bl_rpc_do_nothing(struct rpc_task *task, void *calldata) -{ - return; -} - static enum pnfs_try_status bl_read_pagelist(struct nfs_read_data *rdata) { @@ -247,8 +246,6 @@ bl_read_pagelist(struct nfs_read_data *rdata) par = alloc_parallel(rdata); if (!par) goto use_mds; - par->call_ops = *rdata->mds_ops; - par->call_ops.rpc_call_done = bl_rpc_do_nothing; par->pnfs_callback = bl_end_par_io_read; /* At this point, we can no longer jump to use_mds */ @@ -322,6 +319,7 @@ static void mark_extents_written(struct pnfs_block_layout *bl, { sector_t isect, end; struct pnfs_block_extent *be; + struct pnfs_block_short_extent *se; dprintk("%s(%llu, %u)\n", __func__, offset, count); if (count == 0) @@ -334,8 +332,11 @@ static void mark_extents_written(struct pnfs_block_layout *bl, be = bl_find_get_extent(bl, isect, NULL); BUG_ON(!be); /* FIXME */ len = min(end, be->be_f_offset + be->be_length) - isect; - if (be->be_state == PNFS_BLOCK_INVALID_DATA) - bl_mark_for_commit(be, isect, len); /* What if fails? */ + if (be->be_state == PNFS_BLOCK_INVALID_DATA) { + se = bl_pop_one_short_extent(be->be_inval); + BUG_ON(!se); + bl_mark_for_commit(be, isect, len, se); + } isect += len; bl_put_extent(be); } @@ -357,7 +358,8 @@ static void bl_end_io_write_zero(struct bio *bio, int err) end_page_writeback(page); page_cache_release(page); } while (bvec >= bio->bi_io_vec); - if (!uptodate) { + + if (unlikely(!uptodate)) { if (!wdata->pnfs_error) wdata->pnfs_error = -EIO; pnfs_set_lo_fail(wdata->lseg); @@ -366,7 +368,6 @@ static void bl_end_io_write_zero(struct bio *bio, int err) put_parallel(par); } -/* This is basically copied from mpage_end_io_read */ static void bl_end_io_write(struct bio *bio, int err) { struct parallel_io *par = bio->bi_private; @@ -392,7 +393,7 @@ static void bl_write_cleanup(struct work_struct *work) dprintk("%s enter\n", __func__); task = container_of(work, struct rpc_task, u.tk_work); wdata = container_of(task, struct nfs_write_data, task); - if (!wdata->pnfs_error) { + if (likely(!wdata->pnfs_error)) { /* Marks for LAYOUTCOMMIT */ mark_extents_written(BLK_LSEG2EXT(wdata->lseg), wdata->args.offset, wdata->args.count); @@ -401,11 +402,16 @@ static void bl_write_cleanup(struct work_struct *work) } /* Called when last of bios associated with a bl_write_pagelist call finishes */ -static void bl_end_par_io_write(void *data) +static void bl_end_par_io_write(void *data, int num_se) { struct nfs_write_data *wdata = data; - wdata->task.tk_status = 0; + if (unlikely(wdata->pnfs_error)) { + bl_free_short_extents(&BLK_LSEG2EXT(wdata->lseg)->bl_inval, + num_se); + } + + wdata->task.tk_status = wdata->pnfs_error; wdata->verf.committed = NFS_FILE_SYNC; INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup); schedule_work(&wdata->task.u.tk_work); @@ -484,6 +490,55 @@ cleanup: return ret; } +/* Find or create a zeroing page marked being writeback. + * Return ERR_PTR on error, NULL to indicate skip this page and page itself + * to indicate write out. + */ +static struct page * +bl_find_get_zeroing_page(struct inode *inode, pgoff_t index, + struct pnfs_block_extent *cow_read) +{ + struct page *page; + int locked = 0; + page = find_get_page(inode->i_mapping, index); + if (page) + goto check_page; + + page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); + if (unlikely(!page)) { + dprintk("%s oom\n", __func__); + return ERR_PTR(-ENOMEM); + } + locked = 1; + +check_page: + /* PageDirty: Other will write this out + * PageWriteback: Other is writing this out + * PageUptodate: It was read before + */ + if (PageDirty(page) || PageWriteback(page)) { + print_page(page); + if (locked) + unlock_page(page); + page_cache_release(page); + return NULL; + } + + if (!locked) { + lock_page(page); + locked = 1; + goto check_page; + } + if (!PageUptodate(page)) { + /* New page, readin or zero it */ + init_page_for_write(page, cow_read); + } + set_page_writeback(page); + unlock_page(page); + + return page; +} + static enum pnfs_try_status bl_write_pagelist(struct nfs_write_data *wdata, int sync) { @@ -508,9 +563,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) */ par = alloc_parallel(wdata); if (!par) - return PNFS_NOT_ATTEMPTED; - par->call_ops = *wdata->mds_ops; - par->call_ops.rpc_call_done = bl_rpc_do_nothing; + goto out_mds; par->pnfs_callback = bl_end_par_io_write; /* At this point, have to be more careful with error handling */ @@ -518,12 +571,15 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), isect, &cow_read); if (!be || !is_writable(be, isect)) { dprintk("%s no matching extents!\n", __func__); - wdata->pnfs_error = -EINVAL; - goto out; + goto out_mds; } /* First page inside INVALID extent */ if (be->be_state == PNFS_BLOCK_INVALID_DATA) { + if (likely(!bl_push_one_short_extent(be->be_inval))) + par->bse_count++; + else + goto out_mds; temp = offset >> PAGE_CACHE_SHIFT; npg_zero = do_div(temp, npg_per_block); isect = (sector_t) (((offset - npg_zero * PAGE_CACHE_SIZE) & @@ -543,36 +599,16 @@ fill_invalid_ext: dprintk("%s zero %dth page: index %lu isect %llu\n", __func__, npg_zero, index, (unsigned long long)isect); - page = - find_or_create_page(wdata->inode->i_mapping, index, - GFP_NOFS); - if (!page) { - dprintk("%s oom\n", __func__); - wdata->pnfs_error = -ENOMEM; + page = bl_find_get_zeroing_page(wdata->inode, index, + cow_read); + if (unlikely(IS_ERR(page))) { + wdata->pnfs_error = PTR_ERR(page); goto out; - } - - /* PageDirty: Other will write this out - * PageWriteback: Other is writing this out - * PageUptodate: It was read before - * sector_initialized: already written out - */ - if (PageDirty(page) || PageWriteback(page)) { - print_page(page); - unlock_page(page); - page_cache_release(page); + } else if (page == NULL) goto next_page; - } - if (!PageUptodate(page)) { - /* New page, readin or zero it */ - init_page_for_write(page, cow_read); - } - set_page_writeback(page); - unlock_page(page); ret = bl_mark_sectors_init(be->be_inval, isect, - PAGE_CACHE_SECTORS, - NULL); + PAGE_CACHE_SECTORS); if (unlikely(ret)) { dprintk("%s bl_mark_sectors_init fail %d\n", __func__, ret); @@ -581,6 +617,19 @@ fill_invalid_ext: wdata->pnfs_error = ret; goto out; } + if (likely(!bl_push_one_short_extent(be->be_inval))) + par->bse_count++; + else { + end_page_writeback(page); + page_cache_release(page); + wdata->pnfs_error = -ENOMEM; + goto out; + } + /* FIXME: This should be done in bi_end_io */ + mark_extents_written(BLK_LSEG2EXT(wdata->lseg), + page->index << PAGE_CACHE_SHIFT, + PAGE_CACHE_SIZE); + bio = bl_add_page_to_bio(bio, npg_zero, WRITE, isect, page, be, bl_end_io_write_zero, par); @@ -589,10 +638,6 @@ fill_invalid_ext: bio = NULL; goto out; } - /* FIXME: This should be done in bi_end_io */ - mark_extents_written(BLK_LSEG2EXT(wdata->lseg), - page->index << PAGE_CACHE_SHIFT, - PAGE_CACHE_SIZE); next_page: isect += PAGE_CACHE_SECTORS; extent_length -= PAGE_CACHE_SECTORS; @@ -616,13 +661,21 @@ next_page: wdata->pnfs_error = -EINVAL; goto out; } + if (be->be_state == PNFS_BLOCK_INVALID_DATA) { + if (likely(!bl_push_one_short_extent( + be->be_inval))) + par->bse_count++; + else { + wdata->pnfs_error = -ENOMEM; + goto out; + } + } extent_length = be->be_length - (isect - be->be_f_offset); } if (be->be_state == PNFS_BLOCK_INVALID_DATA) { ret = bl_mark_sectors_init(be->be_inval, isect, - PAGE_CACHE_SECTORS, - NULL); + PAGE_CACHE_SECTORS); if (unlikely(ret)) { dprintk("%s bl_mark_sectors_init fail %d\n", __func__, ret); @@ -664,6 +717,10 @@ out: bl_submit_bio(WRITE, bio); put_parallel(par); return PNFS_ATTEMPTED; +out_mds: + bl_put_extent(be); + kfree(par); + return PNFS_NOT_ATTEMPTED; } /* FIXME - range ignored */ @@ -690,11 +747,17 @@ static void release_inval_marks(struct pnfs_inval_markings *marks) { struct pnfs_inval_tracking *pos, *temp; + struct pnfs_block_short_extent *se, *stemp; list_for_each_entry_safe(pos, temp, &marks->im_tree.mtt_stub, it_link) { list_del(&pos->it_link); kfree(pos); } + + list_for_each_entry_safe(se, stemp, &marks->im_extents, bse_node) { + list_del(&se->bse_node); + kfree(se); + } return; } @@ -779,16 +842,13 @@ bl_cleanup_layoutcommit(struct nfs4_layoutcommit_data *lcdata) static void free_blk_mountid(struct block_mount_id *mid) { if (mid) { - struct pnfs_block_dev *dev; - spin_lock(&mid->bm_lock); - while (!list_empty(&mid->bm_devlist)) { - dev = list_first_entry(&mid->bm_devlist, - struct pnfs_block_dev, - bm_node); + struct pnfs_block_dev *dev, *tmp; + + /* No need to take bm_lock as we are last user freeing bm_devlist */ + list_for_each_entry_safe(dev, tmp, &mid->bm_devlist, bm_node) { list_del(&dev->bm_node); bl_free_block_dev(dev); } - spin_unlock(&mid->bm_lock); kfree(mid); } } diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index 42acf7ef5992..e31a2df28e70 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h @@ -70,6 +70,7 @@ struct pnfs_inval_markings { spinlock_t im_lock; struct my_tree im_tree; /* Sectors that need LAYOUTCOMMIT */ sector_t im_block_size; /* Server blocksize in sectors */ + struct list_head im_extents; /* Short extents for INVAL->RW conversion */ }; struct pnfs_inval_tracking { @@ -105,6 +106,7 @@ BL_INIT_INVAL_MARKS(struct pnfs_inval_markings *marks, sector_t blocksize) { spin_lock_init(&marks->im_lock); INIT_LIST_HEAD(&marks->im_tree.mtt_stub); + INIT_LIST_HEAD(&marks->im_extents); marks->im_block_size = blocksize; marks->im_tree.mtt_step_size = min((sector_t)PAGE_CACHE_SECTORS, blocksize); @@ -186,8 +188,7 @@ struct pnfs_block_extent * bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect, struct pnfs_block_extent **cow_read); int bl_mark_sectors_init(struct pnfs_inval_markings *marks, - sector_t offset, sector_t length, - sector_t **pages); + sector_t offset, sector_t length); void bl_put_extent(struct pnfs_block_extent *be); struct pnfs_block_extent *bl_alloc_extent(void); int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect); @@ -200,6 +201,11 @@ void clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl, int bl_add_merge_extent(struct pnfs_block_layout *bl, struct pnfs_block_extent *new); int bl_mark_for_commit(struct pnfs_block_extent *be, - sector_t offset, sector_t length); + sector_t offset, sector_t length, + struct pnfs_block_short_extent *new); +int bl_push_one_short_extent(struct pnfs_inval_markings *marks); +struct pnfs_block_short_extent * +bl_pop_one_short_extent(struct pnfs_inval_markings *marks); +void bl_free_short_extents(struct pnfs_inval_markings *marks, int num_to_free); #endif /* FS_NFS_NFS4BLOCKLAYOUT_H */ diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c index 19fa7b0b8c00..1abac09f7cd5 100644 --- a/fs/nfs/blocklayout/extents.c +++ b/fs/nfs/blocklayout/extents.c @@ -110,13 +110,7 @@ static int _add_entry(struct my_tree *tree, u64 s, int32_t tag, return 0; } else { struct pnfs_inval_tracking *new; - if (storage) - new = storage; - else { - new = kmalloc(sizeof(*new), GFP_NOFS); - if (!new) - return -ENOMEM; - } + new = storage; new->it_sector = s; new->it_tags = (1 << tag); list_add(&new->it_link, &pos->it_link); @@ -139,11 +133,13 @@ static int _set_range(struct my_tree *tree, int32_t tag, u64 s, u64 length) } /* Ensure that future operations on given range of tree will not malloc */ -static int _preload_range(struct my_tree *tree, u64 offset, u64 length) +static int _preload_range(struct pnfs_inval_markings *marks, + u64 offset, u64 length) { u64 start, end, s; int count, i, used = 0, status = -ENOMEM; struct pnfs_inval_tracking **storage; + struct my_tree *tree = &marks->im_tree; dprintk("%s(%llu, %llu) enter\n", __func__, offset, length); start = normalize(offset, tree->mtt_step_size); @@ -161,12 +157,11 @@ static int _preload_range(struct my_tree *tree, u64 offset, u64 length) goto out_cleanup; } - /* Now need lock - HOW??? */ - + spin_lock_bh(&marks->im_lock); for (s = start; s < end; s += tree->mtt_step_size) used += _add_entry(tree, s, INTERNAL_EXISTS, storage[used]); + spin_unlock_bh(&marks->im_lock); - /* Unlock - HOW??? */ status = 0; out_cleanup: @@ -179,41 +174,14 @@ static int _preload_range(struct my_tree *tree, u64 offset, u64 length) return status; } -static void set_needs_init(sector_t *array, sector_t offset) -{ - sector_t *p = array; - - dprintk("%s enter\n", __func__); - if (!p) - return; - while (*p < offset) - p++; - if (*p == offset) - return; - else if (*p == ~0) { - *p++ = offset; - *p = ~0; - return; - } else { - sector_t *save = p; - dprintk("%s Adding %llu\n", __func__, (u64)offset); - while (*p != ~0) - p++; - p++; - memmove(save + 1, save, (char *)p - (char *)save); - *save = offset; - return; - } -} - /* We are relying on page lock to serialize this */ int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect) { int rv; - spin_lock(&marks->im_lock); + spin_lock_bh(&marks->im_lock); rv = _has_tag(&marks->im_tree, isect, EXTENT_INITIALIZED); - spin_unlock(&marks->im_lock); + spin_unlock_bh(&marks->im_lock); return rv; } @@ -253,78 +221,39 @@ static int is_range_written(struct pnfs_inval_markings *marks, { int rv; - spin_lock(&marks->im_lock); + spin_lock_bh(&marks->im_lock); rv = _range_has_tag(&marks->im_tree, start, end, EXTENT_WRITTEN); - spin_unlock(&marks->im_lock); + spin_unlock_bh(&marks->im_lock); return rv; } /* Marks sectors in [offest, offset_length) as having been initialized. * All lengths are step-aligned, where step is min(pagesize, blocksize). - * Notes where partial block is initialized, and helps prepare it for - * complete initialization later. + * Currently assumes offset is page-aligned */ -/* Currently assumes offset is page-aligned */ int bl_mark_sectors_init(struct pnfs_inval_markings *marks, - sector_t offset, sector_t length, - sector_t **pages) + sector_t offset, sector_t length) { - sector_t s, start, end; - sector_t *array = NULL; /* Pages to mark */ + sector_t start, end; dprintk("%s(offset=%llu,len=%llu) enter\n", __func__, (u64)offset, (u64)length); - s = max((sector_t) 3, - 2 * (marks->im_block_size / (PAGE_CACHE_SECTORS))); - dprintk("%s set max=%llu\n", __func__, (u64)s); - if (pages) { - array = kmalloc(s * sizeof(sector_t), GFP_NOFS); - if (!array) - goto outerr; - array[0] = ~0; - } start = normalize(offset, marks->im_block_size); end = normalize_up(offset + length, marks->im_block_size); - if (_preload_range(&marks->im_tree, start, end - start)) + if (_preload_range(marks, start, end - start)) goto outerr; - spin_lock(&marks->im_lock); - - for (s = normalize_up(start, PAGE_CACHE_SECTORS); - s < offset; s += PAGE_CACHE_SECTORS) { - dprintk("%s pre-area pages\n", __func__); - /* Portion of used block is not initialized */ - if (!_has_tag(&marks->im_tree, s, EXTENT_INITIALIZED)) - set_needs_init(array, s); - } + spin_lock_bh(&marks->im_lock); if (_set_range(&marks->im_tree, EXTENT_INITIALIZED, offset, length)) goto out_unlock; - for (s = normalize_up(offset + length, PAGE_CACHE_SECTORS); - s < end; s += PAGE_CACHE_SECTORS) { - dprintk("%s post-area pages\n", __func__); - if (!_has_tag(&marks->im_tree, s, EXTENT_INITIALIZED)) - set_needs_init(array, s); - } - - spin_unlock(&marks->im_lock); + spin_unlock_bh(&marks->im_lock); - if (pages) { - if (array[0] == ~0) { - kfree(array); - *pages = NULL; - } else - *pages = array; - } return 0; - out_unlock: - spin_unlock(&marks->im_lock); - outerr: - if (pages) { - kfree(array); - *pages = NULL; - } +out_unlock: + spin_unlock_bh(&marks->im_lock); +outerr: return -ENOMEM; } @@ -338,9 +267,9 @@ static int mark_written_sectors(struct pnfs_inval_markings *marks, dprintk("%s(offset=%llu,len=%llu) enter\n", __func__, (u64)offset, (u64)length); - spin_lock(&marks->im_lock); + spin_lock_bh(&marks->im_lock); status = _set_range(&marks->im_tree, EXTENT_WRITTEN, offset, length); - spin_unlock(&marks->im_lock); + spin_unlock_bh(&marks->im_lock); return status; } @@ -440,20 +369,18 @@ static void add_to_commitlist(struct pnfs_block_layout *bl, /* Note the range described by offset, length is guaranteed to be contained * within be. + * new will be freed, either by this function or add_to_commitlist if they + * decide not to use it, or after LAYOUTCOMMIT uses it in the commitlist. */ int bl_mark_for_commit(struct pnfs_block_extent *be, - sector_t offset, sector_t length) + sector_t offset, sector_t length, + struct pnfs_block_short_extent *new) { sector_t new_end, end = offset + length; - struct pnfs_block_short_extent *new; struct pnfs_block_layout *bl = container_of(be->be_inval, struct pnfs_block_layout, bl_inval); - new = kmalloc(sizeof(*new), GFP_NOFS); - if (!new) - return -ENOMEM; - mark_written_sectors(be->be_inval, offset, length); /* We want to add the range to commit list, but it must be * block-normalized, and verified that the normalized range has @@ -483,9 +410,6 @@ int bl_mark_for_commit(struct pnfs_block_extent *be, new->bse_mdev = be->be_mdev; spin_lock(&bl->bl_ext_lock); - /* new will be freed, either by add_to_commitlist if it decides not - * to use it, or after LAYOUTCOMMIT uses it in the commitlist. - */ add_to_commitlist(bl, new); spin_unlock(&bl->bl_ext_lock); return 0; @@ -933,3 +857,53 @@ clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl, } } } + +int bl_push_one_short_extent(struct pnfs_inval_markings *marks) +{ + struct pnfs_block_short_extent *new; + + new = kmalloc(sizeof(*new), GFP_NOFS); + if (unlikely(!new)) + return -ENOMEM; + + spin_lock_bh(&marks->im_lock); + list_add(&new->bse_node, &marks->im_extents); + spin_unlock_bh(&marks->im_lock); + + return 0; +} + +struct pnfs_block_short_extent * +bl_pop_one_short_extent(struct pnfs_inval_markings *marks) +{ + struct pnfs_block_short_extent *rv = NULL; + + spin_lock_bh(&marks->im_lock); + if (!list_empty(&marks->im_extents)) { + rv = list_entry((&marks->im_extents)->next, + struct pnfs_block_short_extent, bse_node); + list_del_init(&rv->bse_node); + } + spin_unlock_bh(&marks->im_lock); + + return rv; +} + +void bl_free_short_extents(struct pnfs_inval_markings *marks, int num_to_free) +{ + struct pnfs_block_short_extent *se = NULL, *tmp; + + if (num_to_free <= 0) + return; + + spin_lock(&marks->im_lock); + list_for_each_entry_safe(se, tmp, &marks->im_extents, bse_node) { + list_del(&se->bse_node); + kfree(se); + if (--num_to_free == 0) + break; + } + spin_unlock(&marks->im_lock); + + BUG_ON(num_to_free > 0); +} diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index 07df5f1d85e5..c89d3b9e483c 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h @@ -162,7 +162,7 @@ struct cb_layoutrecallargs { }; }; -extern unsigned nfs4_callback_layoutrecall( +extern __be32 nfs4_callback_layoutrecall( struct cb_layoutrecallargs *args, void *dummy, struct cb_process_state *cps); diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 726e59a9e50f..d50b2742f23b 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -305,6 +305,10 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp, n = ntohl(*p++); if (n <= 0) goto out; + if (n > ULONG_MAX / sizeof(*args->devs)) { + status = htonl(NFS4ERR_BADXDR); + goto out; + } args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL); if (!args->devs) { diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 277dfaf2e99a..31778f74357d 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -84,7 +84,7 @@ retry: /* * Turn off NFSv4 uid/gid mapping when using AUTH_SYS */ -static int nfs4_disable_idmapping = 1; +static bool nfs4_disable_idmapping = true; /* * RPC cruft for NFS diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 25c3bfad7953..f649fba8c384 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -57,7 +57,7 @@ #define NFS_64_BIT_INODE_NUMBERS_ENABLED 1 /* Default is to see 64-bit inode numbers */ -static int enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED; +static bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED; static void nfs_invalidate_inode(struct inode *); static int nfs_update_inode(struct inode *, struct nfs_fattr *); diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index ed388aae9689..8ae91908f5aa 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c @@ -382,7 +382,7 @@ decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags) { struct nfs4_pnfs_ds_addr *da = NULL; char *buf, *portstr; - u32 port; + __be16 port; int nlen, rlen; int tmp[2]; __be32 *p; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 75366dc89686..f0c849c98fe4 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3587,7 +3587,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu res.acl_flags |= NFS4_ACL_LEN_REQUEST; resp_buf = page_address(pages[0]); - dprintk("%s buf %p buflen %ld npages %d args.acl_len %ld\n", + dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", __func__, buf, buflen, npages, args.acl_len); ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 10e6366608f2..8df1ea4a6ff9 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -80,3 +80,13 @@ config NFSD_V4 available from http://linux-nfs.org/. If unsure, say N. + +config NFSD_FAULT_INJECTION + bool "NFS server manual fault injection" + depends on NFSD_V4 && DEBUG_KERNEL + help + This option enables support for manually injecting faults + into the NFS server. This is intended to be used for + testing error recovery on the NFS client. + + If unsure, say N. diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index 9b118ee20193..af32ef06b4fe 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_NFSD) += nfsd.o nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o +nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 62f3b9074e84..cf8a6bd062fa 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -87,7 +87,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) struct svc_expkey key; struct svc_expkey *ek = NULL; - if (mesg[mlen-1] != '\n') + if (mlen < 1 || mesg[mlen-1] != '\n') return -EINVAL; mesg[mlen-1] = 0; @@ -1226,12 +1226,12 @@ nfsd_export_init(void) int rv; dprintk("nfsd: initializing export module.\n"); - rv = cache_register(&svc_export_cache); + rv = cache_register_net(&svc_export_cache, &init_net); if (rv) return rv; - rv = cache_register(&svc_expkey_cache); + rv = cache_register_net(&svc_expkey_cache, &init_net); if (rv) - cache_unregister(&svc_export_cache); + cache_unregister_net(&svc_export_cache, &init_net); return rv; } @@ -1255,8 +1255,8 @@ nfsd_export_shutdown(void) dprintk("nfsd: shutting down export module.\n"); - cache_unregister(&svc_expkey_cache); - cache_unregister(&svc_export_cache); + cache_unregister_net(&svc_expkey_cache, &init_net); + cache_unregister_net(&svc_export_cache, &init_net); svcauth_unix_purge(); dprintk("nfsd: export shutdown complete.\n"); diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c new file mode 100644 index 000000000000..ce7f0758d84c --- /dev/null +++ b/fs/nfsd/fault_inject.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com> + * + * Uses debugfs to create fault injection points for client testing + */ + +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/debugfs.h> +#include <linux/module.h> + +#include "state.h" +#include "fault_inject.h" + +struct nfsd_fault_inject_op { + char *file; + void (*func)(u64); +}; + +static struct nfsd_fault_inject_op inject_ops[] = { + { + .file = "forget_clients", + .func = nfsd_forget_clients, + }, + { + .file = "forget_locks", + .func = nfsd_forget_locks, + }, + { + .file = "forget_openowners", + .func = nfsd_forget_openowners, + }, + { + .file = "forget_delegations", + .func = nfsd_forget_delegations, + }, + { + .file = "recall_delegations", + .func = nfsd_recall_delegations, + }, +}; + +static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op); +static struct dentry *debug_dir; + +static int nfsd_inject_set(void *op_ptr, u64 val) +{ + struct nfsd_fault_inject_op *op = op_ptr; + + if (val == 0) + printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file); + else + printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val); + + op->func(val); + return 0; +} + +static int nfsd_inject_get(void *data, u64 *val) +{ + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n"); + +void nfsd_fault_inject_cleanup(void) +{ + debugfs_remove_recursive(debug_dir); +} + +int nfsd_fault_inject_init(void) +{ + unsigned int i; + struct nfsd_fault_inject_op *op; + mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; + + debug_dir = debugfs_create_dir("nfsd", NULL); + if (!debug_dir) + goto fail; + + for (i = 0; i < NUM_INJECT_OPS; i++) { + op = &inject_ops[i]; + if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd)) + goto fail; + } + return 0; + +fail: + nfsd_fault_inject_cleanup(); + return -ENOMEM; +} diff --git a/fs/nfsd/fault_inject.h b/fs/nfsd/fault_inject.h new file mode 100644 index 000000000000..90bd0570956c --- /dev/null +++ b/fs/nfsd/fault_inject.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com> + * + * Function definitions for fault injection + */ + +#ifndef LINUX_NFSD_FAULT_INJECT_H +#define LINUX_NFSD_FAULT_INJECT_H + +#ifdef CONFIG_NFSD_FAULT_INJECTION +int nfsd_fault_inject_init(void); +void nfsd_fault_inject_cleanup(void); +void nfsd_forget_clients(u64); +void nfsd_forget_locks(u64); +void nfsd_forget_openowners(u64); +void nfsd_forget_delegations(u64); +void nfsd_recall_delegations(u64); +#else /* CONFIG_NFSD_FAULT_INJECTION */ +static inline int nfsd_fault_inject_init(void) { return 0; } +static inline void nfsd_fault_inject_cleanup(void) {} +static inline void nfsd_forget_clients(u64 num) {} +static inline void nfsd_forget_locks(u64 num) {} +static inline void nfsd_forget_openowners(u64 num) {} +static inline void nfsd_forget_delegations(u64 num) {} +static inline void nfsd_recall_delegations(u64 num) {} +#endif /* CONFIG_NFSD_FAULT_INJECTION */ + +#endif /* LINUX_NFSD_FAULT_INJECT_H */ diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 55780a22fdbd..94096273cd6c 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -36,6 +36,7 @@ #include <linux/seq_file.h> #include <linux/sched.h> #include <linux/slab.h> +#include <net/net_namespace.h> #include "idmap.h" #include "nfsd.h" @@ -466,20 +467,20 @@ nfsd_idmap_init(void) { int rv; - rv = cache_register(&idtoname_cache); + rv = cache_register_net(&idtoname_cache, &init_net); if (rv) return rv; - rv = cache_register(&nametoid_cache); + rv = cache_register_net(&nametoid_cache, &init_net); if (rv) - cache_unregister(&idtoname_cache); + cache_unregister_net(&idtoname_cache, &init_net); return rv; } void nfsd_idmap_shutdown(void) { - cache_unregister(&idtoname_cache); - cache_unregister(&nametoid_cache); + cache_unregister_net(&idtoname_cache, &init_net); + cache_unregister_net(&nametoid_cache, &init_net); } static int diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index c5e28ed8bca0..896da74ec563 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -266,10 +266,6 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ { __be32 status; - /* Only reclaims from previously confirmed clients are valid */ - if ((status = nfs4_check_open_reclaim(&open->op_clientid))) - return status; - /* We don't know the target directory, and therefore can not * set the change info */ @@ -373,6 +369,9 @@ 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); + if (status) + goto out; case NFS4_OPEN_CLAIM_FH: case NFS4_OPEN_CLAIM_DELEG_CUR_FH: status = do_open_fhandle(rqstp, &cstate->current_fh, diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 80a0be9ed008..0b3e875d1abd 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -117,8 +117,7 @@ out_no_tfm: return status; } -int -nfsd4_create_clid_dir(struct nfs4_client *clp) +void nfsd4_create_clid_dir(struct nfs4_client *clp) { const struct cred *original_cred; char *dname = clp->cl_recdir; @@ -127,13 +126,14 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); - if (!rec_file || clp->cl_firststate) - return 0; - + if (clp->cl_firststate) + return; clp->cl_firststate = 1; + if (!rec_file) + return; status = nfs4_save_creds(&original_cred); if (status < 0) - return status; + return; dir = rec_file->f_path.dentry; /* lock the parent */ @@ -144,8 +144,15 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) status = PTR_ERR(dentry); goto out_unlock; } - status = -EEXIST; if (dentry->d_inode) + /* + * In the 4.1 case, where we're called from + * reclaim_complete(), records from the previous reboot + * may still be left, so this is OK. + * + * In the 4.0 case, we should never get here; but we may + * as well be forgiving and just succeed silently. + */ goto out_put; status = mnt_want_write_file(rec_file); if (status) @@ -164,7 +171,6 @@ out_unlock: " and is writeable", status, user_recovery_dirname); nfs4_reset_creds(original_cred); - return status; } typedef int (recdir_func)(struct dentry *, struct dentry *); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9ca16dc09e04..e8c98f009670 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -49,12 +49,20 @@ time_t nfsd4_lease = 90; /* default lease time */ time_t nfsd4_grace = 90; static time_t boot_time; -static stateid_t zerostateid; /* bits all 0 */ -static stateid_t onestateid; /* bits all 1 */ + +#define all_ones {{~0,~0},~0} +static const stateid_t one_stateid = { + .si_generation = ~0, + .si_opaque = all_ones, +}; +static const stateid_t zero_stateid = { + /* all fields zero */ +}; + static u64 current_sessionid = 1; -#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) -#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) +#define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) +#define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) /* forward declarations */ static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); @@ -133,21 +141,21 @@ unsigned int max_delegations; * Open owner state (share locks) */ -/* hash tables for open owners */ -#define OPEN_OWNER_HASH_BITS 8 -#define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS) -#define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1) +/* hash tables for lock and open owners */ +#define OWNER_HASH_BITS 8 +#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) +#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) -static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) +static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) { unsigned int ret; ret = opaque_hashval(ownername->data, ownername->len); ret += clientid; - return ret & OPEN_OWNER_HASH_MASK; + return ret & OWNER_HASH_MASK; } -static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE]; +static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; /* hash table for nfs4_file */ #define FILE_HASH_BITS 8 @@ -514,6 +522,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo) list_del(&lo->lo_owner.so_strhash); list_del(&lo->lo_perstateid); + list_del(&lo->lo_owner_ino_hash); while (!list_empty(&lo->lo_owner.so_stateids)) { stp = list_first_entry(&lo->lo_owner.so_stateids, struct nfs4_ol_stateid, st_perstateowner); @@ -985,12 +994,11 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); if (clp == NULL) return NULL; - clp->cl_name.data = kmalloc(name.len, GFP_KERNEL); + clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); if (clp->cl_name.data == NULL) { kfree(clp); return NULL; } - memcpy(clp->cl_name.data, name.data, name.len); clp->cl_name.len = name.len; return clp; } @@ -1058,7 +1066,6 @@ expire_client(struct nfs4_client *clp) spin_unlock(&recall_lock); while (!list_empty(&reaplist)) { dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); - list_del_init(&dp->dl_recall_lru); unhash_delegation(dp); } while (!list_empty(&clp->cl_openowners)) { @@ -2301,7 +2308,7 @@ nfsd4_free_slabs(void) nfsd4_free_slab(&deleg_slab); } -static int +int nfsd4_init_slabs(void) { openowner_slab = kmem_cache_create("nfsd4_openowners", @@ -2373,7 +2380,7 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) { - list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]); + list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); list_add(&oo->oo_perclient, &clp->cl_openowners); } @@ -2436,7 +2443,9 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) struct nfs4_stateowner *so; struct nfs4_openowner *oo; - list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) { + 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); renew_client(oo->oo_owner.so_client); @@ -2580,7 +2589,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, if (open->op_file == NULL) return nfserr_jukebox; - strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner); + strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); oo = find_openstateowner_str(strhashval, open); open->op_openowner = oo; if (!oo) { @@ -3123,7 +3132,6 @@ nfs4_laundromat(void) spin_unlock(&recall_lock); list_for_each_safe(pos, next, &reaplist) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); - list_del_init(&dp->dl_recall_lru); unhash_delegation(dp); } test_val = nfsd4_lease; @@ -3718,13 +3726,11 @@ out: } -/* - * Lock owner state (byte-range locks) - */ #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) -#define LOCK_HASH_BITS 8 -#define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS) -#define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1) + +#define LOCKOWNER_INO_HASH_BITS 8 +#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS) +#define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) static inline u64 end_offset(u64 start, u64 len) @@ -3746,16 +3752,14 @@ last_byte_offset(u64 start, u64 len) return end > start ? end - 1: NFS4_MAX_UINT64; } -static inline unsigned int -lock_ownerstr_hashval(struct inode *inode, u32 cl_id, - struct xdr_netobj *ownername) +static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername) { return (file_hashval(inode) + cl_id + opaque_hashval(ownername->data, ownername->len)) - & LOCK_HASH_MASK; + & LOCKOWNER_INO_HASH_MASK; } -static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; +static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE]; /* * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that @@ -3809,23 +3813,39 @@ nevermind: deny->ld_type = NFS4_WRITE_LT; } +static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner) +{ + struct nfs4_ol_stateid *lst; + + if (!same_owner_str(&lo->lo_owner, owner, clid)) + return false; + lst = list_first_entry(&lo->lo_owner.so_stateids, + struct nfs4_ol_stateid, st_perstateowner); + return lst->st_file->fi_inode == inode; +} + static struct nfs4_lockowner * find_lockowner_str(struct inode *inode, clientid_t *clid, struct xdr_netobj *owner) { - unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner); - struct nfs4_stateowner *op; + unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); + struct nfs4_lockowner *lo; - list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { - if (same_owner_str(op, owner, clid)) - return lockowner(op); + list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { + if (same_lockowner_ino(lo, inode, clid, owner)) + return lo; } return NULL; } static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp) { - list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]); + struct inode *inode = open_stp->st_file->fi_inode; + unsigned int inohash = lockowner_ino_hashval(inode, + clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); + + list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]); + list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]); list_add(&lo->lo_perstateid, &open_stp->st_lockowners); } @@ -3834,7 +3854,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has * occurred. * - * strhashval = lock_ownerstr_hashval + * strhashval = ownerstr_hashval */ static struct nfs4_lockowner * @@ -3892,6 +3912,37 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) __set_bit(access, &lock_stp->st_access_bmap); } +__be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) +{ + struct nfs4_file *fi = ost->st_file; + struct nfs4_openowner *oo = openowner(ost->st_stateowner); + struct nfs4_client *cl = oo->oo_owner.so_client; + struct nfs4_lockowner *lo; + unsigned int strhashval; + + lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner); + if (lo) { + if (!cstate->minorversion) + return nfserr_bad_seqid; + /* XXX: a lockowner always has exactly one stateid: */ + *lst = list_first_entry(&lo->lo_owner.so_stateids, + struct nfs4_ol_stateid, st_perstateowner); + return nfs_ok; + } + strhashval = ownerstr_hashval(cl->cl_clientid.cl_id, + &lock->v.new.owner); + lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); + if (lo == NULL) + return nfserr_jukebox; + *lst = alloc_init_lock_stateid(lo, fi, ost); + if (*lst == NULL) { + release_lockowner(lo); + return nfserr_jukebox; + } + *new = true; + return nfs_ok; +} + /* * LOCK operation */ @@ -3907,7 +3958,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct file_lock file_lock; struct file_lock conflock; __be32 status = 0; - unsigned int strhashval; + bool new_state = false; int lkflg; int err; @@ -3933,10 +3984,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * lock stateid. */ struct nfs4_ol_stateid *open_stp = NULL; - + + if (nfsd4_has_session(cstate)) + /* See rfc 5661 18.10.3: given clientid is ignored: */ + memcpy(&lock->v.new.clientid, + &cstate->session->se_client->cl_clientid, + sizeof(clientid_t)); + status = nfserr_stale_clientid; - if (!nfsd4_has_session(cstate) && - STALE_CLIENTID(&lock->lk_new_clientid)) + if (STALE_CLIENTID(&lock->lk_new_clientid)) goto out; /* validate and update open stateid and open seqid */ @@ -3948,25 +4004,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; open_sop = openowner(open_stp->st_stateowner); status = nfserr_bad_stateid; - if (!nfsd4_has_session(cstate) && - !same_clid(&open_sop->oo_owner.so_client->cl_clientid, + if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, &lock->v.new.clientid)) goto out; - /* create lockowner and lock stateid */ - fp = open_stp->st_file; - strhashval = lock_ownerstr_hashval(fp->fi_inode, - open_sop->oo_owner.so_client->cl_clientid.cl_id, - &lock->v.new.owner); - /* XXX: Do we need to check for duplicate stateowners on - * the same file, or should they just be allowed (and - * create new stateids)? */ - status = nfserr_jukebox; - lock_sop = alloc_init_lock_stateowner(strhashval, - open_sop->oo_owner.so_client, open_stp, lock); - if (lock_sop == NULL) - goto out; - lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); - if (lock_stp == NULL) + status = lookup_or_create_lock_state(cstate, open_stp, lock, + &lock_stp, &new_state); + if (status) goto out; } else { /* lock (lock owner + lock stateid) already exists */ @@ -3976,10 +4019,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, NFS4_LOCK_STID, &lock_stp); if (status) goto out; - lock_sop = lockowner(lock_stp->st_stateowner); - fp = lock_stp->st_file; } - /* lock_sop and lock_stp have been created or found */ + lock_sop = lockowner(lock_stp->st_stateowner); + fp = lock_stp->st_file; lkflg = setlkflg(lock->lk_type); status = nfs4_check_openmode(lock_stp, lkflg); @@ -4054,7 +4096,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; } out: - if (status && lock->lk_is_new && lock_sop) + if (status && new_state) release_lockowner(lock_sop); if (!cstate->replay_owner) nfs4_unlock_state(); @@ -4251,7 +4293,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfs4_ol_stateid *stp; struct xdr_netobj *owner = &rlockowner->rl_owner; struct list_head matches; - int i; + unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); __be32 status; dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", @@ -4266,22 +4308,19 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, nfs4_lock_state(); status = nfserr_locks_held; - /* XXX: we're doing a linear search through all the lockowners. - * Yipes! For now we'll just hope clients aren't really using - * release_lockowner much, but eventually we have to fix these - * data structures. */ INIT_LIST_HEAD(&matches); - for (i = 0; i < LOCK_HASH_SIZE; i++) { - list_for_each_entry(sop, &lock_ownerstr_hashtbl[i], so_strhash) { - if (!same_owner_str(sop, owner, clid)) - continue; - list_for_each_entry(stp, &sop->so_stateids, - st_perstateowner) { - lo = lockowner(sop); - if (check_for_locks(stp->st_file, lo)) - goto out; - list_add(&lo->lo_list, &matches); - } + + list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) { + if (sop->so_is_open_owner) + continue; + if (!same_owner_str(sop, owner, clid)) + continue; + list_for_each_entry(stp, &sop->so_stateids, + st_perstateowner) { + lo = lockowner(sop); + if (check_for_locks(stp->st_file, lo)) + goto out; + list_add(&lo->lo_list, &matches); } } /* Clients probably won't expect us to return with some (but not all) @@ -4394,16 +4433,127 @@ nfs4_check_open_reclaim(clientid_t *clid) return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; } +#ifdef CONFIG_NFSD_FAULT_INJECTION + +void nfsd_forget_clients(u64 num) +{ + struct nfs4_client *clp, *next; + int count = 0; + + nfs4_lock_state(); + list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { + nfsd4_remove_clid_dir(clp); + expire_client(clp); + if (++count == num) + break; + } + nfs4_unlock_state(); + + printk(KERN_INFO "NFSD: Forgot %d clients", count); +} + +static void release_lockowner_sop(struct nfs4_stateowner *sop) +{ + release_lockowner(lockowner(sop)); +} + +static void release_openowner_sop(struct nfs4_stateowner *sop) +{ + release_openowner(openowner(sop)); +} + +static int nfsd_release_n_owners(u64 num, bool is_open_owner, + void (*release_sop)(struct nfs4_stateowner *)) +{ + int i, count = 0; + struct nfs4_stateowner *sop, *next; + + for (i = 0; i < OWNER_HASH_SIZE; i++) { + list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) { + if (sop->so_is_open_owner != is_open_owner) + continue; + release_sop(sop); + if (++count == num) + return count; + } + } + return count; +} + +void nfsd_forget_locks(u64 num) +{ + int count; + + nfs4_lock_state(); + count = nfsd_release_n_owners(num, false, release_lockowner_sop); + nfs4_unlock_state(); + + printk(KERN_INFO "NFSD: Forgot %d locks", count); +} + +void nfsd_forget_openowners(u64 num) +{ + int count; + + nfs4_lock_state(); + count = nfsd_release_n_owners(num, true, release_openowner_sop); + nfs4_unlock_state(); + + printk(KERN_INFO "NFSD: Forgot %d open owners", count); +} + +int nfsd_process_n_delegations(u64 num, void (*deleg_func)(struct nfs4_delegation *)) +{ + int i, count = 0; + struct nfs4_file *fp, *fnext; + struct nfs4_delegation *dp, *dnext; + + for (i = 0; i < FILE_HASH_SIZE; i++) { + list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) { + list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) { + deleg_func(dp); + if (++count == num) + return count; + } + } + } + + return count; +} + +void nfsd_forget_delegations(u64 num) +{ + unsigned int count; + + nfs4_lock_state(); + count = nfsd_process_n_delegations(num, unhash_delegation); + nfs4_unlock_state(); + + printk(KERN_INFO "NFSD: Forgot %d delegations", count); +} + +void nfsd_recall_delegations(u64 num) +{ + unsigned int count; + + nfs4_lock_state(); + spin_lock(&recall_lock); + count = nfsd_process_n_delegations(num, nfsd_break_one_deleg); + spin_unlock(&recall_lock); + nfs4_unlock_state(); + + printk(KERN_INFO "NFSD: Recalled %d delegations", count); +} + +#endif /* CONFIG_NFSD_FAULT_INJECTION */ + /* initialization to perform at module load time: */ -int +void nfs4_state_init(void) { - int i, status; + int i; - status = nfsd4_init_slabs(); - if (status) - return status; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&conf_id_hashtbl[i]); INIT_LIST_HEAD(&conf_str_hashtbl[i]); @@ -4416,18 +4566,15 @@ nfs4_state_init(void) for (i = 0; i < FILE_HASH_SIZE; i++) { INIT_LIST_HEAD(&file_hashtbl[i]); } - for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) { - INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]); - } - for (i = 0; i < LOCK_HASH_SIZE; i++) { - INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); + for (i = 0; i < OWNER_HASH_SIZE; i++) { + INIT_LIST_HEAD(&ownerstr_hashtbl[i]); } - memset(&onestateid, ~0, sizeof(stateid_t)); + for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) + INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]); INIT_LIST_HEAD(&close_lru); INIT_LIST_HEAD(&client_lru); INIT_LIST_HEAD(&del_recall_lru); reclaim_str_hashtbl_size = 0; - return 0; } static void @@ -4526,7 +4673,6 @@ __nfs4_state_shutdown(void) spin_unlock(&recall_lock); list_for_each_safe(pos, next, &reaplist) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); - list_del_init(&dp->dl_recall_lru); unhash_delegation(dp); } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b6fa792d6b85..0ec5a1b9700e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -215,10 +215,9 @@ defer_free(struct nfsd4_compoundargs *argp, static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) { if (p == argp->tmp) { - p = kmalloc(nbytes, GFP_KERNEL); + p = kmemdup(argp->tmp, nbytes, GFP_KERNEL); if (!p) return NULL; - memcpy(p, argp->tmp, nbytes); } else { BUG_ON(p != argp->tmpp); argp->tmpp = NULL; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index bb4a11d58a5a..748eda93ce59 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -18,6 +18,7 @@ #include "idmap.h" #include "nfsd.h" #include "cache.h" +#include "fault_inject.h" /* * We have a single directory with several nodes in it. @@ -1128,9 +1129,13 @@ static int __init init_nfsd(void) int retval; printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); - retval = nfs4_state_init(); /* nfs4 locking state */ + retval = nfsd4_init_slabs(); if (retval) return retval; + nfs4_state_init(); + retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */ + if (retval) + goto out_free_slabs; nfsd_stat_init(); /* Statistics */ retval = nfsd_reply_cache_init(); if (retval) @@ -1161,6 +1166,8 @@ out_free_cache: nfsd_reply_cache_shutdown(); out_free_stat: nfsd_stat_shutdown(); + nfsd_fault_inject_cleanup(); +out_free_slabs: nfsd4_free_slabs(); return retval; } @@ -1175,6 +1182,7 @@ static void __exit exit_nfsd(void) nfsd_lockd_shutdown(); nfsd_idmap_shutdown(); nfsd4_free_slabs(); + nfsd_fault_inject_cleanup(); unregister_filesystem(&nfsd_fs_type); } diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 58134a23fdfb..1d1e8589b4ce 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -104,14 +104,16 @@ static inline int nfsd_v4client(struct svc_rqst *rq) */ #ifdef CONFIG_NFSD_V4 extern unsigned int max_delegations; -int nfs4_state_init(void); +void nfs4_state_init(void); +int nfsd4_init_slabs(void); void nfsd4_free_slabs(void); int nfs4_state_start(void); void nfs4_state_shutdown(void); void nfs4_reset_lease(time_t leasetime); int nfs4_reset_recoverydir(char *recdir); #else -static inline int nfs4_state_init(void) { return 0; } +static inline void nfs4_state_init(void) { } +static inline int nfsd4_init_slabs(void) { return 0; } static inline void nfsd4_free_slabs(void) { } static inline int nfs4_state_start(void) { return 0; } static inline void nfs4_state_shutdown(void) { } @@ -338,15 +340,15 @@ static inline u32 nfsd_suppattrs2(u32 minorversion) } /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ -#define NFSD_WRITEONLY_ATTRS_WORD1 \ -(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) +#define NFSD_WRITEONLY_ATTRS_WORD1 \ + (FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) /* These are the only attrs allowed in CREATE/OPEN/SETATTR. */ -#define NFSD_WRITEABLE_ATTRS_WORD0 \ -(FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL ) -#define NFSD_WRITEABLE_ATTRS_WORD1 \ -(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ - | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) +#define NFSD_WRITEABLE_ATTRS_WORD0 \ + (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL) +#define NFSD_WRITEABLE_ATTRS_WORD1 \ + (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ + | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) #define NFSD_WRITEABLE_ATTRS_WORD2 0 #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index a3cf38476a1b..ffb5df1db94f 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -366,6 +366,7 @@ struct nfs4_openowner { struct nfs4_lockowner { struct nfs4_stateowner lo_owner; /* must be first element */ + struct list_head lo_owner_ino_hash; /* hash by owner,file */ struct list_head lo_perstateid; /* for lockowners only */ struct list_head lo_list; /* for temporary uses */ }; @@ -482,7 +483,7 @@ extern void nfsd4_shutdown_recdir(void); extern int nfs4_client_to_reclaim(const char *name); extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); extern void nfsd4_recdir_purge_old(void); -extern int nfsd4_create_clid_dir(struct nfs4_client *clp); +extern void nfsd4_create_clid_dir(struct nfs4_client *clp); extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); extern void release_session_client(struct nfsd4_session *); extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index d25a723b68ad..edf6d3ed8777 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -594,8 +594,19 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac return error; } -#define NFSD_XATTR_JUNCTION_PREFIX XATTR_TRUSTED_PREFIX "junction." -#define NFSD_XATTR_JUNCTION_TYPE NFSD_XATTR_JUNCTION_PREFIX "type" +/* + * NFS junction information is stored in an extended attribute. + */ +#define NFSD_JUNCTION_XATTR_NAME XATTR_TRUSTED_PREFIX "junction.nfs" + +/** + * nfsd4_is_junction - Test if an object could be an NFS junction + * + * @dentry: object to test + * + * Returns 1 if "dentry" appears to contain NFS junction information. + * Otherwise 0 is returned. + */ int nfsd4_is_junction(struct dentry *dentry) { struct inode *inode = dentry->d_inode; @@ -606,7 +617,7 @@ int nfsd4_is_junction(struct dentry *dentry) return 0; if (!(inode->i_mode & S_ISVTX)) return 0; - if (vfs_getxattr(dentry, NFSD_XATTR_JUNCTION_TYPE, NULL, 0) <= 0) + if (vfs_getxattr(dentry, NFSD_JUNCTION_XATTR_NAME, NULL, 0) <= 0) return 0; return 1; } diff --git a/fs/notify/mark.c b/fs/notify/mark.c index e14587d55689..f104d565b682 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -135,9 +135,6 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; - /* 1 from caller and 1 for being on i_list/g_list */ - BUG_ON(atomic_read(&mark->refcnt) < 2); - spin_lock(&group->mark_lock); if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { @@ -182,6 +179,11 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) iput(inode); /* + * We don't necessarily have a ref on mark from caller so the above iput + * may have already destroyed it. Don't touch from now on. + */ + + /* * it's possible that this group tried to destroy itself, but this * this mark was simultaneously being freed by inode. If that's the * case, we finish freeing the group here. diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 608be4516091..5a4a8af5c406 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -3198,7 +3198,7 @@ MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2011 Anton Altaparm MODULE_VERSION(NTFS_VERSION); MODULE_LICENSE("GPL"); #ifdef DEBUG -module_param(debug_msgs, bool, 0); +module_param(debug_msgs, bint, 0); MODULE_PARM_DESC(debug_msgs, "Enable debug messages."); #endif diff --git a/fs/proc/array.c b/fs/proc/array.c index 9252ee3b71e3..c602b8d20f06 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -380,7 +380,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, state = *get_task_state(task); vsize = eip = esp = 0; - permitted = ptrace_may_access(task, PTRACE_MODE_READ); + permitted = ptrace_may_access(task, PTRACE_MODE_READ | PTRACE_MODE_NOAUDIT); mm = get_task_mm(task); if (mm) { vsize = task_vsize(mm); diff --git a/fs/proc/base.c b/fs/proc/base.c index 5485a5388ecb..9cde9edf9c4d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -198,65 +198,7 @@ static int proc_root_link(struct dentry *dentry, struct path *path) return result; } -static struct mm_struct *__check_mem_permission(struct task_struct *task) -{ - struct mm_struct *mm; - - mm = get_task_mm(task); - if (!mm) - return ERR_PTR(-EINVAL); - - /* - * A task can always look at itself, in case it chooses - * to use system calls instead of load instructions. - */ - if (task == current) - return mm; - - /* - * If current is actively ptrace'ing, and would also be - * permitted to freshly attach with ptrace now, permit it. - */ - if (task_is_stopped_or_traced(task)) { - int match; - rcu_read_lock(); - match = (ptrace_parent(task) == current); - rcu_read_unlock(); - if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) - return mm; - } - - /* - * No one else is allowed. - */ - mmput(mm); - return ERR_PTR(-EPERM); -} - -/* - * If current may access user memory in @task return a reference to the - * corresponding mm, otherwise ERR_PTR. - */ -static struct mm_struct *check_mem_permission(struct task_struct *task) -{ - struct mm_struct *mm; - int err; - - /* - * Avoid racing if task exec's as we might get a new mm but validate - * against old credentials. - */ - err = mutex_lock_killable(&task->signal->cred_guard_mutex); - if (err) - return ERR_PTR(err); - - mm = __check_mem_permission(task); - mutex_unlock(&task->signal->cred_guard_mutex); - - return mm; -} - -struct mm_struct *mm_for_maps(struct task_struct *task) +static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) { struct mm_struct *mm; int err; @@ -267,7 +209,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task) mm = get_task_mm(task); if (mm && mm != current->mm && - !ptrace_may_access(task, PTRACE_MODE_READ)) { + !ptrace_may_access(task, mode)) { mmput(mm); mm = ERR_PTR(-EACCES); } @@ -276,6 +218,11 @@ struct mm_struct *mm_for_maps(struct task_struct *task) return mm; } +struct mm_struct *mm_for_maps(struct task_struct *task) +{ + return mm_access(task, PTRACE_MODE_READ); +} + static int proc_pid_cmdline(struct task_struct *task, char * buffer) { int res = 0; @@ -752,38 +699,39 @@ static const struct file_operations proc_single_file_operations = { static int mem_open(struct inode* inode, struct file* file) { - file->private_data = (void*)((long)current->self_exec_id); + struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); + struct mm_struct *mm; + + if (!task) + return -ESRCH; + + mm = mm_access(task, PTRACE_MODE_ATTACH); + put_task_struct(task); + + if (IS_ERR(mm)) + return PTR_ERR(mm); + /* OK to pass negative loff_t, we can catch out-of-range */ file->f_mode |= FMODE_UNSIGNED_OFFSET; + file->private_data = mm; + return 0; } static ssize_t mem_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) { - struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); + int ret; char *page; unsigned long src = *ppos; - int ret = -ESRCH; - struct mm_struct *mm; + struct mm_struct *mm = file->private_data; - if (!task) - goto out_no_task; + if (!mm) + return 0; - ret = -ENOMEM; page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) - goto out; - - mm = check_mem_permission(task); - ret = PTR_ERR(mm); - if (IS_ERR(mm)) - goto out_free; - - ret = -EIO; - - if (file->private_data != (void*)((long)current->self_exec_id)) - goto out_put; + return -ENOMEM; ret = 0; @@ -810,13 +758,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, } *ppos = src; -out_put: - mmput(mm); -out_free: free_page((unsigned long) page); -out: - put_task_struct(task); -out_no_task: return ret; } @@ -825,27 +767,15 @@ static ssize_t mem_write(struct file * file, const char __user *buf, { int copied; char *page; - struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); unsigned long dst = *ppos; - struct mm_struct *mm; + struct mm_struct *mm = file->private_data; - copied = -ESRCH; - if (!task) - goto out_no_task; + if (!mm) + return 0; - copied = -ENOMEM; page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) - goto out_task; - - mm = check_mem_permission(task); - copied = PTR_ERR(mm); - if (IS_ERR(mm)) - goto out_free; - - copied = -EIO; - if (file->private_data != (void *)((long)current->self_exec_id)) - goto out_mm; + return -ENOMEM; copied = 0; while (count > 0) { @@ -869,13 +799,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, } *ppos = dst; -out_mm: - mmput(mm); -out_free: free_page((unsigned long) page); -out_task: - put_task_struct(task); -out_no_task: return copied; } @@ -895,11 +819,20 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig) return file->f_pos; } +static int mem_release(struct inode *inode, struct file *file) +{ + struct mm_struct *mm = file->private_data; + + mmput(mm); + return 0; +} + static const struct file_operations proc_mem_operations = { .llseek = mem_lseek, .read = mem_read, .write = mem_write, .open = mem_open, + .release = mem_release, }; static ssize_t environ_read(struct file *file, char __user *buf, @@ -1199,9 +1132,6 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, ssize_t length; uid_t loginuid; - if (!capable(CAP_AUDIT_CONTROL)) - return -EPERM; - rcu_read_lock(); if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { rcu_read_unlock(); @@ -1230,7 +1160,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, goto out_free_page; } - length = audit_set_loginuid(current, loginuid); + length = audit_set_loginuid(loginuid); if (likely(length == 0)) length = count; diff --git a/fs/proc/stat.c b/fs/proc/stat.c index d76ca6ae2b1b..121f77cfef76 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c @@ -77,6 +77,8 @@ static int show_stat(struct seq_file *p, void *v) steal += kcpustat_cpu(i).cpustat[CPUTIME_STEAL]; guest += kcpustat_cpu(i).cpustat[CPUTIME_GUEST]; guest_nice += kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE]; + sum += kstat_cpu_irqs_sum(i); + sum += arch_irq_stat_cpu(i); for (j = 0; j < NR_SOFTIRQS; j++) { unsigned int softirq_stat = kstat_softirqs_cpu(j, i); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index e418c5abdb0e..7dcd2a250495 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -518,6 +518,9 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, if (!page) continue; + if (PageReserved(page)) + continue; + /* Clear accessed and referenced bits. */ ptep_test_and_clear_young(vma, addr, pte); ClearPageReferenced(page); diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 2bfd987f4853..6b009548d2e0 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -179,47 +179,33 @@ static const char *qnx4_checkroot(struct super_block *sb) struct qnx4_inode_entry *rootdir; int rd, rl; int i, j; - int found = 0; - if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') { + if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') return "no qnx4 filesystem (no root dir)."; - } else { - QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id)); - rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; - rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); - for (j = 0; j < rl; j++) { - bh = sb_bread(sb, rd + j); /* root dir, first block */ - if (bh == NULL) { - return "unable to read root entry."; - } - for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) { - rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE); - if (rootdir->di_fname != NULL) { - QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname)); - if (!strcmp(rootdir->di_fname, - QNX4_BMNAME)) { - found = 1; - qnx4_sb(sb)->BitMap = kmemdup(rootdir, - sizeof(struct qnx4_inode_entry), - GFP_KERNEL); - if (!qnx4_sb(sb)->BitMap) { - brelse (bh); - return "not enough memory for bitmap inode"; - }/* keep bitmap inode known */ - break; - } - } - } + QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id)); + rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1; + rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size); + for (j = 0; j < rl; j++) { + bh = sb_bread(sb, rd + j); /* root dir, first block */ + if (bh == NULL) + return "unable to read root entry."; + rootdir = (struct qnx4_inode_entry *) bh->b_data; + for (i = 0; i < QNX4_INODES_PER_BLOCK; i++, rootdir++) { + QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname)); + if (strcmp(rootdir->di_fname, QNX4_BMNAME) != 0) + continue; + qnx4_sb(sb)->BitMap = kmemdup(rootdir, + sizeof(struct qnx4_inode_entry), + GFP_KERNEL); brelse(bh); - if (found != 0) { - break; - } - } - if (found == 0) { - return "bitmap file not found."; + if (!qnx4_sb(sb)->BitMap) + return "not enough memory for bitmap inode"; + /* keep bitmap inode known */ + return NULL; } + brelse(bh); } - return NULL; + return "bitmap file not found."; } static int qnx4_fill_super(struct super_block *s, void *data, int silent) @@ -270,7 +256,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) if (IS_ERR(root)) { printk(KERN_ERR "qnx4: get inode failed\n"); ret = PTR_ERR(root); - goto out; + goto outb; } ret = -ENOMEM; @@ -283,6 +269,8 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) outi: iput(root); + outb: + kfree(qs->BitMap); out: brelse(bh); outnobh: diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 5ec59b20cf76..46741970371b 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -2125,6 +2125,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, mutex_unlock(&dqopt->dqio_mutex); goto out_file_init; } + if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) + dqopt->info[type].dqi_flags |= DQF_SYS_FILE; mutex_unlock(&dqopt->dqio_mutex); spin_lock(&dq_state_lock); dqopt->flags |= dquot_state_flag(flags, type); @@ -2464,7 +2466,7 @@ int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) spin_lock(&dq_data_lock); ii->dqi_bgrace = mi->dqi_bgrace; ii->dqi_igrace = mi->dqi_igrace; - ii->dqi_flags = mi->dqi_flags & DQF_MASK; + ii->dqi_flags = mi->dqi_flags & DQF_GETINFO_MASK; ii->dqi_valid = IIF_ALL; spin_unlock(&dq_data_lock); mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); @@ -2490,8 +2492,8 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) if (ii->dqi_valid & IIF_IGRACE) mi->dqi_igrace = ii->dqi_igrace; if (ii->dqi_valid & IIF_FLAGS) - mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | - (ii->dqi_flags & DQF_MASK); + mi->dqi_flags = (mi->dqi_flags & ~DQF_SETINFO_MASK) | + (ii->dqi_flags & DQF_SETINFO_MASK); spin_unlock(&dq_data_lock); mark_info_dirty(sb, type); /* Force write to disk */ diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index f744be98cd5a..af0b73802592 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c @@ -70,11 +70,15 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb, spin_lock(&cache->lock); while (1) { - for (i = 0; i < cache->entries; i++) - if (cache->entry[i].block == block) + for (i = cache->curr_blk, n = 0; n < cache->entries; n++) { + if (cache->entry[i].block == block) { + cache->curr_blk = i; break; + } + i = (i + 1) % cache->entries; + } - if (i == cache->entries) { + if (n == cache->entries) { /* * Block not in cache, if all cache entries are used * go to sleep waiting for one to become available. @@ -245,6 +249,7 @@ struct squashfs_cache *squashfs_cache_init(char *name, int entries, goto cleanup; } + cache->curr_blk = 0; cache->next_blk = 0; cache->unused = entries; cache->entries = entries; @@ -332,17 +337,20 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer, u64 *block, int *offset, int length) { struct squashfs_sb_info *msblk = sb->s_fs_info; - int bytes, copied = length; + int bytes, res = length; struct squashfs_cache_entry *entry; TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset); while (length) { entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); - if (entry->error) - return entry->error; - else if (*offset >= entry->length) - return -EIO; + if (entry->error) { + res = entry->error; + goto error; + } else if (*offset >= entry->length) { + res = -EIO; + goto error; + } bytes = squashfs_copy_data(buffer, entry, *offset, length); if (buffer) @@ -358,7 +366,11 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer, squashfs_cache_put(entry); } - return copied; + return res; + +error: + squashfs_cache_put(entry); + return res; } diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index fd7b3b3bda13..81afbccfa843 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -208,8 +208,8 @@ int squashfs_read_inode(struct inode *inode, long long ino) inode->i_op = &squashfs_inode_ops; inode->i_fop = &generic_ro_fops; inode->i_mode |= S_IFREG; - inode->i_blocks = ((inode->i_size - - le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1; + inode->i_blocks = (inode->i_size - + le64_to_cpu(sqsh_ino->sparse) + 511) >> 9; squashfs_i(inode)->fragment_block = frag_blk; squashfs_i(inode)->fragment_size = frag_size; diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 651f0b31d296..52934a22f296 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -28,6 +28,7 @@ struct squashfs_cache { char *name; int entries; + int curr_blk; int next_blk; int num_waiters; int unused; diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index d0858c2d9a47..ecaa2f7bdb8f 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -290,7 +290,7 @@ handle_fragments: check_directory_table: /* Sanity check directory_table */ - if (msblk->directory_table >= next_table) { + if (msblk->directory_table > next_table) { err = -EINVAL; goto failed_mount; } diff --git a/fs/super.c b/fs/super.c index de41e1e46f09..6015c02296b7 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1186,6 +1186,8 @@ int freeze_super(struct super_block *sb) printk(KERN_ERR "VFS:Filesystem freeze failed\n"); sb->s_frozen = SB_UNFROZEN; + smp_wmb(); + wake_up(&sb->s_wait_unfrozen); deactivate_locked_super(sb); return ret; } diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index b09ba2dd8b62..f922cbacdb96 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -38,9 +38,6 @@ DEFINE_SPINLOCK(dbg_lock); -static char dbg_key_buf0[128]; -static char dbg_key_buf1[128]; - static const char *get_key_fmt(int fmt) { switch (fmt) { @@ -103,8 +100,8 @@ static const char *get_dent_type(int type) } } -static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key, - char *buffer) +const char *dbg_snprintf_key(const struct ubifs_info *c, + const union ubifs_key *key, char *buffer, int len) { char *p = buffer; int type = key_type(c, key); @@ -112,45 +109,34 @@ static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key, if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) { switch (type) { case UBIFS_INO_KEY: - sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key), - get_key_type(type)); + len -= snprintf(p, len, "(%lu, %s)", + (unsigned long)key_inum(c, key), + get_key_type(type)); break; case UBIFS_DENT_KEY: case UBIFS_XENT_KEY: - sprintf(p, "(%lu, %s, %#08x)", - (unsigned long)key_inum(c, key), - get_key_type(type), key_hash(c, key)); + len -= snprintf(p, len, "(%lu, %s, %#08x)", + (unsigned long)key_inum(c, key), + get_key_type(type), key_hash(c, key)); break; case UBIFS_DATA_KEY: - sprintf(p, "(%lu, %s, %u)", - (unsigned long)key_inum(c, key), - get_key_type(type), key_block(c, key)); + len -= snprintf(p, len, "(%lu, %s, %u)", + (unsigned long)key_inum(c, key), + get_key_type(type), key_block(c, key)); break; case UBIFS_TRUN_KEY: - sprintf(p, "(%lu, %s)", - (unsigned long)key_inum(c, key), - get_key_type(type)); + len -= snprintf(p, len, "(%lu, %s)", + (unsigned long)key_inum(c, key), + get_key_type(type)); break; default: - sprintf(p, "(bad key type: %#08x, %#08x)", - key->u32[0], key->u32[1]); + len -= snprintf(p, len, "(bad key type: %#08x, %#08x)", + key->u32[0], key->u32[1]); } } else - sprintf(p, "bad key format %d", c->key_fmt); -} - -const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key) -{ - /* dbg_lock must be held */ - sprintf_key(c, key, dbg_key_buf0); - return dbg_key_buf0; -} - -const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key) -{ - /* dbg_lock must be held */ - sprintf_key(c, key, dbg_key_buf1); - return dbg_key_buf1; + len -= snprintf(p, len, "bad key format %d", c->key_fmt); + ubifs_assert(len > 0); + return p; } const char *dbg_ntype(int type) @@ -319,6 +305,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node) int i, n; union ubifs_key key; const struct ubifs_ch *ch = node; + char key_buf[DBG_KEY_BUF_LEN]; if (dbg_is_tst_rcvry(c)) return; @@ -474,7 +461,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node) const struct ubifs_ino_node *ino = node; key_read(c, &ino->key, &key); - printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); + printk(KERN_DEBUG "\tkey %s\n", + dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN)); printk(KERN_DEBUG "\tcreat_sqnum %llu\n", (unsigned long long)le64_to_cpu(ino->creat_sqnum)); printk(KERN_DEBUG "\tsize %llu\n", @@ -517,7 +505,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node) int nlen = le16_to_cpu(dent->nlen); key_read(c, &dent->key, &key); - printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); + printk(KERN_DEBUG "\tkey %s\n", + dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN)); printk(KERN_DEBUG "\tinum %llu\n", (unsigned long long)le64_to_cpu(dent->inum)); printk(KERN_DEBUG "\ttype %d\n", (int)dent->type); @@ -541,7 +530,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node) int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ; key_read(c, &dn->key, &key); - printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); + printk(KERN_DEBUG "\tkey %s\n", + dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN)); printk(KERN_DEBUG "\tsize %u\n", le32_to_cpu(dn->size)); printk(KERN_DEBUG "\tcompr_typ %d\n", @@ -582,7 +572,9 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node) key_read(c, &br->key, &key); printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n", i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs), - le32_to_cpu(br->len), DBGKEY(&key)); + le32_to_cpu(br->len), + dbg_snprintf_key(c, &key, key_buf, + DBG_KEY_BUF_LEN)); } break; } @@ -934,6 +926,7 @@ void dbg_dump_znode(const struct ubifs_info *c, { int n; const struct ubifs_zbranch *zbr; + char key_buf[DBG_KEY_BUF_LEN]; spin_lock(&dbg_lock); if (znode->parent) @@ -958,12 +951,16 @@ void dbg_dump_znode(const struct ubifs_info *c, printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key " "%s\n", n, zbr->znode, zbr->lnum, zbr->offs, zbr->len, - DBGKEY(&zbr->key)); + dbg_snprintf_key(c, &zbr->key, + key_buf, + DBG_KEY_BUF_LEN)); else printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key " "%s\n", n, zbr->znode, zbr->lnum, zbr->offs, zbr->len, - DBGKEY(&zbr->key)); + dbg_snprintf_key(c, &zbr->key, + key_buf, + DBG_KEY_BUF_LEN)); } spin_unlock(&dbg_lock); } @@ -1260,6 +1257,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, int err, nlen1, nlen2, cmp; struct ubifs_dent_node *dent1, *dent2; union ubifs_key key; + char key_buf[DBG_KEY_BUF_LEN]; ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key)); dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); @@ -1290,9 +1288,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, key_read(c, &dent1->key, &key); if (keys_cmp(c, &zbr1->key, &key)) { dbg_err("1st entry at %d:%d has key %s", zbr1->lnum, - zbr1->offs, DBGKEY(&key)); + zbr1->offs, dbg_snprintf_key(c, &key, key_buf, + DBG_KEY_BUF_LEN)); dbg_err("but it should have key %s according to tnc", - DBGKEY(&zbr1->key)); + dbg_snprintf_key(c, &zbr1->key, key_buf, + DBG_KEY_BUF_LEN)); dbg_dump_node(c, dent1); goto out_free; } @@ -1300,9 +1300,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, key_read(c, &dent2->key, &key); if (keys_cmp(c, &zbr2->key, &key)) { dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum, - zbr1->offs, DBGKEY(&key)); + zbr1->offs, dbg_snprintf_key(c, &key, key_buf, + DBG_KEY_BUF_LEN)); dbg_err("but it should have key %s according to tnc", - DBGKEY(&zbr2->key)); + dbg_snprintf_key(c, &zbr2->key, key_buf, + DBG_KEY_BUF_LEN)); dbg_dump_node(c, dent2); goto out_free; } @@ -1319,7 +1321,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, dbg_err("2 xent/dent nodes with the same name"); else dbg_err("bad order of colliding key %s", - DBGKEY(&key)); + dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN)); ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs); dbg_dump_node(c, dent1); diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 8d9c46810189..ad1a6fee6010 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -169,40 +169,39 @@ struct ubifs_global_debug_info { spin_unlock(&dbg_lock); \ } while (0) -const char *dbg_key_str0(const struct ubifs_info *c, - const union ubifs_key *key); -const char *dbg_key_str1(const struct ubifs_info *c, - const union ubifs_key *key); - -/* - * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message - * macros. - */ -#define DBGKEY(key) dbg_key_str0(c, (key)) -#define DBGKEY1(key) dbg_key_str1(c, (key)) - -extern spinlock_t dbg_lock; - -#define ubifs_dbg_msg(type, fmt, ...) do { \ - spin_lock(&dbg_lock); \ - pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \ - spin_unlock(&dbg_lock); \ +#define ubifs_dbg_msg(type, fmt, ...) \ + pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__) + +#define DBG_KEY_BUF_LEN 32 +#define ubifs_dbg_msg_key(type, key, fmt, ...) do { \ + char __tmp_key_buf[DBG_KEY_BUF_LEN]; \ + pr_debug("UBIFS DBG " type ": " fmt "%s\n", ##__VA_ARGS__, \ + dbg_snprintf_key(c, key, __tmp_key_buf, DBG_KEY_BUF_LEN)); \ } while (0) /* Just a debugging messages not related to any specific UBIFS subsystem */ -#define dbg_msg(fmt, ...) ubifs_dbg_msg("msg", fmt, ##__VA_ARGS__) +#define dbg_msg(fmt, ...) \ + printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid, \ + __func__, ##__VA_ARGS__) + /* General messages */ #define dbg_gen(fmt, ...) ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__) /* Additional journal messages */ #define dbg_jnl(fmt, ...) ubifs_dbg_msg("jnl", fmt, ##__VA_ARGS__) +#define dbg_jnlk(key, fmt, ...) \ + ubifs_dbg_msg_key("jnl", key, fmt, ##__VA_ARGS__) /* Additional TNC messages */ #define dbg_tnc(fmt, ...) ubifs_dbg_msg("tnc", fmt, ##__VA_ARGS__) +#define dbg_tnck(key, fmt, ...) \ + ubifs_dbg_msg_key("tnc", key, fmt, ##__VA_ARGS__) /* Additional lprops messages */ #define dbg_lp(fmt, ...) ubifs_dbg_msg("lp", fmt, ##__VA_ARGS__) /* Additional LEB find messages */ #define dbg_find(fmt, ...) ubifs_dbg_msg("find", fmt, ##__VA_ARGS__) /* Additional mount messages */ #define dbg_mnt(fmt, ...) ubifs_dbg_msg("mnt", fmt, ##__VA_ARGS__) +#define dbg_mntk(key, fmt, ...) \ + ubifs_dbg_msg_key("mnt", key, fmt, ##__VA_ARGS__) /* Additional I/O messages */ #define dbg_io(fmt, ...) ubifs_dbg_msg("io", fmt, ##__VA_ARGS__) /* Additional commit messages */ @@ -218,6 +217,7 @@ extern spinlock_t dbg_lock; /* Additional recovery messages */ #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__) +extern spinlock_t dbg_lock; extern struct ubifs_global_debug_info ubifs_dbg; static inline int dbg_is_chk_gen(const struct ubifs_info *c) @@ -258,6 +258,8 @@ const char *dbg_cstate(int cmt_state); const char *dbg_jhead(int jhead); const char *dbg_get_key_dump(const struct ubifs_info *c, const union ubifs_key *key); +const char *dbg_snprintf_key(const struct ubifs_info *c, + const union ubifs_key *key, char *buffer, int len); void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode); void dbg_dump_node(const struct ubifs_info *c, const void *node); void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum, @@ -345,20 +347,23 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); #define dbg_dump_stack() #define ubifs_assert_cmt_locked(c) -#define dbg_msg(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_gen(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_jnl(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_tnc(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_lp(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_find(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_mnt(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_io(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_cmt(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_budg(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_log(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_gc(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_msg(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_gen(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_jnl(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_jnlk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_tnc(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_tnck(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_lp(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_find(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_mnt(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_mntk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_io(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_cmt(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_budg(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_log(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_gc(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) +#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) static inline int ubifs_debugging_init(struct ubifs_info *c) { return 0; } static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; } @@ -368,6 +373,10 @@ static inline const char *dbg_jhead(int jhead) { return ""; } static inline const char * dbg_get_key_dump(const struct ubifs_info *c, const union ubifs_key *key) { return ""; } +static inline const char * +dbg_snprintf_key(const struct ubifs_info *c, + const union ubifs_key *key, char *buffer, + int len) { return ""; } static inline void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode) { return; } static inline void dbg_dump_node(const struct ubifs_info *c, diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index cef0460f4c54..2f438ab2e7a2 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -697,9 +697,8 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1; struct ubifs_inode *ui = ubifs_inode(inode); - dbg_jnl("ino %lu, blk %u, len %d, key %s", - (unsigned long)key_inum(c, key), key_block(c, key), len, - DBGKEY(key)); + dbg_jnlk(key, "ino %lu, blk %u, len %d, key ", + (unsigned long)key_inum(c, key), key_block(c, key), len); ubifs_assert(len <= UBIFS_BLOCK_SIZE); data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN); @@ -1177,7 +1176,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, dn = (void *)trun + UBIFS_TRUN_NODE_SZ; blk = new_size >> UBIFS_BLOCK_SHIFT; data_key_init(c, &key, inum, blk); - dbg_jnl("last block key %s", DBGKEY(&key)); + dbg_jnlk(&key, "last block key "); err = ubifs_tnc_lookup(c, &key, dn); if (err == -ENOENT) dlen = 0; /* Not found (so it is a hole) */ diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index ccabaf1164b3..b007637f0406 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c @@ -221,8 +221,8 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) { int err; - dbg_mnt("LEB %d:%d len %d deletion %d sqnum %llu %s", r->lnum, - r->offs, r->len, r->deletion, r->sqnum, DBGKEY(&r->key)); + dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ", + r->lnum, r->offs, r->len, r->deletion, r->sqnum); /* Set c->replay_sqnum to help deal with dangling branches. */ c->replay_sqnum = r->sqnum; @@ -361,7 +361,7 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len, { struct replay_entry *r; - dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key)); + dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs); if (key_inum(c, key) >= c->highest_inum) c->highest_inum = key_inum(c, key); @@ -409,7 +409,7 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, struct replay_entry *r; char *nbuf; - dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key)); + dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs); if (key_inum(c, key) >= c->highest_inum) c->highest_inum = key_inum(c, key); diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index e14ee53159db..16ad84d8402f 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -505,7 +505,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, { int ret; - dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key)); + dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs); ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum, zbr->offs); @@ -519,8 +519,8 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, ret = 0; } if (ret == 0 && c->replaying) - dbg_mnt("dangling branch LEB %d:%d len %d, key %s", - zbr->lnum, zbr->offs, zbr->len, DBGKEY(key)); + dbg_mntk(key, "dangling branch LEB %d:%d len %d, key ", + zbr->lnum, zbr->offs, zbr->len); return ret; } @@ -995,9 +995,9 @@ static int fallible_resolve_collision(struct ubifs_info *c, if (adding || !o_znode) return 0; - dbg_mnt("dangling match LEB %d:%d len %d %s", + dbg_mntk(key, "dangling match LEB %d:%d len %d key ", o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs, - o_znode->zbranch[o_n].len, DBGKEY(key)); + o_znode->zbranch[o_n].len); *zn = o_znode; *n = o_n; return 1; @@ -1179,7 +1179,7 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key, struct ubifs_znode *znode; unsigned long time = get_seconds(); - dbg_tnc("search key %s", DBGKEY(key)); + dbg_tnck(key, "search key "); ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY); znode = c->zroot.znode; @@ -1315,7 +1315,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key, struct ubifs_znode *znode; unsigned long time = get_seconds(); - dbg_tnc("search and dirty key %s", DBGKEY(key)); + dbg_tnck(key, "search and dirty key "); znode = c->zroot.znode; if (unlikely(!znode)) { @@ -1722,8 +1722,8 @@ static int validate_data_node(struct ubifs_info *c, void *buf, if (!keys_eq(c, &zbr->key, &key1)) { ubifs_err("bad key in node at LEB %d:%d", zbr->lnum, zbr->offs); - dbg_tnc("looked for key %s found node's key %s", - DBGKEY(&zbr->key), DBGKEY1(&key1)); + dbg_tnck(&zbr->key, "looked for key "); + dbg_tnck(&key1, "found node's key "); goto out_err; } @@ -1776,7 +1776,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu) ubifs_err("failed to read from LEB %d:%d, error %d", lnum, offs, err); dbg_dump_stack(); - dbg_tnc("key %s", DBGKEY(&bu->key)); + dbg_tnck(&bu->key, "key "); return err; } @@ -1811,7 +1811,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, int found, n, err; struct ubifs_znode *znode; - dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key)); + dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name); mutex_lock(&c->tnc_mutex); found = ubifs_lookup_level0(c, key, &znode, &n); if (!found) { @@ -1985,8 +1985,7 @@ again: zp = znode->parent; if (znode->child_cnt < c->fanout) { ubifs_assert(n != c->fanout); - dbg_tnc("inserted at %d level %d, key %s", n, znode->level, - DBGKEY(key)); + dbg_tnck(key, "inserted at %d level %d, key ", n, znode->level); insert_zbranch(znode, zbr, n); @@ -2001,7 +2000,7 @@ again: * Unfortunately, @znode does not have more empty slots and we have to * split it. */ - dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key)); + dbg_tnck(key, "splitting level %d, key ", znode->level); if (znode->alt) /* @@ -2095,7 +2094,7 @@ do_split: } /* Insert new key and branch */ - dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key)); + dbg_tnck(key, "inserting at %d level %d, key ", n, zn->level); insert_zbranch(zi, zbr, n); @@ -2171,7 +2170,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, struct ubifs_znode *znode; mutex_lock(&c->tnc_mutex); - dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key)); + dbg_tnck(key, "%d:%d, len %d, key ", lnum, offs, len); found = lookup_level0_dirty(c, key, &znode, &n); if (!found) { struct ubifs_zbranch zbr; @@ -2220,8 +2219,8 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, struct ubifs_znode *znode; mutex_lock(&c->tnc_mutex); - dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum, - old_offs, lnum, offs, len, DBGKEY(key)); + dbg_tnck(key, "old LEB %d:%d, new LEB %d:%d, len %d, key ", old_lnum, + old_offs, lnum, offs, len); found = lookup_level0_dirty(c, key, &znode, &n); if (found < 0) { err = found; @@ -2303,8 +2302,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, struct ubifs_znode *znode; mutex_lock(&c->tnc_mutex); - dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name, - DBGKEY(key)); + dbg_tnck(key, "LEB %d:%d, name '%.*s', key ", + lnum, offs, nm->len, nm->name); found = lookup_level0_dirty(c, key, &znode, &n); if (found < 0) { err = found; @@ -2397,7 +2396,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n) /* Delete without merge for now */ ubifs_assert(znode->level == 0); ubifs_assert(n >= 0 && n < c->fanout); - dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key)); + dbg_tnck(&znode->zbranch[n].key, "deleting key "); zbr = &znode->zbranch[n]; lnc_free(zbr); @@ -2507,7 +2506,7 @@ int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key) struct ubifs_znode *znode; mutex_lock(&c->tnc_mutex); - dbg_tnc("key %s", DBGKEY(key)); + dbg_tnck(key, "key "); found = lookup_level0_dirty(c, key, &znode, &n); if (found < 0) { err = found; @@ -2538,7 +2537,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, struct ubifs_znode *znode; mutex_lock(&c->tnc_mutex); - dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key)); + dbg_tnck(key, "%.*s, key ", nm->len, nm->name); err = lookup_level0_dirty(c, key, &znode, &n); if (err < 0) goto out_unlock; @@ -2653,7 +2652,7 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key, dbg_dump_znode(c, znode); goto out_unlock; } - dbg_tnc("removing %s", DBGKEY(key)); + dbg_tnck(key, "removing key "); } if (k) { for (i = n + 1 + k; i < znode->child_cnt; i++) @@ -2773,7 +2772,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, struct ubifs_zbranch *zbr; union ubifs_key *dkey; - dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key)); + dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)"); ubifs_assert(is_hash_key(c, key)); mutex_lock(&c->tnc_mutex); @@ -3332,9 +3331,9 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode, out_dump: block = key_block(c, key); - ubifs_err("inode %lu has size %lld, but there are data at offset %lld " - "(data key %s)", (unsigned long)inode->i_ino, size, - ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key)); + ubifs_err("inode %lu has size %lld, but there are data at offset %lld", + (unsigned long)inode->i_ino, size, + ((loff_t)block) << UBIFS_BLOCK_SHIFT); mutex_unlock(&c->tnc_mutex); dbg_dump_inode(c, inode); dbg_dump_stack(); diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c index b48db999903e..dc28fe6ec07a 100644 --- a/fs/ubifs/tnc_misc.c +++ b/fs/ubifs/tnc_misc.c @@ -328,8 +328,8 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, case UBIFS_XENT_KEY: break; default: - dbg_msg("bad key type at slot %d: %s", i, - DBGKEY(&zbr->key)); + dbg_msg("bad key type at slot %d: %d", + i, key_type(c, &zbr->key)); err = 3; goto out_dump; } @@ -475,7 +475,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, zbr->offs); if (err) { - dbg_tnc("key %s", DBGKEY(key)); + dbg_tnck(key, "key "); return err; } @@ -484,8 +484,8 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, if (!keys_eq(c, key, &key1)) { ubifs_err("bad key in node at LEB %d:%d", zbr->lnum, zbr->offs); - dbg_tnc("looked for key %s found node's key %s", - DBGKEY(key), DBGKEY1(&key1)); + dbg_tnck(key, "looked for key "); + dbg_tnck(&key1, "but found node's key "); dbg_dump_node(c, node); return -EINVAL; } diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 574d4ee9b625..74b9baf36ac3 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -111,8 +111,7 @@ xfs_ioend_new_eof( xfs_fsize_t bsize; bsize = ioend->io_offset + ioend->io_size; - isize = MAX(ip->i_size, ip->i_new_size); - isize = MIN(isize, bsize); + isize = MIN(i_size_read(VFS_I(ip)), bsize); return isize > ip->i_d.di_size ? isize : 0; } @@ -126,11 +125,7 @@ static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend) } /* - * Update on-disk file size now that data has been written to disk. The - * current in-memory file size is i_size. If a write is beyond eof i_new_size - * will be the intended file size until i_size is updated. If this write does - * not extend all the way to the valid file size then restrict this update to - * the end of the write. + * Update on-disk file size now that data has been written to disk. * * This function does not block as blocking on the inode lock in IO completion * can lead to IO completion order dependency deadlocks.. If it can't get the @@ -1279,6 +1274,15 @@ xfs_end_io_direct_write( struct xfs_ioend *ioend = iocb->private; /* + * While the generic direct I/O code updates the inode size, it does + * so only after the end_io handler is called, which means our + * end_io handler thinks the on-disk size is outside the in-core + * size. To prevent this just update it a little bit earlier here. + */ + if (offset + size > i_size_read(ioend->io_inode)) + i_size_write(ioend->io_inode, offset + size); + + /* * blockdev_direct_IO can return an error even after the I/O * completion handler was called. Thus we need to protect * against double-freeing. @@ -1340,12 +1344,11 @@ xfs_vm_write_failed( if (to > inode->i_size) { /* - * punch out the delalloc blocks we have already allocated. We - * don't call xfs_setattr() to do this as we may be in the - * middle of a multi-iovec write and so the vfs inode->i_size - * will not match the xfs ip->i_size and so it will zero too - * much. Hence we jus truncate the page cache to zero what is - * necessary and punch the delalloc blocks directly. + * Punch out the delalloc blocks we have already allocated. + * + * Don't bother with xfs_setattr given that nothing can have + * made it to disk yet as the page is still locked at this + * point. */ struct xfs_inode *ip = XFS_I(inode); xfs_fileoff_t start_fsb; diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 1e5d97f86ea8..08b9ac644c31 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -827,10 +827,6 @@ xfs_attr_inactive(xfs_inode_t *dp) if (error) goto out; - /* - * Commit the last in the sequence of transactions. - */ - xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); xfs_iunlock(dp, XFS_ILOCK_EXCL); diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index c1b55e596551..d25eafd4d28d 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -271,10 +271,6 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) dp = args->dp; mp = dp->i_mount; dp->i_d.di_forkoff = forkoff; - dp->i_df.if_ext_max = - XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); - dp->i_afp->if_ext_max = - XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); ifp = dp->i_afp; ASSERT(ifp->if_flags & XFS_IFINLINE); @@ -326,7 +322,6 @@ xfs_attr_fork_reset( ASSERT(ip->i_d.di_anextents == 0); ASSERT(ip->i_afp == NULL); - ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); } @@ -389,10 +384,6 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) (args->op_flags & XFS_DA_OP_ADDNAME) || !(mp->m_flags & XFS_MOUNT_ATTR2) || dp->i_d.di_format == XFS_DINODE_FMT_BTREE); - dp->i_afp->if_ext_max = - XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); - dp->i_df.if_ext_max = - XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); } diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index d0ab78837057..188ef2fbd628 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -249,7 +249,27 @@ xfs_bmbt_lookup_ge( } /* -* Update the record referred to by cur to the value given + * Check if the inode needs to be converted to btree format. + */ +static inline bool xfs_bmap_needs_btree(struct xfs_inode *ip, int whichfork) +{ + return XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) > + XFS_IFORK_MAXEXT(ip, whichfork); +} + +/* + * Check if the inode should be converted to extent format. + */ +static inline bool xfs_bmap_wants_extents(struct xfs_inode *ip, int whichfork) +{ + return XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && + XFS_IFORK_NEXTENTS(ip, whichfork) <= + XFS_IFORK_MAXEXT(ip, whichfork); +} + +/* + * Update the record referred to by cur to the value given * by [off, bno, len, state]. * This either works (return 0) or gets an EFSCORRUPTED error. */ @@ -683,8 +703,8 @@ xfs_bmap_add_extent_delay_real( goto done; XFS_WANT_CORRUPTED_GOTO(i == 1, done); } - if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && - bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) { + + if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, bma->firstblock, bma->flist, &bma->cur, 1, &tmp_rval, XFS_DATA_FORK); @@ -767,8 +787,8 @@ xfs_bmap_add_extent_delay_real( goto done; XFS_WANT_CORRUPTED_GOTO(i == 1, done); } - if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && - bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) { + + if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, bma->firstblock, bma->flist, &bma->cur, 1, &tmp_rval, XFS_DATA_FORK); @@ -836,8 +856,8 @@ xfs_bmap_add_extent_delay_real( goto done; XFS_WANT_CORRUPTED_GOTO(i == 1, done); } - if (bma->ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && - bma->ip->i_d.di_nextents > bma->ip->i_df.if_ext_max) { + + if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, bma->firstblock, bma->flist, &bma->cur, 1, &tmp_rval, XFS_DATA_FORK); @@ -884,8 +904,7 @@ xfs_bmap_add_extent_delay_real( } /* convert to a btree if necessary */ - if (XFS_IFORK_FORMAT(bma->ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(bma->ip, XFS_DATA_FORK) > ifp->if_ext_max) { + if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { int tmp_logflags; /* partial log flag return val */ ASSERT(bma->cur == NULL); @@ -1421,8 +1440,7 @@ xfs_bmap_add_extent_unwritten_real( } /* convert to a btree if necessary */ - if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) { + if (xfs_bmap_needs_btree(ip, XFS_DATA_FORK)) { int tmp_logflags; /* partial log flag return val */ ASSERT(cur == NULL); @@ -1812,8 +1830,7 @@ xfs_bmap_add_extent_hole_real( } /* convert to a btree if necessary */ - if (XFS_IFORK_FORMAT(bma->ip, whichfork) == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(bma->ip, whichfork) > ifp->if_ext_max) { + if (xfs_bmap_needs_btree(bma->ip, whichfork)) { int tmp_logflags; /* partial log flag return val */ ASSERT(bma->cur == NULL); @@ -3037,8 +3054,7 @@ xfs_bmap_extents_to_btree( ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS); - ASSERT(ifp->if_ext_max == - XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + /* * Make space in the inode incore. */ @@ -3184,13 +3200,8 @@ xfs_bmap_forkoff_reset( ip->i_d.di_format != XFS_DINODE_FMT_BTREE) { uint dfl_forkoff = xfs_default_attroffset(ip) >> 3; - if (dfl_forkoff > ip->i_d.di_forkoff) { + if (dfl_forkoff > ip->i_d.di_forkoff) ip->i_d.di_forkoff = dfl_forkoff; - ip->i_df.if_ext_max = - XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t); - ip->i_afp->if_ext_max = - XFS_IFORK_ASIZE(ip) / sizeof(xfs_bmbt_rec_t); - } } } @@ -3430,8 +3441,6 @@ xfs_bmap_add_attrfork( int error; /* error return value */ ASSERT(XFS_IFORK_Q(ip) == 0); - ASSERT(ip->i_df.if_ext_max == - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); mp = ip->i_mount; ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); @@ -3486,12 +3495,9 @@ xfs_bmap_add_attrfork( error = XFS_ERROR(EINVAL); goto error1; } - ip->i_df.if_ext_max = - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(ip->i_afp == NULL); ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); - ip->i_afp->if_ext_max = - XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); ip->i_afp->if_flags = XFS_IFEXTENTS; logflags = 0; xfs_bmap_init(&flist, &firstblock); @@ -3535,20 +3541,17 @@ xfs_bmap_add_attrfork( } else spin_unlock(&mp->m_sb_lock); } - if ((error = xfs_bmap_finish(&tp, &flist, &committed))) + + error = xfs_bmap_finish(&tp, &flist, &committed); + if (error) goto error2; - error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); - ASSERT(ip->i_df.if_ext_max == - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); - return error; + return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); error2: xfs_bmap_cancel(&flist); error1: xfs_iunlock(ip, XFS_ILOCK_EXCL); error0: xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); - ASSERT(ip->i_df.if_ext_max == - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); return error; } @@ -3994,11 +3997,8 @@ xfs_bmap_one_block( xfs_bmbt_irec_t s; /* internal version of extent */ #ifndef DEBUG - if (whichfork == XFS_DATA_FORK) { - return S_ISREG(ip->i_d.di_mode) ? - (ip->i_size == ip->i_mount->m_sb.sb_blocksize) : - (ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize); - } + if (whichfork == XFS_DATA_FORK) + return XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize; #endif /* !DEBUG */ if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1) return 0; @@ -4010,7 +4010,7 @@ xfs_bmap_one_block( xfs_bmbt_get_all(ep, &s); rval = s.br_startoff == 0 && s.br_blockcount == 1; if (rval && whichfork == XFS_DATA_FORK) - ASSERT(ip->i_size == ip->i_mount->m_sb.sb_blocksize); + ASSERT(XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize); return rval; } @@ -4379,8 +4379,6 @@ xfs_bmapi_read( XFS_STATS_INC(xs_blk_mapr); ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(ifp->if_ext_max == - XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(NULL, ip, whichfork); @@ -4871,8 +4869,6 @@ xfs_bmapi_write( return XFS_ERROR(EIO); ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(ifp->if_ext_max == - XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); XFS_STATS_INC(xs_blk_mapw); @@ -4981,8 +4977,7 @@ xfs_bmapi_write( /* * Transform from btree to extents, give it cur. */ - if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && - XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) { + if (xfs_bmap_wants_extents(ip, whichfork)) { int tmp_logflags = 0; ASSERT(bma.cur); @@ -4992,10 +4987,10 @@ xfs_bmapi_write( if (error) goto error0; } - ASSERT(ifp->if_ext_max == - XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || - XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max); + XFS_IFORK_NEXTENTS(ip, whichfork) > + XFS_IFORK_MAXEXT(ip, whichfork)); error = 0; error0: /* @@ -5095,8 +5090,7 @@ xfs_bunmapi( ASSERT(len > 0); ASSERT(nexts >= 0); - ASSERT(ifp->if_ext_max == - XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + if (!(ifp->if_flags & XFS_IFEXTENTS) && (error = xfs_iread_extents(tp, ip, whichfork))) return error; @@ -5322,7 +5316,8 @@ xfs_bunmapi( */ if (!wasdel && xfs_trans_get_block_res(tp) == 0 && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(ip, whichfork) >= ifp->if_ext_max && + XFS_IFORK_NEXTENTS(ip, whichfork) >= /* Note the >= */ + XFS_IFORK_MAXEXT(ip, whichfork) && del.br_startoff > got.br_startoff && del.br_startoff + del.br_blockcount < got.br_startoff + got.br_blockcount) { @@ -5353,13 +5348,11 @@ nodelete: } } *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0; - ASSERT(ifp->if_ext_max == - XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + /* * Convert to a btree if necessary. */ - if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { + if (xfs_bmap_needs_btree(ip, whichfork)) { ASSERT(cur == NULL); error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0, &tmp_logflags, whichfork); @@ -5370,8 +5363,7 @@ nodelete: /* * transform from btree to extents, give it cur */ - else if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && - XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) { + else if (xfs_bmap_wants_extents(ip, whichfork)) { ASSERT(cur != NULL); error = xfs_bmap_btree_to_extents(tp, ip, cur, &tmp_logflags, whichfork); @@ -5382,8 +5374,6 @@ nodelete: /* * transform from extents to local? */ - ASSERT(ifp->if_ext_max == - XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); error = 0; error0: /* @@ -5434,7 +5424,7 @@ xfs_getbmapx_fix_eof_hole( if (startblock == HOLESTARTBLOCK) { mp = ip->i_mount; out->bmv_block = -1; - fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, ip->i_size)); + fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, XFS_ISIZE(ip))); fixlen -= out->bmv_offset; if (prealloced && out->bmv_offset + out->bmv_length == end) { /* Came to hole at EOF. Trim it. */ @@ -5522,7 +5512,7 @@ xfs_getbmap( fixlen = XFS_MAXIOFFSET(mp); } else { prealloced = 0; - fixlen = ip->i_size; + fixlen = XFS_ISIZE(ip); } } @@ -5551,7 +5541,7 @@ xfs_getbmap( xfs_ilock(ip, XFS_IOLOCK_SHARED); if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) { - if (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size) { + if (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size) { error = xfs_flush_pages(ip, 0, -1, 0, FI_REMAPF); if (error) goto out_unlock_iolock; diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 654dc6f05bac..dd974a55c77d 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -163,12 +163,14 @@ xfs_swap_extents_check_format( /* Check temp in extent form to max in target */ if (tip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) > ip->i_df.if_ext_max) + XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) > + XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)) return EINVAL; /* Check target in extent form to max in temp */ if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > tip->i_df.if_ext_max) + XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > + XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK)) return EINVAL; /* @@ -180,18 +182,25 @@ xfs_swap_extents_check_format( * (a common defrag case) which will occur when the temp inode is in * extent format... */ - if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE && - ((XFS_IFORK_BOFF(ip) && - tip->i_df.if_broot_bytes > XFS_IFORK_BOFF(ip)) || - XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <= ip->i_df.if_ext_max)) - return EINVAL; + if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE) { + if (XFS_IFORK_BOFF(ip) && + tip->i_df.if_broot_bytes > XFS_IFORK_BOFF(ip)) + return EINVAL; + if (XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <= + XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)) + return EINVAL; + } /* Reciprocal target->temp btree format checks */ - if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE && - ((XFS_IFORK_BOFF(tip) && - ip->i_df.if_broot_bytes > XFS_IFORK_BOFF(tip)) || - XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <= tip->i_df.if_ext_max)) - return EINVAL; + if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) { + if (XFS_IFORK_BOFF(tip) && + ip->i_df.if_broot_bytes > XFS_IFORK_BOFF(tip)) + return EINVAL; + + if (XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <= + XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK)) + return EINVAL; + } return 0; } @@ -349,16 +358,6 @@ xfs_swap_extents( *tifp = *tempifp; /* struct copy */ /* - * Fix the in-memory data fork values that are dependent on the fork - * offset in the inode. We can't assume they remain the same as attr2 - * has dynamic fork offsets. - */ - ifp->if_ext_max = XFS_IFORK_SIZE(ip, XFS_DATA_FORK) / - (uint)sizeof(xfs_bmbt_rec_t); - tifp->if_ext_max = XFS_IFORK_SIZE(tip, XFS_DATA_FORK) / - (uint)sizeof(xfs_bmbt_rec_t); - - /* * Fix the on-disk inode values */ tmp = (__uint64_t)ip->i_d.di_nblocks; diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index f675f3d9d7b3..7e5bc872f2b4 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -327,7 +327,7 @@ xfs_file_aio_read( mp->m_rtdev_targp : mp->m_ddev_targp; if ((iocb->ki_pos & target->bt_smask) || (size & target->bt_smask)) { - if (iocb->ki_pos == ip->i_size) + if (iocb->ki_pos == i_size_read(inode)) return 0; return -XFS_ERROR(EINVAL); } @@ -412,51 +412,6 @@ xfs_file_splice_read( return ret; } -STATIC void -xfs_aio_write_isize_update( - struct inode *inode, - loff_t *ppos, - ssize_t bytes_written) -{ - struct xfs_inode *ip = XFS_I(inode); - xfs_fsize_t isize = i_size_read(inode); - - if (bytes_written > 0) - XFS_STATS_ADD(xs_write_bytes, bytes_written); - - if (unlikely(bytes_written < 0 && bytes_written != -EFAULT && - *ppos > isize)) - *ppos = isize; - - if (*ppos > ip->i_size) { - xfs_rw_ilock(ip, XFS_ILOCK_EXCL); - if (*ppos > ip->i_size) - ip->i_size = *ppos; - xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); - } -} - -/* - * If this was a direct or synchronous I/O that failed (such as ENOSPC) then - * part of the I/O may have been written to disk before the error occurred. In - * this case the on-disk file size may have been adjusted beyond the in-memory - * file size and now needs to be truncated back. - */ -STATIC void -xfs_aio_write_newsize_update( - struct xfs_inode *ip, - xfs_fsize_t new_size) -{ - if (new_size == ip->i_new_size) { - xfs_rw_ilock(ip, XFS_ILOCK_EXCL); - if (new_size == ip->i_new_size) - ip->i_new_size = 0; - if (ip->i_d.di_size > ip->i_size) - ip->i_d.di_size = ip->i_size; - xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); - } -} - /* * xfs_file_splice_write() does not use xfs_rw_ilock() because * generic_file_splice_write() takes the i_mutex itself. This, in theory, @@ -475,7 +430,6 @@ xfs_file_splice_write( { struct inode *inode = outfilp->f_mapping->host; struct xfs_inode *ip = XFS_I(inode); - xfs_fsize_t new_size; int ioflags = 0; ssize_t ret; @@ -489,19 +443,12 @@ xfs_file_splice_write( xfs_ilock(ip, XFS_IOLOCK_EXCL); - new_size = *ppos + count; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - if (new_size > ip->i_size) - ip->i_new_size = new_size; - xfs_iunlock(ip, XFS_ILOCK_EXCL); - trace_xfs_file_splice_write(ip, count, *ppos, ioflags); ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); + if (ret > 0) + XFS_STATS_ADD(xs_write_bytes, ret); - xfs_aio_write_isize_update(inode, ppos, ret); - xfs_aio_write_newsize_update(ip, new_size); xfs_iunlock(ip, XFS_IOLOCK_EXCL); return ret; } @@ -689,28 +636,26 @@ out_lock: /* * Common pre-write limit and setup checks. * - * Returns with iolock held according to @iolock. + * Called with the iolocked held either shared and exclusive according to + * @iolock, and returns with it held. Might upgrade the iolock to exclusive + * if called for a direct write beyond i_size. */ STATIC ssize_t xfs_file_aio_write_checks( struct file *file, loff_t *pos, size_t *count, - xfs_fsize_t *new_sizep, int *iolock) { struct inode *inode = file->f_mapping->host; struct xfs_inode *ip = XFS_I(inode); - xfs_fsize_t new_size; int error = 0; xfs_rw_ilock(ip, XFS_ILOCK_EXCL); - *new_sizep = 0; restart: error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode)); if (error) { - xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); - *iolock = 0; + xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); return error; } @@ -720,36 +665,21 @@ restart: /* * If the offset is beyond the size of the file, we need to zero any * blocks that fall between the existing EOF and the start of this - * write. There is no need to issue zeroing if another in-flght IO ends - * at or before this one If zeronig is needed and we are currently - * holding the iolock shared, we need to update it to exclusive which - * involves dropping all locks and relocking to maintain correct locking - * order. If we do this, restart the function to ensure all checks and - * values are still valid. + * write. If zeroing is needed and we are currently holding the + * iolock shared, we need to update it to exclusive which involves + * dropping all locks and relocking to maintain correct locking order. + * If we do this, restart the function to ensure all checks and values + * are still valid. */ - if ((ip->i_new_size && *pos > ip->i_new_size) || - (!ip->i_new_size && *pos > ip->i_size)) { + if (*pos > i_size_read(inode)) { if (*iolock == XFS_IOLOCK_SHARED) { xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); *iolock = XFS_IOLOCK_EXCL; xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); goto restart; } - error = -xfs_zero_eof(ip, *pos, ip->i_size); + error = -xfs_zero_eof(ip, *pos, i_size_read(inode)); } - - /* - * If this IO extends beyond EOF, we may need to update ip->i_new_size. - * We have already zeroed space beyond EOF (if necessary). Only update - * ip->i_new_size if this IO ends beyond any other in-flight writes. - */ - new_size = *pos + *count; - if (new_size > ip->i_size) { - if (new_size > ip->i_new_size) - ip->i_new_size = new_size; - *new_sizep = new_size; - } - xfs_rw_iunlock(ip, XFS_ILOCK_EXCL); if (error) return error; @@ -794,9 +724,7 @@ xfs_file_dio_aio_write( const struct iovec *iovp, unsigned long nr_segs, loff_t pos, - size_t ocount, - xfs_fsize_t *new_size, - int *iolock) + size_t ocount) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -806,10 +734,10 @@ xfs_file_dio_aio_write( ssize_t ret = 0; size_t count = ocount; int unaligned_io = 0; + int iolock; struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; - *iolock = 0; if ((pos & target->bt_smask) || (count & target->bt_smask)) return -XFS_ERROR(EINVAL); @@ -824,31 +752,31 @@ xfs_file_dio_aio_write( * EOF zeroing cases and fill out the new inode size as appropriate. */ if (unaligned_io || mapping->nrpages) - *iolock = XFS_IOLOCK_EXCL; + iolock = XFS_IOLOCK_EXCL; else - *iolock = XFS_IOLOCK_SHARED; - xfs_rw_ilock(ip, *iolock); + iolock = XFS_IOLOCK_SHARED; + xfs_rw_ilock(ip, iolock); /* * Recheck if there are cached pages that need invalidate after we got * the iolock to protect against other threads adding new pages while * we were waiting for the iolock. */ - if (mapping->nrpages && *iolock == XFS_IOLOCK_SHARED) { - xfs_rw_iunlock(ip, *iolock); - *iolock = XFS_IOLOCK_EXCL; - xfs_rw_ilock(ip, *iolock); + if (mapping->nrpages && iolock == XFS_IOLOCK_SHARED) { + xfs_rw_iunlock(ip, iolock); + iolock = XFS_IOLOCK_EXCL; + xfs_rw_ilock(ip, iolock); } - ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock); + ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock); if (ret) - return ret; + goto out; if (mapping->nrpages) { ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1, FI_REMAPF_LOCKED); if (ret) - return ret; + goto out; } /* @@ -857,15 +785,18 @@ xfs_file_dio_aio_write( */ if (unaligned_io) inode_dio_wait(inode); - else if (*iolock == XFS_IOLOCK_EXCL) { + else if (iolock == XFS_IOLOCK_EXCL) { xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL); - *iolock = XFS_IOLOCK_SHARED; + iolock = XFS_IOLOCK_SHARED; } trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0); ret = generic_file_direct_write(iocb, iovp, &nr_segs, pos, &iocb->ki_pos, count, ocount); +out: + xfs_rw_iunlock(ip, iolock); + /* No fallback to buffered IO on errors for XFS. */ ASSERT(ret < 0 || ret == count); return ret; @@ -877,9 +808,7 @@ xfs_file_buffered_aio_write( const struct iovec *iovp, unsigned long nr_segs, loff_t pos, - size_t ocount, - xfs_fsize_t *new_size, - int *iolock) + size_t ocount) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; @@ -887,14 +816,14 @@ xfs_file_buffered_aio_write( struct xfs_inode *ip = XFS_I(inode); ssize_t ret; int enospc = 0; + int iolock = XFS_IOLOCK_EXCL; size_t count = ocount; - *iolock = XFS_IOLOCK_EXCL; - xfs_rw_ilock(ip, *iolock); + xfs_rw_ilock(ip, iolock); - ret = xfs_file_aio_write_checks(file, &pos, &count, new_size, iolock); + ret = xfs_file_aio_write_checks(file, &pos, &count, &iolock); if (ret) - return ret; + goto out; /* We can write back this queue in page reclaim */ current->backing_dev_info = mapping->backing_dev_info; @@ -908,13 +837,15 @@ write_retry: * page locks and retry *once* */ if (ret == -ENOSPC && !enospc) { - ret = -xfs_flush_pages(ip, 0, -1, 0, FI_NONE); - if (ret) - return ret; enospc = 1; - goto write_retry; + ret = -xfs_flush_pages(ip, 0, -1, 0, FI_NONE); + if (!ret) + goto write_retry; } + current->backing_dev_info = NULL; +out: + xfs_rw_iunlock(ip, iolock); return ret; } @@ -930,9 +861,7 @@ xfs_file_aio_write( struct inode *inode = mapping->host; struct xfs_inode *ip = XFS_I(inode); ssize_t ret; - int iolock; size_t ocount = 0; - xfs_fsize_t new_size = 0; XFS_STATS_INC(xs_write_calls); @@ -951,33 +880,22 @@ xfs_file_aio_write( return -EIO; if (unlikely(file->f_flags & O_DIRECT)) - ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, - ocount, &new_size, &iolock); + ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, ocount); else ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos, - ocount, &new_size, &iolock); - - xfs_aio_write_isize_update(inode, &iocb->ki_pos, ret); + ocount); - if (ret <= 0) - goto out_unlock; + if (ret > 0) { + ssize_t err; - /* Handle various SYNC-type writes */ - if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { - loff_t end = pos + ret - 1; - int error; + XFS_STATS_ADD(xs_write_bytes, ret); - xfs_rw_iunlock(ip, iolock); - error = xfs_file_fsync(file, pos, end, - (file->f_flags & __O_SYNC) ? 0 : 1); - xfs_rw_ilock(ip, iolock); - if (error) - ret = error; + /* Handle various SYNC-type writes */ + err = generic_write_sync(file, pos, ret); + if (err < 0) + ret = err; } -out_unlock: - xfs_aio_write_newsize_update(ip, new_size); - xfs_rw_iunlock(ip, iolock); return ret; } diff --git a/fs/xfs/xfs_fs_subr.c b/fs/xfs/xfs_fs_subr.c index ed88ed16811c..652b875a9d4c 100644 --- a/fs/xfs/xfs_fs_subr.c +++ b/fs/xfs/xfs_fs_subr.c @@ -90,7 +90,7 @@ xfs_wait_on_pages( if (mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) { return -filemap_fdatawait_range(mapping, first, - last == -1 ? ip->i_size - 1 : last); + last == -1 ? XFS_ISIZE(ip) - 1 : last); } return 0; } diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 3960a066d7ff..8c3e46394d48 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -77,7 +77,7 @@ xfs_inode_alloc( ASSERT(atomic_read(&ip->i_pincount) == 0); ASSERT(!spin_is_locked(&ip->i_flags_lock)); - ASSERT(completion_done(&ip->i_flush)); + ASSERT(!xfs_isiflocked(ip)); ASSERT(ip->i_ino == 0); mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino); @@ -94,8 +94,6 @@ xfs_inode_alloc( ip->i_update_core = 0; ip->i_delayed_blks = 0; memset(&ip->i_d, 0, sizeof(xfs_icdinode_t)); - ip->i_size = 0; - ip->i_new_size = 0; return ip; } @@ -150,7 +148,7 @@ xfs_inode_free( /* asserts to verify all state is correct here */ ASSERT(atomic_read(&ip->i_pincount) == 0); ASSERT(!spin_is_locked(&ip->i_flags_lock)); - ASSERT(completion_done(&ip->i_flush)); + ASSERT(!xfs_isiflocked(ip)); /* * Because we use RCU freeing we need to ensure the inode always @@ -450,8 +448,6 @@ again: *ipp = ip; - ASSERT(ip->i_df.if_ext_max == - XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t)); /* * If we have a real type for an on-disk inode, we can set ops(&unlock) * now. If it's a new inode being created, xfs_ialloc will handle it. @@ -715,3 +711,19 @@ xfs_isilocked( return 0; } #endif + +void +__xfs_iflock( + struct xfs_inode *ip) +{ + wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT); + DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT); + + do { + prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE); + if (xfs_isiflocked(ip)) + io_schedule(); + } while (!xfs_iflock_nowait(ip)); + + finish_wait(wq, &wait.wait); +} diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 9dda7cc32848..b21022499c2e 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -299,11 +299,8 @@ xfs_iformat( { xfs_attr_shortform_t *atp; int size; - int error; + int error = 0; xfs_fsize_t di_size; - ip->i_df.if_ext_max = - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); - error = 0; if (unlikely(be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) > @@ -350,7 +347,6 @@ xfs_iformat( return XFS_ERROR(EFSCORRUPTED); } ip->i_d.di_size = 0; - ip->i_size = 0; ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip); break; @@ -409,10 +405,10 @@ xfs_iformat( } if (!XFS_DFORK_Q(dip)) return 0; + ASSERT(ip->i_afp == NULL); ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS); - ip->i_afp->if_ext_max = - XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + switch (dip->di_aformat) { case XFS_DINODE_FMT_LOCAL: atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); @@ -604,10 +600,11 @@ xfs_iformat_btree( * or the number of extents is greater than the number of * blocks. */ - if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max - || XFS_BMDR_SPACE_CALC(nrecs) > - XFS_DFORK_SIZE(dip, ip->i_mount, whichfork) - || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) { + if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= + XFS_IFORK_MAXEXT(ip, whichfork) || + XFS_BMDR_SPACE_CALC(nrecs) > + XFS_DFORK_SIZE(dip, ip->i_mount, whichfork) || + XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) { xfs_warn(ip->i_mount, "corrupt inode %Lu (btree).", (unsigned long long) ip->i_ino); XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW, @@ -835,12 +832,6 @@ xfs_iread( * with the uninitialized part of it. */ ip->i_d.di_mode = 0; - /* - * Initialize the per-fork minima and maxima for a new - * inode here. xfs_iformat will do it for old inodes. - */ - ip->i_df.if_ext_max = - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); } /* @@ -861,7 +852,6 @@ xfs_iread( } ip->i_delayed_blks = 0; - ip->i_size = ip->i_d.di_size; /* * Mark the buffer containing the inode as something to keep @@ -1051,7 +1041,6 @@ xfs_ialloc( } ip->i_d.di_size = 0; - ip->i_size = 0; ip->i_d.di_nextents = 0; ASSERT(ip->i_d.di_nblocks == 0); @@ -1166,52 +1155,6 @@ xfs_ialloc( } /* - * Check to make sure that there are no blocks allocated to the - * file beyond the size of the file. We don't check this for - * files with fixed size extents or real time extents, but we - * at least do it for regular files. - */ -#ifdef DEBUG -STATIC void -xfs_isize_check( - struct xfs_inode *ip, - xfs_fsize_t isize) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t map_first; - int nimaps; - xfs_bmbt_irec_t imaps[2]; - int error; - - if (!S_ISREG(ip->i_d.di_mode)) - return; - - if (XFS_IS_REALTIME_INODE(ip)) - return; - - if (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) - return; - - nimaps = 2; - map_first = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); - /* - * The filesystem could be shutting down, so bmapi may return - * an error. - */ - error = xfs_bmapi_read(ip, map_first, - (XFS_B_TO_FSB(mp, - (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - map_first), - imaps, &nimaps, XFS_BMAPI_ENTIRE); - if (error) - return; - ASSERT(nimaps == 1); - ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK); -} -#else /* DEBUG */ -#define xfs_isize_check(ip, isize) -#endif /* DEBUG */ - -/* * Free up the underlying blocks past new_size. The new size must be smaller * than the current size. This routine can be used both for the attribute and * data fork, and does not modify the inode size, which is left to the caller. @@ -1252,12 +1195,14 @@ xfs_itruncate_extents( int done = 0; ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); - ASSERT(new_size <= ip->i_size); + ASSERT(new_size <= XFS_ISIZE(ip)); ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); ASSERT(ip->i_itemp != NULL); ASSERT(ip->i_itemp->ili_lock_flags == 0); ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); + trace_xfs_itruncate_extents_start(ip, new_size); + /* * Since it is possible for space to become allocated beyond * the end of the file (in a crash where the space is allocated @@ -1325,6 +1270,14 @@ xfs_itruncate_extents( goto out; } + /* + * Always re-log the inode so that our permanent transaction can keep + * on rolling it forward in the log. + */ + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + trace_xfs_itruncate_extents_end(ip, new_size); + out: *tpp = tp; return error; @@ -1338,74 +1291,6 @@ out_bmap_cancel: goto out; } -int -xfs_itruncate_data( - struct xfs_trans **tpp, - struct xfs_inode *ip, - xfs_fsize_t new_size) -{ - int error; - - trace_xfs_itruncate_data_start(ip, new_size); - - /* - * The first thing we do is set the size to new_size permanently on - * disk. This way we don't have to worry about anyone ever being able - * to look at the data being freed even in the face of a crash. - * What we're getting around here is the case where we free a block, it - * is allocated to another file, it is written to, and then we crash. - * If the new data gets written to the file but the log buffers - * containing the free and reallocation don't, then we'd end up with - * garbage in the blocks being freed. As long as we make the new_size - * permanent before actually freeing any blocks it doesn't matter if - * they get written to. - */ - if (ip->i_d.di_nextents > 0) { - /* - * If we are not changing the file size then do not update - * the on-disk file size - we may be called from - * xfs_inactive_free_eofblocks(). If we update the on-disk - * file size and then the system crashes before the contents - * of the file are flushed to disk then the files may be - * full of holes (ie NULL files bug). - */ - if (ip->i_size != new_size) { - ip->i_d.di_size = new_size; - ip->i_size = new_size; - xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); - } - } - - error = xfs_itruncate_extents(tpp, ip, XFS_DATA_FORK, new_size); - if (error) - return error; - - /* - * If we are not changing the file size then do not update the on-disk - * file size - we may be called from xfs_inactive_free_eofblocks(). - * If we update the on-disk file size and then the system crashes - * before the contents of the file are flushed to disk then the files - * may be full of holes (ie NULL files bug). - */ - xfs_isize_check(ip, new_size); - if (ip->i_size != new_size) { - ip->i_d.di_size = new_size; - ip->i_size = new_size; - } - - ASSERT(new_size != 0 || ip->i_delayed_blks == 0); - ASSERT(new_size != 0 || ip->i_d.di_nextents == 0); - - /* - * Always re-log the inode so that our permanent transaction can keep - * on rolling it forward in the log. - */ - xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); - - trace_xfs_itruncate_data_end(ip, new_size); - return 0; -} - /* * This is called when the inode's link count goes to 0. * We place the on-disk inode on a list in the AGI. It @@ -1824,8 +1709,7 @@ xfs_ifree( ASSERT(ip->i_d.di_nlink == 0); ASSERT(ip->i_d.di_nextents == 0); ASSERT(ip->i_d.di_anextents == 0); - ASSERT((ip->i_d.di_size == 0 && ip->i_size == 0) || - (!S_ISREG(ip->i_d.di_mode))); + ASSERT(ip->i_d.di_size == 0 || !S_ISREG(ip->i_d.di_mode)); ASSERT(ip->i_d.di_nblocks == 0); /* @@ -1844,8 +1728,6 @@ xfs_ifree( ip->i_d.di_flags = 0; ip->i_d.di_dmevmask = 0; ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ - ip->i_df.if_ext_max = - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; /* @@ -2151,7 +2033,7 @@ xfs_idestroy_fork( * once someone is waiting for it to be unpinned. */ static void -xfs_iunpin_nowait( +xfs_iunpin( struct xfs_inode *ip) { ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); @@ -2163,14 +2045,29 @@ xfs_iunpin_nowait( } +static void +__xfs_iunpin_wait( + struct xfs_inode *ip) +{ + wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IPINNED_BIT); + DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IPINNED_BIT); + + xfs_iunpin(ip); + + do { + prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); + if (xfs_ipincount(ip)) + io_schedule(); + } while (xfs_ipincount(ip)); + finish_wait(wq, &wait.wait); +} + void xfs_iunpin_wait( struct xfs_inode *ip) { - if (xfs_ipincount(ip)) { - xfs_iunpin_nowait(ip); - wait_event(ip->i_ipin_wait, (xfs_ipincount(ip) == 0)); - } + if (xfs_ipincount(ip)) + __xfs_iunpin_wait(ip); } /* @@ -2510,9 +2407,9 @@ xfs_iflush( XFS_STATS_INC(xs_iflush_count); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); - ASSERT(!completion_done(&ip->i_flush)); + ASSERT(xfs_isiflocked(ip)); ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || - ip->i_d.di_nextents > ip->i_df.if_ext_max); + ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)); iip = ip->i_itemp; mp = ip->i_mount; @@ -2529,7 +2426,7 @@ xfs_iflush( * out for us if they occur after the log force completes. */ if (!(flags & SYNC_WAIT) && xfs_ipincount(ip)) { - xfs_iunpin_nowait(ip); + xfs_iunpin(ip); xfs_ifunlock(ip); return EAGAIN; } @@ -2626,9 +2523,9 @@ xfs_iflush_int( #endif ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); - ASSERT(!completion_done(&ip->i_flush)); + ASSERT(xfs_isiflocked(ip)); ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || - ip->i_d.di_nextents > ip->i_df.if_ext_max); + ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)); iip = ip->i_itemp; mp = ip->i_mount; diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index f0e6b151ba37..2f27b7454085 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -66,7 +66,6 @@ typedef struct xfs_ifork { struct xfs_btree_block *if_broot; /* file's incore btree root */ short if_broot_bytes; /* bytes allocated for root */ unsigned char if_flags; /* per-fork flags */ - unsigned char if_ext_max; /* max # of extent records */ union { xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */ xfs_ext_irec_t *if_ext_irec; /* irec map file exts */ @@ -206,12 +205,12 @@ typedef struct xfs_icdinode { ((w) == XFS_DATA_FORK ? \ ((ip)->i_d.di_nextents = (n)) : \ ((ip)->i_d.di_anextents = (n))) - +#define XFS_IFORK_MAXEXT(ip, w) \ + (XFS_IFORK_SIZE(ip, w) / sizeof(xfs_bmbt_rec_t)) #ifdef __KERNEL__ -struct bhv_desc; struct xfs_buf; struct xfs_bmap_free; struct xfs_bmbt_irec; @@ -220,12 +219,6 @@ struct xfs_mount; struct xfs_trans; struct xfs_dquot; -typedef struct dm_attrs_s { - __uint32_t da_dmevmask; /* DMIG event mask */ - __uint16_t da_dmstate; /* DMIG state info */ - __uint16_t da_pad; /* DMIG extra padding */ -} dm_attrs_t; - typedef struct xfs_inode { /* Inode linking and identification information. */ struct xfs_mount *i_mount; /* fs mount struct ptr */ @@ -244,27 +237,19 @@ typedef struct xfs_inode { struct xfs_inode_log_item *i_itemp; /* logging information */ mrlock_t i_lock; /* inode lock */ mrlock_t i_iolock; /* inode IO lock */ - struct completion i_flush; /* inode flush completion q */ atomic_t i_pincount; /* inode pin count */ - wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */ spinlock_t i_flags_lock; /* inode i_flags lock */ /* Miscellaneous state. */ - unsigned short i_flags; /* see defined flags below */ + unsigned long i_flags; /* see defined flags below */ unsigned char i_update_core; /* timestamps/size is dirty */ unsigned int i_delayed_blks; /* count of delay alloc blks */ xfs_icdinode_t i_d; /* most of ondisk inode */ - xfs_fsize_t i_size; /* in-memory size */ - xfs_fsize_t i_new_size; /* size when write completes */ - /* VFS inode */ struct inode i_vnode; /* embedded VFS inode */ } xfs_inode_t; -#define XFS_ISIZE(ip) S_ISREG((ip)->i_d.di_mode) ? \ - (ip)->i_size : (ip)->i_d.di_size; - /* Convert from vfs inode to xfs inode */ static inline struct xfs_inode *XFS_I(struct inode *inode) { @@ -278,6 +263,18 @@ static inline struct inode *VFS_I(struct xfs_inode *ip) } /* + * For regular files we only update the on-disk filesize when actually + * writing data back to disk. Until then only the copy in the VFS inode + * is uptodate. + */ +static inline xfs_fsize_t XFS_ISIZE(struct xfs_inode *ip) +{ + if (S_ISREG(ip->i_d.di_mode)) + return i_size_read(VFS_I(ip)); + return ip->i_d.di_size; +} + +/* * i_flags helper functions */ static inline void @@ -331,6 +328,19 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags) return ret; } +static inline int +xfs_iflags_test_and_set(xfs_inode_t *ip, unsigned short flags) +{ + int ret; + + spin_lock(&ip->i_flags_lock); + ret = ip->i_flags & flags; + if (!ret) + ip->i_flags |= flags; + spin_unlock(&ip->i_flags_lock); + return ret; +} + /* * Project quota id helpers (previously projid was 16bit only * and using two 16bit values to hold new 32bit projid was chosen @@ -351,35 +361,19 @@ xfs_set_projid(struct xfs_inode *ip, } /* - * Manage the i_flush queue embedded in the inode. This completion - * queue synchronizes processes attempting to flush the in-core - * inode back to disk. - */ -static inline void xfs_iflock(xfs_inode_t *ip) -{ - wait_for_completion(&ip->i_flush); -} - -static inline int xfs_iflock_nowait(xfs_inode_t *ip) -{ - return try_wait_for_completion(&ip->i_flush); -} - -static inline void xfs_ifunlock(xfs_inode_t *ip) -{ - complete(&ip->i_flush); -} - -/* * In-core inode flags. */ -#define XFS_IRECLAIM 0x0001 /* started reclaiming this inode */ -#define XFS_ISTALE 0x0002 /* inode has been staled */ -#define XFS_IRECLAIMABLE 0x0004 /* inode can be reclaimed */ -#define XFS_INEW 0x0008 /* inode has just been allocated */ -#define XFS_IFILESTREAM 0x0010 /* inode is in a filestream directory */ -#define XFS_ITRUNCATED 0x0020 /* truncated down so flush-on-close */ -#define XFS_IDIRTY_RELEASE 0x0040 /* dirty release already seen */ +#define XFS_IRECLAIM (1 << 0) /* started reclaiming this inode */ +#define XFS_ISTALE (1 << 1) /* inode has been staled */ +#define XFS_IRECLAIMABLE (1 << 2) /* inode can be reclaimed */ +#define XFS_INEW (1 << 3) /* inode has just been allocated */ +#define XFS_IFILESTREAM (1 << 4) /* inode is in a filestream dir. */ +#define XFS_ITRUNCATED (1 << 5) /* truncated down so flush-on-close */ +#define XFS_IDIRTY_RELEASE (1 << 6) /* dirty release already seen */ +#define __XFS_IFLOCK_BIT 7 /* inode is being flushed right now */ +#define XFS_IFLOCK (1 << __XFS_IFLOCK_BIT) +#define __XFS_IPINNED_BIT 8 /* wakeup key for zero pin count */ +#define XFS_IPINNED (1 << __XFS_IPINNED_BIT) /* * Per-lifetime flags need to be reset when re-using a reclaimable inode during @@ -392,6 +386,34 @@ static inline void xfs_ifunlock(xfs_inode_t *ip) XFS_IFILESTREAM); /* + * Synchronize processes attempting to flush the in-core inode back to disk. + */ + +extern void __xfs_iflock(struct xfs_inode *ip); + +static inline int xfs_iflock_nowait(struct xfs_inode *ip) +{ + return !xfs_iflags_test_and_set(ip, XFS_IFLOCK); +} + +static inline void xfs_iflock(struct xfs_inode *ip) +{ + if (!xfs_iflock_nowait(ip)) + __xfs_iflock(ip); +} + +static inline void xfs_ifunlock(struct xfs_inode *ip) +{ + xfs_iflags_clear(ip, XFS_IFLOCK); + wake_up_bit(&ip->i_flags, __XFS_IFLOCK_BIT); +} + +static inline int xfs_isiflocked(struct xfs_inode *ip) +{ + return xfs_iflags_test(ip, XFS_IFLOCK); +} + +/* * Flags for inode locking. * Bit ranges: 1<<1 - 1<<16-1 -- iolock/ilock modes (bitfield) * 1<<16 - 1<<32-1 -- lockdep annotation (integers) @@ -491,8 +513,6 @@ int xfs_ifree(struct xfs_trans *, xfs_inode_t *, struct xfs_bmap_free *); int xfs_itruncate_extents(struct xfs_trans **, struct xfs_inode *, int, xfs_fsize_t); -int xfs_itruncate_data(struct xfs_trans **, struct xfs_inode *, - xfs_fsize_t); int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); void xfs_iext_realloc(xfs_inode_t *, int, int); diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index cfd6c7f8cc3c..91d71dcd4852 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -79,8 +79,6 @@ xfs_inode_item_size( break; case XFS_DINODE_FMT_BTREE: - ASSERT(ip->i_df.if_ext_max == - XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); iip->ili_format.ilf_fields &= ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT | XFS_ILOG_DEV | XFS_ILOG_UUID); @@ -557,7 +555,7 @@ xfs_inode_item_unpin( trace_xfs_inode_unpin(ip, _RET_IP_); ASSERT(atomic_read(&ip->i_pincount) > 0); if (atomic_dec_and_test(&ip->i_pincount)) - wake_up(&ip->i_ipin_wait); + wake_up_bit(&ip->i_flags, __XFS_IPINNED_BIT); } /* @@ -719,7 +717,7 @@ xfs_inode_item_pushbuf( * If a flush is not in progress anymore, chances are that the * inode was taken off the AIL. So, just get out. */ - if (completion_done(&ip->i_flush) || + if (!xfs_isiflocked(ip) || !(lip->li_flags & XFS_LI_IN_AIL)) { xfs_iunlock(ip, XFS_ILOCK_SHARED); return true; @@ -752,7 +750,7 @@ xfs_inode_item_push( struct xfs_inode *ip = iip->ili_inode; ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED)); - ASSERT(!completion_done(&ip->i_flush)); + ASSERT(xfs_isiflocked(ip)); /* * Since we were able to lock the inode's flush lock and diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 9afa282aa937..246c7d57c6f9 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -57,26 +57,26 @@ xfs_iomap_eof_align_last_fsb( xfs_fileoff_t *last_fsb) { xfs_fileoff_t new_last_fsb = 0; - xfs_extlen_t align; + xfs_extlen_t align = 0; int eof, error; - if (XFS_IS_REALTIME_INODE(ip)) - ; - /* - * If mounted with the "-o swalloc" option, roundup the allocation - * request to a stripe width boundary if the file size is >= - * stripe width and we are allocating past the allocation eof. - */ - else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) && - (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_swidth))) - new_last_fsb = roundup_64(*last_fsb, mp->m_swidth); - /* - * Roundup the allocation request to a stripe unit (m_dalign) boundary - * if the file size is >= stripe unit size, and we are allocating past - * the allocation eof. - */ - else if (mp->m_dalign && (ip->i_size >= XFS_FSB_TO_B(mp, mp->m_dalign))) - new_last_fsb = roundup_64(*last_fsb, mp->m_dalign); + if (!XFS_IS_REALTIME_INODE(ip)) { + /* + * Round up the allocation request to a stripe unit + * (m_dalign) boundary if the file size is >= stripe unit + * size, and we are allocating past the allocation eof. + * + * If mounted with the "-o swalloc" option the alignment is + * increased from the strip unit size to the stripe width. + */ + if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC)) + align = mp->m_swidth; + else if (mp->m_dalign) + align = mp->m_dalign; + + if (align && XFS_ISIZE(ip) >= XFS_FSB_TO_B(mp, align)) + new_last_fsb = roundup_64(*last_fsb, align); + } /* * Always round up the allocation request to an extent boundary @@ -154,7 +154,7 @@ xfs_iomap_write_direct( offset_fsb = XFS_B_TO_FSBT(mp, offset); last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); - if ((offset + count) > ip->i_size) { + if ((offset + count) > XFS_ISIZE(ip)) { error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb); if (error) goto error_out; @@ -211,7 +211,7 @@ xfs_iomap_write_direct( xfs_trans_ijoin(tp, ip, 0); bmapi_flag = 0; - if (offset < ip->i_size || extsz) + if (offset < XFS_ISIZE(ip) || extsz) bmapi_flag |= XFS_BMAPI_PREALLOC; /* @@ -286,7 +286,7 @@ xfs_iomap_eof_want_preallocate( int found_delalloc = 0; *prealloc = 0; - if ((offset + count) <= ip->i_size) + if (offset + count <= XFS_ISIZE(ip)) return 0; /* @@ -340,7 +340,7 @@ xfs_iomap_prealloc_size( * if we pass in alloc_blocks = 0. Hence the "+ 1" to * ensure we always pass in a non-zero value. */ - alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size) + 1; + alloc_blocks = XFS_B_TO_FSB(mp, XFS_ISIZE(ip)) + 1; alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN, rounddown_pow_of_two(alloc_blocks)); @@ -564,7 +564,7 @@ xfs_iomap_write_allocate( * back.... */ nimaps = 1; - end_fsb = XFS_B_TO_FSB(mp, ip->i_size); + end_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip)); error = xfs_bmap_last_offset(NULL, ip, &last_block, XFS_DATA_FORK); if (error) diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index f9babd179223..ab302539e5b9 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -750,6 +750,7 @@ xfs_setattr_size( struct xfs_mount *mp = ip->i_mount; struct inode *inode = VFS_I(ip); int mask = iattr->ia_valid; + xfs_off_t oldsize, newsize; struct xfs_trans *tp; int error; uint lock_flags; @@ -777,11 +778,13 @@ xfs_setattr_size( lock_flags |= XFS_IOLOCK_EXCL; xfs_ilock(ip, lock_flags); + oldsize = inode->i_size; + newsize = iattr->ia_size; + /* * Short circuit the truncate case for zero length files. */ - if (iattr->ia_size == 0 && - ip->i_size == 0 && ip->i_d.di_nextents == 0) { + if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) { if (!(mask & (ATTR_CTIME|ATTR_MTIME))) goto out_unlock; @@ -807,14 +810,14 @@ xfs_setattr_size( * the inode to the transaction, because the inode cannot be unlocked * once it is a part of the transaction. */ - if (iattr->ia_size > ip->i_size) { + if (newsize > oldsize) { /* * Do the first part of growing a file: zero any data in the * last block that is beyond the old EOF. We need to do this * before the inode is joined to the transaction to modify * i_size. */ - error = xfs_zero_eof(ip, iattr->ia_size, ip->i_size); + error = xfs_zero_eof(ip, newsize, oldsize); if (error) goto out_unlock; } @@ -833,8 +836,8 @@ xfs_setattr_size( * here and prevents waiting for other data not within the range we * care about here. */ - if (ip->i_size != ip->i_d.di_size && iattr->ia_size > ip->i_d.di_size) { - error = xfs_flush_pages(ip, ip->i_d.di_size, iattr->ia_size, 0, + if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) { + error = xfs_flush_pages(ip, ip->i_d.di_size, newsize, 0, FI_NONE); if (error) goto out_unlock; @@ -845,8 +848,7 @@ xfs_setattr_size( */ inode_dio_wait(inode); - error = -block_truncate_page(inode->i_mapping, iattr->ia_size, - xfs_get_blocks); + error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks); if (error) goto out_unlock; @@ -857,7 +859,7 @@ xfs_setattr_size( if (error) goto out_trans_cancel; - truncate_setsize(inode, iattr->ia_size); + truncate_setsize(inode, newsize); commit_flags = XFS_TRANS_RELEASE_LOG_RES; lock_flags |= XFS_ILOCK_EXCL; @@ -876,19 +878,29 @@ xfs_setattr_size( * these flags set. For all other operations the VFS set these flags * explicitly if it wants a timestamp update. */ - if (iattr->ia_size != ip->i_size && - (!(mask & (ATTR_CTIME | ATTR_MTIME)))) { + if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) { iattr->ia_ctime = iattr->ia_mtime = current_fs_time(inode->i_sb); mask |= ATTR_CTIME | ATTR_MTIME; } - if (iattr->ia_size > ip->i_size) { - ip->i_d.di_size = iattr->ia_size; - ip->i_size = iattr->ia_size; - } else if (iattr->ia_size <= ip->i_size || - (iattr->ia_size == 0 && ip->i_d.di_nextents)) { - error = xfs_itruncate_data(&tp, ip, iattr->ia_size); + /* + * The first thing we do is set the size to new_size permanently on + * disk. This way we don't have to worry about anyone ever being able + * to look at the data being freed even in the face of a crash. + * What we're getting around here is the case where we free a block, it + * is allocated to another file, it is written to, and then we crash. + * If the new data gets written to the file but the log buffers + * containing the free and reallocation don't, then we'd end up with + * garbage in the blocks being freed. As long as we make the new size + * permanent before actually freeing any blocks it doesn't matter if + * they get written to. + */ + ip->i_d.di_size = newsize; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + if (newsize <= oldsize) { + error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, newsize); if (error) goto out_trans_abort; diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 5cc3dde1bc90..eafbcff81f3a 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c @@ -31,6 +31,7 @@ #include "xfs_mount.h" #include "xfs_bmap_btree.h" #include "xfs_inode.h" +#include "xfs_inode_item.h" #include "xfs_itable.h" #include "xfs_bmap.h" #include "xfs_rtalloc.h" @@ -263,13 +264,18 @@ xfs_qm_scall_trunc_qfile( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - error = xfs_itruncate_data(&tp, ip, 0); + ip->i_d.di_size = 0; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); if (error) { xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); goto out_unlock; } + ASSERT(ip->i_d.di_nextents == 0); + xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 281961c1d81a..ee5b695c99a7 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -828,14 +828,6 @@ xfs_fs_inode_init_once( /* xfs inode */ atomic_set(&ip->i_pincount, 0); spin_lock_init(&ip->i_flags_lock); - init_waitqueue_head(&ip->i_ipin_wait); - /* - * Because we want to use a counting completion, complete - * the flush completion once to allow a single access to - * the flush completion without blocking. - */ - init_completion(&ip->i_flush); - complete(&ip->i_flush); mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, "xfsino", ip->i_ino); diff --git a/fs/xfs/xfs_sync.c b/fs/xfs/xfs_sync.c index 72c01a1c16e7..40b75eecd2b4 100644 --- a/fs/xfs/xfs_sync.c +++ b/fs/xfs/xfs_sync.c @@ -707,14 +707,13 @@ xfs_reclaim_inode_grab( return 1; /* - * do some unlocked checks first to avoid unnecessary lock traffic. - * The first is a flush lock check, the second is a already in reclaim - * check. Only do these checks if we are not going to block on locks. + * If we are asked for non-blocking operation, do unlocked checks to + * see if the inode already is being flushed or in reclaim to avoid + * lock traffic. */ if ((flags & SYNC_TRYLOCK) && - (!ip->i_flush.done || __xfs_iflags_test(ip, XFS_IRECLAIM))) { + __xfs_iflags_test(ip, XFS_IFLOCK | XFS_IRECLAIM)) return 1; - } /* * The radix tree lock here protects a thread in xfs_iget from racing diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index a9d5b1e06efe..6b6df5802e95 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -891,7 +891,6 @@ DECLARE_EVENT_CLASS(xfs_file_class, __field(dev_t, dev) __field(xfs_ino_t, ino) __field(xfs_fsize_t, size) - __field(xfs_fsize_t, new_size) __field(loff_t, offset) __field(size_t, count) __field(int, flags) @@ -900,17 +899,15 @@ DECLARE_EVENT_CLASS(xfs_file_class, __entry->dev = VFS_I(ip)->i_sb->s_dev; __entry->ino = ip->i_ino; __entry->size = ip->i_d.di_size; - __entry->new_size = ip->i_new_size; __entry->offset = offset; __entry->count = count; __entry->flags = flags; ), - TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " + TP_printk("dev %d:%d ino 0x%llx size 0x%llx " "offset 0x%llx count 0x%zx ioflags %s", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino, __entry->size, - __entry->new_size, __entry->offset, __entry->count, __print_flags(__entry->flags, "|", XFS_IO_FLAGS)) @@ -978,7 +975,6 @@ DECLARE_EVENT_CLASS(xfs_imap_class, __field(dev_t, dev) __field(xfs_ino_t, ino) __field(loff_t, size) - __field(loff_t, new_size) __field(loff_t, offset) __field(size_t, count) __field(int, type) @@ -990,7 +986,6 @@ DECLARE_EVENT_CLASS(xfs_imap_class, __entry->dev = VFS_I(ip)->i_sb->s_dev; __entry->ino = ip->i_ino; __entry->size = ip->i_d.di_size; - __entry->new_size = ip->i_new_size; __entry->offset = offset; __entry->count = count; __entry->type = type; @@ -998,13 +993,11 @@ DECLARE_EVENT_CLASS(xfs_imap_class, __entry->startblock = irec ? irec->br_startblock : 0; __entry->blockcount = irec ? irec->br_blockcount : 0; ), - TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " - "offset 0x%llx count %zd type %s " - "startoff 0x%llx startblock %lld blockcount 0x%llx", + TP_printk("dev %d:%d ino 0x%llx size 0x%llx offset 0x%llx count %zd " + "type %s startoff 0x%llx startblock %lld blockcount 0x%llx", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino, __entry->size, - __entry->new_size, __entry->offset, __entry->count, __print_symbolic(__entry->type, XFS_IO_TYPES), @@ -1031,26 +1024,23 @@ DECLARE_EVENT_CLASS(xfs_simple_io_class, __field(xfs_ino_t, ino) __field(loff_t, isize) __field(loff_t, disize) - __field(loff_t, new_size) __field(loff_t, offset) __field(size_t, count) ), TP_fast_assign( __entry->dev = VFS_I(ip)->i_sb->s_dev; __entry->ino = ip->i_ino; - __entry->isize = ip->i_size; + __entry->isize = VFS_I(ip)->i_size; __entry->disize = ip->i_d.di_size; - __entry->new_size = ip->i_new_size; __entry->offset = offset; __entry->count = count; ), - TP_printk("dev %d:%d ino 0x%llx isize 0x%llx disize 0x%llx new_size 0x%llx " + TP_printk("dev %d:%d ino 0x%llx isize 0x%llx disize 0x%llx " "offset 0x%llx count %zd", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino, __entry->isize, __entry->disize, - __entry->new_size, __entry->offset, __entry->count) ); @@ -1090,8 +1080,8 @@ DECLARE_EVENT_CLASS(xfs_itrunc_class, DEFINE_EVENT(xfs_itrunc_class, name, \ TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), \ TP_ARGS(ip, new_size)) -DEFINE_ITRUNC_EVENT(xfs_itruncate_data_start); -DEFINE_ITRUNC_EVENT(xfs_itruncate_data_end); +DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_start); +DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_end); TRACE_EVENT(xfs_pagecache_inval, TP_PROTO(struct xfs_inode *ip, xfs_off_t start, xfs_off_t finish), @@ -1568,7 +1558,6 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class, __field(xfs_ino_t, ino) __field(int, format) __field(int, nex) - __field(int, max_nex) __field(int, broot_size) __field(int, fork_off) ), @@ -1578,18 +1567,16 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class, __entry->ino = ip->i_ino; __entry->format = ip->i_d.di_format; __entry->nex = ip->i_d.di_nextents; - __entry->max_nex = ip->i_df.if_ext_max; __entry->broot_size = ip->i_df.if_broot_bytes; __entry->fork_off = XFS_IFORK_BOFF(ip); ), TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %d, " - "Max in-fork extents %d, broot size %d, fork offset %d", + "broot size %d, fork offset %d", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino, __print_symbolic(__entry->which, XFS_SWAPEXT_INODES), __print_symbolic(__entry->format, XFS_INODE_FORMAT_STR), __entry->nex, - __entry->max_nex, __entry->broot_size, __entry->fork_off) ) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index f2fea868d4db..0cf52da9d246 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -175,7 +175,7 @@ xfs_free_eofblocks( * Figure out if there are any blocks beyond the end * of the file. If not, then there is nothing to do. */ - end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size)); + end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip)); last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp)); if (last_fsb <= end_fsb) return 0; @@ -226,7 +226,14 @@ xfs_free_eofblocks( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - error = xfs_itruncate_data(&tp, ip, ip->i_size); + /* + * Do not update the on-disk file size. If we update the + * on-disk file size and then the system crashes before the + * contents of the file are flushed to disk then the files + * may be full of holes (ie NULL files bug). + */ + error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, + XFS_ISIZE(ip)); if (error) { /* * If we get an error at this point we simply don't @@ -540,8 +547,8 @@ xfs_release( return 0; if ((S_ISREG(ip->i_d.di_mode) && - ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || - ip->i_delayed_blks > 0)) && + (VFS_I(ip)->i_size > 0 || + (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) && (ip->i_df.if_flags & XFS_IFEXTENTS)) && (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { @@ -618,7 +625,7 @@ xfs_inactive( * only one with a reference to the inode. */ truncate = ((ip->i_d.di_nlink == 0) && - ((ip->i_d.di_size != 0) || (ip->i_size != 0) || + ((ip->i_d.di_size != 0) || XFS_ISIZE(ip) != 0 || (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) && S_ISREG(ip->i_d.di_mode)); @@ -632,12 +639,12 @@ xfs_inactive( if (ip->i_d.di_nlink != 0) { if ((S_ISREG(ip->i_d.di_mode) && - ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || - ip->i_delayed_blks > 0)) && - (ip->i_df.if_flags & XFS_IFEXTENTS) && - (!(ip->i_d.di_flags & + (VFS_I(ip)->i_size > 0 || + (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) && + (ip->i_df.if_flags & XFS_IFEXTENTS) && + (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) || - (ip->i_delayed_blks != 0)))) { + ip->i_delayed_blks != 0))) { error = xfs_free_eofblocks(mp, ip, 0); if (error) return VN_INACTIVE_CACHE; @@ -670,13 +677,18 @@ xfs_inactive( xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, 0); - error = xfs_itruncate_data(&tp, ip, 0); + ip->i_d.di_size = 0; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); if (error) { xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); return VN_INACTIVE_CACHE; } + + ASSERT(ip->i_d.di_nextents == 0); } else if (S_ISLNK(ip->i_d.di_mode)) { /* @@ -1961,11 +1973,11 @@ xfs_zero_remaining_bytes( * since nothing can read beyond eof. The space will * be zeroed when the file is extended anyway. */ - if (startoff >= ip->i_size) + if (startoff >= XFS_ISIZE(ip)) return 0; - if (endoff > ip->i_size) - endoff = ip->i_size; + if (endoff > XFS_ISIZE(ip)) + endoff = XFS_ISIZE(ip); bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp, @@ -2260,7 +2272,7 @@ xfs_change_file_space( bf->l_start += offset; break; case 2: /*SEEK_END*/ - bf->l_start += ip->i_size; + bf->l_start += XFS_ISIZE(ip); break; default: return XFS_ERROR(EINVAL); @@ -2277,7 +2289,7 @@ xfs_change_file_space( bf->l_whence = 0; startoffset = bf->l_start; - fsize = ip->i_size; + fsize = XFS_ISIZE(ip); /* * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index fc1575fd4596..5b5af0d30a97 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -58,6 +58,7 @@ #define METHOD_NAME__PRT "_PRT" #define METHOD_NAME__CRS "_CRS" #define METHOD_NAME__PRS "_PRS" +#define METHOD_NAME__AEI "_AEI" #define METHOD_NAME__PRW "_PRW" #define METHOD_NAME__SRS "_SRS" diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h index 173972672175..451823cb8837 100644 --- a/include/acpi/acpi_numa.h +++ b/include/acpi/acpi_numa.h @@ -15,6 +15,7 @@ extern int pxm_to_node(int); extern int node_to_pxm(int); extern void __acpi_map_pxm_to_node(int, int); extern int acpi_map_pxm_to_node(int); +extern unsigned char acpi_srat_revision; #endif /* CONFIG_ACPI_NUMA */ #endif /* __ACP_NUMA_H */ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 83062ed0ef2f..2fe8639b3ae7 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -238,13 +238,6 @@ acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id, /* * Miscellaneous */ -acpi_status -acpi_os_validate_address(u8 space_id, acpi_physical_address address, - acpi_size length, char *name); -acpi_status -acpi_os_invalidate_address(u8 space_id, acpi_physical_address address, - acpi_size length); - u64 acpi_os_get_timer(void); acpi_status acpi_os_signal(u32 function, void *info); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index f554a9313b43..a28da35ba45e 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -47,7 +47,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20110623 +#define ACPI_CA_VERSION 0x20120111 #include "actypes.h" #include "actbl.h" @@ -66,7 +66,7 @@ extern u8 acpi_gbl_create_osi_method; extern u8 acpi_gbl_use_default_register_widths; extern acpi_name acpi_gbl_trace_method_name; extern u32 acpi_gbl_trace_flags; -extern u32 acpi_gbl_enable_aml_debug_object; +extern bool acpi_gbl_enable_aml_debug_object; extern u8 acpi_gbl_copy_dsdt_locally; extern u8 acpi_gbl_truncate_io_addresses; extern u8 acpi_gbl_disable_auto_repair; @@ -74,6 +74,7 @@ extern u8 acpi_gbl_disable_auto_repair; extern u32 acpi_current_gpe_count; extern struct acpi_table_fadt acpi_gbl_FADT; extern u8 acpi_gbl_system_awake_and_running; +extern u8 acpi_gbl_reduced_hardware; /* ACPI 5.0 */ extern u32 acpi_rsdt_forced; /* @@ -111,6 +112,11 @@ acpi_status acpi_install_interface(acpi_string interface_name); acpi_status acpi_remove_interface(acpi_string interface_name); +u32 +acpi_check_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, + acpi_size length, u8 warn); + /* * ACPI Memory management */ @@ -276,12 +282,23 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler); acpi_status acpi_install_interface_handler(acpi_interface_handler handler); /* - * Event interfaces + * Global Lock interfaces */ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle); acpi_status acpi_release_global_lock(u32 handle); +/* + * Interfaces to AML mutex objects + */ +acpi_status +acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout); + +acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname); + +/* + * Fixed Event interfaces + */ acpi_status acpi_enable_event(u32 event, u32 flags); acpi_status acpi_disable_event(u32 event, u32 flags); @@ -291,7 +308,7 @@ acpi_status acpi_clear_event(u32 event); acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status); /* - * GPE Interfaces + * General Purpose Event (GPE) Interfaces */ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number); @@ -346,6 +363,10 @@ acpi_get_possible_resources(acpi_handle device, struct acpi_buffer *ret_buffer); #endif acpi_status +acpi_get_event_resources(acpi_handle device_handle, + struct acpi_buffer *ret_buffer); + +acpi_status acpi_walk_resources(acpi_handle device, char *name, acpi_walk_resource_callback user_function, void *context); @@ -360,6 +381,11 @@ acpi_status acpi_resource_to_address64(struct acpi_resource *resource, struct acpi_resource_address64 *out); +acpi_status +acpi_buffer_to_resource(u8 *aml_buffer, + u16 aml_buffer_length, + struct acpi_resource **resource_ptr); + /* * Hardware (ACPI device) interfaces */ diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h index 0a66cc45dd6b..3506e39a66b1 100644 --- a/include/acpi/acrestyp.h +++ b/include/acpi/acrestyp.h @@ -61,11 +61,14 @@ typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (Length+3) = (6 #define ACPI_WRITE_COMBINING_MEMORY (u8) 0x02 #define ACPI_PREFETCHABLE_MEMORY (u8) 0x03 +/*! [Begin] no source code translation */ /* * IO Attributes - * The ISA IO ranges are: n000-n0_fFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh. - * The non-ISA IO ranges are: n100-n3_fFh, n500-n7_fFh, n900-n_bFFh, n_cd0-n_fFFh. + * The ISA IO ranges are: n000-n0FFh, n400-n4FFh, n800-n8FFh, nC00-nCFFh. + * The non-ISA IO ranges are: n100-n3FFh, n500-n7FFh, n900-nBFFh, nCD0-nFFFh. */ +/*! [End] no source code translation !*/ + #define ACPI_NON_ISA_ONLY_RANGES (u8) 0x01 #define ACPI_ISA_ONLY_RANGES (u8) 0x02 #define ACPI_ENTIRE_RANGE (ACPI_NON_ISA_ONLY_RANGES | ACPI_ISA_ONLY_RANGES) @@ -81,16 +84,26 @@ typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (Length+3) = (6 #define ACPI_DECODE_16 (u8) 0x01 /* 16-bit IO address decode */ /* - * IRQ Attributes + * Interrupt attributes - used in multiple descriptors */ + +/* Triggering */ + #define ACPI_LEVEL_SENSITIVE (u8) 0x00 #define ACPI_EDGE_SENSITIVE (u8) 0x01 +/* Polarity */ + #define ACPI_ACTIVE_HIGH (u8) 0x00 #define ACPI_ACTIVE_LOW (u8) 0x01 +#define ACPI_ACTIVE_BOTH (u8) 0x02 + +/* Sharing */ #define ACPI_EXCLUSIVE (u8) 0x00 #define ACPI_SHARED (u8) 0x01 +#define ACPI_EXCLUSIVE_AND_WAKE (u8) 0x02 +#define ACPI_SHARED_AND_WAKE (u8) 0x03 /* * DMA Attributes @@ -127,6 +140,8 @@ typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (Length+3) = (6 #define ACPI_POS_DECODE (u8) 0x00 #define ACPI_SUB_DECODE (u8) 0x01 +/* Producer/Consumer */ + #define ACPI_PRODUCER (u8) 0x00 #define ACPI_CONSUMER (u8) 0x01 @@ -192,6 +207,21 @@ struct acpi_resource_fixed_io { u8 address_length; }; +struct acpi_resource_fixed_dma { + u16 request_lines; + u16 channels; + u8 width; +}; + +/* Values for Width field above */ + +#define ACPI_DMA_WIDTH8 0 +#define ACPI_DMA_WIDTH16 1 +#define ACPI_DMA_WIDTH32 2 +#define ACPI_DMA_WIDTH64 3 +#define ACPI_DMA_WIDTH128 4 +#define ACPI_DMA_WIDTH256 5 + struct acpi_resource_vendor { u16 byte_length; u8 byte_data[1]; @@ -329,6 +359,166 @@ struct acpi_resource_generic_register { u64 address; }; +struct acpi_resource_gpio { + u8 revision_id; + u8 connection_type; + u8 producer_consumer; /* For values, see Producer/Consumer above */ + u8 pin_config; + u8 sharable; /* For values, see Interrupt Attributes above */ + u8 io_restriction; + u8 triggering; /* For values, see Interrupt Attributes above */ + u8 polarity; /* For values, see Interrupt Attributes above */ + u16 drive_strength; + u16 debounce_timeout; + u16 pin_table_length; + u16 vendor_length; + struct acpi_resource_source resource_source; + u16 *pin_table; + u8 *vendor_data; +}; + +/* Values for GPIO connection_type field above */ + +#define ACPI_RESOURCE_GPIO_TYPE_INT 0 +#define ACPI_RESOURCE_GPIO_TYPE_IO 1 + +/* Values for pin_config field above */ + +#define ACPI_PIN_CONFIG_DEFAULT 0 +#define ACPI_PIN_CONFIG_PULLUP 1 +#define ACPI_PIN_CONFIG_PULLDOWN 2 +#define ACPI_PIN_CONFIG_NOPULL 3 + +/* Values for io_restriction field above */ + +#define ACPI_IO_RESTRICT_NONE 0 +#define ACPI_IO_RESTRICT_INPUT 1 +#define ACPI_IO_RESTRICT_OUTPUT 2 +#define ACPI_IO_RESTRICT_NONE_PRESERVE 3 + +/* Common structure for I2C, SPI, and UART serial descriptors */ + +#define ACPI_RESOURCE_SERIAL_COMMON \ + u8 revision_id; \ + u8 type; \ + u8 producer_consumer; /* For values, see Producer/Consumer above */\ + u8 slave_mode; \ + u8 type_revision_id; \ + u16 type_data_length; \ + u16 vendor_length; \ + struct acpi_resource_source resource_source; \ + u8 *vendor_data; + +struct acpi_resource_common_serialbus { +ACPI_RESOURCE_SERIAL_COMMON}; + +/* Values for the Type field above */ + +#define ACPI_RESOURCE_SERIAL_TYPE_I2C 1 +#define ACPI_RESOURCE_SERIAL_TYPE_SPI 2 +#define ACPI_RESOURCE_SERIAL_TYPE_UART 3 + +/* Values for slave_mode field above */ + +#define ACPI_CONTROLLER_INITIATED 0 +#define ACPI_DEVICE_INITIATED 1 + +struct acpi_resource_i2c_serialbus { + ACPI_RESOURCE_SERIAL_COMMON u8 access_mode; + u16 slave_address; + u32 connection_speed; +}; + +/* Values for access_mode field above */ + +#define ACPI_I2C_7BIT_MODE 0 +#define ACPI_I2C_10BIT_MODE 1 + +struct acpi_resource_spi_serialbus { + ACPI_RESOURCE_SERIAL_COMMON u8 wire_mode; + u8 device_polarity; + u8 data_bit_length; + u8 clock_phase; + u8 clock_polarity; + u16 device_selection; + u32 connection_speed; +}; + +/* Values for wire_mode field above */ + +#define ACPI_SPI_4WIRE_MODE 0 +#define ACPI_SPI_3WIRE_MODE 1 + +/* Values for device_polarity field above */ + +#define ACPI_SPI_ACTIVE_LOW 0 +#define ACPI_SPI_ACTIVE_HIGH 1 + +/* Values for clock_phase field above */ + +#define ACPI_SPI_FIRST_PHASE 0 +#define ACPI_SPI_SECOND_PHASE 1 + +/* Values for clock_polarity field above */ + +#define ACPI_SPI_START_LOW 0 +#define ACPI_SPI_START_HIGH 1 + +struct acpi_resource_uart_serialbus { + ACPI_RESOURCE_SERIAL_COMMON u8 endian; + u8 data_bits; + u8 stop_bits; + u8 flow_control; + u8 parity; + u8 lines_enabled; + u16 rx_fifo_size; + u16 tx_fifo_size; + u32 default_baud_rate; +}; + +/* Values for Endian field above */ + +#define ACPI_UART_LITTLE_ENDIAN 0 +#define ACPI_UART_BIG_ENDIAN 1 + +/* Values for data_bits field above */ + +#define ACPI_UART_5_DATA_BITS 0 +#define ACPI_UART_6_DATA_BITS 1 +#define ACPI_UART_7_DATA_BITS 2 +#define ACPI_UART_8_DATA_BITS 3 +#define ACPI_UART_9_DATA_BITS 4 + +/* Values for stop_bits field above */ + +#define ACPI_UART_NO_STOP_BITS 0 +#define ACPI_UART_1_STOP_BIT 1 +#define ACPI_UART_1P5_STOP_BITS 2 +#define ACPI_UART_2_STOP_BITS 3 + +/* Values for flow_control field above */ + +#define ACPI_UART_FLOW_CONTROL_NONE 0 +#define ACPI_UART_FLOW_CONTROL_HW 1 +#define ACPI_UART_FLOW_CONTROL_XON_XOFF 2 + +/* Values for Parity field above */ + +#define ACPI_UART_PARITY_NONE 0 +#define ACPI_UART_PARITY_EVEN 1 +#define ACPI_UART_PARITY_ODD 2 +#define ACPI_UART_PARITY_MARK 3 +#define ACPI_UART_PARITY_SPACE 4 + +/* Values for lines_enabled bitfield above */ + +#define ACPI_UART_CARRIER_DETECT (1<<2) +#define ACPI_UART_RING_INDICATOR (1<<3) +#define ACPI_UART_DATA_SET_READY (1<<4) +#define ACPI_UART_DATA_TERMINAL_READY (1<<5) +#define ACPI_UART_CLEAR_TO_SEND (1<<6) +#define ACPI_UART_REQUEST_TO_SEND (1<<7) + /* ACPI_RESOURCE_TYPEs */ #define ACPI_RESOURCE_TYPE_IRQ 0 @@ -348,7 +538,10 @@ struct acpi_resource_generic_register { #define ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 14 /* ACPI 3.0 */ #define ACPI_RESOURCE_TYPE_EXTENDED_IRQ 15 #define ACPI_RESOURCE_TYPE_GENERIC_REGISTER 16 -#define ACPI_RESOURCE_TYPE_MAX 16 +#define ACPI_RESOURCE_TYPE_GPIO 17 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_FIXED_DMA 18 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_SERIAL_BUS 19 /* ACPI 5.0 */ +#define ACPI_RESOURCE_TYPE_MAX 19 /* Master union for resource descriptors */ @@ -358,6 +551,7 @@ union acpi_resource_data { struct acpi_resource_start_dependent start_dpf; struct acpi_resource_io io; struct acpi_resource_fixed_io fixed_io; + struct acpi_resource_fixed_dma fixed_dma; struct acpi_resource_vendor vendor; struct acpi_resource_vendor_typed vendor_typed; struct acpi_resource_end_tag end_tag; @@ -370,6 +564,11 @@ union acpi_resource_data { struct acpi_resource_extended_address64 ext_address64; struct acpi_resource_extended_irq extended_irq; struct acpi_resource_generic_register generic_reg; + struct acpi_resource_gpio gpio; + struct acpi_resource_i2c_serialbus i2c_serial_bus; + struct acpi_resource_spi_serialbus spi_serial_bus; + struct acpi_resource_uart_serialbus uart_serial_bus; + struct acpi_resource_common_serialbus common_serial_bus; /* Common fields */ diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index f1380287ed4d..8e1b92f6f650 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -255,6 +255,8 @@ struct acpi_table_fadt { struct acpi_generic_address xpm_timer_block; /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */ struct acpi_generic_address xgpe0_block; /* 64-bit Extended General Purpose Event 0 Reg Blk address */ struct acpi_generic_address xgpe1_block; /* 64-bit Extended General Purpose Event 1 Reg Blk address */ + struct acpi_generic_address sleep_control; /* 64-bit Sleep Control register */ + struct acpi_generic_address sleep_status; /* 64-bit Sleep Status register */ }; /* Masks for FADT Boot Architecture Flags (boot_flags) */ @@ -264,6 +266,7 @@ struct acpi_table_fadt { #define ACPI_FADT_NO_VGA (1<<2) /* 02: [V4] It is not safe to probe for VGA hardware */ #define ACPI_FADT_NO_MSI (1<<3) /* 03: [V4] Message Signaled Interrupts (MSI) must not be enabled */ #define ACPI_FADT_NO_ASPM (1<<4) /* 04: [V4] PCIe ASPM control must not be enabled */ +#define ACPI_FADT_NO_CMOS_RTC (1<<5) /* 05: [V5] No CMOS real-time clock present */ #define FADT2_REVISION_ID 3 @@ -289,6 +292,8 @@ struct acpi_table_fadt { #define ACPI_FADT_REMOTE_POWER_ON (1<<17) /* 17: [V4] System is compatible with remote power on (ACPI 3.0) */ #define ACPI_FADT_APIC_CLUSTER (1<<18) /* 18: [V4] All local APICs must use cluster model (ACPI 3.0) */ #define ACPI_FADT_APIC_PHYSICAL (1<<19) /* 19: [V4] All local x_aPICs must use physical dest mode (ACPI 3.0) */ +#define ACPI_FADT_HW_REDUCED (1<<20) /* 20: [V5] ACPI hardware is not implemented (ACPI 5.0) */ +#define ACPI_FADT_LOW_POWER_S0 (1<<21) /* 21: [V5] S0 power savings are equal or better than S3 (ACPI 5.0) */ /* Values for preferred_profile (Preferred Power Management Profiles) */ @@ -299,14 +304,16 @@ enum acpi_prefered_pm_profiles { PM_WORKSTATION = 3, PM_ENTERPRISE_SERVER = 4, PM_SOHO_SERVER = 5, - PM_APPLIANCE_PC = 6 + PM_APPLIANCE_PC = 6, + PM_PERFORMANCE_SERVER = 7, + PM_TABLET = 8 }; /* Reset to default packing */ #pragma pack() -#define ACPI_FADT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_fadt, f) +#define ACPI_FADT_OFFSET(f) (u16) ACPI_OFFSET (struct acpi_table_fadt, f) /* * Internal table-related structures @@ -342,6 +349,7 @@ struct acpi_table_desc { #include <acpi/actbl1.h> #include <acpi/actbl2.h> +#include <acpi/actbl3.h> /* * Sizes of the various flavors of FADT. We need to look closely @@ -351,12 +359,15 @@ struct acpi_table_desc { * FADT is the bottom line as to what the version really is. * * For reference, the values below are as follows: - * FADT V1 size: 0x74 - * FADT V2 size: 0x84 - * FADT V3+ size: 0xF4 + * FADT V1 size: 0x074 + * FADT V2 size: 0x084 + * FADT V3 size: 0x0F4 + * FADT V4 size: 0x0F4 + * FADT V5 size: 0x10C */ #define ACPI_FADT_V1_SIZE (u32) (ACPI_FADT_OFFSET (flags) + 4) #define ACPI_FADT_V2_SIZE (u32) (ACPI_FADT_OFFSET (reserved4[0]) + 3) -#define ACPI_FADT_V3_SIZE (u32) (sizeof (struct acpi_table_fadt)) +#define ACPI_FADT_V3_SIZE (u32) (ACPI_FADT_OFFSET (sleep_control)) +#define ACPI_FADT_V5_SIZE (u32) (sizeof (struct acpi_table_fadt)) #endif /* __ACTBL_H__ */ diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 7504bc99b29b..71e747beac8f 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -228,7 +228,8 @@ enum acpi_einj_actions { ACPI_EINJ_EXECUTE_OPERATION = 5, ACPI_EINJ_CHECK_BUSY_STATUS = 6, ACPI_EINJ_GET_COMMAND_STATUS = 7, - ACPI_EINJ_ACTION_RESERVED = 8, /* 8 and greater are reserved */ + ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS = 8, + ACPI_EINJ_ACTION_RESERVED = 9, /* 9 and greater are reserved */ ACPI_EINJ_TRIGGER_ERROR = 0xFF /* Except for this value */ }; @@ -240,7 +241,27 @@ enum acpi_einj_instructions { ACPI_EINJ_WRITE_REGISTER = 2, ACPI_EINJ_WRITE_REGISTER_VALUE = 3, ACPI_EINJ_NOOP = 4, - ACPI_EINJ_INSTRUCTION_RESERVED = 5 /* 5 and greater are reserved */ + ACPI_EINJ_FLUSH_CACHELINE = 5, + ACPI_EINJ_INSTRUCTION_RESERVED = 6 /* 6 and greater are reserved */ +}; + +struct acpi_einj_error_type_with_addr { + u32 error_type; + u32 vendor_struct_offset; + u32 flags; + u32 apic_id; + u64 address; + u64 range; + u32 pcie_id; +}; + +struct acpi_einj_vendor { + u32 length; + u32 pcie_id; + u16 vendor_id; + u16 device_id; + u8 revision_id; + u8 reserved[3]; }; /* EINJ Trigger Error Action Table */ @@ -275,6 +296,7 @@ enum acpi_einj_command_status { #define ACPI_EINJ_PLATFORM_CORRECTABLE (1<<9) #define ACPI_EINJ_PLATFORM_UNCORRECTABLE (1<<10) #define ACPI_EINJ_PLATFORM_FATAL (1<<11) +#define ACPI_EINJ_VENDOR_DEFINED (1<<31) /******************************************************************************* * @@ -631,7 +653,9 @@ enum acpi_madt_type { ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, ACPI_MADT_TYPE_LOCAL_X2APIC = 9, ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10, - ACPI_MADT_TYPE_RESERVED = 11 /* 11 and greater are reserved */ + ACPI_MADT_TYPE_GENERIC_INTERRUPT = 11, + ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12, + ACPI_MADT_TYPE_RESERVED = 13 /* 13 and greater are reserved */ }; /* @@ -752,11 +776,36 @@ struct acpi_madt_local_x2apic_nmi { u8 reserved[3]; }; +/* 11: Generic Interrupt (ACPI 5.0) */ + +struct acpi_madt_generic_interrupt { + struct acpi_subtable_header header; + u16 reserved; /* Reserved - must be zero */ + u32 gic_id; + u32 uid; + u32 flags; + u32 parking_version; + u32 performance_interrupt; + u64 parked_address; + u64 base_address; +}; + +/* 12: Generic Distributor (ACPI 5.0) */ + +struct acpi_madt_generic_distributor { + struct acpi_subtable_header header; + u16 reserved; /* Reserved - must be zero */ + u32 gic_id; + u64 base_address; + u32 global_irq_base; + u32 reserved2; /* Reserved - must be zero */ +}; + /* * Common flags fields for MADT subtables */ -/* MADT Local APIC flags (lapic_flags) */ +/* MADT Local APIC flags (lapic_flags) and GIC flags */ #define ACPI_MADT_ENABLED (1) /* 00: Processor is usable if set */ diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h new file mode 100644 index 000000000000..c22ce80e9535 --- /dev/null +++ b/include/acpi/actbl3.h @@ -0,0 +1,552 @@ +/****************************************************************************** + * + * Name: actbl3.h - ACPI Table Definitions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2011, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACTBL3_H__ +#define __ACTBL3_H__ + +/******************************************************************************* + * + * Additional ACPI Tables (3) + * + * These tables are not consumed directly by the ACPICA subsystem, but are + * included here to support device drivers and the AML disassembler. + * + * The tables in this file are fully defined within the ACPI specification. + * + ******************************************************************************/ + +/* + * Values for description table header signatures for tables defined in this + * file. Useful because they make it more difficult to inadvertently type in + * the wrong signature. + */ +#define ACPI_SIG_BGRT "BGRT" /* Boot Graphics Resource Table */ +#define ACPI_SIG_DRTM "DRTM" /* Dynamic Root of Trust for Measurement table */ +#define ACPI_SIG_FPDT "FPDT" /* Firmware Performance Data Table */ +#define ACPI_SIG_GTDT "GTDT" /* Generic Timer Description Table */ +#define ACPI_SIG_MPST "MPST" /* Memory Power State Table */ +#define ACPI_SIG_PCCT "PCCT" /* Platform Communications Channel Table */ +#define ACPI_SIG_PMTT "PMTT" /* Platform Memory Topology Table */ +#define ACPI_SIG_RASF "RASF" /* RAS Feature table */ + +#define ACPI_SIG_S3PT "S3PT" /* S3 Performance (sub)Table */ +#define ACPI_SIG_PCCS "PCC" /* PCC Shared Memory Region */ + +/* Reserved table signatures */ + +#define ACPI_SIG_CSRT "CSRT" /* Core System Resources Table */ +#define ACPI_SIG_DBG2 "DBG2" /* Debug Port table 2 */ +#define ACPI_SIG_MATR "MATR" /* Memory Address Translation Table */ +#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */ +#define ACPI_SIG_WPBT "WPBT" /* Windows Platform Binary Table */ + +/* + * All tables must be byte-packed to match the ACPI specification, since + * the tables are provided by the system BIOS. + */ +#pragma pack(1) + +/* + * Note about bitfields: The u8 type is used for bitfields in ACPI tables. + * This is the only type that is even remotely portable. Anything else is not + * portable, so do not use any other bitfield types. + */ + +/******************************************************************************* + * + * BGRT - Boot Graphics Resource Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_bgrt { + struct acpi_table_header header; /* Common ACPI table header */ + u16 version; + u8 status; + u8 image_type; + u64 image_address; + u32 image_offset_x; + u32 image_offset_y; +}; + +/******************************************************************************* + * + * DRTM - Dynamic Root of Trust for Measurement table + * + ******************************************************************************/ + +struct acpi_table_drtm { + struct acpi_table_header header; /* Common ACPI table header */ + u64 entry_base_address; + u64 entry_length; + u32 entry_address32; + u64 entry_address64; + u64 exit_address; + u64 log_area_address; + u32 log_area_length; + u64 arch_dependent_address; + u32 flags; +}; + +/* 1) Validated Tables List */ + +struct acpi_drtm_vtl_list { + u32 validated_table_list_count; +}; + +/* 2) Resources List */ + +struct acpi_drtm_resource_list { + u32 resource_list_count; +}; + +/* 3) Platform-specific Identifiers List */ + +struct acpi_drtm_id_list { + u32 id_list_count; +}; + +/******************************************************************************* + * + * FPDT - Firmware Performance Data Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_fpdt { + struct acpi_table_header header; /* Common ACPI table header */ +}; + +/* FPDT subtable header */ + +struct acpi_fpdt_header { + u16 type; + u8 length; + u8 revision; +}; + +/* Values for Type field above */ + +enum acpi_fpdt_type { + ACPI_FPDT_TYPE_BOOT = 0, + ACPI_FPDT_TYPE_S3PERF = 1, +}; + +/* + * FPDT subtables + */ + +/* 0: Firmware Basic Boot Performance Record */ + +struct acpi_fpdt_boot { + struct acpi_fpdt_header header; + u8 reserved[4]; + u64 reset_end; + u64 load_start; + u64 startup_start; + u64 exit_services_entry; + u64 exit_services_exit; +}; + +/* 1: S3 Performance Table Pointer Record */ + +struct acpi_fpdt_s3pt_ptr { + struct acpi_fpdt_header header; + u8 reserved[4]; + u64 address; +}; + +/* + * S3PT - S3 Performance Table. This table is pointed to by the + * FPDT S3 Pointer Record above. + */ +struct acpi_table_s3pt { + u8 signature[4]; /* "S3PT" */ + u32 length; +}; + +/* + * S3PT Subtables + */ +struct acpi_s3pt_header { + u16 type; + u8 length; + u8 revision; +}; + +/* Values for Type field above */ + +enum acpi_s3pt_type { + ACPI_S3PT_TYPE_RESUME = 0, + ACPI_S3PT_TYPE_SUSPEND = 1, +}; + +struct acpi_s3pt_resume { + struct acpi_s3pt_header header; + u32 resume_count; + u64 full_resume; + u64 average_resume; +}; + +struct acpi_s3pt_suspend { + struct acpi_s3pt_header header; + u64 suspend_start; + u64 suspend_end; +}; + +/******************************************************************************* + * + * GTDT - Generic Timer Description Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_gtdt { + struct acpi_table_header header; /* Common ACPI table header */ + u64 address; + u32 flags; + u32 secure_pl1_interrupt; + u32 secure_pl1_flags; + u32 non_secure_pl1_interrupt; + u32 non_secure_pl1_flags; + u32 virtual_timer_interrupt; + u32 virtual_timer_flags; + u32 non_secure_pl2_interrupt; + u32 non_secure_pl2_flags; +}; + +/* Values for Flags field above */ + +#define ACPI_GTDT_MAPPED_BLOCK_PRESENT 1 + +/* Values for all "TimerFlags" fields above */ + +#define ACPI_GTDT_INTERRUPT_MODE 1 +#define ACPI_GTDT_INTERRUPT_POLARITY 2 + +/******************************************************************************* + * + * MPST - Memory Power State Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +#define ACPI_MPST_CHANNEL_INFO \ + u16 reserved1; \ + u8 channel_id; \ + u8 reserved2; \ + u16 power_node_count; + +/* Main table */ + +struct acpi_table_mpst { + struct acpi_table_header header; /* Common ACPI table header */ + ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */ +}; + +/* Memory Platform Communication Channel Info */ + +struct acpi_mpst_channel { + ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */ +}; + +/* Memory Power Node Structure */ + +struct acpi_mpst_power_node { + u8 flags; + u8 reserved1; + u16 node_id; + u32 length; + u64 range_address; + u64 range_length; + u8 num_power_states; + u8 num_physical_components; + u16 reserved2; +}; + +/* Values for Flags field above */ + +#define ACPI_MPST_ENABLED 1 +#define ACPI_MPST_POWER_MANAGED 2 +#define ACPI_MPST_HOT_PLUG_CAPABLE 4 + +/* Memory Power State Structure (follows POWER_NODE above) */ + +struct acpi_mpst_power_state { + u8 power_state; + u8 info_index; +}; + +/* Physical Component ID Structure (follows POWER_STATE above) */ + +struct acpi_mpst_component { + u16 component_id; +}; + +/* Memory Power State Characteristics Structure (follows all POWER_NODEs) */ + +struct acpi_mpst_data_hdr { + u16 characteristics_count; +}; + +struct acpi_mpst_power_data { + u8 revision; + u8 flags; + u16 reserved1; + u32 average_power; + u32 power_saving; + u64 exit_latency; + u64 reserved2; +}; + +/* Values for Flags field above */ + +#define ACPI_MPST_PRESERVE 1 +#define ACPI_MPST_AUTOENTRY 2 +#define ACPI_MPST_AUTOEXIT 4 + +/* Shared Memory Region (not part of an ACPI table) */ + +struct acpi_mpst_shared { + u32 signature; + u16 pcc_command; + u16 pcc_status; + u16 command_register; + u16 status_register; + u16 power_state_id; + u16 power_node_id; + u64 energy_consumed; + u64 average_power; +}; + +/******************************************************************************* + * + * PCCT - Platform Communications Channel Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_pcct { + struct acpi_table_header header; /* Common ACPI table header */ + u32 flags; + u32 latency; + u32 reserved; +}; + +/* Values for Flags field above */ + +#define ACPI_PCCT_DOORBELL 1 + +/* + * PCCT subtables + */ + +/* 0: Generic Communications Subspace */ + +struct acpi_pcct_subspace { + struct acpi_subtable_header header; + u8 reserved[6]; + u64 base_address; + u64 length; + struct acpi_generic_address doorbell_register; + u64 preserve_mask; + u64 write_mask; +}; + +/* + * PCC memory structures (not part of the ACPI table) + */ + +/* Shared Memory Region */ + +struct acpi_pcct_shared_memory { + u32 signature; + u16 command; + u16 status; +}; + +/******************************************************************************* + * + * PMTT - Platform Memory Topology Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_pmtt { + struct acpi_table_header header; /* Common ACPI table header */ + u32 reserved; +}; + +/* Common header for PMTT subtables that follow main table */ + +struct acpi_pmtt_header { + u8 type; + u8 reserved1; + u16 length; + u16 flags; + u16 reserved2; +}; + +/* Values for Type field above */ + +#define ACPI_PMTT_TYPE_SOCKET 0 +#define ACPI_PMTT_TYPE_CONTROLLER 1 +#define ACPI_PMTT_TYPE_DIMM 2 +#define ACPI_PMTT_TYPE_RESERVED 3 /* 0x03-0xFF are reserved */ + +/* Values for Flags field above */ + +#define ACPI_PMTT_TOP_LEVEL 0x0001 +#define ACPI_PMTT_PHYSICAL 0x0002 +#define ACPI_PMTT_MEMORY_TYPE 0x000C + +/* + * PMTT subtables, correspond to Type in struct acpi_pmtt_header + */ + +/* 0: Socket Structure */ + +struct acpi_pmtt_socket { + struct acpi_pmtt_header header; + u16 socket_id; + u16 reserved; +}; + +/* 1: Memory Controller subtable */ + +struct acpi_pmtt_controller { + struct acpi_pmtt_header header; + u32 read_latency; + u32 write_latency; + u32 read_bandwidth; + u32 write_bandwidth; + u16 access_width; + u16 alignment; + u16 reserved; + u16 domain_count; +}; + +/* 1a: Proximity Domain substructure */ + +struct acpi_pmtt_domain { + u32 proximity_domain; +}; + +/* 2: Physical Component Identifier (DIMM) */ + +struct acpi_pmtt_physical_component { + struct acpi_pmtt_header header; + u16 component_id; + u16 reserved; + u32 memory_size; + u32 bios_handle; +}; + +/******************************************************************************* + * + * RASF - RAS Feature Table (ACPI 5.0) + * Version 1 + * + ******************************************************************************/ + +struct acpi_table_rasf { + struct acpi_table_header header; /* Common ACPI table header */ + u8 channel_id[12]; +}; + +/* RASF Platform Communication Channel Shared Memory Region */ + +struct acpi_rasf_shared_memory { + u32 signature; + u16 command; + u16 status; + u64 requested_address; + u64 requested_length; + u64 actual_address; + u64 actual_length; + u16 flags; + u8 speed; +}; + +/* Masks for Flags and Speed fields above */ + +#define ACPI_RASF_SCRUBBER_RUNNING 1 +#define ACPI_RASF_SPEED (7<<1) + +/* Channel Commands */ + +enum acpi_rasf_commands { + ACPI_RASF_GET_RAS_CAPABILITIES = 1, + ACPI_RASF_GET_PATROL_PARAMETERS = 2, + ACPI_RASF_START_PATROL_SCRUBBER = 3, + ACPI_RASF_STOP_PATROL_SCRUBBER = 4 +}; + +/* Channel Command flags */ + +#define ACPI_RASF_GENERATE_SCI (1<<15) + +/* Status values */ + +enum acpi_rasf_status { + ACPI_RASF_SUCCESS = 0, + ACPI_RASF_NOT_VALID = 1, + ACPI_RASF_NOT_SUPPORTED = 2, + ACPI_RASF_BUSY = 3, + ACPI_RASF_FAILED = 4, + ACPI_RASF_ABORTED = 5, + ACPI_RASF_INVALID_DATA = 6 +}; + +/* Status flags */ + +#define ACPI_RASF_COMMAND_COMPLETE (1) +#define ACPI_RASF_SCI_DOORBELL (1<<1) +#define ACPI_RASF_ERROR (1<<2) +#define ACPI_RASF_STATUS (0x1F<<3) + +/* Reset to default packing */ + +#pragma pack() + +#endif /* __ACTBL3_H__ */ diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index ed73f6705c86..d5dee7ce9474 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -712,8 +712,10 @@ typedef u8 acpi_adr_space_type; #define ACPI_ADR_SPACE_CMOS (acpi_adr_space_type) 5 #define ACPI_ADR_SPACE_PCI_BAR_TARGET (acpi_adr_space_type) 6 #define ACPI_ADR_SPACE_IPMI (acpi_adr_space_type) 7 +#define ACPI_ADR_SPACE_GPIO (acpi_adr_space_type) 8 +#define ACPI_ADR_SPACE_GSBUS (acpi_adr_space_type) 9 -#define ACPI_NUM_PREDEFINED_REGIONS 8 +#define ACPI_NUM_PREDEFINED_REGIONS 10 /* * Special Address Spaces @@ -957,6 +959,14 @@ acpi_status(*acpi_adr_space_handler) (u32 function, #define ACPI_DEFAULT_HANDLER NULL +/* Special Context data for generic_serial_bus/general_purpose_io (ACPI 5.0) */ + +struct acpi_connection_info { + u8 *connection; + u16 length; + u8 access_length; +}; + typedef acpi_status(*acpi_adr_space_setup) (acpi_handle region_handle, u32 function, diff --git a/include/acpi/apei.h b/include/acpi/apei.h index 51a527d24a8a..04f349d8da73 100644 --- a/include/acpi/apei.h +++ b/include/acpi/apei.h @@ -16,10 +16,10 @@ #ifdef __KERNEL__ -extern int hest_disable; +extern bool hest_disable; extern int erst_disable; #ifdef CONFIG_ACPI_APEI_GHES -extern int ghes_disable; +extern bool ghes_disable; #else #define ghes_disable 1 #endif diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index d466c8d8826d..1ff4e221cb4d 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -177,6 +177,10 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe extern int gpio_request_array(const struct gpio *array, size_t num); extern void gpio_free_array(const struct gpio *array, size_t num); +/* bindings for managed devices that want to request gpios */ +int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); +void devm_gpio_free(struct device *dev, unsigned int gpio); + #ifdef CONFIG_GPIO_SYSFS /* diff --git a/include/asm-generic/param.h b/include/asm-generic/param.h index cdf8251bfb6c..835632a3b468 100644 --- a/include/asm-generic/param.h +++ b/include/asm-generic/param.h @@ -1,12 +1,6 @@ #ifndef __ASM_GENERIC_PARAM_H #define __ASM_GENERIC_PARAM_H -#ifdef __KERNEL__ -# define HZ CONFIG_HZ /* Internal kernel timer frequency */ -# define USER_HZ 100 /* some user interfaces are */ -# define CLOCKS_PER_SEC (USER_HZ) /* in "ticks" like times() */ -#endif - #ifndef HZ #define HZ 100 #endif @@ -21,4 +15,11 @@ #define MAXHOSTNAMELEN 64 /* max length of hostname */ +#ifdef __KERNEL__ +# undef HZ +# define HZ CONFIG_HZ /* Internal kernel timer frequency */ +# define USER_HZ 100 /* some user interfaces are */ +# define CLOCKS_PER_SEC (USER_HZ) /* in "ticks" like times() */ +#endif + #endif /* __ASM_GENERIC_PARAM_H */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 63e4fce67288..4cd4be26722c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -453,7 +453,7 @@ struct drm_encoder_funcs { #define DRM_CONNECTOR_MAX_UMODES 16 #define DRM_CONNECTOR_MAX_PROPERTY 16 #define DRM_CONNECTOR_LEN 32 -#define DRM_CONNECTOR_MAX_ENCODER 2 +#define DRM_CONNECTOR_MAX_ENCODER 3 /** * drm_encoder - central DRM encoder structure diff --git a/include/keys/user-type.h b/include/keys/user-type.h index c37c34275a44..bc9ec1d7698c 100644 --- a/include/keys/user-type.h +++ b/include/keys/user-type.h @@ -17,7 +17,7 @@ /*****************************************************************************/ /* - * the payload for a key of type "user" + * the payload for a key of type "user" or "logon" * - once filled in and attached to a key: * - the payload struct is invariant may not be changed, only replaced * - the payload must be read with RCU procedures or with the key semaphore @@ -33,6 +33,7 @@ struct user_key_payload { }; extern struct key_type key_type_user; +extern struct key_type key_type_logon; extern int user_instantiate(struct key *key, const void *data, size_t datalen); extern int user_update(struct key *key, const void *data, size_t datalen); diff --git a/include/linux/acct.h b/include/linux/acct.h index 3e4737fa6cce..d537aa0ec414 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -146,6 +146,9 @@ extern void acct_exit_ns(struct pid_namespace *); * */ +#undef ACCT_VERSION +#undef AHZ + #ifdef CONFIG_BSD_PROCESS_ACCT_V3 #define ACCT_VERSION 3 #define AHZ 100 diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 627a3a42e4d8..3f968665899b 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -310,6 +310,11 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req); extern void acpi_early_init(void); +extern int acpi_nvs_register(__u64 start, __u64 size); + +extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), + void *data); + #else /* !CONFIG_ACPI */ #define acpi_disabled 1 @@ -352,15 +357,18 @@ static inline int acpi_table_parse(char *id, { return -1; } -#endif /* !CONFIG_ACPI */ -#ifdef CONFIG_ACPI_SLEEP -int suspend_nvs_register(unsigned long start, unsigned long size); -#else -static inline int suspend_nvs_register(unsigned long a, unsigned long b) +static inline int acpi_nvs_register(__u64 start, __u64 size) { return 0; } -#endif + +static inline int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), + void *data) +{ + return 0; +} + +#endif /* !CONFIG_ACPI */ #endif /*_LINUX_ACPI_H*/ diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h index 4afd7102459d..b0ffa219993e 100644 --- a/include/linux/acpi_io.h +++ b/include/linux/acpi_io.h @@ -12,4 +12,7 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); +int acpi_os_map_generic_address(struct acpi_generic_address *addr); +void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); + #endif diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h index 21114810c7c0..0101e9c17fa1 100644 --- a/include/linux/amba/mmci.h +++ b/include/linux/amba/mmci.h @@ -30,6 +30,7 @@ struct dma_chan; * @cd_invert: true if the gpio_cd pin value is active low * @capabilities: the capabilities of the block as implemented in * this platform, signify anything MMC_CAP_* from mmc/host.h + * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h * @dma_filter: function used to select an appropriate RX and TX * DMA channel to be used for DMA, if and only if you're deploying the * generic DMA engine @@ -52,6 +53,7 @@ struct mmci_platform_data { int gpio_cd; bool cd_invert; unsigned long capabilities; + unsigned long capabilities2; bool (*dma_filter)(struct dma_chan *chan, void *filter_param); void *dma_rx_param; void *dma_tx_param; diff --git a/include/linux/amba/pl061.h b/include/linux/amba/pl061.h index 2412af944f1f..fb83c0453489 100644 --- a/include/linux/amba/pl061.h +++ b/include/linux/amba/pl061.h @@ -7,7 +7,7 @@ struct pl061_platform_data { unsigned gpio_base; /* number of the first IRQ. - * If the IRQ functionality in not desired this must be set to NO_IRQ. + * If the IRQ functionality in not desired this must be set to 0. */ unsigned irq_base; diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 9eabffbc4e50..033f6aa670de 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -134,7 +134,7 @@ struct pl08x_txd { struct dma_async_tx_descriptor tx; struct list_head node; struct list_head dsg_list; - enum dma_data_direction direction; + enum dma_transfer_direction direction; dma_addr_t llis_bus; struct pl08x_lli *llis_va; /* Default cctl value for LLIs */ @@ -197,7 +197,7 @@ struct pl08x_dma_chan { dma_addr_t dst_addr; u32 src_cctl; u32 dst_cctl; - enum dma_data_direction runtime_direction; + enum dma_transfer_direction runtime_direction; dma_cookie_t lc; struct list_head pend_list; struct pl08x_txd *at; diff --git a/include/linux/audit.h b/include/linux/audit.h index 426ab9f4dd85..9ff7a2c48b50 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -26,6 +26,7 @@ #include <linux/types.h> #include <linux/elf-em.h> +#include <linux/ptrace.h> /* The netlink messages for the audit system is divided into blocks: * 1000 - 1099 are for commanding the audit system @@ -181,6 +182,40 @@ * AUDIT_UNUSED_BITS is updated if need be. */ #define AUDIT_UNUSED_BITS 0x07FFFC00 +/* AUDIT_FIELD_COMPARE rule list */ +#define AUDIT_COMPARE_UID_TO_OBJ_UID 1 +#define AUDIT_COMPARE_GID_TO_OBJ_GID 2 +#define AUDIT_COMPARE_EUID_TO_OBJ_UID 3 +#define AUDIT_COMPARE_EGID_TO_OBJ_GID 4 +#define AUDIT_COMPARE_AUID_TO_OBJ_UID 5 +#define AUDIT_COMPARE_SUID_TO_OBJ_UID 6 +#define AUDIT_COMPARE_SGID_TO_OBJ_GID 7 +#define AUDIT_COMPARE_FSUID_TO_OBJ_UID 8 +#define AUDIT_COMPARE_FSGID_TO_OBJ_GID 9 + +#define AUDIT_COMPARE_UID_TO_AUID 10 +#define AUDIT_COMPARE_UID_TO_EUID 11 +#define AUDIT_COMPARE_UID_TO_FSUID 12 +#define AUDIT_COMPARE_UID_TO_SUID 13 + +#define AUDIT_COMPARE_AUID_TO_FSUID 14 +#define AUDIT_COMPARE_AUID_TO_SUID 15 +#define AUDIT_COMPARE_AUID_TO_EUID 16 + +#define AUDIT_COMPARE_EUID_TO_SUID 17 +#define AUDIT_COMPARE_EUID_TO_FSUID 18 + +#define AUDIT_COMPARE_SUID_TO_FSUID 19 + +#define AUDIT_COMPARE_GID_TO_EGID 20 +#define AUDIT_COMPARE_GID_TO_FSGID 21 +#define AUDIT_COMPARE_GID_TO_SGID 22 + +#define AUDIT_COMPARE_EGID_TO_FSGID 23 +#define AUDIT_COMPARE_EGID_TO_SGID 24 +#define AUDIT_COMPARE_SGID_TO_FSGID 25 + +#define AUDIT_MAX_FIELD_COMPARE AUDIT_COMPARE_SGID_TO_FSGID /* Rule fields */ /* These are useful when checking the @@ -222,6 +257,9 @@ #define AUDIT_PERM 106 #define AUDIT_DIR 107 #define AUDIT_FILETYPE 108 +#define AUDIT_OBJ_UID 109 +#define AUDIT_OBJ_GID 110 +#define AUDIT_FIELD_COMPARE 111 #define AUDIT_ARG0 200 #define AUDIT_ARG1 (AUDIT_ARG0+1) @@ -408,28 +446,24 @@ struct audit_field { void *lsm_rule; }; -#define AUDITSC_INVALID 0 -#define AUDITSC_SUCCESS 1 -#define AUDITSC_FAILURE 2 -#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS ) 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); #ifdef CONFIG_AUDITSYSCALL /* These are defined in auditsc.c */ /* Public API */ -extern void audit_finish_fork(struct task_struct *child); extern int audit_alloc(struct task_struct *task); -extern void audit_free(struct task_struct *task); -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 failed, long return_code); +extern void __audit_free(struct task_struct *task); +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 void __audit_seccomp(unsigned long syscall); extern void __audit_ptrace(struct task_struct *t); static inline int audit_dummy_context(void) @@ -437,6 +471,27 @@ static inline int audit_dummy_context(void) void *p = current->audit_context; return !p || *(int *)p; } +static inline void audit_free(struct task_struct *task) +{ + if (unlikely(task->audit_context)) + __audit_free(task); +} +static inline void audit_syscall_entry(int arch, int major, unsigned long a0, + unsigned long a1, unsigned long a2, + unsigned long a3) +{ + if (unlikely(!audit_dummy_context())) + __audit_syscall_entry(arch, major, a0, a1, a2, a3); +} +static inline void audit_syscall_exit(void *pt_regs) +{ + if (unlikely(current->audit_context)) { + int success = is_syscall_success(pt_regs); + int return_code = regs_return_value(pt_regs); + + __audit_syscall_exit(success, return_code); + } +} static inline void audit_getname(const char *name) { if (unlikely(!audit_dummy_context())) @@ -453,6 +508,12 @@ static inline void audit_inode_child(const struct dentry *dentry, } void audit_core_dumps(long signr); +static inline void audit_seccomp(unsigned long syscall) +{ + if (unlikely(!audit_dummy_context())) + __audit_seccomp(syscall); +} + static inline void audit_ptrace(struct task_struct *t) { if (unlikely(!audit_dummy_context())) @@ -463,17 +524,16 @@ static inline void audit_ptrace(struct task_struct *t) extern unsigned int audit_serial(void); extern int auditsc_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial); -extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); +extern int audit_set_loginuid(uid_t loginuid); #define audit_get_loginuid(t) ((t)->loginuid) #define audit_get_sessionid(t) ((t)->sessionid) extern void audit_log_task_context(struct audit_buffer *ab); extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp); extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode); -extern int audit_bprm(struct linux_binprm *bprm); -extern void audit_socketcall(int nargs, unsigned long *args); -extern int audit_sockaddr(int len, void *addr); +extern int __audit_bprm(struct linux_binprm *bprm); +extern void __audit_socketcall(int nargs, unsigned long *args); +extern int __audit_sockaddr(int len, void *addr); extern void __audit_fd_pair(int fd1, int fd2); -extern int audit_set_macxattr(const char *name); extern void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr); extern void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout); extern void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification); @@ -499,6 +559,23 @@ static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid if (unlikely(!audit_dummy_context())) __audit_ipc_set_perm(qbytes, uid, gid, mode); } +static inline int audit_bprm(struct linux_binprm *bprm) +{ + if (unlikely(!audit_dummy_context())) + return __audit_bprm(bprm); + return 0; +} +static inline void audit_socketcall(int nargs, unsigned long *args) +{ + if (unlikely(!audit_dummy_context())) + __audit_socketcall(nargs, args); +} +static inline int audit_sockaddr(int len, void *addr) +{ + if (unlikely(!audit_dummy_context())) + return __audit_sockaddr(len, addr); + return 0; +} static inline void audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr) { if (unlikely(!audit_dummy_context())) @@ -544,12 +621,11 @@ static inline void audit_mmap_fd(int fd, int flags) extern int audit_n_rules; extern int audit_signals; -#else -#define audit_finish_fork(t) +#else /* CONFIG_AUDITSYSCALL */ #define audit_alloc(t) ({ 0; }) #define audit_free(t) do { ; } while (0) #define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0) -#define audit_syscall_exit(f,r) do { ; } while (0) +#define audit_syscall_exit(r) do { ; } while (0) #define audit_dummy_context() 1 #define audit_getname(n) do { ; } while (0) #define audit_putname(n) do { ; } while (0) @@ -558,6 +634,7 @@ extern int audit_signals; #define audit_inode(n,d) do { (void)(d); } while (0) #define audit_inode_child(i,p) do { ; } while (0) #define audit_core_dumps(i) do { ; } while (0) +#define audit_seccomp(i) do { ; } while (0) #define auditsc_get_stamp(c,t,s) (0) #define audit_get_loginuid(t) (-1) #define audit_get_sessionid(t) (-1) @@ -568,7 +645,6 @@ extern int audit_signals; #define audit_socketcall(n,a) ((void)0) #define audit_fd_pair(n,a) ((void)0) #define audit_sockaddr(len, addr) ({ 0; }) -#define audit_set_macxattr(n) do { ; } while (0) #define audit_mq_open(o,m,a) ((void)0) #define audit_mq_sendrecv(d,l,p,t) ((void)0) #define audit_mq_notify(d,n) ((void)0) @@ -579,7 +655,7 @@ extern int audit_signals; #define audit_ptrace(t) ((void)0) #define audit_n_rules 0 #define audit_signals 0 -#endif +#endif /* CONFIG_AUDITSYSCALL */ #ifdef CONFIG_AUDIT /* These are defined in audit.c */ diff --git a/include/linux/bio.h b/include/linux/bio.h index 847994aef0e9..129a9c097958 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -515,24 +515,64 @@ extern void bio_integrity_init(void); #else /* CONFIG_BLK_DEV_INTEGRITY */ -#define bio_integrity(a) (0) -#define bioset_integrity_create(a, b) (0) -#define bio_integrity_prep(a) (0) -#define bio_integrity_enabled(a) (0) +static inline int bio_integrity(struct bio *bio) +{ + return 0; +} + +static inline int bio_integrity_enabled(struct bio *bio) +{ + return 0; +} + +static inline int bioset_integrity_create(struct bio_set *bs, int pool_size) +{ + return 0; +} + +static inline void bioset_integrity_free (struct bio_set *bs) +{ + return; +} + +static inline int bio_integrity_prep(struct bio *bio) +{ + return 0; +} + +static inline void bio_integrity_free(struct bio *bio, struct bio_set *bs) +{ + return; +} + static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask, struct bio_set *bs) { return 0; } -#define bioset_integrity_free(a) do { } while (0) -#define bio_integrity_free(a, b) do { } while (0) -#define bio_integrity_endio(a, b) do { } while (0) -#define bio_integrity_advance(a, b) do { } while (0) -#define bio_integrity_trim(a, b, c) do { } while (0) -#define bio_integrity_split(a, b, c) do { } while (0) -#define bio_integrity_set_tag(a, b, c) do { } while (0) -#define bio_integrity_get_tag(a, b, c) do { } while (0) -#define bio_integrity_init(a) do { } while (0) + +static inline void bio_integrity_split(struct bio *bio, struct bio_pair *bp, + int sectors) +{ + return; +} + +static inline void bio_integrity_advance(struct bio *bio, + unsigned int bytes_done) +{ + return; +} + +static inline void bio_integrity_trim(struct bio *bio, unsigned int offset, + unsigned int sectors) +{ + return; +} + +static inline void bio_integrity_init(void) +{ + return; +} #endif /* CONFIG_BLK_DEV_INTEGRITY */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 94acd8172b5b..6c6a1f008065 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -111,10 +111,14 @@ struct request { * Three pointers are available for the IO schedulers, if they need * more they have to dynamically allocate it. Flush requests are * never put on the IO scheduler. So let the flush fields share - * space with the three elevator_private pointers. + * space with the elevator data. */ union { - void *elevator_private[3]; + struct { + struct io_cq *icq; + void *priv[2]; + } elv; + struct { unsigned int seq; struct list_head list; @@ -311,6 +315,12 @@ struct request_queue { unsigned long queue_flags; /* + * ida allocated id for this queue. Used to index queues from + * ioctx. + */ + int id; + + /* * queue needs bounce pages for pages above this limit */ gfp_t bounce_gfp; @@ -351,6 +361,8 @@ struct request_queue { struct timer_list timeout; struct list_head timeout_list; + struct list_head icq_list; + struct queue_limits limits; /* @@ -387,6 +399,9 @@ struct request_queue { /* Throttle data */ struct throtl_data *td; #endif +#ifdef CONFIG_LOCKDEP + int ioc_release_depth; +#endif }; #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ @@ -481,6 +496,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) #define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) +#define blk_queue_dead(q) test_bit(QUEUE_FLAG_DEAD, &(q)->queue_flags) #define blk_queue_nomerges(q) test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags) #define blk_queue_noxmerges(q) \ test_bit(QUEUE_FLAG_NOXMERGES, &(q)->queue_flags) @@ -660,7 +676,6 @@ extern void __blk_put_request(struct request_queue *, struct request *); extern struct request *blk_get_request(struct request_queue *, int, gfp_t); extern struct request *blk_make_request(struct request_queue *, struct bio *, gfp_t); -extern void blk_insert_request(struct request_queue *, struct request *, int, void *); extern void blk_requeue_request(struct request_queue *, struct request *); extern void blk_add_request_payload(struct request *rq, struct page *page, unsigned int len); @@ -675,6 +690,9 @@ extern int blk_insert_cloned_request(struct request_queue *q, struct request *rq); extern void blk_delay_queue(struct request_queue *, unsigned long); extern void blk_recount_segments(struct request_queue *, struct bio *); +extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int); +extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t, + unsigned int, void __user *); extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, unsigned int, void __user *); extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, @@ -826,6 +844,7 @@ extern void blk_queue_io_min(struct request_queue *q, unsigned int min); extern void blk_limits_io_opt(struct queue_limits *limits, unsigned int opt); extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt); extern void blk_set_default_limits(struct queue_limits *lim); +extern void blk_set_stacking_limits(struct queue_limits *lim); extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, sector_t offset); extern int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, @@ -856,7 +875,7 @@ extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatte extern void blk_dump_rq_flags(struct request *, char *); extern long nr_blockdev_pages(void); -int blk_get_queue(struct request_queue *); +bool __must_check blk_get_queue(struct request_queue *); struct request_queue *blk_alloc_queue(gfp_t); struct request_queue *blk_alloc_queue_node(gfp_t, int); extern void blk_put_queue(struct request_queue *); @@ -1279,19 +1298,70 @@ queue_max_integrity_segments(struct request_queue *q) #else /* CONFIG_BLK_DEV_INTEGRITY */ -#define blk_integrity_rq(rq) (0) -#define blk_rq_count_integrity_sg(a, b) (0) -#define blk_rq_map_integrity_sg(a, b, c) (0) -#define bdev_get_integrity(a) (0) -#define blk_get_integrity(a) (0) -#define blk_integrity_compare(a, b) (0) -#define blk_integrity_register(a, b) (0) -#define blk_integrity_unregister(a) do { } while (0) -#define blk_queue_max_integrity_segments(a, b) do { } while (0) -#define queue_max_integrity_segments(a) (0) -#define blk_integrity_merge_rq(a, b, c) (0) -#define blk_integrity_merge_bio(a, b, c) (0) -#define blk_integrity_is_initialized(a) (0) +struct bio; +struct block_device; +struct gendisk; +struct blk_integrity; + +static inline int blk_integrity_rq(struct request *rq) +{ + return 0; +} +static inline int blk_rq_count_integrity_sg(struct request_queue *q, + struct bio *b) +{ + return 0; +} +static inline int blk_rq_map_integrity_sg(struct request_queue *q, + struct bio *b, + struct scatterlist *s) +{ + return 0; +} +static inline struct blk_integrity *bdev_get_integrity(struct block_device *b) +{ + return 0; +} +static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk) +{ + return NULL; +} +static inline int blk_integrity_compare(struct gendisk *a, struct gendisk *b) +{ + return 0; +} +static inline int blk_integrity_register(struct gendisk *d, + struct blk_integrity *b) +{ + return 0; +} +static inline void blk_integrity_unregister(struct gendisk *d) +{ +} +static inline void blk_queue_max_integrity_segments(struct request_queue *q, + unsigned int segs) +{ +} +static inline unsigned short queue_max_integrity_segments(struct request_queue *q) +{ + return 0; +} +static inline int blk_integrity_merge_rq(struct request_queue *rq, + struct request *r1, + struct request *r2) +{ + return 0; +} +static inline int blk_integrity_merge_bio(struct request_queue *rq, + struct request *r, + struct bio *b) +{ + return 0; +} +static inline bool blk_integrity_is_initialized(struct gendisk *g) +{ + return 0; +} #endif /* CONFIG_BLK_DEV_INTEGRITY */ diff --git a/include/linux/capability.h b/include/linux/capability.h index a63d13d84ad8..12d52dedb229 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -380,7 +380,6 @@ struct user_namespace; struct user_namespace *current_user_ns(void); extern const kernel_cap_t __cap_empty_set; -extern const kernel_cap_t __cap_full_set; extern const kernel_cap_t __cap_init_eff_set; /* @@ -544,9 +543,10 @@ extern bool has_capability(struct task_struct *t, int cap); extern bool has_ns_capability(struct task_struct *t, struct user_namespace *ns, int cap); extern bool has_capability_noaudit(struct task_struct *t, int cap); +extern bool has_ns_capability_noaudit(struct task_struct *t, + struct user_namespace *ns, int cap); extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); -extern bool task_ns_capable(struct task_struct *t, int cap); extern bool nsown_capable(int cap); /* audit system wants to get cap info from files as well */ diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 59e4028e833d..3fd17c249221 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -50,6 +50,11 @@ # define inline inline __attribute__((always_inline)) # define __inline__ __inline__ __attribute__((always_inline)) # define __inline __inline __attribute__((always_inline)) +#else +/* A lot of inline functions can cause havoc with function tracing */ +# define inline inline notrace +# define __inline__ __inline__ notrace +# define __inline __inline notrace #endif #define __deprecated __attribute__((deprecated)) diff --git a/include/linux/console.h b/include/linux/console.h index 7453cfd593c8..7201ce4280ca 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -152,7 +152,7 @@ extern int braille_register_console(struct console *, int index, char *console_options, char *braille_options); extern int braille_unregister_console(struct console *); extern void console_sysfs_notify(void); -extern int console_suspend_enabled; +extern bool console_suspend_enabled; /* Suspend and resume console messages over PM events */ extern void suspend_console(void); diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 23f81de51829..712abcc205ae 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -186,7 +186,14 @@ struct cpuidle_governor { extern int cpuidle_register_governor(struct cpuidle_governor *gov); extern void cpuidle_unregister_governor(struct cpuidle_governor *gov); +#ifdef CONFIG_INTEL_IDLE +extern int intel_idle_cpu_init(int cpu); #else +static inline int intel_idle_cpu_init(int cpu) { return -1; } +#endif + +#else +static inline int intel_idle_cpu_init(int cpu) { return -1; } static inline int cpuidle_register_governor(struct cpuidle_governor *gov) {return 0;} diff --git a/include/linux/cred.h b/include/linux/cred.h index 40308969ed00..adadf71a7327 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -358,10 +358,12 @@ static inline void put_cred(const struct cred *_cred) #define current_security() (current_cred_xxx(security)) #ifdef CONFIG_USER_NS -#define current_user_ns() (current_cred_xxx(user_ns)) +#define current_user_ns() (current_cred_xxx(user_ns)) +#define task_user_ns(task) (task_cred_xxx((task), user_ns)) #else extern struct user_namespace init_user_ns; -#define current_user_ns() (&init_user_ns) +#define current_user_ns() (&init_user_ns) +#define task_user_ns(task) (&init_user_ns) #endif diff --git a/include/linux/cuda.h b/include/linux/cuda.h index 6a3e6385d3f3..9f9865ff781e 100644 --- a/include/linux/cuda.h +++ b/include/linux/cuda.h @@ -5,6 +5,9 @@ * Copyright (C) 1996 Paul Mackerras. */ +#ifndef _LINUX_CUDA_H +#define _LINUX_CUDA_H + /* CUDA commands (2nd byte) */ #define CUDA_WARM_START 0 #define CUDA_AUTOPOLL 1 @@ -34,3 +37,5 @@ extern int cuda_request(struct adb_request *req, extern void cuda_poll(void); #endif /* __KERNEL */ + +#endif /* _LINUX_CUDA_H */ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 31f73220e7d7..d64a55b23afd 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -242,6 +242,7 @@ extern struct dentry * d_alloc(struct dentry *, const struct qstr *); extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *); extern struct dentry * d_splice_alias(struct inode *, struct dentry *); extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *); +extern struct dentry *d_find_any_alias(struct inode *inode); extern struct dentry * d_obtain_alias(struct inode *); extern void shrink_dcache_sb(struct super_block *); extern void shrink_dcache_parent(struct dentry *); diff --git a/include/linux/device.h b/include/linux/device.h index 5b3adb8f9588..b63fb393aa58 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -279,11 +279,11 @@ struct device *driver_find_device(struct device_driver *drv, /** * struct subsys_interface - interfaces to device functions - * @name name of the device function - * @subsystem subsytem of the devices to attach to - * @node the list of functions registered at the subsystem - * @add device hookup to device function handler - * @remove device hookup to device function handler + * @name: name of the device function + * @subsys: subsytem of the devices to attach to + * @node: the list of functions registered at the subsystem + * @add_dev: device hookup to device function handler + * @remove_dev: device hookup to device function handler * * Simple interfaces attached to a subsystem. Multiple interfaces can * attach to a subsystem and its devices. Unlike drivers, they do not @@ -612,6 +612,7 @@ struct device_dma_parameters { * @archdata: For arch-specific additions. * @of_node: Associated device tree node. * @devt: For creating the sysfs "dev". + * @id: device instance * @devres_lock: Spinlock to protect the resource of the device. * @devres_head: The resources list of the device. * @knode_class: The node used to add the device to the class list. @@ -1003,6 +1004,10 @@ extern long sysfs_deprecated; * Each module may only use this macro once, and calling it replaces * module_init() and module_exit(). * + * @__driver: driver name + * @__register: register function for this driver type + * @__unregister: unregister function for this driver type + * * Use this macro to construct bus specific macros for registering * drivers, and do not use it on its own. */ diff --git a/include/linux/digsig.h b/include/linux/digsig.h index efae755017d7..b01558b15814 100644 --- a/include/linux/digsig.h +++ b/include/linux/digsig.h @@ -46,7 +46,7 @@ struct signature_hdr { char mpi[0]; } __packed; -#if defined(CONFIG_DIGSIG) || defined(CONFIG_DIGSIG_MODULE) +#if defined(CONFIG_SIGNATURE) || defined(CONFIG_SIGNATURE_MODULE) int digsig_verify(struct key *keyring, const char *sig, int siglen, const char *digest, int digestlen); @@ -59,6 +59,6 @@ static inline int digsig_verify(struct key *keyring, const char *sig, return -EOPNOTSUPP; } -#endif /* CONFIG_DIGSIG */ +#endif /* CONFIG_SIGNATURE */ #endif /* _DIGSIG_H */ diff --git a/include/linux/display.h b/include/linux/display.h deleted file mode 100644 index 3bf70d639728..000000000000 --- a/include/linux/display.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2006 James Simmons <jsimmons@infradead.org> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef _LINUX_DISPLAY_H -#define _LINUX_DISPLAY_H - -#include <linux/device.h> - -struct display_device; - -/* This structure defines all the properties of a Display. */ -struct display_driver { - int (*set_contrast)(struct display_device *, unsigned int); - int (*get_contrast)(struct display_device *); - void (*suspend)(struct display_device *, pm_message_t state); - void (*resume)(struct display_device *); - int (*probe)(struct display_device *, void *); - int (*remove)(struct display_device *); - int max_contrast; -}; - -struct display_device { - struct module *owner; /* Owner module */ - struct display_driver *driver; - struct device *parent; /* This is the parent */ - struct device *dev; /* This is this display device */ - struct mutex lock; - void *priv_data; - char type[16]; - char *name; - int idx; -}; - -extern struct display_device *display_device_register(struct display_driver *driver, - struct device *dev, void *devdata); -extern void display_device_unregister(struct display_device *dev); - -extern int probe_edid(struct display_device *dev, void *devdata); - -#define to_display_device(obj) container_of(obj, struct display_device, class_dev) - -#endif diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 75f53f874b24..679b349d9b66 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -23,7 +23,6 @@ #include <linux/device.h> #include <linux/uio.h> -#include <linux/dma-direction.h> #include <linux/scatterlist.h> #include <linux/bitmap.h> #include <asm/page.h> @@ -72,11 +71,93 @@ enum dma_transaction_type { DMA_ASYNC_TX, DMA_SLAVE, DMA_CYCLIC, + DMA_INTERLEAVE, +/* last transaction type for creation of the capabilities mask */ + DMA_TX_TYPE_END, }; -/* last transaction type for creation of the capabilities mask */ -#define DMA_TX_TYPE_END (DMA_CYCLIC + 1) +/** + * enum dma_transfer_direction - dma transfer mode and direction indicator + * @DMA_MEM_TO_MEM: Async/Memcpy mode + * @DMA_MEM_TO_DEV: Slave mode & From Memory to Device + * @DMA_DEV_TO_MEM: Slave mode & From Device to Memory + * @DMA_DEV_TO_DEV: Slave mode & From Device to Device + */ +enum dma_transfer_direction { + DMA_MEM_TO_MEM, + DMA_MEM_TO_DEV, + DMA_DEV_TO_MEM, + DMA_DEV_TO_DEV, + DMA_TRANS_NONE, +}; + +/** + * Interleaved Transfer Request + * ---------------------------- + * A chunk is collection of contiguous bytes to be transfered. + * The gap(in bytes) between two chunks is called inter-chunk-gap(ICG). + * ICGs may or maynot change between chunks. + * A FRAME is the smallest series of contiguous {chunk,icg} pairs, + * that when repeated an integral number of times, specifies the transfer. + * A transfer template is specification of a Frame, the number of times + * it is to be repeated and other per-transfer attributes. + * + * Practically, a client driver would have ready a template for each + * type of transfer it is going to need during its lifetime and + * set only 'src_start' and 'dst_start' before submitting the requests. + * + * + * | Frame-1 | Frame-2 | ~ | Frame-'numf' | + * |====....==.===...=...|====....==.===...=...| ~ |====....==.===...=...| + * + * == Chunk size + * ... ICG + */ + +/** + * struct data_chunk - Element of scatter-gather list that makes a frame. + * @size: Number of bytes to read from source. + * size_dst := fn(op, size_src), so doesn't mean much for destination. + * @icg: Number of bytes to jump after last src/dst address of this + * chunk and before first src/dst address for next chunk. + * Ignored for dst(assumed 0), if dst_inc is true and dst_sgl is false. + * Ignored for src(assumed 0), if src_inc is true and src_sgl is false. + */ +struct data_chunk { + size_t size; + size_t icg; +}; +/** + * struct dma_interleaved_template - Template to convey DMAC the transfer pattern + * and attributes. + * @src_start: Bus address of source for the first chunk. + * @dst_start: Bus address of destination for the first chunk. + * @dir: Specifies the type of Source and Destination. + * @src_inc: If the source address increments after reading from it. + * @dst_inc: If the destination address increments after writing to it. + * @src_sgl: If the 'icg' of sgl[] applies to Source (scattered read). + * Otherwise, source is read contiguously (icg ignored). + * Ignored if src_inc is false. + * @dst_sgl: If the 'icg' of sgl[] applies to Destination (scattered write). + * Otherwise, destination is filled contiguously (icg ignored). + * Ignored if dst_inc is false. + * @numf: Number of frames in this template. + * @frame_size: Number of chunks in a frame i.e, size of sgl[]. + * @sgl: Array of {chunk,icg} pairs that make up a frame. + */ +struct dma_interleaved_template { + dma_addr_t src_start; + dma_addr_t dst_start; + enum dma_transfer_direction dir; + bool src_inc; + bool dst_inc; + bool src_sgl; + bool dst_sgl; + size_t numf; + size_t frame_size; + struct data_chunk sgl[0]; +}; /** * enum dma_ctrl_flags - DMA flags to augment operation preparation, @@ -269,7 +350,7 @@ enum dma_slave_buswidth { * struct, if applicable. */ struct dma_slave_config { - enum dma_data_direction direction; + enum dma_transfer_direction direction; dma_addr_t src_addr; dma_addr_t dst_addr; enum dma_slave_buswidth src_addr_width; @@ -433,6 +514,7 @@ struct dma_tx_state { * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio. * The function takes a buffer of size buf_len. The callback function will * be called after period_len bytes have been transferred. + * @device_prep_interleaved_dma: Transfer expression in a generic way. * @device_control: manipulate all pending operations on a channel, returns * zero or error code * @device_tx_status: poll for transaction completion, the optional @@ -492,11 +574,14 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_slave_sg)( struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_data_direction direction, + unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_data_direction direction); + size_t period_len, enum dma_transfer_direction direction); + struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)( + struct dma_chan *chan, struct dma_interleaved_template *xt, + unsigned long flags); int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg); @@ -522,7 +607,7 @@ static inline int dmaengine_slave_config(struct dma_chan *chan, static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single( struct dma_chan *chan, void *buf, size_t len, - enum dma_data_direction dir, unsigned long flags) + enum dma_transfer_direction dir, unsigned long flags) { struct scatterlist sg; sg_init_one(&sg, buf, len); diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index 1b1094c35e4f..cb4428ab81ed 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -72,7 +72,7 @@ typedef enum fe_caps { struct dvb_frontend_info { char name[128]; - fe_type_t type; + fe_type_t type; /* DEPRECATED. Use DTV_ENUM_DELSYS instead */ __u32 frequency_min; __u32 frequency_max; __u32 frequency_stepsize; @@ -181,6 +181,7 @@ typedef enum fe_transmit_mode { TRANSMISSION_MODE_32K, } fe_transmit_mode_t; +#if defined(__DVB_CORE__) || !defined (__KERNEL__) typedef enum fe_bandwidth { BANDWIDTH_8_MHZ, BANDWIDTH_7_MHZ, @@ -190,7 +191,7 @@ typedef enum fe_bandwidth { BANDWIDTH_10_MHZ, BANDWIDTH_1_712_MHZ, } fe_bandwidth_t; - +#endif typedef enum fe_guard_interval { GUARD_INTERVAL_1_32, @@ -213,6 +214,7 @@ typedef enum fe_hierarchy { } fe_hierarchy_t; +#if defined(__DVB_CORE__) || !defined (__KERNEL__) struct dvb_qpsk_parameters { __u32 symbol_rate; /* symbol rate in Symbols per second */ fe_code_rate_t fec_inner; /* forward error correction (see above) */ @@ -251,11 +253,11 @@ struct dvb_frontend_parameters { } u; }; - struct dvb_frontend_event { fe_status_t status; struct dvb_frontend_parameters parameters; }; +#endif /* S2API Commands */ #define DTV_UNDEFINED 0 @@ -316,7 +318,9 @@ struct dvb_frontend_event { #define DTV_DVBT2_PLP_ID 43 -#define DTV_MAX_COMMAND DTV_DVBT2_PLP_ID +#define DTV_ENUM_DELSYS 44 + +#define DTV_MAX_COMMAND DTV_ENUM_DELSYS typedef enum fe_pilot { PILOT_ON, @@ -333,7 +337,7 @@ typedef enum fe_rolloff { typedef enum fe_delivery_system { SYS_UNDEFINED, - SYS_DVBC_ANNEX_AC, + SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBT, SYS_DSS, @@ -350,8 +354,13 @@ typedef enum fe_delivery_system { SYS_DAB, SYS_DVBT2, SYS_TURBO, + SYS_DVBC_ANNEX_C, } fe_delivery_system_t; + +#define SYS_DVBC_ANNEX_AC SYS_DVBC_ANNEX_A + + struct dtv_cmds_h { char *name; /* A display name for debugging purposes */ diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h index 66594b1d5d7b..0559e2bd38f9 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 4 +#define DVB_API_VERSION_MINOR 5 #endif /*_DVBVERSION_H_*/ diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h index 4bfe0a2f7d50..f2c64f92c4a0 100644 --- a/include/linux/dw_dmac.h +++ b/include/linux/dw_dmac.h @@ -127,7 +127,7 @@ struct dw_cyclic_desc { struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, - enum dma_data_direction direction); + enum dma_transfer_direction direction); void dw_dma_cyclic_free(struct dma_chan *chan); int dw_dma_cyclic_start(struct dma_chan *chan); void dw_dma_cyclic_stop(struct dma_chan *chan); diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 1d0f7a2ff73b..c24f3d7fbf1e 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -5,6 +5,8 @@ #ifdef CONFIG_BLOCK +struct io_cq; + typedef int (elevator_merge_fn) (struct request_queue *, struct request **, struct bio *); @@ -24,6 +26,8 @@ typedef struct request *(elevator_request_list_fn) (struct request_queue *, stru typedef void (elevator_completed_req_fn) (struct request_queue *, struct request *); typedef int (elevator_may_queue_fn) (struct request_queue *, int); +typedef void (elevator_init_icq_fn) (struct io_cq *); +typedef void (elevator_exit_icq_fn) (struct io_cq *); typedef int (elevator_set_req_fn) (struct request_queue *, struct request *, gfp_t); typedef void (elevator_put_req_fn) (struct request *); typedef void (elevator_activate_req_fn) (struct request_queue *, struct request *); @@ -56,6 +60,9 @@ struct elevator_ops elevator_request_list_fn *elevator_former_req_fn; elevator_request_list_fn *elevator_latter_req_fn; + elevator_init_icq_fn *elevator_init_icq_fn; /* see iocontext.h */ + elevator_exit_icq_fn *elevator_exit_icq_fn; /* ditto */ + elevator_set_req_fn *elevator_set_req_fn; elevator_put_req_fn *elevator_put_req_fn; @@ -63,7 +70,6 @@ struct elevator_ops elevator_init_fn *elevator_init_fn; elevator_exit_fn *elevator_exit_fn; - void (*trim)(struct io_context *); }; #define ELV_NAME_MAX (16) @@ -79,11 +85,20 @@ struct elv_fs_entry { */ struct elevator_type { - struct list_head list; + /* managed by elevator core */ + struct kmem_cache *icq_cache; + + /* fields provided by elevator implementation */ struct elevator_ops ops; + size_t icq_size; /* see iocontext.h */ + size_t icq_align; /* ditto */ struct elv_fs_entry *elevator_attrs; char elevator_name[ELV_NAME_MAX]; struct module *elevator_owner; + + /* managed by elevator core */ + char icq_cache_name[ELV_NAME_MAX + 5]; /* elvname + "_io_cq" */ + struct list_head list; }; /* @@ -91,10 +106,9 @@ struct elevator_type */ struct elevator_queue { - struct elevator_ops *ops; + struct elevator_type *type; void *elevator_data; struct kobject kobj; - struct elevator_type *elevator_type; struct mutex sysfs_lock; struct hlist_head *hash; unsigned int registered:1; @@ -129,7 +143,7 @@ extern void elv_drain_elevator(struct request_queue *); /* * io scheduler registration */ -extern void elv_register(struct elevator_type *); +extern int elv_register(struct elevator_type *); extern void elv_unregister(struct elevator_type *); /* @@ -197,22 +211,5 @@ enum { INIT_LIST_HEAD(&(rq)->csd.list); \ } while (0) -/* - * io context count accounting - */ -#define elv_ioc_count_mod(name, __val) this_cpu_add(name, __val) -#define elv_ioc_count_inc(name) this_cpu_inc(name) -#define elv_ioc_count_dec(name) this_cpu_dec(name) - -#define elv_ioc_count_read(name) \ -({ \ - unsigned long __val = 0; \ - int __cpu; \ - smp_wmb(); \ - for_each_possible_cpu(__cpu) \ - __val += per_cpu(name, __cpu); \ - __val; \ -}) - #endif /* CONFIG_BLOCK */ #endif diff --git a/include/linux/elf.h b/include/linux/elf.h index 31f0508d7da7..999b4f52e8e5 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -7,15 +7,6 @@ #include <asm/elf.h> #endif -struct file; - -#ifndef elf_read_implies_exec - /* Executables for which elf_read_implies_exec() returns TRUE will - have the READ_IMPLIES_EXEC personality flag set automatically. - Override in asm/elf.h as needed. */ -# define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 -#endif - /* 32-bit ELF base types. */ typedef __u32 Elf32_Addr; typedef __u16 Elf32_Half; @@ -414,6 +405,13 @@ typedef struct elf64_note { } Elf64_Nhdr; #ifdef __KERNEL__ +#ifndef elf_read_implies_exec + /* Executables for which elf_read_implies_exec() returns TRUE will + have the READ_IMPLIES_EXEC personality flag set automatically. + Override in asm/elf.h as needed. */ +# define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 +#endif + #if ELF_CLASS == ELFCLASS32 extern Elf32_Dyn _DYNAMIC []; @@ -437,6 +435,8 @@ extern Elf64_Dyn _DYNAMIC []; #endif /* Optional callbacks to write extra ELF notes. */ +struct file; + #ifndef ARCH_HAVE_EXTRA_ELF_NOTES static inline int elf_coredump_extra_notes_size(void) { return 0; } static inline int elf_coredump_extra_notes_write(struct file *file, diff --git a/include/linux/fb.h b/include/linux/fb.h index 1d6836c498dd..c18122f40543 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -45,6 +45,7 @@ #define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ #define FB_TYPE_TEXT 3 /* Text/attributes */ #define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ +#define FB_TYPE_FOURCC 5 /* Type identified by a V4L2 FOURCC */ #define FB_AUX_TEXT_MDA 0 /* Monochrome text */ #define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ @@ -69,6 +70,7 @@ #define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ #define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ #define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ +#define FB_VISUAL_FOURCC 6 /* Visual identified by a V4L2 FOURCC */ #define FB_ACCEL_NONE 0 /* no hardware accelerator */ #define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ @@ -154,6 +156,8 @@ #define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */ +#define FB_CAP_FOURCC 1 /* Device supports FOURCC-based formats */ + struct fb_fix_screeninfo { char id[16]; /* identification string eg "TT Builtin" */ unsigned long smem_start; /* Start of frame buffer mem */ @@ -171,7 +175,8 @@ struct fb_fix_screeninfo { __u32 mmio_len; /* Length of Memory Mapped I/O */ __u32 accel; /* Indicate to driver which */ /* specific chip/card we have */ - __u16 reserved[3]; /* Reserved for future compatibility */ + __u16 capabilities; /* see FB_CAP_* */ + __u16 reserved[2]; /* Reserved for future compatibility */ }; /* Interpretation of offset for color fields: All offsets are from the right, @@ -246,8 +251,8 @@ struct fb_var_screeninfo { __u32 yoffset; /* resolution */ __u32 bits_per_pixel; /* guess what */ - __u32 grayscale; /* != 0 Graylevels instead of colors */ - + __u32 grayscale; /* 0 = color, 1 = grayscale, */ + /* >1 = FOURCC */ struct fb_bitfield red; /* bitfield in fb mem if true color, */ struct fb_bitfield green; /* else only length is significant */ struct fb_bitfield blue; @@ -273,7 +278,8 @@ struct fb_var_screeninfo { __u32 sync; /* see FB_SYNC_* */ __u32 vmode; /* see FB_VMODE_* */ __u32 rotate; /* angle we rotate counter clockwise */ - __u32 reserved[5]; /* Reserved for future compatibility */ + __u32 colorspace; /* colorspace for FOURCC-based modes */ + __u32 reserved[4]; /* Reserved for future compatibility */ }; struct fb_cmap { diff --git a/include/linux/fs.h b/include/linux/fs.h index 4bc8169fb5a1..386da09f229d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -319,6 +319,7 @@ struct inodes_stat_t { #define BLKPBSZGET _IO(0x12,123) #define BLKDISCARDZEROES _IO(0x12,124) #define BLKSECDISCARD _IO(0x12,125) +#define BLKROTATIONAL _IO(0x12,126) #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1) /* bmap access */ @@ -395,6 +396,7 @@ struct inodes_stat_t { #include <linux/rculist_bl.h> #include <linux/atomic.h> #include <linux/shrinker.h> +#include <linux/migrate_mode.h> #include <asm/byteorder.h> @@ -525,7 +527,6 @@ enum positive_aop_returns { struct page; struct address_space; struct writeback_control; -enum migrate_mode; struct iov_iter { const struct iovec *iov; diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 26eafcef75be..028e26f0bf08 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -133,6 +133,8 @@ struct ftrace_func_command { int ftrace_arch_code_modify_prepare(void); int ftrace_arch_code_modify_post_process(void); +void ftrace_bug(int err, unsigned long ip); + struct seq_file; struct ftrace_probe_ops { @@ -161,7 +163,6 @@ extern int ftrace_text_reserved(void *start, void *end); enum { FTRACE_FL_ENABLED = (1 << 30), - FTRACE_FL_FREE = (1 << 31), }; #define FTRACE_FL_MASK (0x3UL << 30) @@ -172,10 +173,7 @@ struct dyn_ftrace { unsigned long ip; /* address of mcount call-site */ struct dyn_ftrace *freelist; }; - union { - unsigned long flags; - struct dyn_ftrace *newlist; - }; + unsigned long flags; struct dyn_arch_ftrace arch; }; @@ -190,6 +188,56 @@ void ftrace_set_global_notrace(unsigned char *buf, int len, int reset); int register_ftrace_command(struct ftrace_func_command *cmd); int unregister_ftrace_command(struct ftrace_func_command *cmd); +enum { + FTRACE_UPDATE_CALLS = (1 << 0), + FTRACE_DISABLE_CALLS = (1 << 1), + FTRACE_UPDATE_TRACE_FUNC = (1 << 2), + FTRACE_START_FUNC_RET = (1 << 3), + FTRACE_STOP_FUNC_RET = (1 << 4), +}; + +enum { + FTRACE_UPDATE_IGNORE, + FTRACE_UPDATE_MAKE_CALL, + FTRACE_UPDATE_MAKE_NOP, +}; + +enum { + FTRACE_ITER_FILTER = (1 << 0), + FTRACE_ITER_NOTRACE = (1 << 1), + FTRACE_ITER_PRINTALL = (1 << 2), + FTRACE_ITER_DO_HASH = (1 << 3), + FTRACE_ITER_HASH = (1 << 4), + FTRACE_ITER_ENABLED = (1 << 5), +}; + +void arch_ftrace_update_code(int command); + +struct ftrace_rec_iter; + +struct ftrace_rec_iter *ftrace_rec_iter_start(void); +struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter); +struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter); + +int ftrace_update_record(struct dyn_ftrace *rec, int enable); +int ftrace_test_record(struct dyn_ftrace *rec, int enable); +void ftrace_run_stop_machine(int command); +int ftrace_location(unsigned long ip); + +extern ftrace_func_t ftrace_trace_function; + +int ftrace_regex_open(struct ftrace_ops *ops, int flag, + struct inode *inode, struct file *file); +ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, + size_t cnt, loff_t *ppos); +ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, + size_t cnt, loff_t *ppos); +loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin); +int ftrace_regex_release(struct inode *inode, struct file *file); + +void __init +ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable); + /* defined in arch */ extern int ftrace_ip_converted(unsigned long ip); extern int ftrace_dyn_arch_init(void *data); @@ -284,6 +332,25 @@ static inline int ftrace_text_reserved(void *start, void *end) { return 0; } + +/* + * Again users of functions that have ftrace_ops may not + * have them defined when ftrace is not enabled, but these + * functions may still be called. Use a macro instead of inline. + */ +#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) +#define ftrace_set_early_filter(ops, buf, enable) do { } while (0) + +static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, + size_t cnt, loff_t *ppos) { return -ENODEV; } +static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, + size_t cnt, loff_t *ppos) { return -ENODEV; } +static inline loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin) +{ + return -ENODEV; +} +static inline int +ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; } #endif /* CONFIG_DYNAMIC_FTRACE */ /* totally disable ftrace - can not re-enable after this */ diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index 4f4462974c14..b148087f49a6 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -22,6 +22,8 @@ #define GFS2_LIVE_LOCK 1 #define GFS2_TRANS_LOCK 2 #define GFS2_RENAME_LOCK 3 +#define GFS2_CONTROL_LOCK 4 +#define GFS2_MOUNTED_LOCK 5 /* Format numbers for various metadata types */ diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 114c0f6fc63d..78d3465251d6 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -652,10 +652,12 @@ struct twl4030_power_data { unsigned num; struct twl4030_resconfig *resource_config; #define TWL4030_RESCONFIG_UNDEF ((u8)-1) + bool use_poweroff; /* Board is wired for TWL poweroff */ }; extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts); extern int twl4030_remove_script(u8 flags); +extern void twl4030_power_off(void); struct twl4030_codec_data { unsigned int digimic_delay; /* in ms */ diff --git a/include/linux/if_team.h b/include/linux/if_team.h index 828181fbad5d..58404b0c5010 100644 --- a/include/linux/if_team.h +++ b/include/linux/if_team.h @@ -46,6 +46,10 @@ struct team_port { u32 speed; u8 duplex; + /* Custom gennetlink interface related flags */ + bool changed; + bool removed; + struct rcu_head rcu; }; @@ -72,6 +76,10 @@ struct team_option { enum team_option_type type; int (*getter)(struct team *team, void *arg); int (*setter)(struct team *team, void *arg); + + /* Custom gennetlink interface related flags */ + bool changed; + bool removed; }; struct team_mode { @@ -207,6 +215,7 @@ enum { TEAM_ATTR_OPTION_CHANGED, /* flag */ TEAM_ATTR_OPTION_TYPE, /* u8 */ TEAM_ATTR_OPTION_DATA, /* dynamic */ + TEAM_ATTR_OPTION_REMOVED, /* flag */ __TEAM_ATTR_OPTION_MAX, TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1, @@ -227,6 +236,7 @@ enum { TEAM_ATTR_PORT_LINKUP, /* flag */ TEAM_ATTR_PORT_SPEED, /* u32 */ TEAM_ATTR_PORT_DUPLEX, /* u8 */ + TEAM_ATTR_PORT_REMOVED, /* flag */ __TEAM_ATTR_PORT_MAX, TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1, diff --git a/include/linux/init.h b/include/linux/init.h index 9146f39cdddf..6b951095a42f 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -2,6 +2,7 @@ #define _LINUX_INIT_H #include <linux/compiler.h> +#include <linux/types.h> /* These macros are used to mark some functions or * initialized data (doesn't apply to uninitialized data) @@ -156,7 +157,7 @@ void prepare_namespace(void); extern void (*late_time_init)(void); -extern int initcall_debug; +extern bool initcall_debug; #endif diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h index 5037a0ad2312..7e1371c4bccf 100644 --- a/include/linux/iocontext.h +++ b/include/linux/iocontext.h @@ -3,32 +3,92 @@ #include <linux/radix-tree.h> #include <linux/rcupdate.h> +#include <linux/workqueue.h> -struct cfq_queue; -struct cfq_ttime { - unsigned long last_end_request; - - unsigned long ttime_total; - unsigned long ttime_samples; - unsigned long ttime_mean; +enum { + ICQ_IOPRIO_CHANGED, + ICQ_CGROUP_CHANGED, }; -struct cfq_io_context { - void *key; - - struct cfq_queue *cfqq[2]; - - struct io_context *ioc; - - struct cfq_ttime ttime; - - struct list_head queue_list; - struct hlist_node cic_list; - - void (*dtor)(struct io_context *); /* destructor */ - void (*exit)(struct io_context *); /* called on task exit */ +/* + * An io_cq (icq) is association between an io_context (ioc) and a + * request_queue (q). This is used by elevators which need to track + * information per ioc - q pair. + * + * Elevator can request use of icq by setting elevator_type->icq_size and + * ->icq_align. Both size and align must be larger than that of struct + * io_cq and elevator can use the tail area for private information. The + * recommended way to do this is defining a struct which contains io_cq as + * the first member followed by private members and using its size and + * align. For example, + * + * struct snail_io_cq { + * struct io_cq icq; + * int poke_snail; + * int feed_snail; + * }; + * + * struct elevator_type snail_elv_type { + * .ops = { ... }, + * .icq_size = sizeof(struct snail_io_cq), + * .icq_align = __alignof__(struct snail_io_cq), + * ... + * }; + * + * If icq_size is set, block core will manage icq's. All requests will + * have its ->elv.icq field set before elevator_ops->elevator_set_req_fn() + * is called and be holding a reference to the associated io_context. + * + * Whenever a new icq is created, elevator_ops->elevator_init_icq_fn() is + * called and, on destruction, ->elevator_exit_icq_fn(). Both functions + * are called with both the associated io_context and queue locks held. + * + * Elevator is allowed to lookup icq using ioc_lookup_icq() while holding + * queue lock but the returned icq is valid only until the queue lock is + * released. Elevators can not and should not try to create or destroy + * icq's. + * + * As icq's are linked from both ioc and q, the locking rules are a bit + * complex. + * + * - ioc lock nests inside q lock. + * + * - ioc->icq_list and icq->ioc_node are protected by ioc lock. + * q->icq_list and icq->q_node by q lock. + * + * - ioc->icq_tree and ioc->icq_hint are protected by ioc lock, while icq + * itself is protected by q lock. However, both the indexes and icq + * itself are also RCU managed and lookup can be performed holding only + * the q lock. + * + * - icq's are not reference counted. They are destroyed when either the + * ioc or q goes away. Each request with icq set holds an extra + * reference to ioc to ensure it stays until the request is completed. + * + * - Linking and unlinking icq's are performed while holding both ioc and q + * locks. Due to the lock ordering, q exit is simple but ioc exit + * requires reverse-order double lock dance. + */ +struct io_cq { + struct request_queue *q; + struct io_context *ioc; - struct rcu_head rcu_head; + /* + * q_node and ioc_node link io_cq through icq_list of q and ioc + * respectively. Both fields are unused once ioc_exit_icq() is + * called and shared with __rcu_icq_cache and __rcu_head which are + * used for RCU free of io_cq. + */ + union { + struct list_head q_node; + struct kmem_cache *__rcu_icq_cache; + }; + union { + struct hlist_node ioc_node; + struct rcu_head __rcu_head; + }; + + unsigned long changed; }; /* @@ -43,11 +103,6 @@ struct io_context { spinlock_t lock; unsigned short ioprio; - unsigned short ioprio_changed; - -#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE) - unsigned short cgroup_changed; -#endif /* * For request batching @@ -55,9 +110,11 @@ struct io_context { int nr_batch_requests; /* Number of requests left in the batch */ unsigned long last_waited; /* Time last woken after wait for request */ - struct radix_tree_root radix_root; - struct hlist_head cic_list; - void __rcu *ioc_data; + struct radix_tree_root icq_tree; + struct io_cq __rcu *icq_hint; + struct hlist_head icq_list; + + struct work_struct release_work; }; static inline struct io_context *ioc_task_link(struct io_context *ioc) @@ -76,20 +133,17 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc) struct task_struct; #ifdef CONFIG_BLOCK -int put_io_context(struct io_context *ioc); +void put_io_context(struct io_context *ioc, struct request_queue *locked_q); void exit_io_context(struct task_struct *task); -struct io_context *get_io_context(gfp_t gfp_flags, int node); -struct io_context *alloc_io_context(gfp_t gfp_flags, int node); +struct io_context *get_task_io_context(struct task_struct *task, + gfp_t gfp_flags, int node); +void ioc_ioprio_changed(struct io_context *ioc, int ioprio); +void ioc_cgroup_changed(struct io_context *ioc); #else -static inline void exit_io_context(struct task_struct *task) -{ -} - struct io_context; -static inline int put_io_context(struct io_context *ioc) -{ - return 1; -} +static inline void put_io_context(struct io_context *ioc, + struct request_queue *locked_q) { } +static inline void exit_io_context(struct task_struct *task) { } #endif #endif diff --git a/include/linux/isdn_divertif.h b/include/linux/isdn_divertif.h index 07821ca5955f..a5a50f523807 100644 --- a/include/linux/isdn_divertif.h +++ b/include/linux/isdn_divertif.h @@ -10,6 +10,8 @@ * */ +#ifndef _LINUX_ISDN_DIVERTIF_H +#define _LINUX_ISDN_DIVERTIF_H /***********************************************************/ /* magic value is also used to control version information */ @@ -45,3 +47,5 @@ typedef struct /*********************/ extern int DIVERT_REG_NAME(isdn_divert_if *); #endif + +#endif /* _LINUX_ISDN_DIVERTIF_H */ diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 2fa0901219d4..0d7d6a1b172f 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -50,9 +50,11 @@ * note header. For kdump, the code in vmcore.c runs in the context * of the second kernel to combine them into one note. */ +#ifndef KEXEC_NOTE_BYTES #define KEXEC_NOTE_BYTES ( (KEXEC_NOTE_HEAD_BYTES * 2) + \ KEXEC_CORE_NOTE_NAME_BYTES + \ KEXEC_CORE_NOTE_DESC_BYTES ) +#endif /* * This structure is used to hold the arguments that are used when loading diff --git a/include/linux/key.h b/include/linux/key.h index 183a6af7715d..5253471cd2ea 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -271,7 +271,7 @@ extern int keyring_add_key(struct key *keyring, extern struct key *key_lookup(key_serial_t id); -static inline key_serial_t key_serial(struct key *key) +static inline key_serial_t key_serial(const struct key *key) { return key ? key->serial : 0; } @@ -293,6 +293,9 @@ static inline bool key_is_instantiated(const struct key *key) (rcu_dereference_protected((KEY)->payload.rcudata, \ rwsem_is_locked(&((struct key *)(KEY))->sem))) +#define rcu_assign_keypointer(KEY, PAYLOAD) \ + (rcu_assign_pointer((KEY)->payload.rcudata, PAYLOAD)) + #ifdef CONFIG_SYSCTL extern ctl_table key_sysctls[]; #endif diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h index 99d9a6766f7e..2a5e5548a1d2 100644 --- a/include/linux/kmemleak.h +++ b/include/linux/kmemleak.h @@ -26,8 +26,10 @@ extern void kmemleak_init(void) __ref; extern void kmemleak_alloc(const void *ptr, size_t size, int min_count, gfp_t gfp) __ref; +extern void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size) __ref; extern void kmemleak_free(const void *ptr) __ref; extern void kmemleak_free_part(const void *ptr, size_t size) __ref; +extern void kmemleak_free_percpu(const void __percpu *ptr) __ref; extern void kmemleak_padding(const void *ptr, unsigned long offset, size_t size) __ref; extern void kmemleak_not_leak(const void *ptr) __ref; @@ -68,6 +70,9 @@ static inline void kmemleak_alloc_recursive(const void *ptr, size_t size, gfp_t gfp) { } +static inline void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size) +{ +} static inline void kmemleak_free(const void *ptr) { } @@ -77,6 +82,9 @@ static inline void kmemleak_free_part(const void *ptr, size_t size) static inline void kmemleak_free_recursive(const void *ptr, unsigned long flags) { } +static inline void kmemleak_free_percpu(const void __percpu *ptr) +{ +} static inline void kmemleak_not_leak(const void *ptr) { } diff --git a/include/linux/kref.h b/include/linux/kref.h index abc0120b09b7..9c07dcebded7 100644 --- a/include/linux/kref.h +++ b/include/linux/kref.h @@ -17,6 +17,7 @@ #include <linux/bug.h> #include <linux/atomic.h> +#include <linux/kernel.h> struct kref { atomic_t refcount; diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 90b0656a869e..88a114fce477 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -195,7 +195,7 @@ extern struct svc_procedure nlmsvc_procedures4[]; #endif extern int nlmsvc_grace_period; extern unsigned long nlmsvc_timeout; -extern int nsm_use_hostnames; +extern bool nsm_use_hostnames; extern u32 nsm_local_state; /* diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index 63b4fb8e3b6f..92be3476c9f5 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h @@ -297,10 +297,11 @@ enum { struct pm860x_chip { struct device *dev; - struct mutex io_lock; struct mutex irq_lock; struct i2c_client *client; struct i2c_client *companion; /* companion chip client */ + struct regmap *regmap; + struct regmap *regmap_companion; int buck3_double; /* DVC ramp slope double */ unsigned short companion_addr; diff --git a/include/linux/mfd/ab5500/ab5500.h b/include/linux/mfd/abx500/ab5500.h index a720051ae933..a720051ae933 100644 --- a/include/linux/mfd/ab5500/ab5500.h +++ b/include/linux/mfd/abx500/ab5500.h diff --git a/include/linux/mfd/ab8500/gpadc.h b/include/linux/mfd/abx500/ab8500-gpadc.h index 252966769d93..252966769d93 100644 --- a/include/linux/mfd/ab8500/gpadc.h +++ b/include/linux/mfd/abx500/ab8500-gpadc.h diff --git a/include/linux/mfd/ab8500/gpio.h b/include/linux/mfd/abx500/ab8500-gpio.h index 488a8c920a29..488a8c920a29 100644 --- a/include/linux/mfd/ab8500/gpio.h +++ b/include/linux/mfd/abx500/ab8500-gpio.h diff --git a/include/linux/mfd/ab8500/sysctrl.h b/include/linux/mfd/abx500/ab8500-sysctrl.h index 10da0291f8f8..10da0291f8f8 100644 --- a/include/linux/mfd/ab8500/sysctrl.h +++ b/include/linux/mfd/abx500/ab8500-sysctrl.h diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/abx500/ab8500.h index 838c6b487cc5..838c6b487cc5 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h diff --git a/include/linux/mfd/max8925.h b/include/linux/mfd/max8925.h index b8e6d9449086..15b2392a56fb 100644 --- a/include/linux/mfd/max8925.h +++ b/include/linux/mfd/max8925.h @@ -203,6 +203,8 @@ struct max8925_chip { int irq_base; int core_irq; int tsc_irq; + + unsigned int wakeup_flag; }; struct max8925_backlight_pdata { diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h index 0bbd13dbe336..fff590521e50 100644 --- a/include/linux/mfd/max8997.h +++ b/include/linux/mfd/max8997.h @@ -77,6 +77,82 @@ struct max8997_regulator_data { struct regulator_init_data *initdata; }; +enum max8997_muic_usb_type { + MAX8997_USB_HOST, + MAX8997_USB_DEVICE, +}; + +enum max8997_muic_charger_type { + MAX8997_CHARGER_TYPE_NONE = 0, + MAX8997_CHARGER_TYPE_USB, + MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT, + MAX8997_CHARGER_TYPE_DEDICATED_CHG, + MAX8997_CHARGER_TYPE_500MA, + MAX8997_CHARGER_TYPE_1A, + MAX8997_CHARGER_TYPE_DEAD_BATTERY = 7, +}; + +struct max8997_muic_reg_data { + u8 addr; + u8 data; +}; + +/** + * struct max8997_muic_platform_data + * @usb_callback: callback function for USB + * inform callee of USB type (HOST or DEVICE) + * and attached state(true or false) + * @charger_callback: callback function for charger + * inform callee of charger_type + * and attached state(true or false) + * @deskdock_callback: callback function for desk dock + * inform callee of attached state(true or false) + * @cardock_callback: callback function for car dock + * inform callee of attached state(true or false) + * @mhl_callback: callback function for MHL (Mobile High-definition Link) + * inform callee of attached state(true or false) + * @uart_callback: callback function for JIG UART + * inform callee of attached state(true or false) + * @init_data: array of max8997_muic_reg_data + * used for initializing registers of MAX8997 MUIC device + * @num_init_data: array size of init_data + */ +struct max8997_muic_platform_data { + void (*usb_callback)(enum max8997_muic_usb_type usb_type, + bool attached); + void (*charger_callback)(bool attached, + enum max8997_muic_charger_type charger_type); + void (*deskdock_callback) (bool attached); + void (*cardock_callback) (bool attached); + void (*mhl_callback) (bool attached); + void (*uart_callback) (bool attached); + + struct max8997_muic_reg_data *init_data; + int num_init_data; +}; + +enum max8997_led_mode { + MAX8997_NONE, + MAX8997_FLASH_MODE, + MAX8997_MOVIE_MODE, + MAX8997_FLASH_PIN_CONTROL_MODE, + MAX8997_MOVIE_PIN_CONTROL_MODE, +}; + +/** + * struct max8997_led_platform_data + * The number of LED devices for MAX8997 is two + * @mode: LED mode for each LED device + * @brightness: initial brightness for each LED device + * range: + * [0 - 31]: MAX8997_FLASH_MODE and MAX8997_FLASH_PIN_CONTROL_MODE + * [0 - 15]: MAX8997_MOVIE_MODE and MAX8997_MOVIE_PIN_CONTROL_MODE + */ +struct max8997_led_platform_data { + enum max8997_led_mode mode[2]; + u8 brightness[2]; +}; + struct max8997_platform_data { /* IRQ */ int irq_base; @@ -113,10 +189,13 @@ struct max8997_platform_data { /* charge Full Timeout */ int timeout; /* 0 (no timeout), 5, 6, 7 hours */ - /* MUIC: Not implemented */ + /* ---- MUIC ---- */ + struct max8997_muic_platform_data *muic_pdata; + /* HAPTIC: Not implemented */ /* RTC: Not implemented */ - /* Flash: Not implemented */ + /* ---- LED ---- */ + struct max8997_led_platform_data *led_pdata; }; #endif /* __LINUX_MFD_MAX8998_H */ diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index a98e2a316d1f..b86ee45c8b03 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -174,6 +174,9 @@ struct mc13xxx_platform_data { #define MC13XXX_ADC_MODE_MULT_CHAN 3 #define MC13XXX_ADC0 43 +#define MC13XXX_ADC0_LICELLCON (1 << 0) +#define MC13XXX_ADC0_CHRGICON (1 << 1) +#define MC13XXX_ADC0_BATICON (1 << 2) #define MC13XXX_ADC0_ADREFEN (1 << 10) #define MC13XXX_ADC0_TSMOD0 (1 << 12) #define MC13XXX_ADC0_TSMOD1 (1 << 13) @@ -185,4 +188,9 @@ struct mc13xxx_platform_data { MC13XXX_ADC0_TSMOD1 | \ MC13XXX_ADC0_TSMOD2) +#define MC13XXX_ADC0_CONFIG_MASK (MC13XXX_ADC0_TSMOD_MASK | \ + MC13XXX_ADC0_LICELLCON | \ + MC13XXX_ADC0_CHRGICON | \ + MC13XXX_ADC0_BATICON) + #endif /* ifndef __LINUX_MFD_MC13XXX_H */ diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h index ee496708e38b..1515e64e3663 100644 --- a/include/linux/mfd/mcp.h +++ b/include/linux/mfd/mcp.h @@ -10,6 +10,7 @@ #ifndef MCP_H #define MCP_H +#include <linux/mod_devicetable.h> #include <mach/dma.h> struct mcp_ops; @@ -26,7 +27,7 @@ struct mcp { dma_device_t dma_telco_rd; dma_device_t dma_telco_wr; struct device attached_device; - int gpio_base; + const char *codec; }; struct mcp_ops { @@ -44,10 +45,11 @@ void mcp_reg_write(struct mcp *, unsigned int, unsigned int); unsigned int mcp_reg_read(struct mcp *, unsigned int); void mcp_enable(struct mcp *); void mcp_disable(struct mcp *); +const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp); #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) struct mcp *mcp_host_alloc(struct device *, size_t); -int mcp_host_register(struct mcp *); +int mcp_host_register(struct mcp *, void *); void mcp_host_unregister(struct mcp *); struct mcp_driver { @@ -56,6 +58,7 @@ struct mcp_driver { void (*remove)(struct mcp *); int (*suspend)(struct mcp *, pm_message_t); int (*resume)(struct mcp *); + const struct mcp_device_id *id_table; }; int mcp_driver_register(struct mcp_driver *); diff --git a/include/linux/mfd/s5m87xx/s5m-core.h b/include/linux/mfd/s5m87xx/s5m-core.h new file mode 100644 index 000000000000..a7480b57f92d --- /dev/null +++ b/include/linux/mfd/s5m87xx/s5m-core.h @@ -0,0 +1,373 @@ +/* + * s5m-core.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 __LINUX_MFD_S5M_CORE_H +#define __LINUX_MFD_S5M_CORE_H + +#define NUM_IRQ_REGS 4 + +enum s5m_device_type { + S5M8751X, + S5M8763X, + S5M8767X, +}; + +/* S5M8767 registers */ +enum s5m8767_reg { + S5M8767_REG_ID, + S5M8767_REG_INT1, + S5M8767_REG_INT2, + S5M8767_REG_INT3, + S5M8767_REG_INT1M, + S5M8767_REG_INT2M, + S5M8767_REG_INT3M, + S5M8767_REG_STATUS1, + S5M8767_REG_STATUS2, + S5M8767_REG_STATUS3, + S5M8767_REG_CTRL1, + S5M8767_REG_CTRL2, + S5M8767_REG_LOWBAT1, + S5M8767_REG_LOWBAT2, + S5M8767_REG_BUCHG, + S5M8767_REG_DVSRAMP, + S5M8767_REG_DVSTIMER2 = 0x10, + S5M8767_REG_DVSTIMER3, + S5M8767_REG_DVSTIMER4, + S5M8767_REG_LDO1, + S5M8767_REG_LDO2, + S5M8767_REG_LDO3, + S5M8767_REG_LDO4, + S5M8767_REG_LDO5, + S5M8767_REG_LDO6, + S5M8767_REG_LDO7, + S5M8767_REG_LDO8, + S5M8767_REG_LDO9, + S5M8767_REG_LDO10, + S5M8767_REG_LDO11, + S5M8767_REG_LDO12, + S5M8767_REG_LDO13, + S5M8767_REG_LDO14 = 0x20, + S5M8767_REG_LDO15, + S5M8767_REG_LDO16, + S5M8767_REG_LDO17, + S5M8767_REG_LDO18, + S5M8767_REG_LDO19, + S5M8767_REG_LDO20, + S5M8767_REG_LDO21, + S5M8767_REG_LDO22, + S5M8767_REG_LDO23, + S5M8767_REG_LDO24, + S5M8767_REG_LDO25, + S5M8767_REG_LDO26, + S5M8767_REG_LDO27, + S5M8767_REG_LDO28, + S5M8767_REG_UVLO = 0x31, + S5M8767_REG_BUCK1CTRL1, + S5M8767_REG_BUCK1CTRL2, + S5M8767_REG_BUCK2CTRL, + S5M8767_REG_BUCK2DVS1, + S5M8767_REG_BUCK2DVS2, + S5M8767_REG_BUCK2DVS3, + S5M8767_REG_BUCK2DVS4, + S5M8767_REG_BUCK2DVS5, + S5M8767_REG_BUCK2DVS6, + S5M8767_REG_BUCK2DVS7, + S5M8767_REG_BUCK2DVS8, + S5M8767_REG_BUCK3CTRL, + S5M8767_REG_BUCK3DVS1, + S5M8767_REG_BUCK3DVS2, + S5M8767_REG_BUCK3DVS3, + S5M8767_REG_BUCK3DVS4, + S5M8767_REG_BUCK3DVS5, + S5M8767_REG_BUCK3DVS6, + S5M8767_REG_BUCK3DVS7, + S5M8767_REG_BUCK3DVS8, + S5M8767_REG_BUCK4CTRL, + S5M8767_REG_BUCK4DVS1, + S5M8767_REG_BUCK4DVS2, + S5M8767_REG_BUCK4DVS3, + S5M8767_REG_BUCK4DVS4, + S5M8767_REG_BUCK4DVS5, + S5M8767_REG_BUCK4DVS6, + S5M8767_REG_BUCK4DVS7, + S5M8767_REG_BUCK4DVS8, + S5M8767_REG_BUCK5CTRL1, + S5M8767_REG_BUCK5CTRL2, + S5M8767_REG_BUCK5CTRL3, + S5M8767_REG_BUCK5CTRL4, + S5M8767_REG_BUCK5CTRL5, + S5M8767_REG_BUCK6CTRL1, + S5M8767_REG_BUCK6CTRL2, + S5M8767_REG_BUCK7CTRL1, + S5M8767_REG_BUCK7CTRL2, + S5M8767_REG_BUCK8CTRL1, + S5M8767_REG_BUCK8CTRL2, + S5M8767_REG_BUCK9CTRL1, + S5M8767_REG_BUCK9CTRL2, + S5M8767_REG_LDO1CTRL, + S5M8767_REG_LDO2_1CTRL, + S5M8767_REG_LDO2_2CTRL, + S5M8767_REG_LDO2_3CTRL, + S5M8767_REG_LDO2_4CTRL, + S5M8767_REG_LDO3CTRL, + S5M8767_REG_LDO4CTRL, + S5M8767_REG_LDO5CTRL, + S5M8767_REG_LDO6CTRL, + S5M8767_REG_LDO7CTRL, + S5M8767_REG_LDO8CTRL, + S5M8767_REG_LDO9CTRL, + S5M8767_REG_LDO10CTRL, + S5M8767_REG_LDO11CTRL, + S5M8767_REG_LDO12CTRL, + S5M8767_REG_LDO13CTRL, + S5M8767_REG_LDO14CTRL, + S5M8767_REG_LDO15CTRL, + S5M8767_REG_LDO16CTRL, + S5M8767_REG_LDO17CTRL, + S5M8767_REG_LDO18CTRL, + S5M8767_REG_LDO19CTRL, + S5M8767_REG_LDO20CTRL, + S5M8767_REG_LDO21CTRL, + S5M8767_REG_LDO22CTRL, + S5M8767_REG_LDO23CTRL, + S5M8767_REG_LDO24CTRL, + S5M8767_REG_LDO25CTRL, + S5M8767_REG_LDO26CTRL, + S5M8767_REG_LDO27CTRL, + S5M8767_REG_LDO28CTRL, +}; + +/* S5M8763 registers */ +enum s5m8763_reg { + S5M8763_REG_IRQ1, + S5M8763_REG_IRQ2, + S5M8763_REG_IRQ3, + S5M8763_REG_IRQ4, + S5M8763_REG_IRQM1, + S5M8763_REG_IRQM2, + S5M8763_REG_IRQM3, + S5M8763_REG_IRQM4, + S5M8763_REG_STATUS1, + S5M8763_REG_STATUS2, + S5M8763_REG_STATUSM1, + S5M8763_REG_STATUSM2, + S5M8763_REG_CHGR1, + S5M8763_REG_CHGR2, + S5M8763_REG_LDO_ACTIVE_DISCHARGE1, + S5M8763_REG_LDO_ACTIVE_DISCHARGE2, + S5M8763_REG_BUCK_ACTIVE_DISCHARGE3, + S5M8763_REG_ONOFF1, + S5M8763_REG_ONOFF2, + S5M8763_REG_ONOFF3, + S5M8763_REG_ONOFF4, + S5M8763_REG_BUCK1_VOLTAGE1, + S5M8763_REG_BUCK1_VOLTAGE2, + S5M8763_REG_BUCK1_VOLTAGE3, + S5M8763_REG_BUCK1_VOLTAGE4, + S5M8763_REG_BUCK2_VOLTAGE1, + S5M8763_REG_BUCK2_VOLTAGE2, + S5M8763_REG_BUCK3, + S5M8763_REG_BUCK4, + S5M8763_REG_LDO1_LDO2, + S5M8763_REG_LDO3, + S5M8763_REG_LDO4, + S5M8763_REG_LDO5, + S5M8763_REG_LDO6, + S5M8763_REG_LDO7, + S5M8763_REG_LDO7_LDO8, + S5M8763_REG_LDO9_LDO10, + S5M8763_REG_LDO11, + S5M8763_REG_LDO12, + S5M8763_REG_LDO13, + S5M8763_REG_LDO14, + S5M8763_REG_LDO15, + S5M8763_REG_LDO16, + S5M8763_REG_BKCHR, + S5M8763_REG_LBCNFG1, + S5M8763_REG_LBCNFG2, +}; + +enum s5m8767_irq { + S5M8767_IRQ_PWRR, + S5M8767_IRQ_PWRF, + S5M8767_IRQ_PWR1S, + S5M8767_IRQ_JIGR, + S5M8767_IRQ_JIGF, + S5M8767_IRQ_LOWBAT2, + S5M8767_IRQ_LOWBAT1, + + S5M8767_IRQ_MRB, + S5M8767_IRQ_DVSOK2, + S5M8767_IRQ_DVSOK3, + S5M8767_IRQ_DVSOK4, + + S5M8767_IRQ_RTC60S, + S5M8767_IRQ_RTCA1, + S5M8767_IRQ_RTCA2, + S5M8767_IRQ_SMPL, + S5M8767_IRQ_RTC1S, + S5M8767_IRQ_WTSR, + + S5M8767_IRQ_NR, +}; + +#define S5M8767_IRQ_PWRR_MASK (1 << 0) +#define S5M8767_IRQ_PWRF_MASK (1 << 1) +#define S5M8767_IRQ_PWR1S_MASK (1 << 3) +#define S5M8767_IRQ_JIGR_MASK (1 << 4) +#define S5M8767_IRQ_JIGF_MASK (1 << 5) +#define S5M8767_IRQ_LOWBAT2_MASK (1 << 6) +#define S5M8767_IRQ_LOWBAT1_MASK (1 << 7) + +#define S5M8767_IRQ_MRB_MASK (1 << 2) +#define S5M8767_IRQ_DVSOK2_MASK (1 << 3) +#define S5M8767_IRQ_DVSOK3_MASK (1 << 4) +#define S5M8767_IRQ_DVSOK4_MASK (1 << 5) + +#define S5M8767_IRQ_RTC60S_MASK (1 << 0) +#define S5M8767_IRQ_RTCA1_MASK (1 << 1) +#define S5M8767_IRQ_RTCA2_MASK (1 << 2) +#define S5M8767_IRQ_SMPL_MASK (1 << 3) +#define S5M8767_IRQ_RTC1S_MASK (1 << 4) +#define S5M8767_IRQ_WTSR_MASK (1 << 5) + +enum s5m8763_irq { + S5M8763_IRQ_DCINF, + S5M8763_IRQ_DCINR, + S5M8763_IRQ_JIGF, + S5M8763_IRQ_JIGR, + S5M8763_IRQ_PWRONF, + S5M8763_IRQ_PWRONR, + + S5M8763_IRQ_WTSREVNT, + S5M8763_IRQ_SMPLEVNT, + S5M8763_IRQ_ALARM1, + S5M8763_IRQ_ALARM0, + + S5M8763_IRQ_ONKEY1S, + S5M8763_IRQ_TOPOFFR, + S5M8763_IRQ_DCINOVPR, + S5M8763_IRQ_CHGRSTF, + S5M8763_IRQ_DONER, + S5M8763_IRQ_CHGFAULT, + + S5M8763_IRQ_LOBAT1, + S5M8763_IRQ_LOBAT2, + + S5M8763_IRQ_NR, +}; + +#define S5M8763_IRQ_DCINF_MASK (1 << 2) +#define S5M8763_IRQ_DCINR_MASK (1 << 3) +#define S5M8763_IRQ_JIGF_MASK (1 << 4) +#define S5M8763_IRQ_JIGR_MASK (1 << 5) +#define S5M8763_IRQ_PWRONF_MASK (1 << 6) +#define S5M8763_IRQ_PWRONR_MASK (1 << 7) + +#define S5M8763_IRQ_WTSREVNT_MASK (1 << 0) +#define S5M8763_IRQ_SMPLEVNT_MASK (1 << 1) +#define S5M8763_IRQ_ALARM1_MASK (1 << 2) +#define S5M8763_IRQ_ALARM0_MASK (1 << 3) + +#define S5M8763_IRQ_ONKEY1S_MASK (1 << 0) +#define S5M8763_IRQ_TOPOFFR_MASK (1 << 2) +#define S5M8763_IRQ_DCINOVPR_MASK (1 << 3) +#define S5M8763_IRQ_CHGRSTF_MASK (1 << 4) +#define S5M8763_IRQ_DONER_MASK (1 << 5) +#define S5M8763_IRQ_CHGFAULT_MASK (1 << 7) + +#define S5M8763_IRQ_LOBAT1_MASK (1 << 0) +#define S5M8763_IRQ_LOBAT2_MASK (1 << 1) + +#define S5M8763_ENRAMP (1 << 4) + +/** + * struct s5m87xx_dev - s5m87xx master device for sub-drivers + * @dev: master device of the chip (can be used to access platform data) + * @i2c: i2c client private data for regulator + * @rtc: i2c client private data for rtc + * @iolock: mutex for serializing io access + * @irqlock: mutex for buslock + * @irq_base: base IRQ number for s5m87xx, required for IRQs + * @irq: generic IRQ number for s5m87xx + * @ono: power onoff IRQ number for s5m87xx + * @irq_masks_cur: currently active value + * @irq_masks_cache: cached hardware value + * @type: indicate which s5m87xx "variant" is used + */ +struct s5m87xx_dev { + struct device *dev; + struct regmap *regmap; + struct i2c_client *i2c; + struct i2c_client *rtc; + struct mutex iolock; + struct mutex irqlock; + + int device_type; + int irq_base; + int irq; + int ono; + u8 irq_masks_cur[NUM_IRQ_REGS]; + u8 irq_masks_cache[NUM_IRQ_REGS]; + int type; + bool wakeup; +}; + +int s5m_irq_init(struct s5m87xx_dev *s5m87xx); +void s5m_irq_exit(struct s5m87xx_dev *s5m87xx); +int s5m_irq_resume(struct s5m87xx_dev *s5m87xx); + +extern int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest); +extern int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf); +extern int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value); +extern int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf); +extern int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask); + +struct s5m_platform_data { + struct s5m_regulator_data *regulators; + int device_type; + int num_regulators; + + int irq_base; + int (*cfg_pmic_irq)(void); + + int ono; + bool wakeup; + bool buck_voltage_lock; + + int buck_gpios[3]; + int buck2_voltage[8]; + bool buck2_gpiodvs; + int buck3_voltage[8]; + bool buck3_gpiodvs; + int buck4_voltage[8]; + bool buck4_gpiodvs; + + int buck_set1; + int buck_set2; + int buck_set3; + int buck2_enable; + int buck3_enable; + int buck4_enable; + int buck_default_idx; + int buck2_default_idx; + int buck3_default_idx; + int buck4_default_idx; + + int buck_ramp_delay; + bool buck2_ramp_enable; + bool buck3_ramp_enable; + bool buck4_ramp_enable; +}; + +#endif /* __LINUX_MFD_S5M_CORE_H */ diff --git a/include/linux/mfd/s5m87xx/s5m-pmic.h b/include/linux/mfd/s5m87xx/s5m-pmic.h new file mode 100644 index 000000000000..a72a5d27e62e --- /dev/null +++ b/include/linux/mfd/s5m87xx/s5m-pmic.h @@ -0,0 +1,100 @@ +/* s5m87xx.h + * + * Copyright (c) 2010-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 version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __LINUX_MFD_S5M_PMIC_H +#define __LINUX_MFD_S5M_PMIC_H + +#include <linux/regulator/machine.h> + +/* S5M8767 regulator ids */ +enum s5m8767_regulators { + S5M8767_LDO1, + S5M8767_LDO2, + S5M8767_LDO3, + S5M8767_LDO4, + S5M8767_LDO5, + S5M8767_LDO6, + S5M8767_LDO7, + S5M8767_LDO8, + S5M8767_LDO9, + S5M8767_LDO10, + S5M8767_LDO11, + S5M8767_LDO12, + S5M8767_LDO13, + S5M8767_LDO14, + S5M8767_LDO15, + S5M8767_LDO16, + S5M8767_LDO17, + S5M8767_LDO18, + S5M8767_LDO19, + S5M8767_LDO20, + S5M8767_LDO21, + S5M8767_LDO22, + S5M8767_LDO23, + S5M8767_LDO24, + S5M8767_LDO25, + S5M8767_LDO26, + S5M8767_LDO27, + S5M8767_LDO28, + S5M8767_BUCK1, + S5M8767_BUCK2, + S5M8767_BUCK3, + S5M8767_BUCK4, + S5M8767_BUCK5, + S5M8767_BUCK6, + S5M8767_BUCK7, + S5M8767_BUCK8, + S5M8767_BUCK9, + S5M8767_AP_EN32KHZ, + S5M8767_CP_EN32KHZ, + + S5M8767_REG_MAX, +}; + +/* S5M8763 regulator ids */ +enum s5m8763_regulators { + S5M8763_LDO1, + S5M8763_LDO2, + S5M8763_LDO3, + S5M8763_LDO4, + S5M8763_LDO5, + S5M8763_LDO6, + S5M8763_LDO7, + S5M8763_LDO8, + S5M8763_LDO9, + S5M8763_LDO10, + S5M8763_LDO11, + S5M8763_LDO12, + S5M8763_LDO13, + S5M8763_LDO14, + S5M8763_LDO15, + S5M8763_LDO16, + S5M8763_BUCK1, + S5M8763_BUCK2, + S5M8763_BUCK3, + S5M8763_BUCK4, + S5M8763_AP_EN32KHZ, + S5M8763_CP_EN32KHZ, + S5M8763_ENCHGVI, + S5M8763_ESAFEUSB1, + S5M8763_ESAFEUSB2, +}; + +/** + * s5m87xx_regulator_data - regulator data + * @id: regulator id + * @initdata: regulator init data (contraints, supplies, ...) + */ +struct s5m_regulator_data { + int id; + struct regulator_init_data *initdata; +}; + +#endif /* __LINUX_MFD_S5M_PMIC_H */ diff --git a/include/linux/mfd/s5m87xx/s5m-rtc.h b/include/linux/mfd/s5m87xx/s5m-rtc.h new file mode 100644 index 000000000000..6ce8da264cec --- /dev/null +++ b/include/linux/mfd/s5m87xx/s5m-rtc.h @@ -0,0 +1,84 @@ +/* + * s5m-rtc.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 __LINUX_MFD_S5M_RTC_H +#define __LINUX_MFD_S5M_RTC_H + +enum s5m87xx_rtc_reg { + S5M87XX_RTC_SEC, + S5M87XX_RTC_MIN, + S5M87XX_RTC_HOUR, + S5M87XX_RTC_WEEKDAY, + S5M87XX_RTC_DATE, + S5M87XX_RTC_MONTH, + S5M87XX_RTC_YEAR1, + S5M87XX_RTC_YEAR2, + S5M87XX_ALARM0_SEC, + S5M87XX_ALARM0_MIN, + S5M87XX_ALARM0_HOUR, + S5M87XX_ALARM0_WEEKDAY, + S5M87XX_ALARM0_DATE, + S5M87XX_ALARM0_MONTH, + S5M87XX_ALARM0_YEAR1, + S5M87XX_ALARM0_YEAR2, + S5M87XX_ALARM1_SEC, + S5M87XX_ALARM1_MIN, + S5M87XX_ALARM1_HOUR, + S5M87XX_ALARM1_WEEKDAY, + S5M87XX_ALARM1_DATE, + S5M87XX_ALARM1_MONTH, + S5M87XX_ALARM1_YEAR1, + S5M87XX_ALARM1_YEAR2, + S5M87XX_ALARM0_CONF, + S5M87XX_ALARM1_CONF, + S5M87XX_RTC_STATUS, + S5M87XX_WTSR_SMPL_CNTL, + S5M87XX_RTC_UDR_CON, +}; + +#define RTC_I2C_ADDR (0x0C >> 1) + +#define HOUR_12 (1 << 7) +#define HOUR_AMPM (1 << 6) +#define HOUR_PM (1 << 5) +#define ALARM0_STATUS (1 << 1) +#define ALARM1_STATUS (1 << 2) +#define UPDATE_AD (1 << 0) + +/* RTC Control Register */ +#define BCD_EN_SHIFT 0 +#define BCD_EN_MASK (1 << BCD_EN_SHIFT) +#define MODEL24_SHIFT 1 +#define MODEL24_MASK (1 << MODEL24_SHIFT) +/* RTC Update Register1 */ +#define RTC_UDR_SHIFT 0 +#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +/* RTC Hour register */ +#define HOUR_PM_SHIFT 6 +#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT) +/* RTC Alarm Enable */ +#define ALARM_ENABLE_SHIFT 7 +#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT) + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_DATE, + RTC_MONTH, + RTC_YEAR1, + RTC_YEAR2, +}; + +#endif /* __LINUX_MFD_S5M_RTC_H */ diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index be1af7c42e57..ca1d7a347600 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h @@ -20,6 +20,8 @@ enum stmpe_block { }; enum stmpe_partnum { + STMPE610, + STMPE801, STMPE811, STMPE1601, STMPE2401, @@ -50,17 +52,20 @@ enum { struct stmpe_variant_info; +struct stmpe_client_info; /** * struct stmpe - STMPE MFD structure * @lock: lock protecting I/O operations * @irq_lock: IRQ bus lock * @dev: device, mostly for dev_dbg() - * @i2c: i2c client + * @client: client - i2c or spi + * @ci: client specific information * @partnum: part number * @variant: the detected STMPE model number * @regs: list of addresses of registers which are at different addresses on * different variants. Indexed by one of STMPE_IDX_*. + * @irq: irq number for stmpe * @irq_base: starting IRQ number for internal IRQs * @num_gpios: number of gpios, differs for variants * @ier: cache of IER registers for bus_lock @@ -71,11 +76,13 @@ struct stmpe { struct mutex lock; struct mutex irq_lock; struct device *dev; - struct i2c_client *i2c; + void *client; + struct stmpe_client_info *ci; enum stmpe_partnum partnum; struct stmpe_variant_info *variant; const u8 *regs; + int irq; int irq_base; int num_gpios; u8 ier[2]; @@ -183,6 +190,9 @@ struct stmpe_ts_platform_data { * @autosleep_timeout: inactivity timeout in milliseconds for autosleep * @irq_base: base IRQ number. %STMPE_NR_IRQS irqs will be used, or * %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used. + * @irq_over_gpio: true if gpio is used to get irq + * @irq_gpio: gpio number over which irq will be requested (significant only if + * irq_over_gpio is true) * @gpio: GPIO-specific platform data * @keypad: keypad-specific platform data * @ts: touchscreen-specific platform data @@ -194,6 +204,8 @@ struct stmpe_platform_data { unsigned int irq_trigger; bool irq_invert_polarity; bool autosleep; + bool irq_over_gpio; + int irq_gpio; int autosleep_timeout; struct stmpe_gpio_platform_data *gpio; diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h index 4321f044d1e4..bc19e5fb7ea8 100644 --- a/include/linux/mfd/ucb1x00.h +++ b/include/linux/mfd/ucb1x00.h @@ -104,6 +104,9 @@ #define UCB_MODE_DYN_VFLAG_ENA (1 << 12) #define UCB_MODE_AUD_OFF_CAN (1 << 13) +struct ucb1x00_plat_data { + int gpio_base; +}; struct ucb1x00_irq { void *devid; @@ -116,7 +119,7 @@ struct ucb1x00 { unsigned int irq; struct semaphore adc_sem; spinlock_t io_lock; - u16 id; + const struct mcp_device_id *id; u16 io_dir; u16 io_out; u16 adc_cr; diff --git a/include/linux/migrate.h b/include/linux/migrate.h index eaf867412f7a..05ed2828a553 100644 --- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -3,22 +3,10 @@ #include <linux/mm.h> #include <linux/mempolicy.h> +#include <linux/migrate_mode.h> typedef struct page *new_page_t(struct page *, unsigned long private, int **); -/* - * MIGRATE_ASYNC means never block - * MIGRATE_SYNC_LIGHT in the current implementation means to allow blocking - * on most operations but not ->writepage as the potential stall time - * is too significant - * MIGRATE_SYNC will block when migrating pages - */ -enum migrate_mode { - MIGRATE_ASYNC, - MIGRATE_SYNC_LIGHT, - MIGRATE_SYNC, -}; - #ifdef CONFIG_MIGRATION #define PAGE_MIGRATION 1 diff --git a/include/linux/migrate_mode.h b/include/linux/migrate_mode.h new file mode 100644 index 000000000000..ebf3d89a3919 --- /dev/null +++ b/include/linux/migrate_mode.h @@ -0,0 +1,16 @@ +#ifndef MIGRATE_MODE_H_INCLUDED +#define MIGRATE_MODE_H_INCLUDED +/* + * MIGRATE_ASYNC means never block + * MIGRATE_SYNC_LIGHT in the current implementation means to allow blocking + * on most operations but not ->writepage as the potential stall time + * is too significant + * MIGRATE_SYNC will block when migrating pages + */ +enum migrate_mode { + MIGRATE_ASYNC, + MIGRATE_SYNC_LIGHT, + MIGRATE_SYNC, +}; + +#endif /* MIGRATE_MODE_H_INCLUDED */ diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 5c4fe8e5bfe5..aea61905499b 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -621,6 +621,7 @@ void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac); int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac); int mlx4_get_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn); void mlx4_put_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int qpn); +void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap); int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index c8ef9bc54d50..9f22ba572de0 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -71,6 +71,8 @@ struct mmc_ext_csd { bool hpi_en; /* HPI enablebit */ bool hpi; /* HPI support bit */ unsigned int hpi_cmd; /* cmd used as HPI */ + unsigned int boot_ro_lock; /* ro lock support */ + bool boot_ro_lockable; u8 raw_partition_support; /* 160 */ u8 raw_erased_mem_count; /* 181 */ u8 raw_ext_csd_structure; /* 194 */ @@ -110,6 +112,7 @@ struct sd_ssr { struct sd_switch_caps { unsigned int hs_max_dtr; unsigned int uhs_max_dtr; +#define HIGH_SPEED_MAX_DTR 50000000 #define UHS_SDR104_MAX_DTR 208000000 #define UHS_SDR50_MAX_DTR 100000000 #define UHS_DDR50_MAX_DTR 50000000 @@ -117,11 +120,13 @@ struct sd_switch_caps { #define UHS_SDR12_MAX_DTR 25000000 unsigned int sd3_bus_mode; #define UHS_SDR12_BUS_SPEED 0 +#define HIGH_SPEED_BUS_SPEED 1 #define UHS_SDR25_BUS_SPEED 1 #define UHS_SDR50_BUS_SPEED 2 #define UHS_SDR104_BUS_SPEED 3 #define UHS_DDR50_BUS_SPEED 4 +#define SD_MODE_HIGH_SPEED (1 << HIGH_SPEED_BUS_SPEED) #define SD_MODE_UHS_SDR12 (1 << UHS_SDR12_BUS_SPEED) #define SD_MODE_UHS_SDR25 (1 << UHS_SDR25_BUS_SPEED) #define SD_MODE_UHS_SDR50 (1 << UHS_SDR50_BUS_SPEED) @@ -184,6 +189,10 @@ struct mmc_part { unsigned int part_cfg; /* partition type */ char name[MAX_MMC_PART_NAME_LEN]; bool force_ro; /* to make boot parts RO by default */ + unsigned int area_type; +#define MMC_BLK_DATA_AREA_MAIN (1<<0) +#define MMC_BLK_DATA_AREA_BOOT (1<<1) +#define MMC_BLK_DATA_AREA_GP (1<<2) }; /* @@ -206,6 +215,8 @@ struct mmc_card { #define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is in high speed mode */ #define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */ #define MMC_CARD_SDXC (1<<6) /* card is SDXC */ +#define MMC_CARD_REMOVED (1<<7) /* card has been removed */ +#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ unsigned int quirks; /* card quirks */ #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ @@ -261,12 +272,14 @@ struct mmc_card { * This function fill contents in mmc_part. */ static inline void mmc_part_add(struct mmc_card *card, unsigned int size, - unsigned int part_cfg, char *name, int idx, bool ro) + unsigned int part_cfg, char *name, int idx, bool ro, + int area_type) { card->part[card->nr_parts].size = size; card->part[card->nr_parts].part_cfg = part_cfg; sprintf(card->part[card->nr_parts].name, name, idx); card->part[card->nr_parts].force_ro = ro; + card->part[card->nr_parts].area_type = area_type; card->nr_parts++; } @@ -362,18 +375,24 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) #define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED) +#define mmc_card_hs200(c) ((c)->state & MMC_STATE_HIGHSPEED_200) #define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) #define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR) -#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) +#define mmc_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) +#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) +#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED) +#define mmc_card_set_hs200(c) ((c)->state |= MMC_STATE_HIGHSPEED_200) #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR) +#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) +#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) /* * Quirk add/remove for MMC products. diff --git a/include/linux/mmc/cd-gpio.h b/include/linux/mmc/cd-gpio.h new file mode 100644 index 000000000000..a8e469783318 --- /dev/null +++ b/include/linux/mmc/cd-gpio.h @@ -0,0 +1,19 @@ +/* + * Generic GPIO card-detect helper header + * + * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> + * + * 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 MMC_CD_GPIO_H +#define MMC_CD_GPIO_H + +struct mmc_host; +int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio, + unsigned int irq, unsigned long flags); +void mmc_cd_gpio_free(struct mmc_host *host); + +#endif diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 174a844a5dda..87a976cc5654 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -180,6 +180,8 @@ extern int mmc_try_claim_host(struct mmc_host *host); extern int mmc_flush_cache(struct mmc_card *); +extern int mmc_detect_card_removed(struct mmc_host *host); + /** * mmc_claim_host - exclusively claim a host * @host: mmc host to claim diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 6dc9b80568a0..e8779c6d1759 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -214,6 +214,7 @@ struct dw_mci_board { unsigned int bus_hz; /* Bus speed */ unsigned int caps; /* Capabilities */ + unsigned int caps2; /* More capabilities */ /* * Override fifo depth. If 0, autodetect it from the FIFOTH register, * but note that this may not be reliable after a bootloader has used diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index a3ac9c48e5de..0beba1e5e1ed 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -56,10 +56,13 @@ struct mmc_ios { #define MMC_TIMING_UHS_SDR50 3 #define MMC_TIMING_UHS_SDR104 4 #define MMC_TIMING_UHS_DDR50 5 +#define MMC_TIMING_MMC_HS200 6 #define MMC_SDR_MODE 0 #define MMC_1_2V_DDR_MODE 1 #define MMC_1_8V_DDR_MODE 2 +#define MMC_1_2V_SDR_MODE 3 +#define MMC_1_8V_SDR_MODE 4 unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */ @@ -148,7 +151,9 @@ struct mmc_host_ops { void (*init_card)(struct mmc_host *host, struct mmc_card *card); int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios); - int (*execute_tuning)(struct mmc_host *host); + + /* The tuning command opcode value is different for SD and eMMC cards */ + int (*execute_tuning)(struct mmc_host *host, u32 opcode); void (*enable_preset_value)(struct mmc_host *host, bool enable); int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv); void (*hw_reset)(struct mmc_host *host); @@ -167,6 +172,11 @@ struct mmc_async_req { int (*err_check) (struct mmc_card *, struct mmc_async_req *); }; +struct mmc_hotplug { + unsigned int irq; + void *handler_priv; +}; + struct mmc_host { struct device *parent; struct device class_dev; @@ -242,6 +252,11 @@ struct mmc_host { #define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */ #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2) /* Notify poweroff supported */ #define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */ +#define MMC_CAP2_NO_SLEEP_CMD (1 << 4) /* Don't allow sleep command */ +#define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */ +#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ +#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ + MMC_CAP2_HS200_1_2V_SDR) mmc_pm_flag_t pm_caps; /* supported pm features */ unsigned int power_notify_type; @@ -253,10 +268,12 @@ struct mmc_host { int clk_requests; /* internal reference counter */ unsigned int clk_delay; /* number of MCI clk hold cycles */ bool clk_gated; /* clock gated */ - struct work_struct clk_gate_work; /* delayed clock gate */ + struct delayed_work clk_gate_work; /* delayed clock gate */ unsigned int clk_old; /* old clock value cache */ spinlock_t clk_lock; /* lock for clk fields */ struct mutex clk_gate_mutex; /* mutex for clock gating */ + struct device_attribute clkgate_delay_attr; + unsigned long clkgate_delay; #endif /* host specific block data */ @@ -297,6 +314,8 @@ struct mmc_host { int claim_cnt; /* "claim" nesting count */ struct delayed_work detect; + int detect_change; /* card detect flag */ + struct mmc_hotplug hotplug; const struct mmc_bus_ops *bus_ops; /* current bus driver */ unsigned int bus_refs; /* reference counter */ @@ -323,6 +342,8 @@ struct mmc_host { struct fault_attr fail_mmc_request; #endif + unsigned int actual_clock; /* Actual HC clock rate */ + unsigned long private[0] ____cacheline_aligned; }; @@ -396,7 +417,7 @@ static inline void mmc_set_disable_delay(struct mmc_host *host, } /* Module parameter */ -extern int mmc_assume_removable; +extern bool mmc_assume_removable; static inline int mmc_card_is_removable(struct mmc_host *host) { diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 0e7135697d11..fb9f6e116e1c 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -51,6 +51,7 @@ #define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ #define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */ +#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */ /* class 3 */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ @@ -280,6 +281,7 @@ struct _mmc_csd { #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ #define EXT_CSD_SANITIZE_START 165 /* W */ #define EXT_CSD_WR_REL_PARAM 166 /* RO */ +#define EXT_CSD_BOOT_WP 173 /* R/W */ #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_PART_CONFIG 179 /* R/W */ #define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ @@ -321,6 +323,11 @@ struct _mmc_csd { #define EXT_CSD_WR_REL_PARAM_EN (1<<2) +#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) +#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) +#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04) +#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) + #define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) #define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) #define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4) @@ -333,13 +340,76 @@ struct _mmc_csd { #define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ #define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ -#define EXT_CSD_CARD_TYPE_MASK 0xF /* Mask out reserved bits */ +#define EXT_CSD_CARD_TYPE_MASK 0x3F /* Mask out reserved bits */ #define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */ /* DDR mode @1.8V or 3V I/O */ #define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */ /* DDR mode @1.2V I/O */ #define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ | EXT_CSD_CARD_TYPE_DDR_1_2V) +#define EXT_CSD_CARD_TYPE_SDR_1_8V (1<<4) /* Card can run at 200MHz */ +#define EXT_CSD_CARD_TYPE_SDR_1_2V (1<<5) /* Card can run at 200MHz */ + /* SDR mode @1.2V I/O */ + +#define EXT_CSD_CARD_TYPE_SDR_200 (EXT_CSD_CARD_TYPE_SDR_1_8V | \ + EXT_CSD_CARD_TYPE_SDR_1_2V) + +#define EXT_CSD_CARD_TYPE_SDR_ALL (EXT_CSD_CARD_TYPE_SDR_200 | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_1_2V_ALL (EXT_CSD_CARD_TYPE_SDR_1_2V | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_1_8V_ALL (EXT_CSD_CARD_TYPE_SDR_1_8V | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_1_2V | \ + EXT_CSD_CARD_TYPE_DDR_1_8V | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_1_8V | \ + EXT_CSD_CARD_TYPE_DDR_1_8V | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_1_2V | \ + EXT_CSD_CARD_TYPE_DDR_1_2V | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_1_8V | \ + EXT_CSD_CARD_TYPE_DDR_1_2V | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52 (EXT_CSD_CARD_TYPE_SDR_1_2V | \ + EXT_CSD_CARD_TYPE_DDR_52 | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52 (EXT_CSD_CARD_TYPE_SDR_1_8V | \ + EXT_CSD_CARD_TYPE_DDR_52 | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_200 | \ + EXT_CSD_CARD_TYPE_DDR_1_8V | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_200 | \ + EXT_CSD_CARD_TYPE_DDR_1_2V | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) + +#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52 (EXT_CSD_CARD_TYPE_SDR_200 | \ + EXT_CSD_CARD_TYPE_DDR_52 | \ + EXT_CSD_CARD_TYPE_52 | \ + EXT_CSD_CARD_TYPE_26) #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ diff --git a/include/linux/mmc/sdhci-pci-data.h b/include/linux/mmc/sdhci-pci-data.h new file mode 100644 index 000000000000..8959604a13d3 --- /dev/null +++ b/include/linux/mmc/sdhci-pci-data.h @@ -0,0 +1,18 @@ +#ifndef LINUX_MMC_SDHCI_PCI_DATA_H +#define LINUX_MMC_SDHCI_PCI_DATA_H + +struct pci_dev; + +struct sdhci_pci_data { + struct pci_dev *pdev; + int slotno; + int rst_n_gpio; /* Set to -EINVAL if unused */ + int cd_gpio; /* Set to -EINVAL if unused */ + int (*setup)(struct sdhci_pci_data *data); + void (*cleanup)(struct sdhci_pci_data *data); +}; + +extern struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, + int slotno); + +#endif diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index e4b69353678d..c750f85177d9 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -90,8 +90,6 @@ struct sdhci_host { unsigned int quirks2; /* More deviations from spec. */ -#define SDHCI_QUIRK2_OWN_CARD_DETECTION (1<<0) - int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ @@ -121,6 +119,7 @@ struct sdhci_host { #define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ #define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ +#define SDHCI_HS200_NEEDS_TUNING (1<<10) /* HS200 needs tuning */ unsigned int version; /* SDHCI spec. version */ diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index e0b1123497b9..c9fe66c58f8f 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -38,6 +38,7 @@ * [8:0] Byte/block count */ +#define R4_18V_PRESENT (1<<24) #define R4_MEMORY_PRESENT (1 << 27) /* @@ -85,6 +86,7 @@ #define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */ #define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */ #define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */ +#define SDIO_SD_REV_3_00 3 /* SD Physical Spev Version 3.00 */ #define SDIO_CCCR_IOEx 0x02 #define SDIO_CCCR_IORx 0x03 @@ -134,8 +136,31 @@ #define SDIO_CCCR_SPEED 0x13 #define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */ -#define SDIO_SPEED_EHS 0x02 /* Enable High-Speed mode */ - +#define SDIO_SPEED_BSS_SHIFT 1 +#define SDIO_SPEED_BSS_MASK (7<<SDIO_SPEED_BSS_SHIFT) +#define SDIO_SPEED_SDR12 (0<<SDIO_SPEED_BSS_SHIFT) +#define SDIO_SPEED_SDR25 (1<<SDIO_SPEED_BSS_SHIFT) +#define SDIO_SPEED_SDR50 (2<<SDIO_SPEED_BSS_SHIFT) +#define SDIO_SPEED_SDR104 (3<<SDIO_SPEED_BSS_SHIFT) +#define SDIO_SPEED_DDR50 (4<<SDIO_SPEED_BSS_SHIFT) +#define SDIO_SPEED_EHS SDIO_SPEED_SDR25 /* Enable High-Speed */ + +#define SDIO_CCCR_UHS 0x14 +#define SDIO_UHS_SDR50 0x01 +#define SDIO_UHS_SDR104 0x02 +#define SDIO_UHS_DDR50 0x04 + +#define SDIO_CCCR_DRIVE_STRENGTH 0x15 +#define SDIO_SDTx_MASK 0x07 +#define SDIO_DRIVE_SDTA (1<<0) +#define SDIO_DRIVE_SDTC (1<<1) +#define SDIO_DRIVE_SDTD (1<<2) +#define SDIO_DRIVE_DTSx_MASK 0x03 +#define SDIO_DRIVE_DTSx_SHIFT 4 +#define SDIO_DTSx_SET_TYPE_B (0 << SDIO_DRIVE_DTSx_SHIFT) +#define SDIO_DTSx_SET_TYPE_A (1 << SDIO_DRIVE_DTSx_SHIFT) +#define SDIO_DTSx_SET_TYPE_C (2 << SDIO_DRIVE_DTSx_SHIFT) +#define SDIO_DTSx_SET_TYPE_D (3 << SDIO_DRIVE_DTSx_SHIFT) /* * Function Basic Registers (FBR) */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 83ac0713ed0a..b29e7f6f8fa5 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -436,6 +436,17 @@ struct spi_device_id { __attribute__((aligned(sizeof(kernel_ulong_t)))); }; +/* mcp */ + +#define MCP_NAME_SIZE 20 +#define MCP_MODULE_PREFIX "mcp:" + +struct mcp_device_id { + char name[MCP_NAME_SIZE]; + kernel_ulong_t driver_data /* Data private to the driver */ + __attribute__((aligned(sizeof(kernel_ulong_t)))); +}; + /* dmi */ enum dmi_field { DMI_NONE, diff --git a/include/linux/module.h b/include/linux/module.h index 3cb7839a60b9..4598bf03e98b 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -205,6 +205,20 @@ enum module_state MODULE_STATE_GOING, }; +/** + * struct module_ref - per cpu module reference counts + * @incs: number of module get on this cpu + * @decs: number of module put on this cpu + * + * We force an alignment on 8 or 16 bytes, so that alloc_percpu() + * put @incs/@decs in same cache line, with no extra memory cost, + * since alloc_percpu() is fine grained. + */ +struct module_ref { + unsigned long incs; + unsigned long decs; +} __attribute((aligned(2 * sizeof(unsigned long)))); + struct module { enum module_state state; @@ -347,10 +361,7 @@ struct module /* Destruction function. */ void (*exit)(void); - struct module_ref { - unsigned int incs; - unsigned int decs; - } __percpu *refptr; + struct module_ref __percpu *refptr; #endif #ifdef CONFIG_CONSTRUCTORS @@ -434,7 +445,7 @@ extern void __module_put_and_exit(struct module *mod, long code) #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code); #ifdef CONFIG_MODULE_UNLOAD -unsigned int module_refcount(struct module *mod); +unsigned long module_refcount(struct module *mod); void __symbol_put(const char *symbol); #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) void symbol_put_addr(void *addr); diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 7939f636c8ba..c47f4d60db0b 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -350,23 +350,23 @@ extern int param_set_charp(const char *val, const struct kernel_param *kp); extern int param_get_charp(char *buffer, const struct kernel_param *kp); #define param_check_charp(name, p) __param_check(name, p, char *) -/* For historical reasons "bool" parameters can be (unsigned) "int". */ +/* We used to allow int as well as bool. We're taking that away! */ extern struct kernel_param_ops param_ops_bool; extern int param_set_bool(const char *val, const struct kernel_param *kp); extern int param_get_bool(char *buffer, const struct kernel_param *kp); -#define param_check_bool(name, p) \ - static inline void __check_##name(void) \ - { \ - BUILD_BUG_ON(!__same_type((p), bool *) && \ - !__same_type((p), unsigned int *) && \ - !__same_type((p), int *)); \ - } +#define param_check_bool(name, p) __param_check(name, p, bool) extern struct kernel_param_ops param_ops_invbool; extern int param_set_invbool(const char *val, const struct kernel_param *kp); extern int param_get_invbool(char *buffer, const struct kernel_param *kp); #define param_check_invbool(name, p) __param_check(name, p, bool) +/* An int, which can only be set like a bool (though it shows as an int). */ +extern struct kernel_param_ops param_ops_bint; +extern int param_set_bint(const char *val, const struct kernel_param *kp); +#define param_get_bint param_get_int +#define param_check_bint param_check_int + /** * module_param_array - a parameter which is an array of some type * @name: the name of the array variable @@ -395,6 +395,7 @@ extern int param_get_invbool(char *buffer, const struct kernel_param *kp); * module_param_named() for why this might be necessary. */ #define module_param_array_named(name, array, type, nump, perm) \ + param_check_##type(name, &(array)[0]); \ static const struct kparam_array __param_arr_##name \ = { .max = ARRAY_SIZE(array), .num = nump, \ .ops = ¶m_ops_##type, \ diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index a3759cb0ac10..6d8c7251eb8d 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -43,9 +43,11 @@ typedef unsigned short mifi_t; typedef __u32 if_mask; #define NIFBITS (sizeof(if_mask) * 8) /* bits per mask */ -#if !defined(__KERNEL__) && !defined(DIV_ROUND_UP) +#if !defined(__KERNEL__) +#if !defined(DIV_ROUND_UP) #define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y)) #endif +#endif typedef struct if_set { if_mask ifs_bits[DIV_ROUND_UP(IF_SETSIZE, NIFBITS)]; diff --git a/include/linux/mtd/gpmi-nand.h b/include/linux/mtd/gpmi-nand.h new file mode 100644 index 000000000000..69b6dbf46b5e --- /dev/null +++ b/include/linux/mtd/gpmi-nand.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 __MACH_MXS_GPMI_NAND_H__ +#define __MACH_MXS_GPMI_NAND_H__ + +/* The size of the resources is fixed. */ +#define GPMI_NAND_RES_SIZE 6 + +/* Resource names for the GPMI NAND driver. */ +#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "GPMI NAND GPMI Registers" +#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt" +#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "GPMI NAND BCH Registers" +#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "GPMI NAND BCH Interrupt" +#define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels" +#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "GPMI NAND DMA Interrupt" + +/** + * struct gpmi_nand_platform_data - GPMI NAND driver platform data. + * + * This structure communicates platform-specific information to the GPMI NAND + * driver that can't be expressed as resources. + * + * @platform_init: A pointer to a function the driver will call to + * initialize the platform (e.g., set up the pin mux). + * @min_prop_delay_in_ns: Minimum propagation delay of GPMI signals to and + * from the NAND Flash device, in nanoseconds. + * @max_prop_delay_in_ns: Maximum propagation delay of GPMI signals to and + * from the NAND Flash device, in nanoseconds. + * @max_chip_count: The maximum number of chips for which the driver + * should configure the hardware. This value most + * likely reflects the number of pins that are + * connected to a NAND Flash device. If this is + * greater than the SoC hardware can support, the + * driver will print a message and fail to initialize. + * @partitions: An optional pointer to an array of partition + * descriptions. + * @partition_count: The number of elements in the partitions array. + */ +struct gpmi_nand_platform_data { + /* SoC hardware information. */ + int (*platform_init)(void); + + /* NAND Flash information. */ + unsigned int min_prop_delay_in_ns; + unsigned int max_prop_delay_in_ns; + unsigned int max_chip_count; + + /* Medium information. */ + struct mtd_partition *partitions; + unsigned partition_count; +}; +#endif diff --git a/include/linux/nvme.h b/include/linux/nvme.h new file mode 100644 index 000000000000..9490a00529f4 --- /dev/null +++ b/include/linux/nvme.h @@ -0,0 +1,434 @@ +/* + * Definitions for the NVM Express interface + * Copyright (c) 2011, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LINUX_NVME_H +#define _LINUX_NVME_H + +#include <linux/types.h> + +struct nvme_bar { + __u64 cap; /* Controller Capabilities */ + __u32 vs; /* Version */ + __u32 intms; /* Interrupt Mask Set */ + __u32 intmc; /* Interrupt Mask Clear */ + __u32 cc; /* Controller Configuration */ + __u32 rsvd1; /* Reserved */ + __u32 csts; /* Controller Status */ + __u32 rsvd2; /* Reserved */ + __u32 aqa; /* Admin Queue Attributes */ + __u64 asq; /* Admin SQ Base Address */ + __u64 acq; /* Admin CQ Base Address */ +}; + +#define NVME_CAP_TIMEOUT(cap) (((cap) >> 24) & 0xff) +#define NVME_CAP_STRIDE(cap) (((cap) >> 32) & 0xf) + +enum { + NVME_CC_ENABLE = 1 << 0, + NVME_CC_CSS_NVM = 0 << 4, + NVME_CC_MPS_SHIFT = 7, + NVME_CC_ARB_RR = 0 << 11, + NVME_CC_ARB_WRRU = 1 << 11, + NVME_CC_ARB_VS = 7 << 11, + NVME_CC_SHN_NONE = 0 << 14, + NVME_CC_SHN_NORMAL = 1 << 14, + NVME_CC_SHN_ABRUPT = 2 << 14, + NVME_CC_IOSQES = 6 << 16, + NVME_CC_IOCQES = 4 << 20, + NVME_CSTS_RDY = 1 << 0, + NVME_CSTS_CFS = 1 << 1, + NVME_CSTS_SHST_NORMAL = 0 << 2, + NVME_CSTS_SHST_OCCUR = 1 << 2, + NVME_CSTS_SHST_CMPLT = 2 << 2, +}; + +struct nvme_id_power_state { + __le16 max_power; /* centiwatts */ + __u16 rsvd2; + __le32 entry_lat; /* microseconds */ + __le32 exit_lat; /* microseconds */ + __u8 read_tput; + __u8 read_lat; + __u8 write_tput; + __u8 write_lat; + __u8 rsvd16[16]; +}; + +#define NVME_VS(major, minor) (major << 16 | minor) + +struct nvme_id_ctrl { + __le16 vid; + __le16 ssvid; + char sn[20]; + char mn[40]; + char fr[8]; + __u8 rab; + __u8 ieee[3]; + __u8 mic; + __u8 mdts; + __u8 rsvd78[178]; + __le16 oacs; + __u8 acl; + __u8 aerl; + __u8 frmw; + __u8 lpa; + __u8 elpe; + __u8 npss; + __u8 rsvd264[248]; + __u8 sqes; + __u8 cqes; + __u8 rsvd514[2]; + __le32 nn; + __le16 oncs; + __le16 fuses; + __u8 fna; + __u8 vwc; + __le16 awun; + __le16 awupf; + __u8 rsvd530[1518]; + struct nvme_id_power_state psd[32]; + __u8 vs[1024]; +}; + +struct nvme_lbaf { + __le16 ms; + __u8 ds; + __u8 rp; +}; + +struct nvme_id_ns { + __le64 nsze; + __le64 ncap; + __le64 nuse; + __u8 nsfeat; + __u8 nlbaf; + __u8 flbas; + __u8 mc; + __u8 dpc; + __u8 dps; + __u8 rsvd30[98]; + struct nvme_lbaf lbaf[16]; + __u8 rsvd192[192]; + __u8 vs[3712]; +}; + +enum { + NVME_NS_FEAT_THIN = 1 << 0, + NVME_LBAF_RP_BEST = 0, + NVME_LBAF_RP_BETTER = 1, + NVME_LBAF_RP_GOOD = 2, + NVME_LBAF_RP_DEGRADED = 3, +}; + +struct nvme_lba_range_type { + __u8 type; + __u8 attributes; + __u8 rsvd2[14]; + __u64 slba; + __u64 nlb; + __u8 guid[16]; + __u8 rsvd48[16]; +}; + +enum { + NVME_LBART_TYPE_FS = 0x01, + NVME_LBART_TYPE_RAID = 0x02, + NVME_LBART_TYPE_CACHE = 0x03, + NVME_LBART_TYPE_SWAP = 0x04, + + NVME_LBART_ATTRIB_TEMP = 1 << 0, + NVME_LBART_ATTRIB_HIDE = 1 << 1, +}; + +/* I/O commands */ + +enum nvme_opcode { + nvme_cmd_flush = 0x00, + nvme_cmd_write = 0x01, + nvme_cmd_read = 0x02, + nvme_cmd_write_uncor = 0x04, + nvme_cmd_compare = 0x05, + nvme_cmd_dsm = 0x09, +}; + +struct nvme_common_command { + __u8 opcode; + __u8 flags; + __u16 command_id; + __le32 nsid; + __u32 cdw2[2]; + __le64 metadata; + __le64 prp1; + __le64 prp2; + __u32 cdw10[6]; +}; + +struct nvme_rw_command { + __u8 opcode; + __u8 flags; + __u16 command_id; + __le32 nsid; + __u64 rsvd2; + __le64 metadata; + __le64 prp1; + __le64 prp2; + __le64 slba; + __le16 length; + __le16 control; + __le32 dsmgmt; + __le32 reftag; + __le16 apptag; + __le16 appmask; +}; + +enum { + NVME_RW_LR = 1 << 15, + NVME_RW_FUA = 1 << 14, + NVME_RW_DSM_FREQ_UNSPEC = 0, + NVME_RW_DSM_FREQ_TYPICAL = 1, + NVME_RW_DSM_FREQ_RARE = 2, + NVME_RW_DSM_FREQ_READS = 3, + NVME_RW_DSM_FREQ_WRITES = 4, + NVME_RW_DSM_FREQ_RW = 5, + NVME_RW_DSM_FREQ_ONCE = 6, + NVME_RW_DSM_FREQ_PREFETCH = 7, + NVME_RW_DSM_FREQ_TEMP = 8, + NVME_RW_DSM_LATENCY_NONE = 0 << 4, + NVME_RW_DSM_LATENCY_IDLE = 1 << 4, + NVME_RW_DSM_LATENCY_NORM = 2 << 4, + NVME_RW_DSM_LATENCY_LOW = 3 << 4, + NVME_RW_DSM_SEQ_REQ = 1 << 6, + NVME_RW_DSM_COMPRESSED = 1 << 7, +}; + +/* Admin commands */ + +enum nvme_admin_opcode { + nvme_admin_delete_sq = 0x00, + nvme_admin_create_sq = 0x01, + nvme_admin_get_log_page = 0x02, + nvme_admin_delete_cq = 0x04, + nvme_admin_create_cq = 0x05, + nvme_admin_identify = 0x06, + nvme_admin_abort_cmd = 0x08, + nvme_admin_set_features = 0x09, + nvme_admin_get_features = 0x0a, + nvme_admin_async_event = 0x0c, + nvme_admin_activate_fw = 0x10, + nvme_admin_download_fw = 0x11, + nvme_admin_format_nvm = 0x80, + nvme_admin_security_send = 0x81, + nvme_admin_security_recv = 0x82, +}; + +enum { + NVME_QUEUE_PHYS_CONTIG = (1 << 0), + NVME_CQ_IRQ_ENABLED = (1 << 1), + NVME_SQ_PRIO_URGENT = (0 << 1), + NVME_SQ_PRIO_HIGH = (1 << 1), + NVME_SQ_PRIO_MEDIUM = (2 << 1), + NVME_SQ_PRIO_LOW = (3 << 1), + NVME_FEAT_ARBITRATION = 0x01, + NVME_FEAT_POWER_MGMT = 0x02, + NVME_FEAT_LBA_RANGE = 0x03, + NVME_FEAT_TEMP_THRESH = 0x04, + NVME_FEAT_ERR_RECOVERY = 0x05, + NVME_FEAT_VOLATILE_WC = 0x06, + NVME_FEAT_NUM_QUEUES = 0x07, + NVME_FEAT_IRQ_COALESCE = 0x08, + NVME_FEAT_IRQ_CONFIG = 0x09, + NVME_FEAT_WRITE_ATOMIC = 0x0a, + NVME_FEAT_ASYNC_EVENT = 0x0b, + NVME_FEAT_SW_PROGRESS = 0x0c, +}; + +struct nvme_identify { + __u8 opcode; + __u8 flags; + __u16 command_id; + __le32 nsid; + __u64 rsvd2[2]; + __le64 prp1; + __le64 prp2; + __le32 cns; + __u32 rsvd11[5]; +}; + +struct nvme_features { + __u8 opcode; + __u8 flags; + __u16 command_id; + __le32 nsid; + __u64 rsvd2[2]; + __le64 prp1; + __le64 prp2; + __le32 fid; + __le32 dword11; + __u32 rsvd12[4]; +}; + +struct nvme_create_cq { + __u8 opcode; + __u8 flags; + __u16 command_id; + __u32 rsvd1[5]; + __le64 prp1; + __u64 rsvd8; + __le16 cqid; + __le16 qsize; + __le16 cq_flags; + __le16 irq_vector; + __u32 rsvd12[4]; +}; + +struct nvme_create_sq { + __u8 opcode; + __u8 flags; + __u16 command_id; + __u32 rsvd1[5]; + __le64 prp1; + __u64 rsvd8; + __le16 sqid; + __le16 qsize; + __le16 sq_flags; + __le16 cqid; + __u32 rsvd12[4]; +}; + +struct nvme_delete_queue { + __u8 opcode; + __u8 flags; + __u16 command_id; + __u32 rsvd1[9]; + __le16 qid; + __u16 rsvd10; + __u32 rsvd11[5]; +}; + +struct nvme_download_firmware { + __u8 opcode; + __u8 flags; + __u16 command_id; + __u32 rsvd1[5]; + __le64 prp1; + __le64 prp2; + __le32 numd; + __le32 offset; + __u32 rsvd12[4]; +}; + +struct nvme_command { + union { + struct nvme_common_command common; + struct nvme_rw_command rw; + struct nvme_identify identify; + struct nvme_features features; + struct nvme_create_cq create_cq; + struct nvme_create_sq create_sq; + struct nvme_delete_queue delete_queue; + struct nvme_download_firmware dlfw; + }; +}; + +enum { + NVME_SC_SUCCESS = 0x0, + NVME_SC_INVALID_OPCODE = 0x1, + NVME_SC_INVALID_FIELD = 0x2, + NVME_SC_CMDID_CONFLICT = 0x3, + NVME_SC_DATA_XFER_ERROR = 0x4, + NVME_SC_POWER_LOSS = 0x5, + NVME_SC_INTERNAL = 0x6, + NVME_SC_ABORT_REQ = 0x7, + NVME_SC_ABORT_QUEUE = 0x8, + NVME_SC_FUSED_FAIL = 0x9, + NVME_SC_FUSED_MISSING = 0xa, + NVME_SC_INVALID_NS = 0xb, + NVME_SC_LBA_RANGE = 0x80, + NVME_SC_CAP_EXCEEDED = 0x81, + NVME_SC_NS_NOT_READY = 0x82, + NVME_SC_CQ_INVALID = 0x100, + NVME_SC_QID_INVALID = 0x101, + NVME_SC_QUEUE_SIZE = 0x102, + NVME_SC_ABORT_LIMIT = 0x103, + NVME_SC_ABORT_MISSING = 0x104, + NVME_SC_ASYNC_LIMIT = 0x105, + NVME_SC_FIRMWARE_SLOT = 0x106, + NVME_SC_FIRMWARE_IMAGE = 0x107, + NVME_SC_INVALID_VECTOR = 0x108, + NVME_SC_INVALID_LOG_PAGE = 0x109, + NVME_SC_INVALID_FORMAT = 0x10a, + NVME_SC_BAD_ATTRIBUTES = 0x180, + NVME_SC_WRITE_FAULT = 0x280, + NVME_SC_READ_ERROR = 0x281, + NVME_SC_GUARD_CHECK = 0x282, + NVME_SC_APPTAG_CHECK = 0x283, + NVME_SC_REFTAG_CHECK = 0x284, + NVME_SC_COMPARE_FAILED = 0x285, + NVME_SC_ACCESS_DENIED = 0x286, +}; + +struct nvme_completion { + __le32 result; /* Used by admin commands to return data */ + __u32 rsvd; + __le16 sq_head; /* how much of this queue may be reclaimed */ + __le16 sq_id; /* submission queue that generated this entry */ + __u16 command_id; /* of the command which completed */ + __le16 status; /* did the command fail, and if so, why? */ +}; + +struct nvme_user_io { + __u8 opcode; + __u8 flags; + __u16 control; + __u16 nblocks; + __u16 rsvd; + __u64 metadata; + __u64 addr; + __u64 slba; + __u32 dsmgmt; + __u32 reftag; + __u16 apptag; + __u16 appmask; +}; + +struct nvme_admin_cmd { + __u8 opcode; + __u8 flags; + __u16 rsvd1; + __u32 nsid; + __u32 cdw2; + __u32 cdw3; + __u64 metadata; + __u64 addr; + __u32 metadata_len; + __u32 data_len; + __u32 cdw10; + __u32 cdw11; + __u32 cdw12; + __u32 cdw13; + __u32 cdw14; + __u32 cdw15; + __u32 timeout_ms; + __u32 result; +}; + +#define NVME_IOCTL_ID _IO('N', 0x40) +#define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd) +#define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct nvme_user_io) + +#endif /* _LINUX_NVME_H */ diff --git a/include/linux/patchkey.h b/include/linux/patchkey.h index d974a6e92372..aefda0ec6e62 100644 --- a/include/linux/patchkey.h +++ b/include/linux/patchkey.h @@ -32,7 +32,8 @@ # else # error "could not determine byte order" # endif -#elif defined(__BYTE_ORDER) +#else +#if defined(__BYTE_ORDER) # if __BYTE_ORDER == __BIG_ENDIAN # define _PATCHKEY(id) (0xfd00|id) # elif __BYTE_ORDER == __LITTLE_ENDIAN @@ -41,5 +42,6 @@ # error "could not determine byte order" # endif #endif +#endif #endif /* _LINUX_PATCHKEY_H */ diff --git a/include/linux/pmu.h b/include/linux/pmu.h index cafe98d96948..84e6a55a1202 100644 --- a/include/linux/pmu.h +++ b/include/linux/pmu.h @@ -6,6 +6,8 @@ * Copyright (C) 1998 Paul Mackerras. */ +#ifndef _LINUX_PMU_H +#define _LINUX_PMU_H #define PMU_DRIVER_VERSION 2 @@ -207,3 +209,5 @@ extern int pmu_sys_suspended; #endif #endif /* __KERNEL__ */ + +#endif /* _LINUX_PMU_H */ diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 800f113bea66..c2f1f6a5fcb8 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -112,6 +112,7 @@ #include <linux/compiler.h> /* For unlikely. */ #include <linux/sched.h> /* For struct task_struct. */ +#include <linux/err.h> /* for IS_ERR_VALUE */ extern long arch_ptrace(struct task_struct *child, long request, @@ -127,8 +128,9 @@ extern void __ptrace_link(struct task_struct *child, struct task_struct *new_parent); extern void __ptrace_unlink(struct task_struct *child); extern void exit_ptrace(struct task_struct *tracer); -#define PTRACE_MODE_READ 1 -#define PTRACE_MODE_ATTACH 2 +#define PTRACE_MODE_READ 0x01 +#define PTRACE_MODE_ATTACH 0x02 +#define PTRACE_MODE_NOAUDIT 0x04 /* Returns 0 on success, -errno on denial. */ extern int __ptrace_may_access(struct task_struct *task, unsigned int mode); /* Returns true on success, false on denial. */ @@ -265,6 +267,15 @@ static inline void ptrace_release_task(struct task_struct *task) #define force_successful_syscall_return() do { } while (0) #endif +#ifndef is_syscall_success +/* + * On most systems we can tell if a syscall is a success based on if the retval + * is an error value. On some systems like ia64 and powerpc they have different + * indicators of success/failure and must define their own. + */ +#define is_syscall_success(regs) (!IS_ERR_VALUE((unsigned long)(regs_return_value(regs)))) +#endif + /* * <asm/ptrace.h> should define the following things inside #ifdef __KERNEL__. * diff --git a/include/linux/quota.h b/include/linux/quota.h index cb7855699037..c09fa042b5ea 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -230,7 +230,11 @@ struct mem_dqinfo { struct super_block; #define DQF_MASK 0xffff /* Mask for format specific flags */ -#define DQF_INFO_DIRTY_B 16 +#define DQF_GETINFO_MASK 0x1ffff /* Mask for flags passed to userspace */ +#define DQF_SETINFO_MASK 0xffff /* Mask for flags modifiable from userspace */ +#define DQF_SYS_FILE_B 16 +#define DQF_SYS_FILE (1 << DQF_SYS_FILE_B) /* Quota file stored as system file */ +#define DQF_INFO_DIRTY_B 31 #define DQF_INFO_DIRTY (1 << DQF_INFO_DIRTY_B) /* Is info dirty? */ extern void mark_info_dirty(struct super_block *sb, int type); diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h index c9d625ca659e..da81af086eaf 100644 --- a/include/linux/res_counter.h +++ b/include/linux/res_counter.h @@ -109,12 +109,18 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent); * * returns 0 on success and <0 if the counter->usage will exceed the * counter->limit _locked call expects the counter->lock to be taken + * + * charge_nofail works the same, except that it charges the resource + * counter unconditionally, and returns < 0 if the after the current + * charge we are over limit. */ int __must_check res_counter_charge_locked(struct res_counter *counter, unsigned long val); int __must_check res_counter_charge(struct res_counter *counter, unsigned long val, struct res_counter **limit_fail_at); +int __must_check res_counter_charge_nofail(struct res_counter *counter, + unsigned long val, struct res_counter **limit_fail_at); /* * uncharge - tell that some portion of the resource is released @@ -142,7 +148,10 @@ static inline unsigned long long res_counter_margin(struct res_counter *cnt) unsigned long flags; spin_lock_irqsave(&cnt->lock, flags); - margin = cnt->limit - cnt->usage; + if (cnt->limit > cnt->usage) + margin = cnt->limit - cnt->usage; + else + margin = 0; spin_unlock_irqrestore(&cnt->lock, flags); return margin; } diff --git a/include/linux/sched.h b/include/linux/sched.h index 4032ec1cf836..513f52459872 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2088,7 +2088,7 @@ extern int sched_setscheduler_nocheck(struct task_struct *, int, extern struct task_struct *idle_task(int cpu); /** * is_idle_task - is the specified task an idle task? - * @tsk: the task in question. + * @p: the task in question. */ static inline bool is_idle_task(struct task_struct *p) { diff --git a/include/linux/security.h b/include/linux/security.h index 0ccceb9b1046..83c18e8c846d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -54,8 +54,8 @@ struct user_namespace; * These functions are in security/capability.c and are used * as the default capabilities functions */ -extern int cap_capable(struct task_struct *tsk, const struct cred *cred, - struct user_namespace *ns, int cap, int audit); +extern int cap_capable(const struct cred *cred, struct user_namespace *ns, + int cap, int audit); extern int cap_settime(const struct timespec *ts, const struct timezone *tz); extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); extern int cap_ptrace_traceme(struct task_struct *parent); @@ -96,7 +96,6 @@ struct xfrm_user_sec_ctx; struct seq_file; extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); -extern int cap_netlink_recv(struct sk_buff *skb, int cap); void reset_security_ops(void); @@ -799,12 +798,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @skb contains the sk_buff structure for the netlink message. * Return 0 if the information was successfully saved and message * is allowed to be transmitted. - * @netlink_recv: - * Check permission before processing the received netlink message in - * @skb. - * @skb contains the sk_buff structure for the netlink message. - * @cap indicates the capability required - * Return 0 if permission is granted. * * Security hooks for Unix domain networking. * @@ -1268,7 +1261,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @capable: * Check whether the @tsk process has the @cap capability in the indicated * credentials. - * @tsk contains the task_struct for the process. * @cred contains the credentials to use. * @ns contains the user namespace we want the capability in * @cap contains the capability <include/linux/capability.h>. @@ -1392,8 +1384,8 @@ struct security_operations { const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted); - int (*capable) (struct task_struct *tsk, const struct cred *cred, - struct user_namespace *ns, int cap, int audit); + int (*capable) (const struct cred *cred, struct user_namespace *ns, + int cap, int audit); int (*quotactl) (int cmds, int type, int id, struct super_block *sb); int (*quota_on) (struct dentry *dentry); int (*syslog) (int type); @@ -1563,7 +1555,6 @@ struct security_operations { struct sembuf *sops, unsigned nsops, int alter); int (*netlink_send) (struct sock *sk, struct sk_buff *skb); - int (*netlink_recv) (struct sk_buff *skb, int cap); void (*d_instantiate) (struct dentry *dentry, struct inode *inode); @@ -1675,12 +1666,10 @@ int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted); -int security_capable(struct user_namespace *ns, const struct cred *cred, - int cap); -int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, +int security_capable(const struct cred *cred, struct user_namespace *ns, int cap); -int security_real_capable_noaudit(struct task_struct *tsk, - struct user_namespace *ns, int cap); +int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, + int cap); int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); @@ -1817,7 +1806,6 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode); int security_getprocattr(struct task_struct *p, char *name, char **value); int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size); int security_netlink_send(struct sock *sk, struct sk_buff *skb); -int security_netlink_recv(struct sk_buff *skb, int cap); int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); void security_release_secctx(char *secdata, u32 seclen); @@ -1875,32 +1863,15 @@ static inline int security_capset(struct cred *new, return cap_capset(new, old, effective, inheritable, permitted); } -static inline int security_capable(struct user_namespace *ns, - const struct cred *cred, int cap) -{ - return cap_capable(current, cred, ns, cap, SECURITY_CAP_AUDIT); -} - -static inline int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap) +static inline int security_capable(const struct cred *cred, + struct user_namespace *ns, int cap) { - int ret; - - rcu_read_lock(); - ret = cap_capable(tsk, __task_cred(tsk), ns, cap, SECURITY_CAP_AUDIT); - rcu_read_unlock(); - return ret; + return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT); } -static inline -int security_real_capable_noaudit(struct task_struct *tsk, struct user_namespace *ns, int cap) -{ - int ret; - - rcu_read_lock(); - ret = cap_capable(tsk, __task_cred(tsk), ns, cap, - SECURITY_CAP_NOAUDIT); - rcu_read_unlock(); - return ret; +static inline int security_capable_noaudit(const struct cred *cred, + struct user_namespace *ns, int cap) { + return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); } static inline int security_quotactl(int cmds, int type, int id, @@ -2517,11 +2488,6 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb) return cap_netlink_send(sk, skb); } -static inline int security_netlink_recv(struct sk_buff *skb, int cap) -{ - return cap_netlink_recv(skb, cap); -} - static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { return -EOPNOTSUPP; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index b67305e3ad57..c91ace70c21d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -207,6 +207,10 @@ /* Xilinx PSS UART */ #define PORT_XUARTPS 98 +/* Atheros AR933X SoC */ +#define PORT_AR933X 99 + + #ifdef __KERNEL__ #include <linux/compiler.h> diff --git a/include/linux/sh_dma.h b/include/linux/sh_dma.h index cb2dd118cc0f..8cd7fe59cf1a 100644 --- a/include/linux/sh_dma.h +++ b/include/linux/sh_dma.h @@ -30,7 +30,7 @@ struct sh_desc { struct sh_dmae_regs hw; struct list_head node; struct dma_async_tx_descriptor async_tx; - enum dma_data_direction direction; + enum dma_transfer_direction direction; dma_cookie_t cookie; size_t partial; int chunks; @@ -48,6 +48,7 @@ struct sh_dmae_channel { unsigned int offset; unsigned int dmars; unsigned int dmars_bit; + unsigned int chclr_offset; }; struct sh_dmae_pdata { @@ -68,6 +69,7 @@ struct sh_dmae_pdata { unsigned int dmaor_is_32bit:1; unsigned int needs_tend_set:1; unsigned int no_dmars:1; + unsigned int chclr_present:1; }; /* DMA register */ diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index e4c711c6f321..79ab2555b3b0 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -48,6 +48,7 @@ extern struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags); extern int shmem_zero_setup(struct vm_area_struct *); extern int shmem_lock(struct file *file, int lock, struct user_struct *user); +extern void shmem_unlock_mapping(struct address_space *mapping); extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp_mask); extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end); diff --git a/include/linux/sirfsoc_dma.h b/include/linux/sirfsoc_dma.h new file mode 100644 index 000000000000..29d959333d81 --- /dev/null +++ b/include/linux/sirfsoc_dma.h @@ -0,0 +1,6 @@ +#ifndef _SIRFSOC_DMA_H_ +#define _SIRFSOC_DMA_H_ + +bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id); + +#endif diff --git a/include/linux/snmp.h b/include/linux/snmp.h index e16557a357e5..c1241c428179 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -192,7 +192,6 @@ enum LINUX_MIB_TCPPARTIALUNDO, /* TCPPartialUndo */ LINUX_MIB_TCPDSACKUNDO, /* TCPDSACKUndo */ LINUX_MIB_TCPLOSSUNDO, /* TCPLossUndo */ - LINUX_MIB_TCPLOSS, /* TCPLoss */ LINUX_MIB_TCPLOSTRETRANSMIT, /* TCPLostRetransmit */ LINUX_MIB_TCPRENOFAILURES, /* TCPRenoFailures */ LINUX_MIB_TCPSACKFAILURES, /* TCPSackFailures */ diff --git a/include/linux/sound.h b/include/linux/sound.h index 44dcf0570432..fae20ba01fbf 100644 --- a/include/linux/sound.h +++ b/include/linux/sound.h @@ -1,3 +1,5 @@ +#ifndef _LINUX_SOUND_H +#define _LINUX_SOUND_H /* * Minor numbers for the sound driver. @@ -42,3 +44,5 @@ extern void unregister_sound_mixer(int unit); extern void unregister_sound_midi(int unit); extern void unregister_sound_dsp(int unit); #endif /* __KERNEL__ */ + +#endif /* _LINUX_SOUND_H */ diff --git a/include/linux/soundcard.h b/include/linux/soundcard.h index fe204fe39f7c..dfcf86f013a9 100644 --- a/include/linux/soundcard.h +++ b/include/linux/soundcard.h @@ -198,7 +198,8 @@ typedef struct seq_event_rec { # else # error "could not determine byte order" # endif -#elif defined(__BYTE_ORDER) +#else +# if defined(__BYTE_ORDER) # if __BYTE_ORDER == __BIG_ENDIAN # define AFMT_S16_NE AFMT_S16_BE # elif __BYTE_ORDER == __LITTLE_ENDIAN @@ -206,6 +207,7 @@ typedef struct seq_event_rec { # else # error "could not determine byte order" # endif +# endif #endif /* diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 8620f79658d4..dfa900948af7 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -109,7 +109,7 @@ static inline int register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u int svc_reg_xprt_class(struct svc_xprt_class *); void svc_unreg_xprt_class(struct svc_xprt_class *); -void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *, +void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, struct svc_serv *); int svc_create_xprt(struct svc_serv *, const char *, struct net *, const int, const unsigned short, int); @@ -118,7 +118,6 @@ 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); -void svc_delete_xprt(struct svc_xprt *xprt); int svc_port_is_privileged(struct sockaddr *sin); int svc_print_xprts(char *buf, int maxlen); struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 85c50b40759d..c84e9741cb2a 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -34,7 +34,7 @@ struct svc_sock { /* * Function prototypes. */ -void svc_close_all(struct list_head *); +void svc_close_all(struct svc_serv *); int svc_recv(struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 95040cc33107..91784a4f8608 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -357,14 +357,29 @@ extern bool pm_save_wakeup_count(unsigned int count); static inline void lock_system_sleep(void) { - freezer_do_not_count(); + current->flags |= PF_FREEZER_SKIP; mutex_lock(&pm_mutex); } static inline void unlock_system_sleep(void) { + /* + * Don't use freezer_count() because we don't want the call to + * try_to_freeze() here. + * + * Reason: + * Fundamentally, we just don't need it, because freezing condition + * doesn't come into effect until we release the pm_mutex lock, + * since the freezer always works with pm_mutex held. + * + * More importantly, in the case of hibernation, + * unlock_system_sleep() gets called in snapshot_read() and + * snapshot_write() when the freezing condition is still in effect. + * Which means, if we use try_to_freeze() here, it would make them + * enter the refrigerator, thus causing hibernation to lockup. + */ + current->flags &= ~PF_FREEZER_SKIP; mutex_unlock(&pm_mutex); - freezer_count(); } #else /* !CONFIG_PM_SLEEP */ diff --git a/include/linux/swap.h b/include/linux/swap.h index 06061a7f8e69..3e60228e7299 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -273,7 +273,7 @@ static inline int zone_reclaim(struct zone *z, gfp_t mask, unsigned int order) #endif extern int page_evictable(struct page *page, struct vm_area_struct *vma); -extern void scan_mapping_unevictable_pages(struct address_space *); +extern void check_move_unevictable_pages(struct page **, int nr_pages); extern unsigned long scan_unevictable_pages; extern int scan_unevictable_handler(struct ctl_table *, int, diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index ecdaeb98b293..5cf685086dd3 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -312,7 +312,6 @@ struct tty_driver { */ struct tty_struct **ttys; struct ktermios **termios; - struct ktermios **termios_locked; void *driver_state; /* diff --git a/include/linux/usb.h b/include/linux/usb.h index 27a4e16d2bf1..69d845739bc2 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1073,6 +1073,7 @@ typedef void (*usb_complete_t)(struct urb *); * which the host controller driver should use in preference to the * transfer_buffer. * @sg: scatter gather buffer list + * @num_mapped_sgs: (internal) number of mapped sg entries * @num_sgs: number of entries in the sg list * @transfer_buffer_length: How big is transfer_buffer. The transfer may * be broken up into chunks according to the current maximum packet diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 4b752d5ee80e..5e11f8a1f867 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -343,6 +343,8 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ #define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */ #define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ +#define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ +#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ /* 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 */ @@ -401,6 +403,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */ #define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */ #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */ +#define V4L2_PIX_FMT_JL2005BCD v4l2_fourcc('J', 'L', '2', '0') /* compressed RGGB bayer */ #define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */ #define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */ #define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */ @@ -742,6 +745,48 @@ struct v4l2_crop { struct v4l2_rect c; }; +/* Hints for adjustments of selection rectangle */ +#define V4L2_SEL_FLAG_GE 0x00000001 +#define V4L2_SEL_FLAG_LE 0x00000002 + +/* Selection targets */ + +/* current cropping area */ +#define V4L2_SEL_TGT_CROP_ACTIVE 0 +/* default cropping area */ +#define V4L2_SEL_TGT_CROP_DEFAULT 1 +/* cropping bounds */ +#define V4L2_SEL_TGT_CROP_BOUNDS 2 +/* current composing area */ +#define V4L2_SEL_TGT_COMPOSE_ACTIVE 256 +/* default composing area */ +#define V4L2_SEL_TGT_COMPOSE_DEFAULT 257 +/* composing bounds */ +#define V4L2_SEL_TGT_COMPOSE_BOUNDS 258 +/* current composing area plus all padding pixels */ +#define V4L2_SEL_TGT_COMPOSE_PADDED 259 + +/** + * struct v4l2_selection - selection info + * @type: buffer type (do not use *_MPLANE types) + * @target: selection target, used to choose one of possible rectangles + * @flags: constraints flags + * @r: coordinates of selection window + * @reserved: for future use, rounds structure size to 64 bytes, set to zero + * + * Hardware may use multiple helper window to process a video stream. + * The structure is used to exchange this selection areas between + * an application and a driver. + */ +struct v4l2_selection { + __u32 type; + __u32 target; + __u32 flags; + struct v4l2_rect r; + __u32 reserved[9]; +}; + + /* * A N A L O G V I D E O S T A N D A R D */ @@ -1131,6 +1176,7 @@ struct v4l2_querymenu { #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 /* User-class control IDs defined by V4L2 */ +#define V4L2_CID_MAX_CTRLS 1024 #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) #define V4L2_CID_USER_BASE V4L2_CID_BASE /* IDs reserved for driver specific controls */ @@ -1204,10 +1250,10 @@ enum v4l2_colorfx { #define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE (V4L2_CID_BASE+39) #define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT (V4L2_CID_BASE+40) -/* last CID + 1 */ -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+41) +#define V4L2_CID_ALPHA_COMPONENT (V4L2_CID_BASE+41) -/* Minimum number of buffer neede by the device */ +/* last CID + 1 */ +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+42) /* MPEG-class control IDs defined by V4L2 */ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) @@ -1682,6 +1728,8 @@ enum v4l2_flash_strobe_source { #define V4L2_FLASH_FAULT_TIMEOUT (1 << 1) #define V4L2_FLASH_FAULT_OVER_TEMPERATURE (1 << 2) #define V4L2_FLASH_FAULT_SHORT_CIRCUIT (1 << 3) +#define V4L2_FLASH_FAULT_OVER_CURRENT (1 << 4) +#define V4L2_FLASH_FAULT_INDICATOR (1 << 5) #define V4L2_CID_FLASH_CHARGE (V4L2_CID_FLASH_CLASS_BASE + 11) #define V4L2_CID_FLASH_READY (V4L2_CID_FLASH_CLASS_BASE + 12) @@ -2255,6 +2303,10 @@ struct v4l2_create_buffers { #define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) #define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) +/* Experimental selection API */ +#define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection) +#define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection) + /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ diff --git a/include/linux/zorro_ids.h b/include/linux/zorro_ids.h index 7e749088910d..74bc53bcfdcf 100644 --- a/include/linux/zorro_ids.h +++ b/include/linux/zorro_ids.h @@ -360,8 +360,8 @@ #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM ZORRO_ID(VILLAGE_TRONIC, 0x0B, 0) #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG ZORRO_ID(VILLAGE_TRONIC, 0x0C, 0) #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE ZORRO_ID(VILLAGE_TRONIC, 0x0D, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1 ZORRO_ID(VILLAGE_TRONIC, 0x15, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2 ZORRO_ID(VILLAGE_TRONIC, 0x16, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1 ZORRO_ID(VILLAGE_TRONIC, 0x15, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2 ZORRO_ID(VILLAGE_TRONIC, 0x16, 0) #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG ZORRO_ID(VILLAGE_TRONIC, 0x17, 0) #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 ZORRO_ID(VILLAGE_TRONIC, 0x18, 0) #define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE ZORRO_ID(VILLAGE_TRONIC, 0xC9, 0) diff --git a/include/media/as3645a.h b/include/media/as3645a.h new file mode 100644 index 000000000000..5075496d2c9e --- /dev/null +++ b/include/media/as3645a.h @@ -0,0 +1,71 @@ +/* + * include/media/as3645a.h + * + * Copyright (C) 2008-2011 Nokia Corporation + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __AS3645A_H__ +#define __AS3645A_H__ + +#include <media/v4l2-subdev.h> + +#define AS3645A_NAME "as3645a" +#define AS3645A_I2C_ADDR (0x60 >> 1) /* W:0x60, R:0x61 */ + +#define AS3645A_FLASH_TIMEOUT_MIN 100000 /* us */ +#define AS3645A_FLASH_TIMEOUT_MAX 850000 +#define AS3645A_FLASH_TIMEOUT_STEP 50000 + +#define AS3645A_FLASH_INTENSITY_MIN 200 /* mA */ +#define AS3645A_FLASH_INTENSITY_MAX_1LED 500 +#define AS3645A_FLASH_INTENSITY_MAX_2LEDS 400 +#define AS3645A_FLASH_INTENSITY_STEP 20 + +#define AS3645A_TORCH_INTENSITY_MIN 20 /* mA */ +#define AS3645A_TORCH_INTENSITY_MAX 160 +#define AS3645A_TORCH_INTENSITY_STEP 20 + +#define AS3645A_INDICATOR_INTENSITY_MIN 0 /* uA */ +#define AS3645A_INDICATOR_INTENSITY_MAX 10000 +#define AS3645A_INDICATOR_INTENSITY_STEP 2500 + +/* + * as3645a_platform_data - Flash controller platform data + * @set_power: Set power callback + * @vref: VREF offset (0=0V, 1=+0.3V, 2=-0.3V, 3=+0.6V) + * @peak: Inductor peak current limit (0=1.25A, 1=1.5A, 2=1.75A, 3=2.0A) + * @ext_strobe: True if external flash strobe can be used + * @flash_max_current: Max flash current (mA, <= AS3645A_FLASH_INTENSITY_MAX) + * @torch_max_current: Max torch current (mA, >= AS3645A_TORCH_INTENSITY_MAX) + * @timeout_max: Max flash timeout (us, <= AS3645A_FLASH_TIMEOUT_MAX) + */ +struct as3645a_platform_data { + int (*set_power)(struct v4l2_subdev *subdev, int on); + unsigned int vref; + unsigned int peak; + bool ext_strobe; + + /* Flash and torch currents and timeout limits */ + unsigned int flash_max_current; + unsigned int torch_max_current; + unsigned int timeout_max; +}; + +#endif /* __AS3645A_H__ */ diff --git a/include/media/atmel-isi.h b/include/media/atmel-isi.h index 26cece595121..656823075709 100644 --- a/include/media/atmel-isi.h +++ b/include/media/atmel-isi.h @@ -110,10 +110,12 @@ struct isi_platform_data { u8 hsync_act_low; u8 vsync_act_low; u8 pclk_act_falling; - u8 isi_full_mode; + u8 full_mode; u32 data_width_flags; /* Using for ISI_CFG1 */ u32 frate; + /* Using for ISI_MCK */ + u32 mck_hz; }; #endif /* __ATMEL_ISI_H__ */ diff --git a/include/media/cx25840.h b/include/media/cx25840.h index 46d1a141208e..783c5bdd63eb 100644 --- a/include/media/cx25840.h +++ b/include/media/cx25840.h @@ -85,6 +85,7 @@ enum cx25840_video_input { CX25840_NONE1_CH3 = 0x800000c0, CX25840_SVIDEO_ON = 0x80000100, CX25840_COMPONENT_ON = 0x80000200, + CX25840_DIF_ON = 0x80000400, }; enum cx25840_audio_input { diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index 8b11fb037980..8bc1b3c0e679 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -63,6 +63,7 @@ struct vpbe_output { * output basis. If per mode is needed, we may have to move this to * mode_info structure */ + enum v4l2_mbus_pixelcode if_params; }; /* encoder configuration info */ @@ -74,6 +75,15 @@ struct encoder_config_info { struct i2c_board_info board_info; }; +/*amplifier configuration info */ +struct amp_config_info { + char module_name[32]; + /* Is this an i2c device ? */ + unsigned int is_i2c:1; + /* i2c subdevice board info */ + struct i2c_board_info board_info; +}; + /* structure for defining vpbe display subsystem components */ struct vpbe_config { char module_name[32]; @@ -84,6 +94,8 @@ struct vpbe_config { /* external encoder information goes here */ int num_ext_encoders; struct encoder_config_info *ext_encoders; + /* amplifier information goes here */ + struct amp_config_info *amp; int num_outputs; /* Order is venc outputs followed by LCD and then external encoders */ struct vpbe_output *outputs; @@ -158,6 +170,8 @@ struct vpbe_device { struct v4l2_subdev **encoders; /* current encoder index */ int current_sd_index; + /* external amplifier v4l2 subdevice */ + struct v4l2_subdev *amp; struct mutex lock; /* device initialized */ int initialized; @@ -165,6 +179,8 @@ struct vpbe_device { struct clk *dac_clk; /* osd_device pointer */ struct osd_state *osd_device; + /* venc device pointer */ + struct venc_platform_data *venc_device; /* * fields below are accessed by users of vpbe_device. Not the * ones above diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h index 426c205831a2..6b57334f4029 100644 --- a/include/media/davinci/vpbe_venc.h +++ b/include/media/davinci/vpbe_venc.h @@ -29,10 +29,14 @@ struct venc_platform_data { enum vpbe_version venc_type; + int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type, + int field); int (*setup_clock)(enum vpbe_enc_timings_type type, unsigned int mode); + int (*setup_if_config)(enum v4l2_mbus_pixelcode pixcode); /* Number of LCD outputs supported */ int num_lcd_outputs; + struct vpbe_if_params *lcd_if_params; }; enum venc_ioctls { diff --git a/include/media/media-entity.h b/include/media/media-entity.h index cd8bca63a502..29e7bba78ffe 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -98,7 +98,7 @@ struct media_entity { /* Sub-device specifications */ /* Nothing needed yet */ - }; + } info; }; static inline u32 media_entity_type(struct media_entity *entity) diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h index e917b1da6577..042849a34640 100644 --- a/include/media/omap3isp.h +++ b/include/media/omap3isp.h @@ -58,7 +58,7 @@ enum { * ISP_LANE_SHIFT_4 - CAMEXT[13:4] -> CAM[9:0] * ISP_LANE_SHIFT_6 - CAMEXT[13:6] -> CAM[7:0] * @clk_pol: Pixel clock polarity - * 0 - Non Inverted, 1 - Inverted + * 0 - Sample on rising edge, 1 - Sample on falling edge * @hs_pol: Horizontal synchronization polarity * 0 - Active high, 1 - Active low * @vs_pol: Vertical synchronization polarity diff --git a/include/media/pwc-ioctl.h b/include/media/pwc-ioctl.h deleted file mode 100644 index 1ed1e616fe33..000000000000 --- a/include/media/pwc-ioctl.h +++ /dev/null @@ -1,323 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2004 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to <luc@saillard.org>. - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This is pwc-ioctl.h belonging to PWC 10.0.10 - It contains structures and defines to communicate from user space - directly to the driver. - */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - 2003/12/13 Nemosft Unv. Some modifications to make interfacing to - PWCX easier - 2006/01/01 Luc Saillard Add raw format definition - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - -#include <linux/types.h> - -/* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - This value can also be passing using the private flag when using v4l2 and - VIDIOC_S_FMT ioctl. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 -#define PWC_QLT_MASK 0x03000000 -#define PWC_QLT_SHIFT 24 - - -/* structure for transferring x & y coordinates */ -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - - -/* Used with VIDIOCPWCPROBE */ -struct pwc_probe -{ - char name[32]; - int type; -}; - -struct pwc_serial -{ - char serial[30]; /* String with serial number. Contains terminating 0 */ -}; - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute != 0, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - -/* This is used for out-of-kernel decompression. With it, you can get - all the necessary information to initialize and use the decompressor - routines in standalone applications. - */ -struct pwc_video_command -{ - int type; /* camera type (645, 675, 730, etc.) */ - int release; /* release number */ - - int size; /* one of PSZ_* */ - int alternate; - int command_len; /* length of USB video command */ - unsigned char command_buf[13]; /* Actual USB video command */ - int bandlength; /* >0 = compressed */ - int frame_size; /* Size of one (un)compressed frame */ -}; - -/* Flags for PWCX subroutines. Not all modules honour all flags. */ -#define PWCX_FLAG_PLANAR 0x0001 -#define PWCX_FLAG_BAYER 0x0008 - - -/* IOCTL definitions */ - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - -/* Retrieve serial number of camera */ -#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - - /* Get the USB set-video command; needed for initializing libpwcx */ -#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) -struct pwc_table_init_buffer { - int len; - char *buffer; - -}; -#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) - -/* - * This is private command used when communicating with v4l2. - * In the future all private ioctl will be remove/replace to - * use interface offer by v4l2. - */ - -#define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) - -struct pwc_raw_frame { - __le16 type; /* type of the webcam */ - __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */ - __u8 cmd[4]; /* the four byte of the command (in case of nala, - only the first 3 bytes is filled) */ - __u8 rawframe[0]; /* frame_size = H/4*vbandlength */ -} __attribute__ ((packed)); - - -#endif diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 26a3bd0fe57c..f688bde61228 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -18,13 +18,15 @@ #define RC_TYPE_JVC (1 << 3) /* JVC protocol */ #define RC_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */ #define RC_TYPE_RC5_SZ (1 << 5) /* RC5 variant used by Streamzap */ +#define RC_TYPE_SANYO (1 << 6) /* Sanyo protocol */ #define RC_TYPE_MCE_KBD (1 << 29) /* RC6-ish MCE keyboard/mouse */ #define RC_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */ #define RC_TYPE_OTHER (1u << 31) -#define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC | RC_TYPE_RC6 | \ - RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \ - RC_TYPE_RC5_SZ | RC_TYPE_MCE_KBD | RC_TYPE_OTHER) +#define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC | RC_TYPE_RC6 | \ + RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \ + RC_TYPE_RC5_SZ | RC_TYPE_SANYO | RC_TYPE_MCE_KBD | \ + RC_TYPE_OTHER) struct rc_map_table { u32 scancode; @@ -145,7 +147,7 @@ void rc_map_init(void); #define RC_MAP_TREKSTOR "rc-trekstor" #define RC_MAP_TT_1500 "rc-tt-1500" #define RC_MAP_TWINHAN_VP1027_DVBS "rc-twinhan1027" -#define RC_MAP_VIDEOMATE_M1F "rc-videomate-m1f" +#define RC_MAP_VIDEOMATE_K100 "rc-videomate-k100" #define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350" #define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr" #define RC_MAP_WINFAST "rc-winfast" diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 5fb2c3d10c05..b5c2b6cb0d81 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -94,7 +94,7 @@ struct soc_camera_host_ops { struct soc_camera_device *); int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *); int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); - int (*set_bus_param)(struct soc_camera_device *, __u32); + int (*set_bus_param)(struct soc_camera_device *); int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *); int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *); int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *); diff --git a/include/media/tuner.h b/include/media/tuner.h index 89c290b69a5c..29e1920e7339 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -127,7 +127,6 @@ #define TUNER_PHILIPS_FMD1216MEX_MK3 78 #define TUNER_PHILIPS_FM1216MK5 79 #define TUNER_PHILIPS_FQ1216LME_MK3 80 /* Active loopthrough, no FM */ -#define TUNER_XC4000 81 /* Xceive Silicon Tuner */ #define TUNER_PARTSNIC_PTI_5NF05 81 #define TUNER_PHILIPS_CU1216L 82 @@ -136,6 +135,8 @@ #define TUNER_PHILIPS_FQ1236_MK5 85 /* NTSC, TDA9885, no FM radio */ #define TUNER_TENA_TNF_5337 86 +#define TUNER_XC4000 87 /* Xceive Silicon Tuner */ + /* tv card specific */ #define TDA9887_PRESENT (1<<0) #define TDA9887_PORT1_INACTIVE (1<<1) diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 4d1c74ad4c84..3f5d60fc5df6 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -196,6 +196,10 @@ struct v4l2_ioctl_ops { struct v4l2_crop *a); int (*vidioc_s_crop) (struct file *file, void *fh, struct v4l2_crop *a); + int (*vidioc_g_selection) (struct file *file, void *fh, + struct v4l2_selection *s); + int (*vidioc_s_selection) (struct file *file, void *fh, + struct v4l2_selection *s); /* Compression ioctls */ int (*vidioc_g_jpegcomp) (struct file *file, void *fh, struct v4l2_jpegcompression *a); diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index abaad6ed9b83..4a82ca0bb0b2 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -256,4 +256,6 @@ void l2cap_exit(void); int sco_init(void); void sco_exit(void); +void bt_sock_reclassify_lock(struct sock *sk, int proto); + #endif /* __BLUETOOTH_H */ diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5b2fed5eebf2..00596e816b4d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1388,6 +1388,6 @@ struct hci_inquiry_req { }; #define IREQ_CACHE_FLUSH 0x0001 -extern int enable_hs; +extern bool enable_hs; #endif /* __HCI_H */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ea9231f4935f..453893b3120e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -540,7 +540,7 @@ void hci_conn_put_device(struct hci_conn *conn); static inline void hci_conn_hold(struct hci_conn *conn) { atomic_inc(&conn->refcnt); - cancel_delayed_work_sync(&conn->disc_work); + cancel_delayed_work(&conn->disc_work); } static inline void hci_conn_put(struct hci_conn *conn) @@ -559,9 +559,9 @@ static inline void hci_conn_put(struct hci_conn *conn) } else { timeo = msecs_to_jiffies(10); } - cancel_delayed_work_sync(&conn->disc_work); + cancel_delayed_work(&conn->disc_work); queue_delayed_work(conn->hdev->workqueue, - &conn->disc_work, jiffies + timeo); + &conn->disc_work, timeo); } } diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 68f589150692..b1664ed884e6 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -611,7 +611,7 @@ static inline void l2cap_set_timer(struct l2cap_chan *chan, { BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout); - if (!__cancel_delayed_work(work)) + if (!cancel_delayed_work(work)) l2cap_chan_hold(chan); schedule_delayed_work(work, timeout); } @@ -619,20 +619,20 @@ static inline void l2cap_set_timer(struct l2cap_chan *chan, static inline void l2cap_clear_timer(struct l2cap_chan *chan, struct delayed_work *work) { - if (__cancel_delayed_work(work)) + if (cancel_delayed_work(work)) l2cap_chan_put(chan); } #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ - L2CAP_DEFAULT_RETRANS_TO); + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) #define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ - L2CAP_DEFAULT_MONITOR_TO); + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ - L2CAP_DEFAULT_ACK_TO); + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer) static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) @@ -834,7 +834,7 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); -inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); diff --git a/include/net/netns/generic.h b/include/net/netns/generic.h index 3419bf5cd154..d55f43443335 100644 --- a/include/net/netns/generic.h +++ b/include/net/netns/generic.h @@ -41,6 +41,7 @@ static inline void *net_generic(const struct net *net, int id) ptr = ng->ptr[id - 1]; rcu_read_unlock(); + BUG_ON(!ptr); return ptr; } #endif diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h index e503b87c4c1b..7b2d43139c8e 100644 --- a/include/net/netprio_cgroup.h +++ b/include/net/netprio_cgroup.h @@ -13,7 +13,6 @@ #ifndef _NETPRIO_CGROUP_H #define _NETPRIO_CGROUP_H -#include <linux/module.h> #include <linux/cgroup.h> #include <linux/hardirq.h> #include <linux/rcupdate.h> diff --git a/include/net/sock.h b/include/net/sock.h index bb972d254dff..91c1c8baf020 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -55,6 +55,7 @@ #include <linux/uaccess.h> #include <linux/memcontrol.h> #include <linux/res_counter.h> +#include <linux/jump_label.h> #include <linux/filter.h> #include <linux/rculist_nulls.h> @@ -226,6 +227,7 @@ struct cg_proto; * @sk_ack_backlog: current listen backlog * @sk_max_ack_backlog: listen backlog set in listen() * @sk_priority: %SO_PRIORITY setting + * @sk_cgrp_prioidx: socket group's priority map index * @sk_type: socket type (%SOCK_STREAM, etc) * @sk_protocol: which protocol this socket belongs in this network family * @sk_peer_pid: &struct pid for this socket's peer @@ -921,7 +923,7 @@ inline void sk_refcnt_debug_release(const struct sock *sk) #define sk_refcnt_debug_release(sk) do { } while (0) #endif /* SOCK_REFCNT_DEBUG */ -#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +#if defined(CONFIG_CGROUP_MEM_RES_CTLR_KMEM) && defined(CONFIG_NET) extern struct jump_label_key memcg_socket_limit_enabled; static inline struct cg_proto *parent_cg_proto(struct proto *proto, struct cg_proto *cg_proto) @@ -1007,9 +1009,8 @@ static inline void memcg_memory_allocated_add(struct cg_proto *prot, struct res_counter *fail; int ret; - ret = res_counter_charge(prot->memory_allocated, - amt << PAGE_SHIFT, &fail); - + ret = res_counter_charge_nofail(prot->memory_allocated, + amt << PAGE_SHIFT, &fail); if (ret < 0) *parent_status = OVER_LIMIT; } @@ -1053,12 +1054,11 @@ sk_memory_allocated_add(struct sock *sk, int amt, int *parent_status) } static inline void -sk_memory_allocated_sub(struct sock *sk, int amt, int parent_status) +sk_memory_allocated_sub(struct sock *sk, int amt) { struct proto *prot = sk->sk_prot; - if (mem_cgroup_sockets_enabled && sk->sk_cgrp && - parent_status != OVER_LIMIT) /* Otherwise was uncharged already */ + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) memcg_memory_allocated_sub(sk->sk_cgrp, amt); atomic_long_sub(amt, prot->memory_allocated); diff --git a/include/net/tcp.h b/include/net/tcp.h index 0118ea999f67..d49db0113a06 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -311,6 +311,8 @@ extern struct proto tcp_prot; #define TCP_ADD_STATS_USER(net, field, val) SNMP_ADD_STATS_USER((net)->mib.tcp_statistics, field, val) #define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val) +extern void tcp_init_mem(struct net *net); + extern void tcp_v4_err(struct sk_buff *skb, u32); extern void tcp_shutdown (struct sock *sk, int how); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 5d1a758e0595..6a3922fe0be0 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -857,7 +857,7 @@ struct fc_lport { enum fc_lport_state state; unsigned long boot_time; struct fc_host_statistics host_stats; - struct fcoe_dev_stats *dev_stats; + struct fcoe_dev_stats __percpu *dev_stats; u8 retry_count; /* Fabric information */ diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h new file mode 100644 index 000000000000..4866499bdeeb --- /dev/null +++ b/include/target/target_core_backend.h @@ -0,0 +1,65 @@ +#ifndef TARGET_CORE_BACKEND_H +#define TARGET_CORE_BACKEND_H + +#define TRANSPORT_PLUGIN_PHBA_PDEV 1 +#define TRANSPORT_PLUGIN_VHBA_PDEV 2 +#define TRANSPORT_PLUGIN_VHBA_VDEV 3 + +struct se_subsystem_api { + struct list_head sub_api_list; + + char name[16]; + struct module *owner; + + u8 transport_type; + + unsigned int fua_write_emulated : 1; + unsigned int write_cache_emulated : 1; + + int (*attach_hba)(struct se_hba *, u32); + void (*detach_hba)(struct se_hba *); + int (*pmode_enable_hba)(struct se_hba *, unsigned long); + void *(*allocate_virtdevice)(struct se_hba *, const char *); + struct se_device *(*create_virtdevice)(struct se_hba *, + struct se_subsystem_dev *, void *); + void (*free_device)(void *); + int (*transport_complete)(struct se_task *task); + struct se_task *(*alloc_task)(unsigned char *cdb); + int (*do_task)(struct se_task *); + int (*do_discard)(struct se_device *, sector_t, u32); + void (*do_sync_cache)(struct se_task *); + void (*free_task)(struct se_task *); + ssize_t (*check_configfs_dev_params)(struct se_hba *, + struct se_subsystem_dev *); + ssize_t (*set_configfs_dev_params)(struct se_hba *, + struct se_subsystem_dev *, const char *, ssize_t); + ssize_t (*show_configfs_dev_params)(struct se_hba *, + struct se_subsystem_dev *, char *); + u32 (*get_device_rev)(struct se_device *); + u32 (*get_device_type)(struct se_device *); + sector_t (*get_blocks)(struct se_device *); + unsigned char *(*get_sense_buffer)(struct se_task *); +}; + +int transport_subsystem_register(struct se_subsystem_api *); +void transport_subsystem_release(struct se_subsystem_api *); + +struct se_device *transport_add_device_to_core_hba(struct se_hba *, + struct se_subsystem_api *, struct se_subsystem_dev *, u32, + void *, struct se_dev_limits *, const char *, const char *); + +void transport_complete_sync_cache(struct se_cmd *, int); +void transport_complete_task(struct se_task *, int); + +void target_get_task_cdb(struct se_task *, unsigned char *); + +void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); +int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); +int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); +int transport_set_vpd_ident(struct t10_vpd *, unsigned char *); + +/* core helpers also used by command snooping in pscsi */ +void *transport_kmap_first_data_page(struct se_cmd *); +void transport_kunmap_first_data_page(struct se_cmd *); + +#endif /* TARGET_CORE_BACKEND_H */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 6873c7dd9145..daf532bc721a 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -10,6 +10,7 @@ #include <net/tcp.h> #define TARGET_CORE_MOD_VERSION "v4.1.0-rc1-ml" +#define TARGET_CORE_VERSION TARGET_CORE_MOD_VERSION /* Maximum Number of LUNs per Target Portal Group */ /* Don't raise above 511 or REPORT_LUNS needs to handle >1 page */ @@ -34,6 +35,7 @@ #define TRANSPORT_SENSE_BUFFER SCSI_SENSE_BUFFERSIZE /* Used by transport_send_check_condition_and_sense() */ #define SPC_SENSE_KEY_OFFSET 2 +#define SPC_ADD_SENSE_LEN_OFFSET 7 #define SPC_ASC_KEY_OFFSET 12 #define SPC_ASCQ_KEY_OFFSET 13 #define TRANSPORT_IQN_LEN 224 @@ -53,6 +55,72 @@ /* Used by transport_get_inquiry_vpd_device_ident() */ #define INQUIRY_VPD_DEVICE_IDENTIFIER_LEN 254 +/* Attempts before moving from SHORT to LONG */ +#define PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD 3 +#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT 3 /* In milliseconds */ +#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG 10 /* In milliseconds */ + +#define PYX_TRANSPORT_STATUS_INTERVAL 5 /* In seconds */ + +/* + * struct se_subsystem_dev->su_dev_flags +*/ +#define SDF_FIRMWARE_VPD_UNIT_SERIAL 0x00000001 +#define SDF_EMULATED_VPD_UNIT_SERIAL 0x00000002 +#define SDF_USING_UDEV_PATH 0x00000004 +#define SDF_USING_ALIAS 0x00000008 + +/* + * struct se_device->dev_flags + */ +#define DF_READ_ONLY 0x00000001 +#define DF_SPC2_RESERVATIONS 0x00000002 +#define DF_SPC2_RESERVATIONS_WITH_ISID 0x00000004 + +/* struct se_dev_attrib sanity values */ +/* Default max_unmap_lba_count */ +#define DA_MAX_UNMAP_LBA_COUNT 0 +/* Default max_unmap_block_desc_count */ +#define DA_MAX_UNMAP_BLOCK_DESC_COUNT 0 +/* Default unmap_granularity */ +#define DA_UNMAP_GRANULARITY_DEFAULT 0 +/* Default unmap_granularity_alignment */ +#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0 +/* Emulation for Direct Page Out */ +#define DA_EMULATE_DPO 0 +/* Emulation for Forced Unit Access WRITEs */ +#define DA_EMULATE_FUA_WRITE 1 +/* Emulation for Forced Unit Access READs */ +#define DA_EMULATE_FUA_READ 0 +/* Emulation for WriteCache and SYNCHRONIZE_CACHE */ +#define DA_EMULATE_WRITE_CACHE 0 +/* Emulation for UNIT ATTENTION Interlock Control */ +#define DA_EMULATE_UA_INTLLCK_CTRL 0 +/* Emulation for TASK_ABORTED status (TAS) by default */ +#define DA_EMULATE_TAS 1 +/* Emulation for Thin Provisioning UNMAP using block/blk-lib.c:blkdev_issue_discard() */ +#define DA_EMULATE_TPU 0 +/* + * Emulation for Thin Provisioning WRITE_SAME w/ UNMAP=1 bit using + * block/blk-lib.c:blkdev_issue_discard() + */ +#define DA_EMULATE_TPWS 0 +/* No Emulation for PSCSI by default */ +#define DA_EMULATE_RESERVATIONS 0 +/* No Emulation for PSCSI by default */ +#define DA_EMULATE_ALUA 0 +/* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */ +#define DA_ENFORCE_PR_ISIDS 1 +#define DA_STATUS_MAX_SECTORS_MIN 16 +#define DA_STATUS_MAX_SECTORS_MAX 8192 +/* By default don't report non-rotating (solid state) medium */ +#define DA_IS_NONROT 0 +/* Queue Algorithm Modifier default for restricted reordering in control mode page */ +#define DA_EMULATE_REST_REORD 0 + +#define SE_MODE_PAGE_BUF 512 + + /* struct se_hba->hba_flags */ enum hba_flags_table { HBA_FLAGS_INTERNAL_USE = 0x01, @@ -71,11 +139,12 @@ enum transport_tpg_type_table { TRANSPORT_TPG_TYPE_DISCOVERY = 1, }; -/* Used for generate timer flags */ +/* struct se_task->task_flags */ enum se_task_flags { TF_ACTIVE = (1 << 0), TF_SENT = (1 << 1), TF_REQUEST_STOP = (1 << 2), + TF_HAS_SENSE = (1 << 3), }; /* Special transport agnostic struct se_cmd->t_states */ @@ -158,9 +227,38 @@ enum tcm_sense_reason_table { TCM_RESERVATION_CONFLICT = 0x10, }; +enum target_sc_flags_table { + TARGET_SCF_BIDI_OP = 0x01, + TARGET_SCF_ACK_KREF = 0x02, +}; + +/* fabric independent task management function values */ +enum tcm_tmreq_table { + TMR_ABORT_TASK = 1, + TMR_ABORT_TASK_SET = 2, + TMR_CLEAR_ACA = 3, + TMR_CLEAR_TASK_SET = 4, + TMR_LUN_RESET = 5, + TMR_TARGET_WARM_RESET = 6, + TMR_TARGET_COLD_RESET = 7, + TMR_FABRIC_TMR = 255, +}; + +/* fabric independent task management response values */ +enum tcm_tmrsp_table { + TMR_FUNCTION_COMPLETE = 0, + TMR_TASK_DOES_NOT_EXIST = 1, + TMR_LUN_DOES_NOT_EXIST = 2, + TMR_TASK_STILL_ALLEGIANT = 3, + TMR_TASK_FAILOVER_NOT_SUPPORTED = 4, + TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED = 5, + TMR_FUNCTION_AUTHORIZATION_FAILED = 6, + TMR_FUNCTION_REJECTED = 255, +}; + struct se_obj { atomic_t obj_access_count; -} ____cacheline_aligned; +}; /* * Used by TCM Core internally to signal if ALUA emulation is enabled or @@ -207,7 +305,7 @@ struct t10_alua { struct config_group alua_tg_pt_gps_group; int (*alua_state_check)(struct se_cmd *, unsigned char *, u8 *); struct list_head tg_pt_gps_list; -} ____cacheline_aligned; +}; struct t10_alua_lu_gp { u16 lu_gp_id; @@ -218,7 +316,7 @@ struct t10_alua_lu_gp { struct config_group lu_gp_group; struct list_head lu_gp_node; struct list_head lu_gp_mem_list; -} ____cacheline_aligned; +}; struct t10_alua_lu_gp_member { bool lu_gp_assoc; @@ -227,7 +325,7 @@ struct t10_alua_lu_gp_member { struct t10_alua_lu_gp *lu_gp; struct se_device *lu_gp_mem_dev; struct list_head lu_gp_mem_list; -} ____cacheline_aligned; +}; struct t10_alua_tg_pt_gp { u16 tg_pt_gp_id; @@ -250,7 +348,7 @@ struct t10_alua_tg_pt_gp { struct config_group tg_pt_gp_group; struct list_head tg_pt_gp_list; struct list_head tg_pt_gp_mem_list; -} ____cacheline_aligned; +}; struct t10_alua_tg_pt_gp_member { bool tg_pt_gp_assoc; @@ -259,7 +357,7 @@ struct t10_alua_tg_pt_gp_member { struct t10_alua_tg_pt_gp *tg_pt_gp; struct se_port *tg_pt; struct list_head tg_pt_gp_mem_list; -} ____cacheline_aligned; +}; struct t10_vpd { unsigned char device_identifier[INQUIRY_VPD_DEVICE_IDENTIFIER_LEN]; @@ -269,7 +367,7 @@ struct t10_vpd { u32 association; u32 device_identifier_type; struct list_head vpd_list; -} ____cacheline_aligned; +}; struct t10_wwn { char vendor[8]; @@ -280,7 +378,7 @@ struct t10_wwn { struct se_subsystem_dev *t10_sub_dev; struct config_group t10_wwn_group; struct list_head t10_vpd_list; -} ____cacheline_aligned; +}; /* @@ -333,7 +431,7 @@ struct t10_pr_registration { struct list_head pr_reg_aptpl_list; struct list_head pr_reg_atp_list; struct list_head pr_reg_atp_mem_list; -} ____cacheline_aligned; +}; /* * This set of function pointer ops is set based upon SPC3_PERSISTENT_RESERVATIONS, @@ -374,20 +472,20 @@ struct t10_reservation { struct list_head registration_list; struct list_head aptpl_reg_list; struct t10_reservation_ops pr_ops; -} ____cacheline_aligned; +}; struct se_queue_req { int state; struct se_cmd *cmd; struct list_head qr_list; -} ____cacheline_aligned; +}; struct se_queue_obj { atomic_t queue_cnt; spinlock_t cmd_queue_lock; struct list_head qobj_list; wait_queue_head_t thread_wq; -} ____cacheline_aligned; +}; struct se_task { unsigned long long task_lba; @@ -397,16 +495,14 @@ struct se_task { struct scatterlist *task_sg; u32 task_sg_nents; u16 task_flags; - u8 task_sense; u8 task_scsi_status; - int task_error_status; enum dma_data_direction task_data_direction; - atomic_t task_state_active; struct list_head t_list; struct list_head t_execute_list; struct list_head t_state_list; + bool t_state_active; struct completion task_stop_comp; -} ____cacheline_aligned; +}; struct se_cmd { /* SAM response code being sent to initiator */ @@ -451,6 +547,7 @@ struct se_cmd { struct list_head se_queue_node; struct list_head se_cmd_list; struct completion cmd_wait_comp; + struct kref cmd_kref; struct target_core_fabric_ops *se_tfo; int (*execute_task)(struct se_task *); void (*transport_complete_callback)(struct se_cmd *); @@ -492,7 +589,7 @@ struct se_cmd { struct list_head t_task_list; u32 t_task_list_num; -} ____cacheline_aligned; +}; struct se_tmr_req { /* Task Management function to be preformed */ @@ -510,7 +607,7 @@ struct se_tmr_req { struct se_device *tmr_dev; struct se_lun *tmr_lun; struct list_head tmr_list; -} ____cacheline_aligned; +}; struct se_ua { u8 ua_asc; @@ -518,7 +615,7 @@ struct se_ua { struct se_node_acl *ua_nacl; struct list_head ua_dev_list; struct list_head ua_nacl_list; -} ____cacheline_aligned; +}; struct se_node_acl { char initiatorname[TRANSPORT_IQN_LEN]; @@ -545,7 +642,7 @@ struct se_node_acl { struct config_group *acl_default_groups[5]; struct list_head acl_list; struct list_head acl_sess_list; -} ____cacheline_aligned; +}; struct se_session { unsigned sess_tearing_down:1; @@ -558,7 +655,7 @@ struct se_session { struct list_head sess_cmd_list; struct list_head sess_wait_list; spinlock_t sess_cmd_lock; -} ____cacheline_aligned; +}; struct se_device; struct se_transform_info; @@ -578,7 +675,7 @@ struct se_lun_acl { struct list_head lacl_list; struct config_group se_lun_group; struct se_ml_stat_grps ml_stat_grps; -} ____cacheline_aligned; +}; struct se_dev_entry { bool def_pr_registered; @@ -603,7 +700,7 @@ struct se_dev_entry { struct se_lun *se_lun; struct list_head alua_port_list; struct list_head ua_list; -} ____cacheline_aligned; +}; struct se_dev_limits { /* Max supported HW queue depth */ @@ -612,7 +709,7 @@ struct se_dev_limits { u32 queue_depth; /* From include/linux/blkdev.h for the other HW/SW limits. */ struct queue_limits limits; -} ____cacheline_aligned; +}; struct se_dev_attrib { int emulate_dpo; @@ -641,7 +738,7 @@ struct se_dev_attrib { u32 unmap_granularity_alignment; struct se_subsystem_dev *da_sub_dev; struct config_group da_group; -} ____cacheline_aligned; +}; struct se_dev_stat_grps { struct config_group stat_group; @@ -674,7 +771,7 @@ struct se_subsystem_dev { struct config_group se_dev_pr_group; /* For target_core_stat.c groups */ struct se_dev_stat_grps dev_stat_grps; -} ____cacheline_aligned; +}; struct se_device { /* RELATIVE TARGET PORT IDENTIFER Counter */ @@ -685,7 +782,6 @@ struct se_device { u32 dev_port_count; /* See transport_device_status_table */ u32 dev_status; - u32 dev_tcq_window_closed; /* Physical device queue depth */ u32 queue_depth; /* Used for SPC-2 reservations enforce of ISIDs */ @@ -702,7 +798,6 @@ struct se_device { spinlock_t stats_lock; /* Active commands on this virtual SE device */ atomic_t simple_cmds; - atomic_t depth_left; atomic_t dev_ordered_id; atomic_t execute_tasks; atomic_t dev_ordered_sync; @@ -740,7 +835,7 @@ struct se_device { struct se_subsystem_api *transport; /* Linked list for struct se_hba struct se_device list */ struct list_head dev_list; -} ____cacheline_aligned; +}; struct se_hba { u16 hba_tpgt; @@ -759,7 +854,7 @@ struct se_hba { struct config_group hba_group; struct mutex hba_access_mutex; struct se_subsystem_api *transport; -} ____cacheline_aligned; +}; struct se_port_stat_grps { struct config_group stat_group; @@ -785,13 +880,13 @@ struct se_lun { struct se_port *lun_sep; struct config_group lun_group; struct se_port_stat_grps port_stat_grps; -} ____cacheline_aligned; +}; struct scsi_port_stats { u64 cmd_pdus; u64 tx_data_octets; u64 rx_data_octets; -} ____cacheline_aligned; +}; struct se_port { /* RELATIVE TARGET PORT IDENTIFER */ @@ -811,12 +906,12 @@ struct se_port { struct se_portal_group *sep_tpg; struct list_head sep_alua_list; struct list_head sep_list; -} ____cacheline_aligned; +}; struct se_tpg_np { struct se_portal_group *tpg_np_parent; struct config_group tpg_np_group; -} ____cacheline_aligned; +}; struct se_portal_group { /* Type of target portal group, see transport_tpg_type_table */ @@ -849,13 +944,13 @@ struct se_portal_group { struct config_group tpg_acl_group; struct config_group tpg_attrib_group; struct config_group tpg_param_group; -} ____cacheline_aligned; +}; struct se_wwn { struct target_fabric_configfs *wwn_tf; struct config_group wwn_group; struct config_group *wwn_default_groups[2]; struct config_group fabric_stat_group; -} ____cacheline_aligned; +}; #endif /* TARGET_CORE_BASE_H */ diff --git a/include/target/target_core_device.h b/include/target/target_core_device.h deleted file mode 100644 index 2be31ff8763b..000000000000 --- a/include/target/target_core_device.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef TARGET_CORE_DEVICE_H -#define TARGET_CORE_DEVICE_H - -extern int transport_lookup_cmd_lun(struct se_cmd *, u32); -extern int transport_lookup_tmr_lun(struct se_cmd *, u32); -extern struct se_dev_entry *core_get_se_deve_from_rtpi( - struct se_node_acl *, u16); -extern int core_free_device_list_for_node(struct se_node_acl *, - struct se_portal_group *); -extern void core_dec_lacl_count(struct se_node_acl *, struct se_cmd *); -extern void core_update_device_list_access(u32, u32, struct se_node_acl *); -extern int core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *, u32, - u32, struct se_node_acl *, - struct se_portal_group *, int); -extern void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); -extern int core_dev_export(struct se_device *, struct se_portal_group *, - struct se_lun *); -extern void core_dev_unexport(struct se_device *, struct se_portal_group *, - struct se_lun *); -extern int target_report_luns(struct se_task *); -extern void se_release_device_for_hba(struct se_device *); -extern void se_release_vpd_for_dev(struct se_device *); -extern void se_clear_dev_ports(struct se_device *); -extern int se_free_virtual_device(struct se_device *, struct se_hba *); -extern int se_dev_check_online(struct se_device *); -extern int se_dev_check_shutdown(struct se_device *); -extern void se_dev_set_default_attribs(struct se_device *, struct se_dev_limits *); -extern int se_dev_set_task_timeout(struct se_device *, u32); -extern int se_dev_set_max_unmap_lba_count(struct se_device *, u32); -extern int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32); -extern int se_dev_set_unmap_granularity(struct se_device *, u32); -extern int se_dev_set_unmap_granularity_alignment(struct se_device *, u32); -extern int se_dev_set_emulate_dpo(struct se_device *, int); -extern int se_dev_set_emulate_fua_write(struct se_device *, int); -extern int se_dev_set_emulate_fua_read(struct se_device *, int); -extern int se_dev_set_emulate_write_cache(struct se_device *, int); -extern int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int); -extern int se_dev_set_emulate_tas(struct se_device *, int); -extern int se_dev_set_emulate_tpu(struct se_device *, int); -extern int se_dev_set_emulate_tpws(struct se_device *, int); -extern int se_dev_set_enforce_pr_isids(struct se_device *, int); -extern int se_dev_set_is_nonrot(struct se_device *, int); -extern int se_dev_set_emulate_rest_reord(struct se_device *dev, int); -extern int se_dev_set_queue_depth(struct se_device *, u32); -extern int se_dev_set_max_sectors(struct se_device *, u32); -extern int se_dev_set_optimal_sectors(struct se_device *, u32); -extern int se_dev_set_block_size(struct se_device *, u32); -extern struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *, - struct se_device *, u32); -extern int core_dev_del_lun(struct se_portal_group *, u32); -extern struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); -extern struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, - u32, char *, int *); -extern int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, - struct se_lun_acl *, u32, u32); -extern int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, - struct se_lun *, struct se_lun_acl *); -extern void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, - struct se_lun_acl *lacl); -extern int core_dev_setup_virtual_lun0(void); -extern void core_dev_release_virtual_lun0(void); - -#endif /* TARGET_CORE_DEVICE_H */ diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric.h index 0256825f923d..523e8bc104d4 100644 --- a/include/target/target_core_fabric_ops.h +++ b/include/target/target_core_fabric.h @@ -1,5 +1,5 @@ -/* Defined in target_core_configfs.h */ -struct target_fabric_configfs; +#ifndef TARGET_CORE_FABRIC_H +#define TARGET_CORE_FABRIC_H struct target_core_fabric_ops { struct configfs_subsystem *tf_subsys; @@ -52,10 +52,6 @@ struct target_core_fabric_ops { * Returning 0 will signal a descriptor has not been released. */ int (*check_stop_free)(struct se_cmd *); - /* - * Optional check for active I/O shutdown - */ - int (*check_release_cmd)(struct se_cmd *); void (*release_cmd)(struct se_cmd *); /* * Called with spin_lock_bh(struct se_portal_group->session_lock held. @@ -103,3 +99,89 @@ struct target_core_fabric_ops { struct config_group *, const char *); void (*fabric_drop_nodeacl)(struct se_node_acl *); }; + +struct se_session *transport_init_session(void); +void __transport_register_session(struct se_portal_group *, + struct se_node_acl *, struct se_session *, void *); +void transport_register_session(struct se_portal_group *, + struct se_node_acl *, struct se_session *, void *); +void transport_free_session(struct se_session *); +void transport_deregister_session_configfs(struct se_session *); +void transport_deregister_session(struct se_session *); + + +void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, + struct se_session *, u32, int, int, unsigned char *); +int transport_lookup_cmd_lun(struct se_cmd *, u32); +int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *); +int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, + unsigned char *, u32, u32, int, int, int); +int transport_handle_cdb_direct(struct se_cmd *); +int transport_generic_handle_cdb_map(struct se_cmd *); +int transport_generic_handle_data(struct se_cmd *); +int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, + struct scatterlist *, u32, struct scatterlist *, u32); +void transport_do_task_sg_chain(struct se_cmd *); +int transport_generic_new_cmd(struct se_cmd *); + +void transport_generic_process_write(struct se_cmd *); + +void transport_generic_free_cmd(struct se_cmd *, int); + +bool transport_wait_for_tasks(struct se_cmd *); +int transport_check_aborted_status(struct se_cmd *, int); +int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); + +void target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); +int target_put_sess_cmd(struct se_session *, struct se_cmd *); +void target_splice_sess_cmd_list(struct se_session *); +void target_wait_for_sess_cmds(struct se_session *, int); + +int core_alua_check_nonop_delay(struct se_cmd *); + +struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t); +void core_tmr_release_req(struct se_tmr_req *); +int transport_generic_handle_tmr(struct se_cmd *); +int transport_lookup_tmr_lun(struct se_cmd *, u32); + +struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *, + unsigned char *); +void core_tpg_clear_object_luns(struct se_portal_group *); +struct se_node_acl *core_tpg_add_initiator_node_acl(struct se_portal_group *, + struct se_node_acl *, const char *, u32); +int core_tpg_del_initiator_node_acl(struct se_portal_group *, + struct se_node_acl *, int); +int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, + unsigned char *, u32, int); +int core_tpg_register(struct target_core_fabric_ops *, struct se_wwn *, + struct se_portal_group *, void *, int); +int core_tpg_deregister(struct se_portal_group *); + +/* SAS helpers */ +u8 sas_get_fabric_proto_ident(struct se_portal_group *); +u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *, unsigned char *); +u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *); +char *sas_parse_pr_out_transport_id(struct se_portal_group *, const char *, + u32 *, char **); + +/* FC helpers */ +u8 fc_get_fabric_proto_ident(struct se_portal_group *); +u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *, unsigned char *); +u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *); +char *fc_parse_pr_out_transport_id(struct se_portal_group *, const char *, + u32 *, char **); + +/* iSCSI helpers */ +u8 iscsi_get_fabric_proto_ident(struct se_portal_group *); +u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *, unsigned char *); +u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, + struct t10_pr_registration *, int *); +char *iscsi_parse_pr_out_transport_id(struct se_portal_group *, const char *, + u32 *, char **); + +#endif /* TARGET_CORE_FABRICH */ diff --git a/include/target/target_core_fabric_lib.h b/include/target/target_core_fabric_lib.h deleted file mode 100644 index c2f8d0e3a03b..000000000000 --- a/include/target/target_core_fabric_lib.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef TARGET_CORE_FABRIC_LIB_H -#define TARGET_CORE_FABRIC_LIB_H - -extern u8 sas_get_fabric_proto_ident(struct se_portal_group *); -extern u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -extern u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -extern char *sas_parse_pr_out_transport_id(struct se_portal_group *, - const char *, u32 *, char **); - -extern u8 fc_get_fabric_proto_ident(struct se_portal_group *); -extern u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -extern u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -extern char *fc_parse_pr_out_transport_id(struct se_portal_group *, - const char *, u32 *, char **); - -extern u8 iscsi_get_fabric_proto_ident(struct se_portal_group *); -extern u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -extern u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -extern char *iscsi_parse_pr_out_transport_id(struct se_portal_group *, - const char *, u32 *, char **); - -#endif /* TARGET_CORE_FABRIC_LIB_H */ diff --git a/include/target/target_core_tmr.h b/include/target/target_core_tmr.h deleted file mode 100644 index d5876e17d3fb..000000000000 --- a/include/target/target_core_tmr.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TARGET_CORE_TMR_H -#define TARGET_CORE_TMR_H - -/* fabric independent task management function values */ -enum tcm_tmreq_table { - TMR_ABORT_TASK = 1, - TMR_ABORT_TASK_SET = 2, - TMR_CLEAR_ACA = 3, - TMR_CLEAR_TASK_SET = 4, - TMR_LUN_RESET = 5, - TMR_TARGET_WARM_RESET = 6, - TMR_TARGET_COLD_RESET = 7, - TMR_FABRIC_TMR = 255, -}; - -/* fabric independent task management response values */ -enum tcm_tmrsp_table { - TMR_FUNCTION_COMPLETE = 0, - TMR_TASK_DOES_NOT_EXIST = 1, - TMR_LUN_DOES_NOT_EXIST = 2, - TMR_TASK_STILL_ALLEGIANT = 3, - TMR_TASK_FAILOVER_NOT_SUPPORTED = 4, - TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED = 5, - TMR_FUNCTION_AUTHORIZATION_FAILED = 6, - TMR_FUNCTION_REJECTED = 255, -}; - -extern struct kmem_cache *se_tmr_req_cache; - -extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t); -extern void core_tmr_release_req(struct se_tmr_req *); -extern int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *, - struct list_head *, struct se_cmd *); - -#endif /* TARGET_CORE_TMR_H */ diff --git a/include/target/target_core_tpg.h b/include/target/target_core_tpg.h deleted file mode 100644 index 77e18729c4c1..000000000000 --- a/include/target/target_core_tpg.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TARGET_CORE_TPG_H -#define TARGET_CORE_TPG_H - -extern struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, - const char *); -extern struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, - unsigned char *); -extern void core_tpg_add_node_to_devs(struct se_node_acl *, - struct se_portal_group *); -extern struct se_node_acl *core_tpg_check_initiator_node_acl( - struct se_portal_group *, - unsigned char *); -extern void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *); -extern void core_tpg_wait_for_mib_ref(struct se_node_acl *); -extern void core_tpg_clear_object_luns(struct se_portal_group *); -extern struct se_node_acl *core_tpg_add_initiator_node_acl( - struct se_portal_group *, - struct se_node_acl *, - const char *, u32); -extern int core_tpg_del_initiator_node_acl(struct se_portal_group *, - struct se_node_acl *, int); -extern int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, - unsigned char *, u32, int); -extern int core_tpg_register(struct target_core_fabric_ops *, - struct se_wwn *, - struct se_portal_group *, void *, - int); -extern int core_tpg_deregister(struct se_portal_group *); -extern struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32); -extern int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, u32, - void *); -extern struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32, int *); -extern int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *); - -#endif /* TARGET_CORE_TPG_H */ diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h deleted file mode 100644 index dac4f2d859fd..000000000000 --- a/include/target/target_core_transport.h +++ /dev/null @@ -1,287 +0,0 @@ -#ifndef TARGET_CORE_TRANSPORT_H -#define TARGET_CORE_TRANSPORT_H - -#define TARGET_CORE_VERSION TARGET_CORE_MOD_VERSION - -/* Attempts before moving from SHORT to LONG */ -#define PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD 3 -#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT 3 /* In milliseconds */ -#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG 10 /* In milliseconds */ - -#define PYX_TRANSPORT_STATUS_INTERVAL 5 /* In seconds */ - -#define TRANSPORT_PLUGIN_PHBA_PDEV 1 -#define TRANSPORT_PLUGIN_VHBA_PDEV 2 -#define TRANSPORT_PLUGIN_VHBA_VDEV 3 - -/* - * struct se_subsystem_dev->su_dev_flags -*/ -#define SDF_FIRMWARE_VPD_UNIT_SERIAL 0x00000001 -#define SDF_EMULATED_VPD_UNIT_SERIAL 0x00000002 -#define SDF_USING_UDEV_PATH 0x00000004 -#define SDF_USING_ALIAS 0x00000008 - -/* - * struct se_device->dev_flags - */ -#define DF_READ_ONLY 0x00000001 -#define DF_SPC2_RESERVATIONS 0x00000002 -#define DF_SPC2_RESERVATIONS_WITH_ISID 0x00000004 - -/* struct se_dev_attrib sanity values */ -/* Default max_unmap_lba_count */ -#define DA_MAX_UNMAP_LBA_COUNT 0 -/* Default max_unmap_block_desc_count */ -#define DA_MAX_UNMAP_BLOCK_DESC_COUNT 0 -/* Default unmap_granularity */ -#define DA_UNMAP_GRANULARITY_DEFAULT 0 -/* Default unmap_granularity_alignment */ -#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0 -/* Emulation for Direct Page Out */ -#define DA_EMULATE_DPO 0 -/* Emulation for Forced Unit Access WRITEs */ -#define DA_EMULATE_FUA_WRITE 1 -/* Emulation for Forced Unit Access READs */ -#define DA_EMULATE_FUA_READ 0 -/* Emulation for WriteCache and SYNCHRONIZE_CACHE */ -#define DA_EMULATE_WRITE_CACHE 0 -/* Emulation for UNIT ATTENTION Interlock Control */ -#define DA_EMULATE_UA_INTLLCK_CTRL 0 -/* Emulation for TASK_ABORTED status (TAS) by default */ -#define DA_EMULATE_TAS 1 -/* Emulation for Thin Provisioning UNMAP using block/blk-lib.c:blkdev_issue_discard() */ -#define DA_EMULATE_TPU 0 -/* - * Emulation for Thin Provisioning WRITE_SAME w/ UNMAP=1 bit using - * block/blk-lib.c:blkdev_issue_discard() - */ -#define DA_EMULATE_TPWS 0 -/* No Emulation for PSCSI by default */ -#define DA_EMULATE_RESERVATIONS 0 -/* No Emulation for PSCSI by default */ -#define DA_EMULATE_ALUA 0 -/* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */ -#define DA_ENFORCE_PR_ISIDS 1 -#define DA_STATUS_MAX_SECTORS_MIN 16 -#define DA_STATUS_MAX_SECTORS_MAX 8192 -/* By default don't report non-rotating (solid state) medium */ -#define DA_IS_NONROT 0 -/* Queue Algorithm Modifier default for restricted reordering in control mode page */ -#define DA_EMULATE_REST_REORD 0 - -#define SE_MODE_PAGE_BUF 512 - -#define MOD_MAX_SECTORS(ms, bs) (ms % (PAGE_SIZE / bs)) - -struct se_subsystem_api; - -extern int init_se_kmem_caches(void); -extern void release_se_kmem_caches(void); -extern u32 scsi_get_new_index(scsi_index_t); -extern void transport_init_queue_obj(struct se_queue_obj *); -extern void transport_subsystem_check_init(void); -extern int transport_subsystem_register(struct se_subsystem_api *); -extern void transport_subsystem_release(struct se_subsystem_api *); -extern void transport_load_plugins(void); -extern struct se_session *transport_init_session(void); -extern void __transport_register_session(struct se_portal_group *, - struct se_node_acl *, - struct se_session *, void *); -extern void transport_register_session(struct se_portal_group *, - struct se_node_acl *, - struct se_session *, void *); -extern void transport_free_session(struct se_session *); -extern void transport_deregister_session_configfs(struct se_session *); -extern void transport_deregister_session(struct se_session *); -extern void transport_cmd_finish_abort(struct se_cmd *, int); -extern void transport_complete_sync_cache(struct se_cmd *, int); -extern void transport_complete_task(struct se_task *, int); -extern void transport_add_task_to_execute_queue(struct se_task *, - struct se_task *, - struct se_device *); -extern void transport_remove_task_from_execute_queue(struct se_task *, - struct se_device *); -extern void __transport_remove_task_from_execute_queue(struct se_task *, - struct se_device *); -unsigned char *transport_dump_cmd_direction(struct se_cmd *); -extern void transport_dump_dev_state(struct se_device *, char *, int *); -extern void transport_dump_dev_info(struct se_device *, struct se_lun *, - unsigned long long, char *, int *); -extern void transport_dump_vpd_proto_id(struct t10_vpd *, - unsigned char *, int); -extern void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); -extern int transport_dump_vpd_assoc(struct t10_vpd *, - unsigned char *, int); -extern int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); -extern int transport_dump_vpd_ident_type(struct t10_vpd *, - unsigned char *, int); -extern int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); -extern int transport_dump_vpd_ident(struct t10_vpd *, - unsigned char *, int); -extern int transport_set_vpd_ident(struct t10_vpd *, unsigned char *); -extern struct se_device *transport_add_device_to_core_hba(struct se_hba *, - struct se_subsystem_api *, - struct se_subsystem_dev *, u32, - void *, struct se_dev_limits *, - const char *, const char *); -extern void transport_init_se_cmd(struct se_cmd *, - struct target_core_fabric_ops *, - struct se_session *, u32, int, int, - unsigned char *); -void *transport_kmap_first_data_page(struct se_cmd *cmd); -void transport_kunmap_first_data_page(struct se_cmd *cmd); -extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *); -extern int transport_handle_cdb_direct(struct se_cmd *); -extern int transport_generic_handle_cdb_map(struct se_cmd *); -extern int transport_generic_handle_data(struct se_cmd *); -extern int transport_generic_handle_tmr(struct se_cmd *); -extern bool target_stop_task(struct se_task *task, unsigned long *flags); -extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32, - struct scatterlist *, u32); -extern int transport_clear_lun_from_sessions(struct se_lun *); -extern bool transport_wait_for_tasks(struct se_cmd *); -extern int transport_check_aborted_status(struct se_cmd *, int); -extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int); -extern void transport_send_task_abort(struct se_cmd *); -extern void transport_release_cmd(struct se_cmd *); -extern void transport_generic_free_cmd(struct se_cmd *, int); -extern void target_get_sess_cmd(struct se_session *, struct se_cmd *); -extern int target_put_sess_cmd(struct se_session *, struct se_cmd *); -extern void target_splice_sess_cmd_list(struct se_session *); -extern void target_wait_for_sess_cmds(struct se_session *, int); -extern void transport_generic_wait_for_cmds(struct se_cmd *, int); -extern void transport_do_task_sg_chain(struct se_cmd *); -extern void transport_generic_process_write(struct se_cmd *); -extern int transport_generic_new_cmd(struct se_cmd *); -extern int transport_generic_do_tmr(struct se_cmd *); -/* From target_core_alua.c */ -extern int core_alua_check_nonop_delay(struct se_cmd *); -/* From target_core_cdb.c */ -extern int transport_emulate_control_cdb(struct se_task *); -extern void target_get_task_cdb(struct se_task *task, unsigned char *cdb); - -/* - * Each se_transport_task_t can have N number of possible struct se_task's - * for the storage transport(s) to possibly execute. - * Used primarily for splitting up CDBs that exceed the physical storage - * HBA's maximum sector count per task. - */ -struct se_mem { - struct page *se_page; - u32 se_len; - u32 se_off; - struct list_head se_list; -} ____cacheline_aligned; - -/* - * Each type of disk transport supported MUST have a template defined - * within its .h file. - */ -struct se_subsystem_api { - /* - * The Name. :-) - */ - char name[16]; - /* - * Transport Type. - */ - u8 transport_type; - - unsigned int fua_write_emulated : 1; - unsigned int write_cache_emulated : 1; - - /* - * struct module for struct se_hba references - */ - struct module *owner; - /* - * Used for global se_subsystem_api list_head - */ - struct list_head sub_api_list; - /* - * attach_hba(): - */ - int (*attach_hba)(struct se_hba *, u32); - /* - * detach_hba(): - */ - void (*detach_hba)(struct se_hba *); - /* - * pmode_hba(): Used for TCM/pSCSI subsystem plugin HBA -> - * Linux/SCSI struct Scsi_Host passthrough - */ - int (*pmode_enable_hba)(struct se_hba *, unsigned long); - /* - * allocate_virtdevice(): - */ - void *(*allocate_virtdevice)(struct se_hba *, const char *); - /* - * create_virtdevice(): Only for Virtual HBAs - */ - struct se_device *(*create_virtdevice)(struct se_hba *, - struct se_subsystem_dev *, void *); - /* - * free_device(): - */ - void (*free_device)(void *); - - /* - * transport_complete(): - * - * Use transport_generic_complete() for majority of DAS transport - * drivers. Provided out of convenience. - */ - int (*transport_complete)(struct se_task *task); - struct se_task *(*alloc_task)(unsigned char *cdb); - /* - * do_task(): - */ - int (*do_task)(struct se_task *); - /* - * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate - * UNMAP and WRITE_SAME_* w/ UNMAP=1 <-> Linux/Block Discard - */ - int (*do_discard)(struct se_device *, sector_t, u32); - /* - * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate - * SYNCHRONIZE_CACHE_* <-> Linux/Block blkdev_issue_flush() - */ - void (*do_sync_cache)(struct se_task *); - /* - * free_task(): - */ - void (*free_task)(struct se_task *); - /* - * check_configfs_dev_params(): - */ - ssize_t (*check_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *); - /* - * set_configfs_dev_params(): - */ - ssize_t (*set_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *, - const char *, ssize_t); - /* - * show_configfs_dev_params(): - */ - ssize_t (*show_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *, - char *); - /* - * get_device_rev(): - */ - u32 (*get_device_rev)(struct se_device *); - /* - * get_device_type(): - */ - u32 (*get_device_type)(struct se_device *); - /* - * Get the sector_t from a subsystem backstore.. - */ - sector_t (*get_blocks)(struct se_device *); - /* - * get_sense_buffer(): - */ - unsigned char *(*get_sense_buffer)(struct se_task *); -} ____cacheline_aligned; - -#endif /* TARGET_CORE_TRANSPORT_H */ diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index b31702ac15be..84f3001a568d 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -16,6 +16,8 @@ struct btrfs_delayed_ref_node; struct btrfs_delayed_tree_ref; struct btrfs_delayed_data_ref; struct btrfs_delayed_ref_head; +struct btrfs_block_group_cache; +struct btrfs_free_cluster; struct map_lookup; struct extent_buffer; @@ -44,6 +46,17 @@ struct extent_buffer; obj, ((obj >= BTRFS_DATA_RELOC_TREE_OBJECTID) || \ (obj <= BTRFS_CSUM_TREE_OBJECTID )) ? __show_root_type(obj) : "-" +#define BTRFS_GROUP_FLAGS \ + { BTRFS_BLOCK_GROUP_DATA, "DATA"}, \ + { BTRFS_BLOCK_GROUP_SYSTEM, "SYSTEM"}, \ + { BTRFS_BLOCK_GROUP_METADATA, "METADATA"}, \ + { BTRFS_BLOCK_GROUP_RAID0, "RAID0"}, \ + { BTRFS_BLOCK_GROUP_RAID1, "RAID1"}, \ + { BTRFS_BLOCK_GROUP_DUP, "DUP"}, \ + { BTRFS_BLOCK_GROUP_RAID10, "RAID10"} + +#define BTRFS_UUID_SIZE 16 + TRACE_EVENT(btrfs_transaction_commit, TP_PROTO(struct btrfs_root *root), @@ -621,6 +634,34 @@ TRACE_EVENT(btrfs_cow_block, __entry->cow_level) ); +TRACE_EVENT(btrfs_space_reservation, + + TP_PROTO(struct btrfs_fs_info *fs_info, char *type, u64 val, + u64 bytes, int reserve), + + TP_ARGS(fs_info, type, val, bytes, reserve), + + TP_STRUCT__entry( + __array( u8, fsid, BTRFS_UUID_SIZE ) + __string( type, type ) + __field( u64, val ) + __field( u64, bytes ) + __field( int, reserve ) + ), + + TP_fast_assign( + memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE); + __assign_str(type, type); + __entry->val = val; + __entry->bytes = bytes; + __entry->reserve = reserve; + ), + + TP_printk("%pU: %s: %Lu %s %Lu", __entry->fsid, __get_str(type), + __entry->val, __entry->reserve ? "reserve" : "release", + __entry->bytes) +); + DECLARE_EVENT_CLASS(btrfs__reserved_extent, TP_PROTO(struct btrfs_root *root, u64 start, u64 len), @@ -659,6 +700,168 @@ DEFINE_EVENT(btrfs__reserved_extent, btrfs_reserved_extent_free, TP_ARGS(root, start, len) ); +TRACE_EVENT(find_free_extent, + + TP_PROTO(struct btrfs_root *root, u64 num_bytes, u64 empty_size, + u64 data), + + TP_ARGS(root, num_bytes, empty_size, data), + + TP_STRUCT__entry( + __field( u64, root_objectid ) + __field( u64, num_bytes ) + __field( u64, empty_size ) + __field( u64, data ) + ), + + TP_fast_assign( + __entry->root_objectid = root->root_key.objectid; + __entry->num_bytes = num_bytes; + __entry->empty_size = empty_size; + __entry->data = data; + ), + + TP_printk("root = %Lu(%s), len = %Lu, empty_size = %Lu, " + "flags = %Lu(%s)", show_root_type(__entry->root_objectid), + __entry->num_bytes, __entry->empty_size, __entry->data, + __print_flags((unsigned long)__entry->data, "|", + BTRFS_GROUP_FLAGS)) +); + +DECLARE_EVENT_CLASS(btrfs__reserve_extent, + + TP_PROTO(struct btrfs_root *root, + struct btrfs_block_group_cache *block_group, u64 start, + u64 len), + + TP_ARGS(root, block_group, start, len), + + TP_STRUCT__entry( + __field( u64, root_objectid ) + __field( u64, bg_objectid ) + __field( u64, flags ) + __field( u64, start ) + __field( u64, len ) + ), + + TP_fast_assign( + __entry->root_objectid = root->root_key.objectid; + __entry->bg_objectid = block_group->key.objectid; + __entry->flags = block_group->flags; + __entry->start = start; + __entry->len = len; + ), + + TP_printk("root = %Lu(%s), block_group = %Lu, flags = %Lu(%s), " + "start = %Lu, len = %Lu", + show_root_type(__entry->root_objectid), __entry->bg_objectid, + __entry->flags, __print_flags((unsigned long)__entry->flags, + "|", BTRFS_GROUP_FLAGS), + __entry->start, __entry->len) +); + +DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent, + + TP_PROTO(struct btrfs_root *root, + struct btrfs_block_group_cache *block_group, u64 start, + u64 len), + + TP_ARGS(root, block_group, start, len) +); + +DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent_cluster, + + TP_PROTO(struct btrfs_root *root, + struct btrfs_block_group_cache *block_group, u64 start, + u64 len), + + TP_ARGS(root, block_group, start, len) +); + +TRACE_EVENT(btrfs_find_cluster, + + TP_PROTO(struct btrfs_block_group_cache *block_group, u64 start, + u64 bytes, u64 empty_size, u64 min_bytes), + + TP_ARGS(block_group, start, bytes, empty_size, min_bytes), + + TP_STRUCT__entry( + __field( u64, bg_objectid ) + __field( u64, flags ) + __field( u64, start ) + __field( u64, bytes ) + __field( u64, empty_size ) + __field( u64, min_bytes ) + ), + + TP_fast_assign( + __entry->bg_objectid = block_group->key.objectid; + __entry->flags = block_group->flags; + __entry->start = start; + __entry->bytes = bytes; + __entry->empty_size = empty_size; + __entry->min_bytes = min_bytes; + ), + + TP_printk("block_group = %Lu, flags = %Lu(%s), start = %Lu, len = %Lu," + " empty_size = %Lu, min_bytes = %Lu", __entry->bg_objectid, + __entry->flags, + __print_flags((unsigned long)__entry->flags, "|", + BTRFS_GROUP_FLAGS), __entry->start, + __entry->bytes, __entry->empty_size, __entry->min_bytes) +); + +TRACE_EVENT(btrfs_failed_cluster_setup, + + TP_PROTO(struct btrfs_block_group_cache *block_group), + + TP_ARGS(block_group), + + TP_STRUCT__entry( + __field( u64, bg_objectid ) + ), + + TP_fast_assign( + __entry->bg_objectid = block_group->key.objectid; + ), + + TP_printk("block_group = %Lu", __entry->bg_objectid) +); + +TRACE_EVENT(btrfs_setup_cluster, + + TP_PROTO(struct btrfs_block_group_cache *block_group, + struct btrfs_free_cluster *cluster, u64 size, int bitmap), + + TP_ARGS(block_group, cluster, size, bitmap), + + TP_STRUCT__entry( + __field( u64, bg_objectid ) + __field( u64, flags ) + __field( u64, start ) + __field( u64, max_size ) + __field( u64, size ) + __field( int, bitmap ) + ), + + TP_fast_assign( + __entry->bg_objectid = block_group->key.objectid; + __entry->flags = block_group->flags; + __entry->start = cluster->window_start; + __entry->max_size = cluster->max_size; + __entry->size = size; + __entry->bitmap = bitmap; + ), + + TP_printk("block_group = %Lu, flags = %Lu(%s), window_start = %Lu, " + "size = %Lu, max_size = %Lu, bitmap = %d", + __entry->bg_objectid, + __entry->flags, + __print_flags((unsigned long)__entry->flags, "|", + BTRFS_GROUP_FLAGS), __entry->start, + __entry->size, __entry->max_size, __entry->bitmap) +); + #endif /* _TRACE_BTRFS_H */ /* This part must be outside protection */ diff --git a/include/video/edid.h b/include/video/edid.h index 928c342b33d6..c5f198704912 100644 --- a/include/video/edid.h +++ b/include/video/edid.h @@ -1,16 +1,14 @@ #ifndef __linux_video_edid_h__ #define __linux_video_edid_h__ -#if !defined(__KERNEL__) || defined(CONFIG_X86) - struct edid_info { unsigned char dummy[128]; }; #ifdef __KERNEL__ +#ifdef CONFIG_X86 extern struct edid_info edid_info; -#endif /* __KERNEL__ */ - +#endif #endif #endif /* __linux_video_edid_h__ */ diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 378c7ed6760b..062b3b24ff10 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -200,6 +200,10 @@ enum omap_dss_clk_source { OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, /* OMAP4: PLL2_CLK2 */ }; +enum omap_hdmi_flags { + OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0, +}; + /* RFBI */ struct rfbi_timings { @@ -294,8 +298,8 @@ int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel, u16 len); int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel); -int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel); -void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel); +int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel); +void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel); /* Board specific data */ struct omap_dss_board_info { @@ -309,6 +313,8 @@ struct omap_dss_board_info { /* Init with the board info */ extern int omap_display_init(struct omap_dss_board_info *board_data); +/* HDMI mux init*/ +extern int omap_hdmi_init(enum omap_hdmi_flags flags); struct omap_display_platform_data { struct omap_dss_board_info *board_data; @@ -352,8 +358,6 @@ struct omap_dss_cpr_coefs { }; struct omap_overlay_info { - bool enabled; - u32 paddr; u32 p_uv_addr; /* for NV12 format */ u16 screen_width; @@ -385,11 +389,21 @@ struct omap_overlay { /* dynamic fields */ struct omap_overlay_manager *manager; - struct omap_overlay_info info; - bool manager_changed; - /* if true, info has been changed, but not applied() yet */ - bool info_dirty; + /* + * The following functions do not block: + * + * is_enabled + * set_overlay_info + * get_overlay_info + * + * The rest of the functions may block and cannot be called from + * interrupt context + */ + + int (*enable)(struct omap_overlay *ovl); + int (*disable)(struct omap_overlay *ovl); + bool (*is_enabled)(struct omap_overlay *ovl); int (*set_manager)(struct omap_overlay *ovl, struct omap_overlay_manager *mgr); @@ -418,23 +432,27 @@ struct omap_overlay_manager_info { struct omap_overlay_manager { struct kobject kobj; - struct list_head list; /* static fields */ const char *name; enum omap_channel id; enum omap_overlay_manager_caps caps; - int num_overlays; - struct omap_overlay **overlays; + struct list_head overlays; enum omap_display_type supported_displays; /* dynamic fields */ struct omap_dss_device *device; - struct omap_overlay_manager_info info; - bool device_changed; - /* if true, info has been changed but not applied() yet */ - bool info_dirty; + /* + * The following functions do not block: + * + * set_manager_info + * get_manager_info + * apply + * + * The rest of the functions may block and cannot be called from + * interrupt context + */ int (*set_device)(struct omap_overlay_manager *mgr, struct omap_dss_device *dssdev); @@ -448,9 +466,6 @@ 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); - - int (*enable)(struct omap_overlay_manager *mgr); - int (*disable)(struct omap_overlay_manager *mgr); }; struct omap_dss_device { @@ -662,12 +677,7 @@ 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); -int omap_dsi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h, - bool enlarge_update_area); -int omap_dsi_update(struct omap_dss_device *dssdev, - int channel, - u16 x, u16 y, u16 w, u16 h, +int omap_dsi_update(struct omap_dss_device *dssdev, int channel, void (*callback)(int, void *), void *data); int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel); int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id); diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h index 6cb95c977de9..434d56b4a1a5 100644 --- a/include/video/sh_mipi_dsi.h +++ b/include/video/sh_mipi_dsi.h @@ -28,14 +28,33 @@ enum sh_mipi_dsi_data_fmt { struct sh_mobile_lcdc_chan_cfg; #define SH_MIPI_DSI_HSABM (1 << 0) -#define SH_MIPI_DSI_HSPBM (1 << 1) +#define SH_MIPI_DSI_HBPBM (1 << 1) +#define SH_MIPI_DSI_HFPBM (1 << 2) +#define SH_MIPI_DSI_BL2E (1 << 3) +#define SH_MIPI_DSI_VSEE (1 << 4) +#define SH_MIPI_DSI_HSEE (1 << 5) +#define SH_MIPI_DSI_HSAE (1 << 6) + +#define SH_MIPI_DSI_HSbyteCLK (1 << 24) +#define SH_MIPI_DSI_HS6divCLK (1 << 25) +#define SH_MIPI_DSI_HS4divCLK (1 << 26) + +#define SH_MIPI_DSI_SYNC_PULSES_MODE (SH_MIPI_DSI_VSEE | \ + SH_MIPI_DSI_HSEE | \ + SH_MIPI_DSI_HSAE) +#define SH_MIPI_DSI_SYNC_EVENTS_MODE (0) +#define SH_MIPI_DSI_SYNC_BURST_MODE (SH_MIPI_DSI_BL2E) struct sh_mipi_dsi_info { enum sh_mipi_dsi_data_fmt data_format; struct sh_mobile_lcdc_chan_cfg *lcd_chan; + int lane; unsigned long flags; u32 clksrc; unsigned int vsynw_offset; + int (*set_dot_clock)(struct platform_device *pdev, + void __iomem *base, + int enable); }; #endif diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 8101b726b48a..fe30b759c51e 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h @@ -174,7 +174,8 @@ struct sh_mobile_lcdc_bl_info { struct sh_mobile_lcdc_chan_cfg { int chan; - int bpp; + int fourcc; + int colorspace; int interface_type; /* selects RGBn or SYSn I/F, see above */ int clock_divider; unsigned long flags; /* LCDC_FLAGS_... */ @@ -184,7 +185,6 @@ struct sh_mobile_lcdc_chan_cfg { struct sh_mobile_lcdc_board_cfg board_cfg; struct sh_mobile_lcdc_bl_info bl_info; struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ - int nonstd; struct sh_mobile_meram_cfg *meram_cfg; }; diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h index 9324488f23f0..ee338bfde18b 100644 --- a/include/xen/interface/io/blkif.h +++ b/include/xen/interface/io/blkif.h @@ -84,6 +84,21 @@ typedef uint64_t blkif_sector_t; * e07154r6-Data_Set_Management_Proposal_for_ATA-ACS2.doc * http://www.seagate.com/staticfiles/support/disc/manuals/ * Interface%20manuals/100293068c.pdf + * The backend can optionally provide three extra XenBus attributes to + * further optimize the discard functionality: + * 'discard-aligment' - Devices that support discard functionality may + * internally allocate space in units that are bigger than the exported + * logical block size. The discard-alignment parameter indicates how many bytes + * the beginning of the partition is offset from the internal allocation unit's + * natural alignment. + * 'discard-granularity' - Devices that support discard functionality may + * internally allocate space using units that are bigger than the logical block + * size. The discard-granularity parameter indicates the size of the internal + * allocation unit in bytes if reported by the device. Otherwise the + * discard-granularity will be set to match the device's physical block size. + * 'discard-secure' - All copies of the discarded sectors (potentially created + * by garbage collection) must also be erased. To use this feature, the flag + * BLKIF_DISCARD_SECURE must be set in the blkif_request_trim. */ #define BLKIF_OP_DISCARD 5 @@ -95,6 +110,12 @@ typedef uint64_t blkif_sector_t; #define BLKIF_MAX_SEGMENTS_PER_REQUEST 11 struct blkif_request_rw { + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ +#ifdef CONFIG_X86_64 + uint32_t _pad1; /* offsetof(blkif_request,u.rw.id) == 8 */ +#endif + uint64_t id; /* private guest value, echoed in resp */ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ struct blkif_request_segment { grant_ref_t gref; /* reference to I/O buffer frame */ @@ -102,23 +123,28 @@ struct blkif_request_rw { /* @last_sect: last sector in frame to transfer (inclusive). */ uint8_t first_sect, last_sect; } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; -}; +} __attribute__((__packed__)); struct blkif_request_discard { + uint8_t flag; /* BLKIF_DISCARD_SECURE or zero. */ +#define BLKIF_DISCARD_SECURE (1<<0) /* ignored if discard-secure=0 */ + blkif_vdev_t _pad1; /* only for read/write requests */ +#ifdef CONFIG_X86_64 + uint32_t _pad2; /* offsetof(blkif_req..,u.discard.id)==8*/ +#endif + uint64_t id; /* private guest value, echoed in resp */ blkif_sector_t sector_number; - uint64_t nr_sectors; -}; + uint64_t nr_sectors; + uint8_t _pad3; +} __attribute__((__packed__)); struct blkif_request { uint8_t operation; /* BLKIF_OP_??? */ - uint8_t nr_segments; /* number of segments */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t id; /* private guest value, echoed in resp */ union { struct blkif_request_rw rw; struct blkif_request_discard discard; } u; -}; +} __attribute__((__packed__)); struct blkif_response { uint64_t id; /* copied from request */ diff --git a/init/Kconfig b/init/Kconfig index 6ac2236244c3..3f42cd66f0f8 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -355,7 +355,7 @@ config AUDIT config AUDITSYSCALL bool "Enable system-call auditing support" - depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH) + depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || ARM) default y if SECURITY_SELINUX help Enable low-overhead system-call auditing infrastructure that @@ -372,6 +372,20 @@ config AUDIT_TREE depends on AUDITSYSCALL select FSNOTIFY +config AUDIT_LOGINUID_IMMUTABLE + bool "Make audit loginuid immutable" + depends on AUDIT + help + The config option toggles if a task setting its loginuid requires + CAP_SYS_AUDITCONTROL or if that task should require no special permissions + but should instead only allow setting its loginuid if it was never + previously set. On systems which use systemd or a similar central + process to restart login services this should be set to true. On older + systems in which an admin would typically have to directly stop and + start processes this should be set to false. Setting this to true allows + one to drop potentially dangerous capabilites from the login tasks, + but may not be backwards compatible with older init systems. + source "kernel/irq/Kconfig" menu "RCU Subsystem" diff --git a/init/main.c b/init/main.c index 415548e808d2..ff49a6dacfbb 100644 --- a/init/main.c +++ b/init/main.c @@ -648,7 +648,7 @@ static void __init do_ctors(void) #endif } -int initcall_debug; +bool initcall_debug; core_param(initcall_debug, initcall_debug, bool, 0644); static char msgbuf[64]; diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 9b7c8ab7d75c..86ee272de210 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -128,7 +128,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, if (S_ISREG(mode)) { struct mqueue_inode_info *info; - struct task_struct *p = current; unsigned long mq_bytes, mq_msg_tblsz; inode->i_fop = &mqueue_file_operations; @@ -159,7 +158,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, spin_lock(&mq_lock); if (u->mq_bytes + mq_bytes < u->mq_bytes || - u->mq_bytes + mq_bytes > task_rlimit(p, RLIMIT_MSGQUEUE)) { + u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) { spin_unlock(&mq_lock); /* mqueue_evict_inode() releases info->messages */ ret = -EMFILE; diff --git a/ipc/shm.c b/ipc/shm.c index 02ecf2c078fc..b76be5bda6c2 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -870,9 +870,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) case SHM_LOCK: case SHM_UNLOCK: { - struct file *uninitialized_var(shm_file); - - lru_add_drain_all(); /* drain pagevecs to lru lists */ + struct file *shm_file; shp = shm_lock_check(ns, shmid); if (IS_ERR(shp)) { @@ -895,22 +893,31 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) err = security_shm_shmctl(shp, cmd); if (err) goto out_unlock; - - if(cmd==SHM_LOCK) { + + shm_file = shp->shm_file; + if (is_file_hugepages(shm_file)) + goto out_unlock; + + if (cmd == SHM_LOCK) { struct user_struct *user = current_user(); - if (!is_file_hugepages(shp->shm_file)) { - err = shmem_lock(shp->shm_file, 1, user); - if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){ - shp->shm_perm.mode |= SHM_LOCKED; - shp->mlock_user = user; - } + err = shmem_lock(shm_file, 1, user); + if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) { + shp->shm_perm.mode |= SHM_LOCKED; + shp->mlock_user = user; } - } else if (!is_file_hugepages(shp->shm_file)) { - shmem_lock(shp->shm_file, 0, shp->mlock_user); - shp->shm_perm.mode &= ~SHM_LOCKED; - shp->mlock_user = NULL; + goto out_unlock; } + + /* SHM_UNLOCK */ + if (!(shp->shm_perm.mode & SHM_LOCKED)) + goto out_unlock; + shmem_lock(shm_file, 0, shp->mlock_user); + shp->shm_perm.mode &= ~SHM_LOCKED; + shp->mlock_user = NULL; + get_file(shm_file); shm_unlock(shp); + shmem_unlock_mapping(shm_file->f_mapping); + fput(shm_file); goto out; } case IPC_RMID: diff --git a/kernel/Makefile b/kernel/Makefile index f70396e5a24b..2d9de86b7e76 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -23,6 +23,7 @@ CFLAGS_REMOVE_irq_work.o = -pg endif obj-y += sched/ +obj-y += power/ obj-$(CONFIG_FREEZER) += freezer.o obj-$(CONFIG_PROFILING) += profile.o @@ -52,8 +53,6 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KALLSYMS) += kallsyms.o -obj-$(CONFIG_PM) += power/ -obj-$(CONFIG_FREEZER) += power/ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o diff --git a/kernel/async.c b/kernel/async.c index 80b74b88fefe..bd0c168a3bbe 100644 --- a/kernel/async.c +++ b/kernel/async.c @@ -78,8 +78,6 @@ static DECLARE_WAIT_QUEUE_HEAD(async_done); static atomic_t entry_count; -extern int initcall_debug; - /* * MUST be called with the lock held! diff --git a/kernel/audit.c b/kernel/audit.c index 2c1d6ab7106e..bb0eb5bb9a0a 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -601,13 +601,13 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type) case AUDIT_TTY_SET: case AUDIT_TRIM: case AUDIT_MAKE_EQUIV: - if (security_netlink_recv(skb, CAP_AUDIT_CONTROL)) + if (!capable(CAP_AUDIT_CONTROL)) err = -EPERM; break; case AUDIT_USER: case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG: case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: - if (security_netlink_recv(skb, CAP_AUDIT_WRITE)) + if (!capable(CAP_AUDIT_WRITE)) err = -EPERM; break; default: /* bad msg */ @@ -631,7 +631,7 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, } *ab = audit_log_start(NULL, GFP_KERNEL, msg_type); - audit_log_format(*ab, "user pid=%d uid=%u auid=%u ses=%u", + audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u", pid, uid, auid, ses); if (sid) { rc = security_secid_to_secctx(sid, &ctx, &len); @@ -1423,7 +1423,7 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, char *p, *pathname; if (prefix) - audit_log_format(ab, " %s", prefix); + audit_log_format(ab, "%s", prefix); /* We will allow 11 spaces for ' (deleted)' to be appended */ pathname = kmalloc(PATH_MAX+11, ab->gfp_mask); diff --git a/kernel/audit.h b/kernel/audit.h index 91e7071c4d2c..816766803371 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -36,12 +36,8 @@ enum audit_state { AUDIT_DISABLED, /* Do not create per-task audit_context. * No syscall-specific audit records can * be generated. */ - AUDIT_SETUP_CONTEXT, /* Create the per-task audit_context, - * but don't necessarily fill it in at - * syscall entry time (i.e., filter - * instead). */ AUDIT_BUILD_CONTEXT, /* Create the per-task audit_context, - * and always fill it in at syscall + * and fill it in at syscall * entry time. This makes a full * syscall record available if some * other part of the kernel decides it diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index f8277c80d678..a6c3f1abd206 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -235,13 +235,15 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) switch(listnr) { default: goto exit_err; - case AUDIT_FILTER_USER: - case AUDIT_FILTER_TYPE: #ifdef CONFIG_AUDITSYSCALL case AUDIT_FILTER_ENTRY: + if (rule->action == AUDIT_ALWAYS) + goto exit_err; case AUDIT_FILTER_EXIT: case AUDIT_FILTER_TASK: #endif + case AUDIT_FILTER_USER: + case AUDIT_FILTER_TYPE: ; } if (unlikely(rule->action == AUDIT_POSSIBLE)) { @@ -385,7 +387,7 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) goto exit_free; break; case AUDIT_FILETYPE: - if ((f->val & ~S_IFMT) > S_IFMT) + if (f->val & ~S_IFMT) goto exit_free; break; case AUDIT_INODE: @@ -459,6 +461,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, case AUDIT_ARG1: case AUDIT_ARG2: case AUDIT_ARG3: + case AUDIT_OBJ_UID: + case AUDIT_OBJ_GID: break; case AUDIT_ARCH: entry->rule.arch_f = f; @@ -522,7 +526,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, goto exit_free; break; case AUDIT_FILTERKEY: - err = -EINVAL; if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN) goto exit_free; str = audit_unpack_string(&bufp, &remain, f->val); @@ -536,7 +539,11 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, goto exit_free; break; case AUDIT_FILETYPE: - if ((f->val & ~S_IFMT) > S_IFMT) + if (f->val & ~S_IFMT) + goto exit_free; + break; + case AUDIT_FIELD_COMPARE: + if (f->val > AUDIT_MAX_FIELD_COMPARE) goto exit_free; break; default: diff --git a/kernel/auditsc.c b/kernel/auditsc.c index e7fe2b0d29b3..af1de0f34eae 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -70,9 +70,15 @@ #include "audit.h" +/* flags stating the success for a syscall */ +#define AUDITSC_INVALID 0 +#define AUDITSC_SUCCESS 1 +#define AUDITSC_FAILURE 2 + /* AUDIT_NAMES is the number of slots we reserve in the audit_context - * for saving names from getname(). */ -#define AUDIT_NAMES 20 + * for saving names from getname(). If we get more names we will allocate + * 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 @@ -101,9 +107,8 @@ struct audit_cap_data { * * 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; - int name_len; /* number of name's characters to log */ - unsigned name_put; /* call __putname() for this name */ unsigned long ino; dev_t dev; umode_t mode; @@ -113,6 +118,14 @@ struct audit_names { 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 */ + /* + * 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; }; struct audit_aux_data { @@ -174,8 +187,17 @@ struct audit_context { long return_code;/* syscall return code */ u64 prio; int return_valid; /* return code is valid */ - int name_count; - struct audit_names names[AUDIT_NAMES]; + /* + * The names_list is the list of all audit_names collected during this + * syscall. The first AUDIT_NAMES entries in the names_list will + * actually be from the preallocated_names array for performance + * reasons. Except during allocation they should never be referenced + * through the preallocated_names array and should only be found/used + * by running the names_list. + */ + struct audit_names preallocated_names[AUDIT_NAMES]; + int name_count; /* total records in names_list */ + struct list_head names_list; /* anchor for struct audit_names->list */ char * filterkey; /* key for rule that triggered record */ struct path pwd; struct audit_context *previous; /* For nested syscalls */ @@ -305,21 +327,21 @@ static int audit_match_perm(struct audit_context *ctx, int mask) } } -static int audit_match_filetype(struct audit_context *ctx, int which) +static int audit_match_filetype(struct audit_context *ctx, int val) { - unsigned index = which & ~S_IFMT; - umode_t mode = which & S_IFMT; + struct audit_names *n; + umode_t mode = (umode_t)val; if (unlikely(!ctx)) return 0; - if (index >= ctx->name_count) - return 0; - if (ctx->names[index].ino == -1) - return 0; - if ((ctx->names[index].mode ^ mode) & S_IFMT) - return 0; - return 1; + list_for_each_entry(n, &ctx->names_list, list) { + if ((n->ino != -1) && + ((n->mode & S_IFMT) == mode)) + return 1; + } + + return 0; } /* @@ -441,6 +463,134 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree) return 0; } +static int audit_compare_id(uid_t uid1, + struct audit_names *name, + unsigned long name_offset, + struct audit_field *f, + struct audit_context *ctx) +{ + struct audit_names *n; + unsigned long addr; + uid_t uid2; + int rc; + + BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t)); + + if (name) { + addr = (unsigned long)name; + addr += name_offset; + + uid2 = *(uid_t *)addr; + rc = audit_comparator(uid1, f->op, uid2); + if (rc) + return rc; + } + + if (ctx) { + list_for_each_entry(n, &ctx->names_list, list) { + addr = (unsigned long)n; + addr += name_offset; + + uid2 = *(uid_t *)addr; + + rc = audit_comparator(uid1, f->op, uid2); + if (rc) + return rc; + } + } + return 0; +} + +static int audit_field_compare(struct task_struct *tsk, + const struct cred *cred, + struct audit_field *f, + struct audit_context *ctx, + struct audit_names *name) +{ + switch (f->val) { + /* process to file object comparisons */ + case AUDIT_COMPARE_UID_TO_OBJ_UID: + return audit_compare_id(cred->uid, + name, offsetof(struct audit_names, uid), + f, ctx); + case AUDIT_COMPARE_GID_TO_OBJ_GID: + return audit_compare_id(cred->gid, + name, offsetof(struct audit_names, gid), + f, ctx); + case AUDIT_COMPARE_EUID_TO_OBJ_UID: + return audit_compare_id(cred->euid, + name, offsetof(struct audit_names, uid), + f, ctx); + case AUDIT_COMPARE_EGID_TO_OBJ_GID: + return audit_compare_id(cred->egid, + name, offsetof(struct audit_names, gid), + f, ctx); + case AUDIT_COMPARE_AUID_TO_OBJ_UID: + return audit_compare_id(tsk->loginuid, + name, offsetof(struct audit_names, uid), + f, ctx); + case AUDIT_COMPARE_SUID_TO_OBJ_UID: + return audit_compare_id(cred->suid, + name, offsetof(struct audit_names, uid), + f, ctx); + case AUDIT_COMPARE_SGID_TO_OBJ_GID: + return audit_compare_id(cred->sgid, + name, offsetof(struct audit_names, gid), + f, ctx); + case AUDIT_COMPARE_FSUID_TO_OBJ_UID: + return audit_compare_id(cred->fsuid, + name, offsetof(struct audit_names, uid), + f, ctx); + case AUDIT_COMPARE_FSGID_TO_OBJ_GID: + return audit_compare_id(cred->fsgid, + name, offsetof(struct audit_names, gid), + f, ctx); + /* uid comparisons */ + case AUDIT_COMPARE_UID_TO_AUID: + return audit_comparator(cred->uid, f->op, tsk->loginuid); + case AUDIT_COMPARE_UID_TO_EUID: + return audit_comparator(cred->uid, f->op, cred->euid); + case AUDIT_COMPARE_UID_TO_SUID: + return audit_comparator(cred->uid, f->op, cred->suid); + case AUDIT_COMPARE_UID_TO_FSUID: + return audit_comparator(cred->uid, f->op, cred->fsuid); + /* auid comparisons */ + case AUDIT_COMPARE_AUID_TO_EUID: + return audit_comparator(tsk->loginuid, f->op, cred->euid); + case AUDIT_COMPARE_AUID_TO_SUID: + return audit_comparator(tsk->loginuid, f->op, cred->suid); + case AUDIT_COMPARE_AUID_TO_FSUID: + return audit_comparator(tsk->loginuid, f->op, cred->fsuid); + /* euid comparisons */ + case AUDIT_COMPARE_EUID_TO_SUID: + return audit_comparator(cred->euid, f->op, cred->suid); + case AUDIT_COMPARE_EUID_TO_FSUID: + return audit_comparator(cred->euid, f->op, cred->fsuid); + /* suid comparisons */ + case AUDIT_COMPARE_SUID_TO_FSUID: + return audit_comparator(cred->suid, f->op, cred->fsuid); + /* gid comparisons */ + case AUDIT_COMPARE_GID_TO_EGID: + return audit_comparator(cred->gid, f->op, cred->egid); + case AUDIT_COMPARE_GID_TO_SGID: + return audit_comparator(cred->gid, f->op, cred->sgid); + case AUDIT_COMPARE_GID_TO_FSGID: + return audit_comparator(cred->gid, f->op, cred->fsgid); + /* egid comparisons */ + case AUDIT_COMPARE_EGID_TO_SGID: + return audit_comparator(cred->egid, f->op, cred->sgid); + case AUDIT_COMPARE_EGID_TO_FSGID: + return audit_comparator(cred->egid, f->op, cred->fsgid); + /* sgid comparison */ + case AUDIT_COMPARE_SGID_TO_FSGID: + return audit_comparator(cred->sgid, f->op, cred->fsgid); + default: + WARN(1, "Missing AUDIT_COMPARE define. Report as a bug\n"); + return 0; + } + return 0; +} + /* Determine if any context name data matches a rule's watch data */ /* Compare a task_struct with an audit_rule. Return 1 on match, 0 * otherwise. @@ -457,13 +607,14 @@ static int audit_filter_rules(struct task_struct *tsk, bool task_creation) { const struct cred *cred; - int i, j, need_sid = 1; + int i, need_sid = 1; u32 sid; cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); for (i = 0; i < rule->field_count; i++) { struct audit_field *f = &rule->fields[i]; + struct audit_names *n; int result = 0; switch (f->type) { @@ -522,12 +673,14 @@ static int audit_filter_rules(struct task_struct *tsk, } break; case AUDIT_DEVMAJOR: - if (name) - result = audit_comparator(MAJOR(name->dev), - f->op, f->val); - else if (ctx) { - for (j = 0; j < ctx->name_count; j++) { - if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { + if (name) { + if (audit_comparator(MAJOR(name->dev), f->op, f->val) || + audit_comparator(MAJOR(name->rdev), f->op, f->val)) + ++result; + } else if (ctx) { + list_for_each_entry(n, &ctx->names_list, list) { + if (audit_comparator(MAJOR(n->dev), f->op, f->val) || + audit_comparator(MAJOR(n->rdev), f->op, f->val)) { ++result; break; } @@ -535,12 +688,14 @@ static int audit_filter_rules(struct task_struct *tsk, } break; case AUDIT_DEVMINOR: - if (name) - result = audit_comparator(MINOR(name->dev), - f->op, f->val); - else if (ctx) { - for (j = 0; j < ctx->name_count; j++) { - if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { + if (name) { + if (audit_comparator(MINOR(name->dev), f->op, f->val) || + audit_comparator(MINOR(name->rdev), f->op, f->val)) + ++result; + } else if (ctx) { + list_for_each_entry(n, &ctx->names_list, list) { + if (audit_comparator(MINOR(n->dev), f->op, f->val) || + audit_comparator(MINOR(n->rdev), f->op, f->val)) { ++result; break; } @@ -551,8 +706,32 @@ static int audit_filter_rules(struct task_struct *tsk, if (name) result = (name->ino == f->val); else if (ctx) { - for (j = 0; j < ctx->name_count; j++) { - if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { + list_for_each_entry(n, &ctx->names_list, list) { + if (audit_comparator(n->ino, f->op, f->val)) { + ++result; + break; + } + } + } + break; + case AUDIT_OBJ_UID: + if (name) { + result = audit_comparator(name->uid, f->op, f->val); + } else if (ctx) { + list_for_each_entry(n, &ctx->names_list, list) { + if (audit_comparator(n->uid, f->op, f->val)) { + ++result; + break; + } + } + } + break; + case AUDIT_OBJ_GID: + if (name) { + result = audit_comparator(name->gid, f->op, f->val); + } else if (ctx) { + list_for_each_entry(n, &ctx->names_list, list) { + if (audit_comparator(n->gid, f->op, f->val)) { ++result; break; } @@ -607,11 +786,10 @@ static int audit_filter_rules(struct task_struct *tsk, name->osid, f->type, f->op, f->lsm_rule, ctx); } else if (ctx) { - for (j = 0; j < ctx->name_count; j++) { - if (security_audit_rule_match( - ctx->names[j].osid, - f->type, f->op, - f->lsm_rule, ctx)) { + list_for_each_entry(n, &ctx->names_list, list) { + if (security_audit_rule_match(n->osid, f->type, + f->op, f->lsm_rule, + ctx)) { ++result; break; } @@ -643,8 +821,10 @@ static int audit_filter_rules(struct task_struct *tsk, case AUDIT_FILETYPE: result = audit_match_filetype(ctx, f->val); break; + case AUDIT_FIELD_COMPARE: + result = audit_field_compare(tsk, cred, f, ctx, name); + break; } - if (!result) return 0; } @@ -722,40 +902,53 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, return AUDIT_BUILD_CONTEXT; } -/* At syscall exit time, this filter is called if any audit_names[] have been +/* + * Given an audit_name check the inode hash table to see if they match. + * Called holding the rcu read lock to protect the use of audit_inode_hash + */ +static int audit_filter_inode_name(struct task_struct *tsk, + struct audit_names *n, + struct audit_context *ctx) { + int word, bit; + int h = audit_hash_ino((u32)n->ino); + struct list_head *list = &audit_inode_hash[h]; + struct audit_entry *e; + enum audit_state state; + + word = AUDIT_WORD(ctx->major); + bit = AUDIT_BIT(ctx->major); + + if (list_empty(list)) + return 0; + + list_for_each_entry_rcu(e, list, list) { + if ((e->rule.mask[word] & bit) == bit && + audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) { + ctx->current_state = state; + return 1; + } + } + + return 0; +} + +/* At syscall exit time, this filter is called if any audit_names have been * collected during syscall processing. We only check rules in sublists at hash - * buckets applicable to the inode numbers in audit_names[]. + * buckets applicable to the inode numbers in audit_names. * Regarding audit_state, same rules apply as for audit_filter_syscall(). */ void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx) { - int i; - struct audit_entry *e; - enum audit_state state; + struct audit_names *n; if (audit_pid && tsk->tgid == audit_pid) return; rcu_read_lock(); - for (i = 0; i < ctx->name_count; i++) { - int word = AUDIT_WORD(ctx->major); - int bit = AUDIT_BIT(ctx->major); - struct audit_names *n = &ctx->names[i]; - int h = audit_hash_ino((u32)n->ino); - struct list_head *list = &audit_inode_hash[h]; - - if (list_empty(list)) - continue; - list_for_each_entry_rcu(e, list, list) { - if ((e->rule.mask[word] & bit) == bit && - audit_filter_rules(tsk, &e->rule, ctx, n, - &state, false)) { - rcu_read_unlock(); - ctx->current_state = state; - return; - } - } + list_for_each_entry(n, &ctx->names_list, list) { + if (audit_filter_inode_name(tsk, n, ctx)) + break; } rcu_read_unlock(); } @@ -766,7 +959,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, { struct audit_context *context = tsk->audit_context; - if (likely(!context)) + if (!context) return NULL; context->return_valid = return_valid; @@ -799,7 +992,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, static inline void audit_free_names(struct audit_context *context) { - int i; + struct audit_names *n, *next; #if AUDIT_DEBUG == 2 if (context->put_count + context->ino_count != context->name_count) { @@ -810,10 +1003,9 @@ static inline void audit_free_names(struct audit_context *context) context->serial, context->major, context->in_syscall, context->name_count, context->put_count, context->ino_count); - for (i = 0; i < context->name_count; i++) { + list_for_each_entry(n, &context->names_list, list) { printk(KERN_ERR "names[%d] = %p = %s\n", i, - context->names[i].name, - context->names[i].name ?: "(null)"); + n->name, n->name ?: "(null)"); } dump_stack(); return; @@ -824,9 +1016,12 @@ static inline void audit_free_names(struct audit_context *context) context->ino_count = 0; #endif - for (i = 0; i < context->name_count; i++) { - if (context->names[i].name && context->names[i].name_put) - __putname(context->names[i].name); + list_for_each_entry_safe(n, next, &context->names_list, list) { + list_del(&n->list); + if (n->name && n->name_put) + __putname(n->name); + if (n->should_free) + kfree(n); } context->name_count = 0; path_put(&context->pwd); @@ -864,6 +1059,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state) return NULL; audit_zero_context(context, state); INIT_LIST_HEAD(&context->killed_trees); + INIT_LIST_HEAD(&context->names_list); return context; } @@ -886,7 +1082,7 @@ int audit_alloc(struct task_struct *tsk) return 0; /* Return if not auditing. */ state = audit_filter_task(tsk, &key); - if (likely(state == AUDIT_DISABLED)) + if (state == AUDIT_DISABLED) return 0; if (!(context = audit_alloc_context(state))) { @@ -975,7 +1171,7 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk while (vma) { if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { - audit_log_d_path(ab, "exe=", + audit_log_d_path(ab, " exe=", &vma->vm_file->f_path); break; } @@ -1166,8 +1362,8 @@ static void audit_log_execve_info(struct audit_context *context, struct audit_buffer **ab, struct audit_aux_data_execve *axi) { - int i; - size_t len, len_sent = 0; + int i, len; + size_t len_sent = 0; const char __user *p; char *buf; @@ -1324,6 +1520,68 @@ static void show_special(struct audit_context *context, int *call_panic) audit_log_end(ab); } +static void audit_log_name(struct audit_context *context, struct audit_names *n, + int record_num, int *call_panic) +{ + struct audit_buffer *ab; + ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); + if (!ab) + return; /* audit_panic has been called */ + + audit_log_format(ab, "item=%d", record_num); + + if (n->name) { + switch (n->name_len) { + case AUDIT_NAME_FULL: + /* log the full path */ + audit_log_format(ab, " name="); + audit_log_untrustedstring(ab, n->name); + break; + case 0: + /* name was specified as a relative path and the + * directory component is the cwd */ + audit_log_d_path(ab, " name=", &context->pwd); + break; + default: + /* log the name's directory component */ + audit_log_format(ab, " name="); + audit_log_n_untrustedstring(ab, n->name, + n->name_len); + } + } else + audit_log_format(ab, " name=(null)"); + + if (n->ino != (unsigned long)-1) { + audit_log_format(ab, " inode=%lu" + " dev=%02x:%02x mode=%#ho" + " ouid=%u ogid=%u rdev=%02x:%02x", + n->ino, + MAJOR(n->dev), + MINOR(n->dev), + n->mode, + n->uid, + n->gid, + MAJOR(n->rdev), + MINOR(n->rdev)); + } + if (n->osid != 0) { + char *ctx = NULL; + u32 len; + if (security_secid_to_secctx( + n->osid, &ctx, &len)) { + audit_log_format(ab, " osid=%u", n->osid); + *call_panic = 2; + } else { + audit_log_format(ab, " obj=%s", ctx); + security_release_secctx(ctx, len); + } + } + + audit_log_fcaps(ab, n); + + audit_log_end(ab); +} + static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) { const struct cred *cred; @@ -1331,6 +1589,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts struct audit_buffer *ab; struct audit_aux_data *aux; const char *tty; + struct audit_names *n; /* tsk == current */ context->pid = tsk->pid; @@ -1466,70 +1725,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts if (context->pwd.dentry && context->pwd.mnt) { ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD); if (ab) { - audit_log_d_path(ab, "cwd=", &context->pwd); + audit_log_d_path(ab, " cwd=", &context->pwd); audit_log_end(ab); } } - for (i = 0; i < context->name_count; i++) { - struct audit_names *n = &context->names[i]; - ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); - if (!ab) - continue; /* audit_panic has been called */ - - audit_log_format(ab, "item=%d", i); - - if (n->name) { - switch(n->name_len) { - case AUDIT_NAME_FULL: - /* log the full path */ - audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, n->name); - break; - case 0: - /* name was specified as a relative path and the - * directory component is the cwd */ - audit_log_d_path(ab, "name=", &context->pwd); - break; - default: - /* log the name's directory component */ - audit_log_format(ab, " name="); - audit_log_n_untrustedstring(ab, n->name, - n->name_len); - } - } else - audit_log_format(ab, " name=(null)"); - - if (n->ino != (unsigned long)-1) { - audit_log_format(ab, " inode=%lu" - " dev=%02x:%02x mode=%#ho" - " ouid=%u ogid=%u rdev=%02x:%02x", - n->ino, - MAJOR(n->dev), - MINOR(n->dev), - n->mode, - n->uid, - n->gid, - MAJOR(n->rdev), - MINOR(n->rdev)); - } - if (n->osid != 0) { - char *ctx = NULL; - u32 len; - if (security_secid_to_secctx( - n->osid, &ctx, &len)) { - audit_log_format(ab, " osid=%u", n->osid); - call_panic = 2; - } else { - audit_log_format(ab, " obj=%s", ctx); - security_release_secctx(ctx, len); - } - } - - audit_log_fcaps(ab, n); - - audit_log_end(ab); - } + i = 0; + list_for_each_entry(n, &context->names_list, list) + audit_log_name(context, n, i++, &call_panic); /* Send end of event record to help user space know we are finished */ ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); @@ -1545,12 +1748,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts * * Called from copy_process and do_exit */ -void audit_free(struct task_struct *tsk) +void __audit_free(struct task_struct *tsk) { struct audit_context *context; context = audit_get_context(tsk, 0, 0); - if (likely(!context)) + if (!context) return; /* Check for system calls that do not go through the exit @@ -1583,7 +1786,7 @@ void audit_free(struct task_struct *tsk) * will only be written if another part of the kernel requests that it * be written). */ -void audit_syscall_entry(int arch, int major, +void __audit_syscall_entry(int arch, int major, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4) { @@ -1591,7 +1794,7 @@ void audit_syscall_entry(int arch, int major, struct audit_context *context = tsk->audit_context; enum audit_state state; - if (unlikely(!context)) + if (!context) return; /* @@ -1648,7 +1851,7 @@ void audit_syscall_entry(int arch, int major, context->prio = 0; state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]); } - if (likely(state == AUDIT_DISABLED)) + if (state == AUDIT_DISABLED) return; context->serial = 0; @@ -1658,45 +1861,29 @@ void audit_syscall_entry(int arch, int major, context->ppid = 0; } -void audit_finish_fork(struct task_struct *child) -{ - struct audit_context *ctx = current->audit_context; - struct audit_context *p = child->audit_context; - if (!p || !ctx) - return; - if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT) - return; - p->arch = ctx->arch; - p->major = ctx->major; - memcpy(p->argv, ctx->argv, sizeof(ctx->argv)); - p->ctime = ctx->ctime; - p->dummy = ctx->dummy; - p->in_syscall = ctx->in_syscall; - p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL); - p->ppid = current->pid; - p->prio = ctx->prio; - p->current_state = ctx->current_state; -} - /** * audit_syscall_exit - deallocate audit context after a system call - * @valid: success/failure flag - * @return_code: syscall return value + * @success: success value of the syscall + * @return_code: return value of the syscall * * Tear down after system call. If the audit context has been marked as * auditable (either because of the AUDIT_RECORD_CONTEXT state from - * filtering, or because some other part of the kernel write an audit + * filtering, or because some other part of the kernel wrote an audit * message), then write out the syscall information. In call cases, * free the names stored from getname(). */ -void audit_syscall_exit(int valid, long return_code) +void __audit_syscall_exit(int success, long return_code) { struct task_struct *tsk = current; struct audit_context *context; - context = audit_get_context(tsk, valid, return_code); + if (success) + success = AUDITSC_SUCCESS; + else + success = AUDITSC_FAILURE; - if (likely(!context)) + context = audit_get_context(tsk, success, return_code); + if (!context) return; if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT) @@ -1821,6 +2008,30 @@ retry: #endif } +static struct audit_names *audit_alloc_name(struct audit_context *context) +{ + struct audit_names *aname; + + if (context->name_count < AUDIT_NAMES) { + aname = &context->preallocated_names[context->name_count]; + memset(aname, 0, sizeof(*aname)); + } else { + aname = kzalloc(sizeof(*aname), GFP_NOFS); + if (!aname) + return NULL; + aname->should_free = true; + } + + aname->ino = (unsigned long)-1; + list_add_tail(&aname->list, &context->names_list); + + context->name_count++; +#if AUDIT_DEBUG + context->ino_count++; +#endif + return aname; +} + /** * audit_getname - add a name to the list * @name: name to add @@ -1831,9 +2042,7 @@ retry: void __audit_getname(const char *name) { struct audit_context *context = current->audit_context; - - if (IS_ERR(name) || !name) - return; + struct audit_names *n; if (!context->in_syscall) { #if AUDIT_DEBUG == 2 @@ -1843,13 +2052,15 @@ void __audit_getname(const char *name) #endif return; } - BUG_ON(context->name_count >= AUDIT_NAMES); - context->names[context->name_count].name = name; - context->names[context->name_count].name_len = AUDIT_NAME_FULL; - context->names[context->name_count].name_put = 1; - context->names[context->name_count].ino = (unsigned long)-1; - context->names[context->name_count].osid = 0; - ++context->name_count; + + n = audit_alloc_name(context); + if (!n) + return; + + n->name = name; + n->name_len = AUDIT_NAME_FULL; + n->name_put = true; + if (!context->pwd.dentry) get_fs_pwd(current->fs, &context->pwd); } @@ -1871,12 +2082,13 @@ void audit_putname(const char *name) printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n", __FILE__, __LINE__, context->serial, name); if (context->name_count) { + struct audit_names *n; int i; - for (i = 0; i < context->name_count; i++) + + list_for_each_entry(n, &context->names_list, list) printk(KERN_ERR "name[%d] = %p = %s\n", i, - context->names[i].name, - context->names[i].name ?: "(null)"); - } + n->name, n->name ?: "(null)"); + } #endif __putname(name); } @@ -1897,39 +2109,11 @@ void audit_putname(const char *name) #endif } -static int audit_inc_name_count(struct audit_context *context, - const struct inode *inode) -{ - if (context->name_count >= AUDIT_NAMES) { - if (inode) - printk(KERN_DEBUG "audit: name_count maxed, losing inode data: " - "dev=%02x:%02x, inode=%lu\n", - MAJOR(inode->i_sb->s_dev), - MINOR(inode->i_sb->s_dev), - inode->i_ino); - - else - printk(KERN_DEBUG "name_count maxed, losing inode data\n"); - return 1; - } - context->name_count++; -#if AUDIT_DEBUG - context->ino_count++; -#endif - return 0; -} - - static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry) { struct cpu_vfs_cap_data caps; int rc; - memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t)); - memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t)); - name->fcap.fE = 0; - name->fcap_ver = 0; - if (!dentry) return 0; @@ -1969,30 +2153,25 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent */ void __audit_inode(const char *name, const struct dentry *dentry) { - int idx; struct audit_context *context = current->audit_context; const struct inode *inode = dentry->d_inode; + struct audit_names *n; if (!context->in_syscall) return; - if (context->name_count - && context->names[context->name_count-1].name - && context->names[context->name_count-1].name == name) - idx = context->name_count - 1; - else if (context->name_count > 1 - && context->names[context->name_count-2].name - && context->names[context->name_count-2].name == name) - idx = context->name_count - 2; - else { - /* FIXME: how much do we care about inodes that have no - * associated name? */ - if (audit_inc_name_count(context, inode)) - return; - idx = context->name_count - 1; - context->names[idx].name = NULL; + + list_for_each_entry_reverse(n, &context->names_list, list) { + if (n->name && (n->name == name)) + goto out; } + + /* unable to find the name from a previous getname() */ + n = audit_alloc_name(context); + if (!n) + return; +out: handle_path(dentry); - audit_copy_inode(&context->names[idx], dentry, inode); + audit_copy_inode(n, dentry, inode); } /** @@ -2011,11 +2190,11 @@ void __audit_inode(const char *name, const struct dentry *dentry) void __audit_inode_child(const struct dentry *dentry, const struct inode *parent) { - int idx; 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; if (!context->in_syscall) @@ -2025,9 +2204,7 @@ void __audit_inode_child(const struct dentry *dentry, handle_one(inode); /* parent is more likely, look for it first */ - for (idx = 0; idx < context->name_count; idx++) { - struct audit_names *n = &context->names[idx]; - + list_for_each_entry(n, &context->names_list, list) { if (!n->name) continue; @@ -2040,9 +2217,7 @@ void __audit_inode_child(const struct dentry *dentry, } /* no matching parent, look for matching child */ - for (idx = 0; idx < context->name_count; idx++) { - struct audit_names *n = &context->names[idx]; - + list_for_each_entry(n, &context->names_list, list) { if (!n->name) continue; @@ -2060,34 +2235,29 @@ void __audit_inode_child(const struct dentry *dentry, add_names: if (!found_parent) { - if (audit_inc_name_count(context, parent)) + n = audit_alloc_name(context); + if (!n) return; - idx = context->name_count - 1; - context->names[idx].name = NULL; - audit_copy_inode(&context->names[idx], NULL, parent); + audit_copy_inode(n, NULL, parent); } if (!found_child) { - if (audit_inc_name_count(context, inode)) + n = audit_alloc_name(context); + if (!n) return; - idx = context->name_count - 1; /* 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) { - context->names[idx].name = found_parent; - context->names[idx].name_len = AUDIT_NAME_FULL; + n->name = found_parent; + n->name_len = AUDIT_NAME_FULL; /* don't call __putname() */ - context->names[idx].name_put = 0; - } else { - context->names[idx].name = NULL; + n->name_put = false; } if (inode) - audit_copy_inode(&context->names[idx], NULL, inode); - else - context->names[idx].ino = (unsigned long)-1; + audit_copy_inode(n, NULL, inode); } } EXPORT_SYMBOL_GPL(__audit_inode_child); @@ -2121,19 +2291,28 @@ int auditsc_get_stamp(struct audit_context *ctx, static atomic_t session_id = ATOMIC_INIT(0); /** - * audit_set_loginuid - set a task's audit_context loginuid - * @task: task whose audit context is being modified + * audit_set_loginuid - set current task's audit_context loginuid * @loginuid: loginuid value * * Returns 0. * * Called (set) from fs/proc/base.c::proc_loginuid_write(). */ -int audit_set_loginuid(struct task_struct *task, uid_t loginuid) +int audit_set_loginuid(uid_t loginuid) { - unsigned int sessionid = atomic_inc_return(&session_id); + struct task_struct *task = current; struct audit_context *context = task->audit_context; + unsigned int sessionid; + +#ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE + if (task->loginuid != -1) + return -EPERM; +#else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */ + if (!capable(CAP_AUDIT_CONTROL)) + return -EPERM; +#endif /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */ + sessionid = atomic_inc_return(&session_id); if (context && context->in_syscall) { struct audit_buffer *ab; @@ -2271,14 +2450,11 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mo context->ipc.has_perm = 1; } -int audit_bprm(struct linux_binprm *bprm) +int __audit_bprm(struct linux_binprm *bprm) { struct audit_aux_data_execve *ax; struct audit_context *context = current->audit_context; - if (likely(!audit_enabled || !context || context->dummy)) - return 0; - ax = kmalloc(sizeof(*ax), GFP_KERNEL); if (!ax) return -ENOMEM; @@ -2299,13 +2475,10 @@ int audit_bprm(struct linux_binprm *bprm) * @args: args array * */ -void audit_socketcall(int nargs, unsigned long *args) +void __audit_socketcall(int nargs, unsigned long *args) { struct audit_context *context = current->audit_context; - if (likely(!context || context->dummy)) - return; - context->type = AUDIT_SOCKETCALL; context->socketcall.nargs = nargs; memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long)); @@ -2331,13 +2504,10 @@ void __audit_fd_pair(int fd1, int fd2) * * Returns 0 for success or NULL context or < 0 on error. */ -int audit_sockaddr(int len, void *a) +int __audit_sockaddr(int len, void *a) { struct audit_context *context = current->audit_context; - if (likely(!context || context->dummy)) - return 0; - if (!context->sockaddr) { void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL); if (!p) @@ -2499,6 +2669,25 @@ void __audit_mmap_fd(int fd, int flags) context->type = AUDIT_MMAP; } +static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr) +{ + uid_t auid, uid; + gid_t gid; + unsigned int sessionid; + + auid = audit_get_loginuid(current); + sessionid = audit_get_sessionid(current); + current_uid_gid(&uid, &gid); + + audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u", + auid, uid, gid, sessionid); + audit_log_task_context(ab); + audit_log_format(ab, " pid=%d comm=", current->pid); + audit_log_untrustedstring(ab, current->comm); + audit_log_format(ab, " reason="); + audit_log_string(ab, reason); + audit_log_format(ab, " sig=%ld", signr); +} /** * audit_core_dumps - record information about processes that end abnormally * @signr: signal value @@ -2509,10 +2698,6 @@ void __audit_mmap_fd(int fd, int flags) void audit_core_dumps(long signr) { struct audit_buffer *ab; - u32 sid; - uid_t auid = audit_get_loginuid(current), uid; - gid_t gid; - unsigned int sessionid = audit_get_sessionid(current); if (!audit_enabled) return; @@ -2521,24 +2706,17 @@ void audit_core_dumps(long signr) return; ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); - current_uid_gid(&uid, &gid); - audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u", - auid, uid, gid, sessionid); - security_task_getsecid(current, &sid); - if (sid) { - char *ctx = NULL; - u32 len; + audit_log_abend(ab, "memory violation", signr); + audit_log_end(ab); +} - if (security_secid_to_secctx(sid, &ctx, &len)) - audit_log_format(ab, " ssid=%u", sid); - else { - audit_log_format(ab, " subj=%s", ctx); - security_release_secctx(ctx, len); - } - } - audit_log_format(ab, " pid=%d comm=", current->pid); - audit_log_untrustedstring(ab, current->comm); - audit_log_format(ab, " sig=%ld", signr); +void __audit_seccomp(unsigned long syscall) +{ + struct audit_buffer *ab; + + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); + audit_log_abend(ab, "seccomp", SIGKILL); + audit_log_format(ab, " syscall=%ld", syscall); audit_log_end(ab); } diff --git a/kernel/capability.c b/kernel/capability.c index b463871a4e69..3f1adb6c6470 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -287,74 +287,84 @@ error: } /** - * has_capability - Does a task have a capability in init_user_ns + * has_ns_capability - Does a task have a capability in a specific user ns * @t: The task in question + * @ns: target user namespace * @cap: The capability to be tested for * * Return true if the specified task has the given superior capability - * currently in effect to the initial user namespace, false if not. + * currently in effect to the specified user namespace, false if not. * * Note that this does not set PF_SUPERPRIV on the task. */ -bool has_capability(struct task_struct *t, int cap) +bool has_ns_capability(struct task_struct *t, + struct user_namespace *ns, int cap) { - int ret = security_real_capable(t, &init_user_ns, cap); + int ret; + + rcu_read_lock(); + ret = security_capable(__task_cred(t), ns, cap); + rcu_read_unlock(); return (ret == 0); } /** - * has_capability - Does a task have a capability in a specific user ns + * has_capability - Does a task have a capability in init_user_ns * @t: The task in question - * @ns: target user namespace * @cap: The capability to be tested for * * Return true if the specified task has the given superior capability - * currently in effect to the specified user namespace, false if not. + * currently in effect to the initial user namespace, false if not. * * Note that this does not set PF_SUPERPRIV on the task. */ -bool has_ns_capability(struct task_struct *t, - struct user_namespace *ns, int cap) +bool has_capability(struct task_struct *t, int cap) { - int ret = security_real_capable(t, ns, cap); - - return (ret == 0); + return has_ns_capability(t, &init_user_ns, cap); } /** - * has_capability_noaudit - Does a task have a capability (unaudited) + * has_ns_capability_noaudit - Does a task have a capability (unaudited) + * in a specific user ns. * @t: The task in question + * @ns: target user namespace * @cap: The capability to be tested for * * Return true if the specified task has the given superior capability - * currently in effect to init_user_ns, false if not. Don't write an - * audit message for the check. + * currently in effect to the specified user namespace, false if not. + * Do not write an audit message for the check. * * Note that this does not set PF_SUPERPRIV on the task. */ -bool has_capability_noaudit(struct task_struct *t, int cap) +bool has_ns_capability_noaudit(struct task_struct *t, + struct user_namespace *ns, int cap) { - int ret = security_real_capable_noaudit(t, &init_user_ns, cap); + int ret; + + rcu_read_lock(); + ret = security_capable_noaudit(__task_cred(t), ns, cap); + rcu_read_unlock(); return (ret == 0); } /** - * capable - Determine if the current task has a superior capability in effect + * has_capability_noaudit - Does a task have a capability (unaudited) in the + * initial user ns + * @t: The task in question * @cap: The capability to be tested for * - * Return true if the current task has the given superior capability currently - * available for use, false if not. + * Return true if the specified task has the given superior capability + * currently in effect to init_user_ns, false if not. Don't write an + * audit message for the check. * - * This sets PF_SUPERPRIV on the task if the capability is available on the - * assumption that it's about to be used. + * Note that this does not set PF_SUPERPRIV on the task. */ -bool capable(int cap) +bool has_capability_noaudit(struct task_struct *t, int cap) { - return ns_capable(&init_user_ns, cap); + return has_ns_capability_noaudit(t, &init_user_ns, cap); } -EXPORT_SYMBOL(capable); /** * ns_capable - Determine if the current task has a superior capability in effect @@ -374,7 +384,7 @@ bool ns_capable(struct user_namespace *ns, int cap) BUG(); } - if (security_capable(ns, current_cred(), cap) == 0) { + if (security_capable(current_cred(), ns, cap) == 0) { current->flags |= PF_SUPERPRIV; return true; } @@ -383,18 +393,20 @@ bool ns_capable(struct user_namespace *ns, int cap) EXPORT_SYMBOL(ns_capable); /** - * task_ns_capable - Determine whether current task has a superior - * capability targeted at a specific task's user namespace. - * @t: The task whose user namespace is targeted. - * @cap: The capability in question. + * capable - Determine if the current task has a superior capability in effect + * @cap: The capability to be tested for + * + * Return true if the current task has the given superior capability currently + * available for use, false if not. * - * Return true if it does, false otherwise. + * This sets PF_SUPERPRIV on the task if the capability is available on the + * assumption that it's about to be used. */ -bool task_ns_capable(struct task_struct *t, int cap) +bool capable(int cap) { - return ns_capable(task_cred_xxx(t, user)->user_ns, cap); + return ns_capable(&init_user_ns, cap); } -EXPORT_SYMBOL(task_ns_capable); +EXPORT_SYMBOL(capable); /** * nsown_capable - Check superior capability to one's own user_ns diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 63786e71a3cd..e2ae7349437f 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1982,7 +1982,7 @@ static int kdb_lsmod(int argc, const char **argv) kdb_printf("%-20s%8u 0x%p ", mod->name, mod->core_size, (void *)mod); #ifdef CONFIG_MODULE_UNLOAD - kdb_printf("%4d ", module_refcount(mod)); + kdb_printf("%4ld ", module_refcount(mod)); #endif if (mod->state == MODULE_STATE_GOING) kdb_printf(" (Unloading)"); diff --git a/kernel/exit.c b/kernel/exit.c index c44738267be7..294b1709170d 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -964,8 +964,7 @@ void do_exit(long code) acct_collect(code, group_dead); if (group_dead) tty_audit_exit(); - if (unlikely(tsk->audit_context)) - audit_free(tsk); + audit_free(tsk); tsk->exit_code = code; taskstats_exit(tsk, group_dead); diff --git a/kernel/fork.c b/kernel/fork.c index 443f5125f11e..051f090d40c1 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -873,6 +873,7 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk) { #ifdef CONFIG_BLOCK struct io_context *ioc = current->io_context; + struct io_context *new_ioc; if (!ioc) return 0; @@ -884,11 +885,12 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk) if (unlikely(!tsk->io_context)) return -ENOMEM; } else if (ioprio_valid(ioc->ioprio)) { - tsk->io_context = alloc_io_context(GFP_KERNEL, -1); - if (unlikely(!tsk->io_context)) + new_ioc = get_task_io_context(tsk, GFP_KERNEL, NUMA_NO_NODE); + if (unlikely(!new_ioc)) return -ENOMEM; - tsk->io_context->ioprio = ioc->ioprio; + new_ioc->ioprio = ioc->ioprio; + put_io_context(new_ioc, NULL); } #endif return 0; @@ -1525,8 +1527,6 @@ long do_fork(unsigned long clone_flags, init_completion(&vfork); } - audit_finish_fork(p); - /* * We set PF_STARTING at creation in case tracing wants to * use this to distinguish a fully live task from one that diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index a73dd6c7372d..b7952316016a 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -15,7 +15,7 @@ #define istate core_internal_state__do_not_mess_with_it -extern int noirqdebug; +extern bool noirqdebug; /* * Bits used by threaded handlers: diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index dc813a948be2..611cd6003c45 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -325,7 +325,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, desc->irqs_unhandled = 0; } -int noirqdebug __read_mostly; +bool noirqdebug __read_mostly; int noirqdebug_setup(char *str) { diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 95dd7212e610..29f5b65bee29 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1077,6 +1077,7 @@ void __kprobes kprobe_flush_task(struct task_struct *tk) /* Early boot. kretprobe_table_locks not yet initialized. */ return; + INIT_HLIST_HEAD(&empty_rp); hash = hash_ptr(tk, KPROBE_HASH_BITS); head = &kretprobe_inst_table[hash]; kretprobe_table_lock(hash, &flags); @@ -1085,7 +1086,6 @@ void __kprobes kprobe_flush_task(struct task_struct *tk) recycle_rp_inst(ri, &empty_rp); } kretprobe_table_unlock(hash, &flags); - INIT_HLIST_HEAD(&empty_rp); hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { hlist_del(&ri->hlist); kfree(ri); diff --git a/kernel/module.c b/kernel/module.c index 178333c48d1e..2c932760fd33 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -62,12 +62,6 @@ #define CREATE_TRACE_POINTS #include <trace/events/module.h> -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt , a...) -#endif - #ifndef ARCH_SHF_SMALL #define ARCH_SHF_SMALL 0 #endif @@ -138,7 +132,6 @@ struct load_info { unsigned long len; Elf_Shdr *sechdrs; char *secstrings, *strtab; - unsigned long *strmap; unsigned long symoffs, stroffs; struct _ddebug *debug; unsigned int num_debug; @@ -410,7 +403,7 @@ const struct kernel_symbol *find_symbol(const char *name, return fsa.sym; } - DEBUGP("Failed to find symbol %s\n", name); + pr_debug("Failed to find symbol %s\n", name); return NULL; } EXPORT_SYMBOL_GPL(find_symbol); @@ -600,11 +593,11 @@ static int already_uses(struct module *a, struct module *b) list_for_each_entry(use, &b->source_list, source_list) { if (use->source == a) { - DEBUGP("%s uses %s!\n", a->name, b->name); + pr_debug("%s uses %s!\n", a->name, b->name); return 1; } } - DEBUGP("%s does not use %s!\n", a->name, b->name); + pr_debug("%s does not use %s!\n", a->name, b->name); return 0; } @@ -619,7 +612,7 @@ static int add_module_usage(struct module *a, struct module *b) { struct module_use *use; - DEBUGP("Allocating new usage for %s.\n", a->name); + pr_debug("Allocating new usage for %s.\n", a->name); use = kmalloc(sizeof(*use), GFP_ATOMIC); if (!use) { printk(KERN_WARNING "%s: out of memory loading\n", a->name); @@ -663,7 +656,7 @@ static void module_unload_free(struct module *mod) mutex_lock(&module_mutex); list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) { struct module *i = use->target; - DEBUGP("%s unusing %s\n", mod->name, i->name); + pr_debug("%s unusing %s\n", mod->name, i->name); module_put(i); list_del(&use->source_list); list_del(&use->target_list); @@ -726,9 +719,9 @@ static int try_stop_module(struct module *mod, int flags, int *forced) } } -unsigned int module_refcount(struct module *mod) +unsigned long module_refcount(struct module *mod) { - unsigned int incs = 0, decs = 0; + unsigned long incs = 0, decs = 0; int cpu; for_each_possible_cpu(cpu) @@ -761,7 +754,7 @@ static void wait_for_zero_refcount(struct module *mod) /* Since we might sleep for some time, release the mutex first */ mutex_unlock(&module_mutex); for (;;) { - DEBUGP("Looking at refcount...\n"); + pr_debug("Looking at refcount...\n"); set_current_state(TASK_UNINTERRUPTIBLE); if (module_refcount(mod) == 0) break; @@ -804,7 +797,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, if (mod->state != MODULE_STATE_LIVE) { /* FIXME: if (force), slam module count and wake up waiter --RR */ - DEBUGP("%s already dying\n", mod->name); + pr_debug("%s already dying\n", mod->name); ret = -EBUSY; goto out; } @@ -854,7 +847,7 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod) struct module_use *use; int printed_something = 0; - seq_printf(m, " %u ", module_refcount(mod)); + seq_printf(m, " %lu ", module_refcount(mod)); /* Always include a trailing , so userspace can differentiate between this and the old multi-field proc format. */ @@ -904,13 +897,11 @@ EXPORT_SYMBOL_GPL(symbol_put_addr); static ssize_t show_refcnt(struct module_attribute *mattr, struct module_kobject *mk, char *buffer) { - return sprintf(buffer, "%u\n", module_refcount(mk->mod)); + return sprintf(buffer, "%lu\n", module_refcount(mk->mod)); } -static struct module_attribute refcnt = { - .attr = { .name = "refcnt", .mode = 0444 }, - .show = show_refcnt, -}; +static struct module_attribute modinfo_refcnt = + __ATTR(refcnt, 0444, show_refcnt, NULL); void module_put(struct module *module) { @@ -951,6 +942,26 @@ static inline int module_unload_init(struct module *mod) } #endif /* CONFIG_MODULE_UNLOAD */ +static size_t module_flags_taint(struct module *mod, char *buf) +{ + size_t l = 0; + + if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE)) + buf[l++] = 'P'; + if (mod->taints & (1 << TAINT_OOT_MODULE)) + buf[l++] = 'O'; + if (mod->taints & (1 << TAINT_FORCED_MODULE)) + buf[l++] = 'F'; + if (mod->taints & (1 << TAINT_CRAP)) + buf[l++] = 'C'; + /* + * TAINT_FORCED_RMMOD: could be added. + * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't + * apply to modules. + */ + return l; +} + static ssize_t show_initstate(struct module_attribute *mattr, struct module_kobject *mk, char *buffer) { @@ -970,10 +981,8 @@ static ssize_t show_initstate(struct module_attribute *mattr, return sprintf(buffer, "%s\n", state); } -static struct module_attribute initstate = { - .attr = { .name = "initstate", .mode = 0444 }, - .show = show_initstate, -}; +static struct module_attribute modinfo_initstate = + __ATTR(initstate, 0444, show_initstate, NULL); static ssize_t store_uevent(struct module_attribute *mattr, struct module_kobject *mk, @@ -986,18 +995,50 @@ static ssize_t store_uevent(struct module_attribute *mattr, return count; } -struct module_attribute module_uevent = { - .attr = { .name = "uevent", .mode = 0200 }, - .store = store_uevent, -}; +struct module_attribute module_uevent = + __ATTR(uevent, 0200, NULL, store_uevent); + +static ssize_t show_coresize(struct module_attribute *mattr, + struct module_kobject *mk, char *buffer) +{ + return sprintf(buffer, "%u\n", mk->mod->core_size); +} + +static struct module_attribute modinfo_coresize = + __ATTR(coresize, 0444, show_coresize, NULL); + +static ssize_t show_initsize(struct module_attribute *mattr, + struct module_kobject *mk, char *buffer) +{ + return sprintf(buffer, "%u\n", mk->mod->init_size); +} + +static struct module_attribute modinfo_initsize = + __ATTR(initsize, 0444, show_initsize, NULL); + +static ssize_t show_taint(struct module_attribute *mattr, + struct module_kobject *mk, char *buffer) +{ + size_t l; + + l = module_flags_taint(mk->mod, buffer); + buffer[l++] = '\n'; + return l; +} + +static struct module_attribute modinfo_taint = + __ATTR(taint, 0444, show_taint, NULL); static struct module_attribute *modinfo_attrs[] = { + &module_uevent, &modinfo_version, &modinfo_srcversion, - &initstate, - &module_uevent, + &modinfo_initstate, + &modinfo_coresize, + &modinfo_initsize, + &modinfo_taint, #ifdef CONFIG_MODULE_UNLOAD - &refcnt, + &modinfo_refcnt, #endif NULL, }; @@ -1057,7 +1098,7 @@ static int check_version(Elf_Shdr *sechdrs, if (versions[i].crc == maybe_relocated(*crc, crc_owner)) return 1; - DEBUGP("Found checksum %lX vs module %lX\n", + pr_debug("Found checksum %lX vs module %lX\n", maybe_relocated(*crc, crc_owner), versions[i].crc); goto bad_version; } @@ -1834,7 +1875,7 @@ static int simplify_symbols(struct module *mod, const struct load_info *info) case SHN_COMMON: /* We compiled with -fno-common. These are not supposed to happen. */ - DEBUGP("Common symbol: %s\n", name); + pr_debug("Common symbol: %s\n", name); printk("%s: please compile with -fno-common\n", mod->name); ret = -ENOEXEC; @@ -1842,7 +1883,7 @@ static int simplify_symbols(struct module *mod, const struct load_info *info) case SHN_ABS: /* Don't need to do anything */ - DEBUGP("Absolute symbol: 0x%08lx\n", + pr_debug("Absolute symbol: 0x%08lx\n", (long)sym[i].st_value); break; @@ -1966,7 +2007,7 @@ static void layout_sections(struct module *mod, struct load_info *info) for (i = 0; i < info->hdr->e_shnum; i++) info->sechdrs[i].sh_entsize = ~0UL; - DEBUGP("Core section allocation order:\n"); + pr_debug("Core section allocation order:\n"); for (m = 0; m < ARRAY_SIZE(masks); ++m) { for (i = 0; i < info->hdr->e_shnum; ++i) { Elf_Shdr *s = &info->sechdrs[i]; @@ -1978,7 +2019,7 @@ static void layout_sections(struct module *mod, struct load_info *info) || strstarts(sname, ".init")) continue; s->sh_entsize = get_offset(mod, &mod->core_size, s, i); - DEBUGP("\t%s\n", name); + pr_debug("\t%s\n", sname); } switch (m) { case 0: /* executable */ @@ -1995,7 +2036,7 @@ static void layout_sections(struct module *mod, struct load_info *info) } } - DEBUGP("Init section allocation order:\n"); + pr_debug("Init section allocation order:\n"); for (m = 0; m < ARRAY_SIZE(masks); ++m) { for (i = 0; i < info->hdr->e_shnum; ++i) { Elf_Shdr *s = &info->sechdrs[i]; @@ -2008,7 +2049,7 @@ static void layout_sections(struct module *mod, struct load_info *info) continue; s->sh_entsize = (get_offset(mod, &mod->init_size, s, i) | INIT_OFFSET_MASK); - DEBUGP("\t%s\n", sname); + pr_debug("\t%s\n", sname); } switch (m) { case 0: /* executable */ @@ -2178,45 +2219,46 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs, return true; } +/* + * We only allocate and copy the strings needed by the parts of symtab + * we keep. This is simple, but has the effect of making multiple + * copies of duplicates. We could be more sophisticated, see + * linux-kernel thread starting with + * <73defb5e4bca04a6431392cc341112b1@localhost>. + */ static void layout_symtab(struct module *mod, struct load_info *info) { Elf_Shdr *symsect = info->sechdrs + info->index.sym; Elf_Shdr *strsect = info->sechdrs + info->index.str; const Elf_Sym *src; - unsigned int i, nsrc, ndst; + unsigned int i, nsrc, ndst, strtab_size; /* Put symbol section at end of init part of module. */ symsect->sh_flags |= SHF_ALLOC; symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect, info->index.sym) | INIT_OFFSET_MASK; - DEBUGP("\t%s\n", info->secstrings + symsect->sh_name); + pr_debug("\t%s\n", info->secstrings + symsect->sh_name); src = (void *)info->hdr + symsect->sh_offset; nsrc = symsect->sh_size / sizeof(*src); - for (ndst = i = 1; i < nsrc; ++i, ++src) - if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) { - unsigned int j = src->st_name; - while (!__test_and_set_bit(j, info->strmap) - && info->strtab[j]) - ++j; - ++ndst; + /* Compute total space required for the core symbols' strtab. */ + for (ndst = i = strtab_size = 1; i < nsrc; ++i, ++src) + if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) { + strtab_size += strlen(&info->strtab[src->st_name]) + 1; + ndst++; } /* Append room for core symbols at end of core part. */ info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1); - mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym); + info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym); + mod->core_size += strtab_size; /* Put string table section at end of init part of module. */ strsect->sh_flags |= SHF_ALLOC; strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect, info->index.str) | INIT_OFFSET_MASK; - DEBUGP("\t%s\n", info->secstrings + strsect->sh_name); - - /* Append room for core symbols' strings at end of core part. */ - info->stroffs = mod->core_size; - __set_bit(0, info->strmap); - mod->core_size += bitmap_weight(info->strmap, strsect->sh_size); + pr_debug("\t%s\n", info->secstrings + strsect->sh_name); } static void add_kallsyms(struct module *mod, const struct load_info *info) @@ -2237,22 +2279,19 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); mod->core_symtab = dst = mod->module_core + info->symoffs; + mod->core_strtab = s = mod->module_core + info->stroffs; src = mod->symtab; *dst = *src; + *s++ = 0; for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) { if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) continue; + dst[ndst] = *src; - dst[ndst].st_name = bitmap_weight(info->strmap, - dst[ndst].st_name); - ++ndst; + dst[ndst++].st_name = s - mod->core_strtab; + s += strlcpy(s, &mod->strtab[src->st_name], KSYM_NAME_LEN) + 1; } mod->core_num_syms = ndst; - - mod->core_strtab = s = mod->module_core + info->stroffs; - for (*s = 0, i = 1; i < info->sechdrs[info->index.str].sh_size; ++i) - if (test_bit(i, info->strmap)) - *++s = mod->strtab[i]; } #else static inline void layout_symtab(struct module *mod, struct load_info *info) @@ -2621,7 +2660,7 @@ static int move_module(struct module *mod, struct load_info *info) mod->module_init = ptr; /* Transfer each section which specifies SHF_ALLOC */ - DEBUGP("final section addresses:\n"); + pr_debug("final section addresses:\n"); for (i = 0; i < info->hdr->e_shnum; i++) { void *dest; Elf_Shdr *shdr = &info->sechdrs[i]; @@ -2639,8 +2678,8 @@ static int move_module(struct module *mod, struct load_info *info) memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size); /* Update sh_addr to point to copy in image. */ shdr->sh_addr = (unsigned long)dest; - DEBUGP("\t0x%lx %s\n", - shdr->sh_addr, info->secstrings + shdr->sh_name); + pr_debug("\t0x%lx %s\n", + (long)shdr->sh_addr, info->secstrings + shdr->sh_name); } return 0; @@ -2742,27 +2781,18 @@ static struct module *layout_and_allocate(struct load_info *info) this is done generically; there doesn't appear to be any special cases for the architectures. */ layout_sections(mod, info); - - info->strmap = kzalloc(BITS_TO_LONGS(info->sechdrs[info->index.str].sh_size) - * sizeof(long), GFP_KERNEL); - if (!info->strmap) { - err = -ENOMEM; - goto free_percpu; - } layout_symtab(mod, info); /* Allocate and move to the final place */ err = move_module(mod, info); if (err) - goto free_strmap; + goto free_percpu; /* Module has been copied to its final place now: return it. */ mod = (void *)info->sechdrs[info->index.mod].sh_addr; kmemleak_load_module(mod, info); return mod; -free_strmap: - kfree(info->strmap); free_percpu: percpu_modfree(mod); out: @@ -2772,7 +2802,6 @@ out: /* mod is no longer valid after this! */ static void module_deallocate(struct module *mod, struct load_info *info) { - kfree(info->strmap); percpu_modfree(mod); module_free(mod, mod->module_init); module_free(mod, mod->module_core); @@ -2811,7 +2840,7 @@ static struct module *load_module(void __user *umod, struct module *mod; long err; - DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", + pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n", umod, len, uargs); /* Copy in the blobs from userspace, check they are vaguely sane. */ @@ -2902,8 +2931,7 @@ static struct module *load_module(void __user *umod, if (err < 0) goto unlink; - /* Get rid of temporary copy and strmap. */ - kfree(info.strmap); + /* Get rid of temporary copy. */ free_copy(&info); /* Done! */ @@ -3256,20 +3284,7 @@ static char *module_flags(struct module *mod, char *buf) mod->state == MODULE_STATE_GOING || mod->state == MODULE_STATE_COMING) { buf[bx++] = '('; - if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE)) - buf[bx++] = 'P'; - else if (mod->taints & (1 << TAINT_OOT_MODULE)) - buf[bx++] = 'O'; - if (mod->taints & (1 << TAINT_FORCED_MODULE)) - buf[bx++] = 'F'; - if (mod->taints & (1 << TAINT_CRAP)) - buf[bx++] = 'C'; - /* - * TAINT_FORCED_RMMOD: could be added. - * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't - * apply to modules. - */ - + bx += module_flags_taint(mod, buf + bx); /* Show a - for module-is-being-unloaded */ if (mod->state == MODULE_STATE_GOING) buf[bx++] = '-'; diff --git a/kernel/params.c b/kernel/params.c index 65aae11eb93f..32ee04308285 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -25,12 +25,6 @@ #include <linux/slab.h> #include <linux/ctype.h> -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt, a...) -#endif - /* Protects all parameters, and incidentally kmalloced_param list. */ static DEFINE_MUTEX(param_lock); @@ -105,7 +99,7 @@ static int parse_one(char *param, /* No one handled NULL, so do it here. */ if (!val && params[i].ops->set != param_set_bool) return -EINVAL; - DEBUGP("They are equal! Calling %p\n", + pr_debug("They are equal! Calling %p\n", params[i].ops->set); mutex_lock(¶m_lock); err = params[i].ops->set(val, ¶ms[i]); @@ -115,11 +109,11 @@ static int parse_one(char *param, } if (handle_unknown) { - DEBUGP("Unknown argument: calling %p\n", handle_unknown); + pr_debug("Unknown argument: calling %p\n", handle_unknown); return handle_unknown(param, val); } - DEBUGP("Unknown argument `%s'\n", param); + pr_debug("Unknown argument `%s'\n", param); return -ENOENT; } @@ -184,7 +178,7 @@ int parse_args(const char *name, { char *param, *val; - DEBUGP("Parsing ARGS: %s\n", args); + pr_debug("Parsing ARGS: %s\n", args); /* Chew leading spaces */ args = skip_spaces(args); @@ -369,6 +363,30 @@ struct kernel_param_ops param_ops_invbool = { }; EXPORT_SYMBOL(param_ops_invbool); +int param_set_bint(const char *val, const struct kernel_param *kp) +{ + struct kernel_param boolkp; + bool v; + int ret; + + /* Match bool exactly, by re-using it. */ + boolkp = *kp; + boolkp.arg = &v; + boolkp.flags |= KPARAM_ISBOOL; + + ret = param_set_bool(val, &boolkp); + if (ret == 0) + *(int *)kp->arg = v; + return ret; +} +EXPORT_SYMBOL(param_set_bint); + +struct kernel_param_ops param_ops_bint = { + .set = param_set_bint, + .get = param_get_int, +}; +EXPORT_SYMBOL(param_ops_bint); + /* We break the rule and mangle the string. */ static int param_array(const char *name, const char *val, diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 1cf88900ec4f..6a768e537001 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -812,7 +812,8 @@ unsigned int snapshot_additional_pages(struct zone *zone) unsigned int res; res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); - res += DIV_ROUND_UP(res * sizeof(struct bm_block), PAGE_SIZE); + res += DIV_ROUND_UP(res * sizeof(struct bm_block), + LINKED_PAGE_DATA_SIZE); return 2 * res; } diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 3739ecced085..8742fd013a94 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -773,8 +773,7 @@ static int enough_swap(unsigned int nr_pages, unsigned int flags) pr_debug("PM: Free swap pages: %u\n", free_swap); - required = PAGES_FOR_IO + ((flags & SF_NOCOMPRESS_MODE) ? - nr_pages : (nr_pages * LZO_CMP_PAGES) / LZO_UNC_PAGES + 1); + required = PAGES_FOR_IO + nr_pages; return free_swap > required; } @@ -802,10 +801,12 @@ int swsusp_write(unsigned int flags) printk(KERN_ERR "PM: Cannot get swap writer\n"); return error; } - if (!enough_swap(pages, flags)) { - printk(KERN_ERR "PM: Not enough free swap\n"); - error = -ENOSPC; - goto out_finish; + if (flags & SF_NOCOMPRESS_MODE) { + if (!enough_swap(pages, flags)) { + printk(KERN_ERR "PM: Not enough free swap\n"); + error = -ENOSPC; + goto out_finish; + } } memset(&snapshot, 0, sizeof(struct snapshot_handle)); error = snapshot_read_next(&snapshot); diff --git a/kernel/printk.c b/kernel/printk.c index 989e4a52da76..13c0a1143f49 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -521,7 +521,7 @@ static void __call_console_drivers(unsigned start, unsigned end) } } -static int __read_mostly ignore_loglevel; +static bool __read_mostly ignore_loglevel; static int __init ignore_loglevel_setup(char *str) { @@ -532,7 +532,7 @@ static int __init ignore_loglevel_setup(char *str) } early_param("ignore_loglevel", ignore_loglevel_setup); -module_param_named(ignore_loglevel, ignore_loglevel, bool, S_IRUGO | S_IWUSR); +module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ignore_loglevel, "ignore loglevel setting, to" "print all kernel messages to the console."); @@ -696,9 +696,9 @@ static void zap_locks(void) } #if defined(CONFIG_PRINTK_TIME) -static int printk_time = 1; +static bool printk_time = 1; #else -static int printk_time = 0; +static bool printk_time = 0; #endif module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); @@ -1098,7 +1098,7 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha return -1; } -int console_suspend_enabled = 1; +bool console_suspend_enabled = 1; EXPORT_SYMBOL(console_suspend_enabled); static int __init console_suspend_disable(char *str) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 78ab24a7b0e4..00ab2ca5ed11 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -172,6 +172,14 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state) return ret; } +static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) +{ + if (mode & PTRACE_MODE_NOAUDIT) + return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); + else + return has_ns_capability(current, ns, CAP_SYS_PTRACE); +} + int __ptrace_may_access(struct task_struct *task, unsigned int mode) { const struct cred *cred = current_cred(), *tcred; @@ -198,7 +206,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) cred->gid == tcred->sgid && cred->gid == tcred->gid)) goto ok; - if (ns_capable(tcred->user->user_ns, CAP_SYS_PTRACE)) + if (ptrace_has_cap(tcred->user->user_ns, mode)) goto ok; rcu_read_unlock(); return -EPERM; @@ -207,7 +215,7 @@ ok: smp_rmb(); if (task->mm) dumpable = get_dumpable(task->mm); - if (!dumpable && !task_ns_capable(task, CAP_SYS_PTRACE)) + if (!dumpable && !ptrace_has_cap(task_user_ns(task), mode)) return -EPERM; return security_ptrace_access_check(task, mode); @@ -277,7 +285,7 @@ static int ptrace_attach(struct task_struct *task, long request, task->ptrace = PT_PTRACED; if (seize) task->ptrace |= PT_SEIZED; - if (task_ns_capable(task, CAP_SYS_PTRACE)) + if (ns_capable(task_user_ns(task), CAP_SYS_PTRACE)) task->ptrace |= PT_PTRACE_CAP; __ptrace_link(task, current); diff --git a/kernel/res_counter.c b/kernel/res_counter.c index 6d269cce7aa1..d508363858b3 100644 --- a/kernel/res_counter.c +++ b/kernel/res_counter.c @@ -66,6 +66,31 @@ done: return ret; } +int res_counter_charge_nofail(struct res_counter *counter, unsigned long val, + struct res_counter **limit_fail_at) +{ + int ret, r; + unsigned long flags; + struct res_counter *c; + + r = ret = 0; + *limit_fail_at = NULL; + local_irq_save(flags); + for (c = counter; c != NULL; c = c->parent) { + spin_lock(&c->lock); + r = res_counter_charge_locked(c, val); + if (r) + c->usage += val; + spin_unlock(&c->lock); + if (r < 0 && ret == 0) { + *limit_fail_at = c; + ret = r; + } + } + local_irq_restore(flags); + + return ret; +} void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val) { if (WARN_ON(counter->usage < val)) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index fd7b25e90079..df00cb09263e 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4330,7 +4330,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) goto out_free_cpus_allowed; } retval = -EPERM; - if (!check_same_owner(p) && !task_ns_capable(p, CAP_SYS_NICE)) + if (!check_same_owner(p) && !ns_capable(task_user_ns(p), CAP_SYS_NICE)) goto out_unlock; retval = security_task_setscheduler(p); diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index b0d798eaf130..d72586fdf660 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -129,7 +129,7 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p, * cpupri_set - update the cpu priority setting * @cp: The cpupri context * @cpu: The target cpu - * @pri: The priority (INVALID-RT99) to assign to this CPU + * @newpri: The priority (INVALID-RT99) to assign to this CPU * * Note: Assumes cpu_rq(cpu)->lock is locked * @@ -200,7 +200,6 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri) /** * cpupri_init - initialize the cpupri structure * @cp: The cpupri context - * @bootmem: true if allocations need to use bootmem * * Returns: -ENOMEM if memory fails. */ diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 57d4b13b631d..e8d76c5895ea 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -6,6 +6,7 @@ * This defines a simple but solid secure-computing mode. */ +#include <linux/audit.h> #include <linux/seccomp.h> #include <linux/sched.h> #include <linux/compat.h> @@ -54,6 +55,7 @@ void __secure_computing(int this_syscall) #ifdef SECCOMP_DEBUG dump_stack(); #endif + audit_seccomp(this_syscall); do_exit(SIGKILL); } diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index b1e8943fed1d..683d559a0eef 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -22,11 +22,13 @@ #include <linux/hardirq.h> #include <linux/kthread.h> #include <linux/uaccess.h> +#include <linux/bsearch.h> #include <linux/module.h> #include <linux/ftrace.h> #include <linux/sysctl.h> #include <linux/slab.h> #include <linux/ctype.h> +#include <linux/sort.h> #include <linux/list.h> #include <linux/hash.h> #include <linux/rcupdate.h> @@ -947,13 +949,6 @@ struct ftrace_func_probe { struct rcu_head rcu; }; -enum { - FTRACE_ENABLE_CALLS = (1 << 0), - FTRACE_DISABLE_CALLS = (1 << 1), - FTRACE_UPDATE_TRACE_FUNC = (1 << 2), - FTRACE_START_FUNC_RET = (1 << 3), - FTRACE_STOP_FUNC_RET = (1 << 4), -}; struct ftrace_func_entry { struct hlist_node hlist; unsigned long ip; @@ -984,18 +979,19 @@ static struct ftrace_ops global_ops = { .filter_hash = EMPTY_HASH, }; -static struct dyn_ftrace *ftrace_new_addrs; - static DEFINE_MUTEX(ftrace_regex_lock); struct ftrace_page { struct ftrace_page *next; + struct dyn_ftrace *records; int index; - struct dyn_ftrace records[]; + int size; }; -#define ENTRIES_PER_PAGE \ - ((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct dyn_ftrace)) +static struct ftrace_page *ftrace_new_pgs; + +#define ENTRY_SIZE sizeof(struct dyn_ftrace) +#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE) /* estimate from running different kernels */ #define NR_TO_INIT 10000 @@ -1003,7 +999,10 @@ struct ftrace_page { static struct ftrace_page *ftrace_pages_start; static struct ftrace_page *ftrace_pages; -static struct dyn_ftrace *ftrace_free_records; +static bool ftrace_hash_empty(struct ftrace_hash *hash) +{ + return !hash || !hash->count; +} static struct ftrace_func_entry * ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip) @@ -1013,7 +1012,7 @@ ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip) struct hlist_head *hhd; struct hlist_node *n; - if (!hash->count) + if (ftrace_hash_empty(hash)) return NULL; if (hash->size_bits > 0) @@ -1157,7 +1156,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash) return NULL; /* Empty hash? */ - if (!hash || !hash->count) + if (ftrace_hash_empty(hash)) return new_hash; size = 1 << hash->size_bits; @@ -1282,9 +1281,9 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) filter_hash = rcu_dereference_raw(ops->filter_hash); notrace_hash = rcu_dereference_raw(ops->notrace_hash); - if ((!filter_hash || !filter_hash->count || + if ((ftrace_hash_empty(filter_hash) || ftrace_lookup_ip(filter_hash, ip)) && - (!notrace_hash || !notrace_hash->count || + (ftrace_hash_empty(notrace_hash) || !ftrace_lookup_ip(notrace_hash, ip))) ret = 1; else @@ -1307,6 +1306,47 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) } \ } + +static int ftrace_cmp_recs(const void *a, const void *b) +{ + const struct dyn_ftrace *reca = a; + const struct dyn_ftrace *recb = b; + + if (reca->ip > recb->ip) + return 1; + if (reca->ip < recb->ip) + return -1; + return 0; +} + +/** + * ftrace_location - return true if the ip giving is a traced location + * @ip: the instruction pointer to check + * + * Returns 1 if @ip given is a pointer to a ftrace location. + * That is, the instruction that is either a NOP or call to + * the function tracer. It checks the ftrace internal tables to + * determine if the address belongs or not. + */ +int ftrace_location(unsigned long ip) +{ + struct ftrace_page *pg; + struct dyn_ftrace *rec; + struct dyn_ftrace key; + + key.ip = ip; + + for (pg = ftrace_pages_start; pg; pg = pg->next) { + rec = bsearch(&key, pg->records, pg->index, + sizeof(struct dyn_ftrace), + ftrace_cmp_recs); + if (rec) + return 1; + } + + return 0; +} + static void __ftrace_hash_rec_update(struct ftrace_ops *ops, int filter_hash, bool inc) @@ -1336,7 +1376,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, if (filter_hash) { hash = ops->filter_hash; other_hash = ops->notrace_hash; - if (!hash || !hash->count) + if (ftrace_hash_empty(hash)) all = 1; } else { inc = !inc; @@ -1346,7 +1386,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, * If the notrace hash has no items, * then there's nothing to do. */ - if (hash && !hash->count) + if (ftrace_hash_empty(hash)) return; } @@ -1363,8 +1403,8 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, if (!other_hash || !ftrace_lookup_ip(other_hash, rec->ip)) match = 1; } else { - in_hash = hash && !!ftrace_lookup_ip(hash, rec->ip); - in_other_hash = other_hash && !!ftrace_lookup_ip(other_hash, rec->ip); + in_hash = !!ftrace_lookup_ip(hash, rec->ip); + in_other_hash = !!ftrace_lookup_ip(other_hash, rec->ip); /* * @@ -1372,7 +1412,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, if (filter_hash && in_hash && !in_other_hash) match = 1; else if (!filter_hash && in_hash && - (in_other_hash || !other_hash->count)) + (in_other_hash || ftrace_hash_empty(other_hash))) match = 1; } if (!match) @@ -1406,40 +1446,12 @@ static void ftrace_hash_rec_enable(struct ftrace_ops *ops, __ftrace_hash_rec_update(ops, filter_hash, 1); } -static void ftrace_free_rec(struct dyn_ftrace *rec) -{ - rec->freelist = ftrace_free_records; - ftrace_free_records = rec; - rec->flags |= FTRACE_FL_FREE; -} - static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) { - struct dyn_ftrace *rec; - - /* First check for freed records */ - if (ftrace_free_records) { - rec = ftrace_free_records; - - if (unlikely(!(rec->flags & FTRACE_FL_FREE))) { - FTRACE_WARN_ON_ONCE(1); - ftrace_free_records = NULL; + if (ftrace_pages->index == ftrace_pages->size) { + /* We should have allocated enough */ + if (WARN_ON(!ftrace_pages->next)) return NULL; - } - - ftrace_free_records = rec->freelist; - memset(rec, 0, sizeof(*rec)); - return rec; - } - - if (ftrace_pages->index == ENTRIES_PER_PAGE) { - if (!ftrace_pages->next) { - /* allocate another page */ - ftrace_pages->next = - (void *)get_zeroed_page(GFP_KERNEL); - if (!ftrace_pages->next) - return NULL; - } ftrace_pages = ftrace_pages->next; } @@ -1459,8 +1471,6 @@ ftrace_record_ip(unsigned long ip) return NULL; rec->ip = ip; - rec->newlist = ftrace_new_addrs; - ftrace_new_addrs = rec; return rec; } @@ -1475,7 +1485,19 @@ static void print_ip_ins(const char *fmt, unsigned char *p) printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]); } -static void ftrace_bug(int failed, unsigned long ip) +/** + * ftrace_bug - report and shutdown function tracer + * @failed: The failed type (EFAULT, EINVAL, EPERM) + * @ip: The address that failed + * + * The arch code that enables or disables the function tracing + * can call ftrace_bug() when it has detected a problem in + * modifying the code. @failed should be one of either: + * EFAULT - if the problem happens on reading the @ip address + * EINVAL - if what is read at @ip is not what was expected + * EPERM - if the problem happens on writting to the @ip address + */ +void ftrace_bug(int failed, unsigned long ip) { switch (failed) { case -EFAULT: @@ -1517,24 +1539,19 @@ int ftrace_text_reserved(void *start, void *end) return 0; } - -static int -__ftrace_replace_code(struct dyn_ftrace *rec, int enable) +static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update) { - unsigned long ftrace_addr; unsigned long flag = 0UL; - ftrace_addr = (unsigned long)FTRACE_ADDR; - /* - * If we are enabling tracing: + * If we are updating calls: * * If the record has a ref count, then we need to enable it * because someone is using it. * * Otherwise we make sure its disabled. * - * If we are disabling tracing, then disable all records that + * If we are disabling calls, then disable all records that * are enabled. */ if (enable && (rec->flags & ~FTRACE_FL_MASK)) @@ -1542,18 +1559,72 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) /* If the state of this record hasn't changed, then do nothing */ if ((rec->flags & FTRACE_FL_ENABLED) == flag) - return 0; + return FTRACE_UPDATE_IGNORE; if (flag) { - rec->flags |= FTRACE_FL_ENABLED; + if (update) + rec->flags |= FTRACE_FL_ENABLED; + return FTRACE_UPDATE_MAKE_CALL; + } + + if (update) + rec->flags &= ~FTRACE_FL_ENABLED; + + return FTRACE_UPDATE_MAKE_NOP; +} + +/** + * ftrace_update_record, set a record that now is tracing or not + * @rec: the record to update + * @enable: set to 1 if the record is tracing, zero to force disable + * + * The records that represent all functions that can be traced need + * to be updated when tracing has been enabled. + */ +int ftrace_update_record(struct dyn_ftrace *rec, int enable) +{ + return ftrace_check_record(rec, enable, 1); +} + +/** + * ftrace_test_record, check if the record has been enabled or not + * @rec: the record to test + * @enable: set to 1 to check if enabled, 0 if it is disabled + * + * The arch code may need to test if a record is already set to + * tracing to determine how to modify the function code that it + * represents. + */ +int ftrace_test_record(struct dyn_ftrace *rec, int enable) +{ + return ftrace_check_record(rec, enable, 0); +} + +static int +__ftrace_replace_code(struct dyn_ftrace *rec, int enable) +{ + unsigned long ftrace_addr; + int ret; + + ftrace_addr = (unsigned long)FTRACE_ADDR; + + ret = ftrace_update_record(rec, enable); + + switch (ret) { + case FTRACE_UPDATE_IGNORE: + return 0; + + case FTRACE_UPDATE_MAKE_CALL: return ftrace_make_call(rec, ftrace_addr); + + case FTRACE_UPDATE_MAKE_NOP: + return ftrace_make_nop(NULL, rec, ftrace_addr); } - rec->flags &= ~FTRACE_FL_ENABLED; - return ftrace_make_nop(NULL, rec, ftrace_addr); + return -1; /* unknow ftrace bug */ } -static void ftrace_replace_code(int enable) +static void ftrace_replace_code(int update) { struct dyn_ftrace *rec; struct ftrace_page *pg; @@ -1563,11 +1634,7 @@ static void ftrace_replace_code(int enable) return; do_for_each_ftrace_rec(pg, rec) { - /* Skip over free records */ - if (rec->flags & FTRACE_FL_FREE) - continue; - - failed = __ftrace_replace_code(rec, enable); + failed = __ftrace_replace_code(rec, update); if (failed) { ftrace_bug(failed, rec->ip); /* Stop processing */ @@ -1576,6 +1643,78 @@ static void ftrace_replace_code(int enable) } while_for_each_ftrace_rec(); } +struct ftrace_rec_iter { + struct ftrace_page *pg; + int index; +}; + +/** + * ftrace_rec_iter_start, start up iterating over traced functions + * + * Returns an iterator handle that is used to iterate over all + * the records that represent address locations where functions + * are traced. + * + * May return NULL if no records are available. + */ +struct ftrace_rec_iter *ftrace_rec_iter_start(void) +{ + /* + * We only use a single iterator. + * Protected by the ftrace_lock mutex. + */ + static struct ftrace_rec_iter ftrace_rec_iter; + struct ftrace_rec_iter *iter = &ftrace_rec_iter; + + iter->pg = ftrace_pages_start; + iter->index = 0; + + /* Could have empty pages */ + while (iter->pg && !iter->pg->index) + iter->pg = iter->pg->next; + + if (!iter->pg) + return NULL; + + return iter; +} + +/** + * ftrace_rec_iter_next, get the next record to process. + * @iter: The handle to the iterator. + * + * Returns the next iterator after the given iterator @iter. + */ +struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter) +{ + iter->index++; + + if (iter->index >= iter->pg->index) { + iter->pg = iter->pg->next; + iter->index = 0; + + /* Could have empty pages */ + while (iter->pg && !iter->pg->index) + iter->pg = iter->pg->next; + } + + if (!iter->pg) + return NULL; + + return iter; +} + +/** + * ftrace_rec_iter_record, get the record at the iterator location + * @iter: The current iterator location + * + * Returns the record that the current @iter is at. + */ +struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter) +{ + return &iter->pg->records[iter->index]; +} + static int ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec) { @@ -1617,13 +1756,7 @@ static int __ftrace_modify_code(void *data) { int *command = data; - /* - * Do not call function tracer while we update the code. - * We are in stop machine, no worrying about races. - */ - function_trace_stop++; - - if (*command & FTRACE_ENABLE_CALLS) + if (*command & FTRACE_UPDATE_CALLS) ftrace_replace_code(1); else if (*command & FTRACE_DISABLE_CALLS) ftrace_replace_code(0); @@ -1636,21 +1769,33 @@ static int __ftrace_modify_code(void *data) else if (*command & FTRACE_STOP_FUNC_RET) ftrace_disable_ftrace_graph_caller(); -#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST - /* - * For archs that call ftrace_test_stop_func(), we must - * wait till after we update all the function callers - * before we update the callback. This keeps different - * ops that record different functions from corrupting - * each other. - */ - __ftrace_trace_function = __ftrace_trace_function_delay; -#endif - function_trace_stop--; - return 0; } +/** + * ftrace_run_stop_machine, go back to the stop machine method + * @command: The command to tell ftrace what to do + * + * If an arch needs to fall back to the stop machine method, the + * it can call this function. + */ +void ftrace_run_stop_machine(int command) +{ + stop_machine(__ftrace_modify_code, &command, NULL); +} + +/** + * arch_ftrace_update_code, modify the code to trace or not trace + * @command: The command that needs to be done + * + * Archs can override this function if it does not need to + * run stop_machine() to modify code. + */ +void __weak arch_ftrace_update_code(int command) +{ + ftrace_run_stop_machine(command); +} + static void ftrace_run_update_code(int command) { int ret; @@ -1659,8 +1804,31 @@ static void ftrace_run_update_code(int command) FTRACE_WARN_ON(ret); if (ret) return; + /* + * Do not call function tracer while we update the code. + * We are in stop machine. + */ + function_trace_stop++; - stop_machine(__ftrace_modify_code, &command, NULL); + /* + * By default we use stop_machine() to modify the code. + * But archs can do what ever they want as long as it + * is safe. The stop_machine() is the safest, but also + * produces the most overhead. + */ + arch_ftrace_update_code(command); + +#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST + /* + * For archs that call ftrace_test_stop_func(), we must + * wait till after we update all the function callers + * before we update the callback. This keeps different + * ops that record different functions from corrupting + * each other. + */ + __ftrace_trace_function = __ftrace_trace_function_delay; +#endif + function_trace_stop--; ret = ftrace_arch_code_modify_post_process(); FTRACE_WARN_ON(ret); @@ -1691,7 +1859,7 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) return -ENODEV; ftrace_start_up++; - command |= FTRACE_ENABLE_CALLS; + command |= FTRACE_UPDATE_CALLS; /* ops marked global share the filter hashes */ if (ops->flags & FTRACE_OPS_FL_GLOBAL) { @@ -1743,8 +1911,7 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command) if (ops != &global_ops || !global_start_up) ops->flags &= ~FTRACE_OPS_FL_ENABLED; - if (!ftrace_start_up) - command |= FTRACE_DISABLE_CALLS; + command |= FTRACE_UPDATE_CALLS; if (saved_ftrace_func != ftrace_trace_function) { saved_ftrace_func = ftrace_trace_function; @@ -1766,7 +1933,7 @@ static void ftrace_startup_sysctl(void) saved_ftrace_func = NULL; /* ftrace_start_up is true if we want ftrace running */ if (ftrace_start_up) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); + ftrace_run_update_code(FTRACE_UPDATE_CALLS); } static void ftrace_shutdown_sysctl(void) @@ -1788,14 +1955,16 @@ static int ops_traces_mod(struct ftrace_ops *ops) struct ftrace_hash *hash; hash = ops->filter_hash; - return !!(!hash || !hash->count); + return ftrace_hash_empty(hash); } static int ftrace_update_code(struct module *mod) { + struct ftrace_page *pg; struct dyn_ftrace *p; cycle_t start, stop; unsigned long ref = 0; + int i; /* * When adding a module, we need to check if tracers are @@ -1817,46 +1986,44 @@ static int ftrace_update_code(struct module *mod) start = ftrace_now(raw_smp_processor_id()); ftrace_update_cnt = 0; - while (ftrace_new_addrs) { + for (pg = ftrace_new_pgs; pg; pg = pg->next) { - /* If something went wrong, bail without enabling anything */ - if (unlikely(ftrace_disabled)) - return -1; + for (i = 0; i < pg->index; i++) { + /* If something went wrong, bail without enabling anything */ + if (unlikely(ftrace_disabled)) + return -1; - p = ftrace_new_addrs; - ftrace_new_addrs = p->newlist; - p->flags = ref; + p = &pg->records[i]; + p->flags = ref; - /* - * Do the initial record conversion from mcount jump - * to the NOP instructions. - */ - if (!ftrace_code_disable(mod, p)) { - ftrace_free_rec(p); - /* Game over */ - break; - } + /* + * Do the initial record conversion from mcount jump + * to the NOP instructions. + */ + if (!ftrace_code_disable(mod, p)) + break; - ftrace_update_cnt++; + ftrace_update_cnt++; - /* - * If the tracing is enabled, go ahead and enable the record. - * - * The reason not to enable the record immediatelly is the - * inherent check of ftrace_make_nop/ftrace_make_call for - * correct previous instructions. Making first the NOP - * conversion puts the module to the correct state, thus - * passing the ftrace_make_call check. - */ - if (ftrace_start_up && ref) { - int failed = __ftrace_replace_code(p, 1); - if (failed) { - ftrace_bug(failed, p->ip); - ftrace_free_rec(p); + /* + * If the tracing is enabled, go ahead and enable the record. + * + * The reason not to enable the record immediatelly is the + * inherent check of ftrace_make_nop/ftrace_make_call for + * correct previous instructions. Making first the NOP + * conversion puts the module to the correct state, thus + * passing the ftrace_make_call check. + */ + if (ftrace_start_up && ref) { + int failed = __ftrace_replace_code(p, 1); + if (failed) + ftrace_bug(failed, p->ip); } } } + ftrace_new_pgs = NULL; + stop = ftrace_now(raw_smp_processor_id()); ftrace_update_time = stop - start; ftrace_update_tot_cnt += ftrace_update_cnt; @@ -1864,57 +2031,108 @@ static int ftrace_update_code(struct module *mod) return 0; } -static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) +static int ftrace_allocate_records(struct ftrace_page *pg, int count) { - struct ftrace_page *pg; + int order; int cnt; - int i; - /* allocate a few pages */ - ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL); - if (!ftrace_pages_start) - return -1; + if (WARN_ON(!count)) + return -EINVAL; + + order = get_count_order(DIV_ROUND_UP(count, ENTRIES_PER_PAGE)); /* - * Allocate a few more pages. - * - * TODO: have some parser search vmlinux before - * final linking to find all calls to ftrace. - * Then we can: - * a) know how many pages to allocate. - * and/or - * b) set up the table then. - * - * The dynamic code is still necessary for - * modules. + * We want to fill as much as possible. No more than a page + * may be empty. */ + while ((PAGE_SIZE << order) / ENTRY_SIZE >= count + ENTRIES_PER_PAGE) + order--; - pg = ftrace_pages = ftrace_pages_start; + again: + pg->records = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); - cnt = num_to_init / ENTRIES_PER_PAGE; - pr_info("ftrace: allocating %ld entries in %d pages\n", - num_to_init, cnt + 1); + if (!pg->records) { + /* if we can't allocate this size, try something smaller */ + if (!order) + return -ENOMEM; + order >>= 1; + goto again; + } - for (i = 0; i < cnt; i++) { - pg->next = (void *)get_zeroed_page(GFP_KERNEL); + cnt = (PAGE_SIZE << order) / ENTRY_SIZE; + pg->size = cnt; - /* If we fail, we'll try later anyway */ - if (!pg->next) + if (cnt > count) + cnt = count; + + return cnt; +} + +static struct ftrace_page * +ftrace_allocate_pages(unsigned long num_to_init) +{ + struct ftrace_page *start_pg; + struct ftrace_page *pg; + int order; + int cnt; + + if (!num_to_init) + return 0; + + start_pg = pg = kzalloc(sizeof(*pg), GFP_KERNEL); + if (!pg) + return NULL; + + /* + * Try to allocate as much as possible in one continues + * location that fills in all of the space. We want to + * waste as little space as possible. + */ + for (;;) { + cnt = ftrace_allocate_records(pg, num_to_init); + if (cnt < 0) + goto free_pages; + + num_to_init -= cnt; + if (!num_to_init) break; + pg->next = kzalloc(sizeof(*pg), GFP_KERNEL); + if (!pg->next) + goto free_pages; + pg = pg->next; } - return 0; + return start_pg; + + free_pages: + while (start_pg) { + order = get_count_order(pg->size / ENTRIES_PER_PAGE); + free_pages((unsigned long)pg->records, order); + start_pg = pg->next; + kfree(pg); + pg = start_pg; + } + pr_info("ftrace: FAILED to allocate memory for functions\n"); + return NULL; } -enum { - FTRACE_ITER_FILTER = (1 << 0), - FTRACE_ITER_NOTRACE = (1 << 1), - FTRACE_ITER_PRINTALL = (1 << 2), - FTRACE_ITER_HASH = (1 << 3), - FTRACE_ITER_ENABLED = (1 << 4), -}; +static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) +{ + int cnt; + + if (!num_to_init) { + pr_info("ftrace: No functions to be traced?\n"); + return -1; + } + + cnt = num_to_init / ENTRIES_PER_PAGE; + pr_info("ftrace: allocating %ld entries in %d pages\n", + num_to_init, cnt + 1); + + return 0; +} #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ @@ -1980,6 +2198,9 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) void *p = NULL; loff_t l; + if (!(iter->flags & FTRACE_ITER_DO_HASH)) + return NULL; + if (iter->func_pos > *pos) return NULL; @@ -2023,7 +2244,7 @@ static void * t_next(struct seq_file *m, void *v, loff_t *pos) { struct ftrace_iterator *iter = m->private; - struct ftrace_ops *ops = &global_ops; + struct ftrace_ops *ops = iter->ops; struct dyn_ftrace *rec = NULL; if (unlikely(ftrace_disabled)) @@ -2047,9 +2268,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos) } } else { rec = &iter->pg->records[iter->idx++]; - if ((rec->flags & FTRACE_FL_FREE) || - - ((iter->flags & FTRACE_ITER_FILTER) && + if (((iter->flags & FTRACE_ITER_FILTER) && !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) || ((iter->flags & FTRACE_ITER_NOTRACE) && @@ -2081,7 +2300,7 @@ static void reset_iter_read(struct ftrace_iterator *iter) static void *t_start(struct seq_file *m, loff_t *pos) { struct ftrace_iterator *iter = m->private; - struct ftrace_ops *ops = &global_ops; + struct ftrace_ops *ops = iter->ops; void *p = NULL; loff_t l; @@ -2101,7 +2320,8 @@ static void *t_start(struct seq_file *m, loff_t *pos) * off, we can short cut and just print out that all * functions are enabled. */ - if (iter->flags & FTRACE_ITER_FILTER && !ops->filter_hash->count) { + if (iter->flags & FTRACE_ITER_FILTER && + ftrace_hash_empty(ops->filter_hash)) { if (*pos > 0) return t_hash_start(m, pos); iter->flags |= FTRACE_ITER_PRINTALL; @@ -2126,12 +2346,8 @@ static void *t_start(struct seq_file *m, loff_t *pos) break; } - if (!p) { - if (iter->flags & FTRACE_ITER_FILTER) - return t_hash_start(m, pos); - - return NULL; - } + if (!p) + return t_hash_start(m, pos); return iter; } @@ -2189,6 +2405,7 @@ ftrace_avail_open(struct inode *inode, struct file *file) return -ENOMEM; iter->pg = ftrace_pages_start; + iter->ops = &global_ops; ret = seq_open(file, &show_ftrace_seq_ops); if (!ret) { @@ -2217,6 +2434,7 @@ ftrace_enabled_open(struct inode *inode, struct file *file) iter->pg = ftrace_pages_start; iter->flags = FTRACE_ITER_ENABLED; + iter->ops = &global_ops; ret = seq_open(file, &show_ftrace_seq_ops); if (!ret) { @@ -2237,7 +2455,23 @@ static void ftrace_filter_reset(struct ftrace_hash *hash) mutex_unlock(&ftrace_lock); } -static int +/** + * ftrace_regex_open - initialize function tracer filter files + * @ops: The ftrace_ops that hold the hash filters + * @flag: The type of filter to process + * @inode: The inode, usually passed in to your open routine + * @file: The file, usually passed in to your open routine + * + * ftrace_regex_open() initializes the filter files for the + * @ops. Depending on @flag it may process the filter hash or + * the notrace hash of @ops. With this called from the open + * routine, you can use ftrace_filter_write() for the write + * routine if @flag has FTRACE_ITER_FILTER set, or + * ftrace_notrace_write() if @flag has FTRACE_ITER_NOTRACE set. + * ftrace_regex_lseek() should be used as the lseek routine, and + * release must call ftrace_regex_release(). + */ +int ftrace_regex_open(struct ftrace_ops *ops, int flag, struct inode *inode, struct file *file) { @@ -2306,8 +2540,9 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag, static int ftrace_filter_open(struct inode *inode, struct file *file) { - return ftrace_regex_open(&global_ops, FTRACE_ITER_FILTER, - inode, file); + return ftrace_regex_open(&global_ops, + FTRACE_ITER_FILTER | FTRACE_ITER_DO_HASH, + inode, file); } static int @@ -2317,7 +2552,7 @@ ftrace_notrace_open(struct inode *inode, struct file *file) inode, file); } -static loff_t +loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin) { loff_t ret; @@ -2426,7 +2661,6 @@ match_records(struct ftrace_hash *hash, char *buff, goto out_unlock; do_for_each_ftrace_rec(pg, rec) { - if (ftrace_match_record(rec, mod, search, search_len, type)) { ret = enter_record(hash, rec, not); if (ret < 0) { @@ -2871,14 +3105,14 @@ out_unlock: return ret; } -static ssize_t +ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos) { return ftrace_regex_write(file, ubuf, cnt, ppos, 1); } -static ssize_t +ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos) { @@ -2919,7 +3153,7 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, ret = ftrace_hash_move(ops, enable, orig_hash, hash); if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); + ftrace_run_update_code(FTRACE_UPDATE_CALLS); mutex_unlock(&ftrace_lock); @@ -3045,8 +3279,8 @@ static void __init set_ftrace_early_graph(char *buf) } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -static void __init -set_ftrace_early_filter(struct ftrace_ops *ops, char *buf, int enable) +void __init +ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable) { char *func; @@ -3059,17 +3293,16 @@ set_ftrace_early_filter(struct ftrace_ops *ops, char *buf, int enable) static void __init set_ftrace_early_filters(void) { if (ftrace_filter_buf[0]) - set_ftrace_early_filter(&global_ops, ftrace_filter_buf, 1); + ftrace_set_early_filter(&global_ops, ftrace_filter_buf, 1); if (ftrace_notrace_buf[0]) - set_ftrace_early_filter(&global_ops, ftrace_notrace_buf, 0); + ftrace_set_early_filter(&global_ops, ftrace_notrace_buf, 0); #ifdef CONFIG_FUNCTION_GRAPH_TRACER if (ftrace_graph_buf[0]) set_ftrace_early_graph(ftrace_graph_buf); #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ } -static int -ftrace_regex_release(struct inode *inode, struct file *file) +int ftrace_regex_release(struct inode *inode, struct file *file) { struct seq_file *m = (struct seq_file *)file->private_data; struct ftrace_iterator *iter; @@ -3107,7 +3340,7 @@ ftrace_regex_release(struct inode *inode, struct file *file) orig_hash, iter->hash); if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED) && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); + ftrace_run_update_code(FTRACE_UPDATE_CALLS); mutex_unlock(&ftrace_lock); } @@ -3270,9 +3503,6 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) do_for_each_ftrace_rec(pg, rec) { - if (rec->flags & FTRACE_FL_FREE) - continue; - if (ftrace_match_record(rec, NULL, search, search_len, type)) { /* if it is in the array */ exists = false; @@ -3381,15 +3611,62 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) return 0; } +static void ftrace_swap_recs(void *a, void *b, int size) +{ + struct dyn_ftrace *reca = a; + struct dyn_ftrace *recb = b; + struct dyn_ftrace t; + + t = *reca; + *reca = *recb; + *recb = t; +} + static int ftrace_process_locs(struct module *mod, unsigned long *start, unsigned long *end) { + struct ftrace_page *pg; + unsigned long count; unsigned long *p; unsigned long addr; unsigned long flags = 0; /* Shut up gcc */ + int ret = -ENOMEM; + + count = end - start; + + if (!count) + return 0; + + pg = ftrace_allocate_pages(count); + if (!pg) + return -ENOMEM; mutex_lock(&ftrace_lock); + + /* + * Core and each module needs their own pages, as + * modules will free them when they are removed. + * Force a new page to be allocated for modules. + */ + if (!mod) { + WARN_ON(ftrace_pages || ftrace_pages_start); + /* First initialization */ + ftrace_pages = ftrace_pages_start = pg; + } else { + if (!ftrace_pages) + goto out; + + if (WARN_ON(ftrace_pages->next)) { + /* Hmm, we have free pages? */ + while (ftrace_pages->next) + ftrace_pages = ftrace_pages->next; + } + + ftrace_pages->next = pg; + ftrace_pages = pg; + } + p = start; while (p < end) { addr = ftrace_call_adjust(*p++); @@ -3401,9 +3678,18 @@ static int ftrace_process_locs(struct module *mod, */ if (!addr) continue; - ftrace_record_ip(addr); + if (!ftrace_record_ip(addr)) + break; } + /* These new locations need to be initialized */ + ftrace_new_pgs = pg; + + /* Make each individual set of pages sorted by ips */ + for (; pg; pg = pg->next) + sort(pg->records, pg->index, sizeof(struct dyn_ftrace), + ftrace_cmp_recs, ftrace_swap_recs); + /* * We only need to disable interrupts on start up * because we are modifying code that an interrupt @@ -3417,32 +3703,55 @@ static int ftrace_process_locs(struct module *mod, ftrace_update_code(mod); if (!mod) local_irq_restore(flags); + ret = 0; + out: mutex_unlock(&ftrace_lock); - return 0; + return ret; } #ifdef CONFIG_MODULES + +#define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next) + void ftrace_release_mod(struct module *mod) { struct dyn_ftrace *rec; + struct ftrace_page **last_pg; struct ftrace_page *pg; + int order; mutex_lock(&ftrace_lock); if (ftrace_disabled) goto out_unlock; - do_for_each_ftrace_rec(pg, rec) { + /* + * Each module has its own ftrace_pages, remove + * them from the list. + */ + last_pg = &ftrace_pages_start; + for (pg = ftrace_pages_start; pg; pg = *last_pg) { + rec = &pg->records[0]; if (within_module_core(rec->ip, mod)) { /* - * rec->ip is changed in ftrace_free_rec() - * It should not between s and e if record was freed. + * As core pages are first, the first + * page should never be a module page. */ - FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE); - ftrace_free_rec(rec); - } - } while_for_each_ftrace_rec(); + if (WARN_ON(pg == ftrace_pages_start)) + goto out_unlock; + + /* Check if we are deleting the last page */ + if (pg == ftrace_pages) + ftrace_pages = next_to_ftrace_page(last_pg); + + *last_pg = pg->next; + order = get_count_order(pg->size / ENTRIES_PER_PAGE); + free_pages((unsigned long)pg->records, order); + kfree(pg); + } else + last_pg = &pg->next; + } out_unlock: mutex_unlock(&ftrace_lock); } diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index f04cc3136bd3..24aee7127451 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -1738,11 +1738,121 @@ static int replace_system_preds(struct event_subsystem *system, return -ENOMEM; } +static int create_filter_start(char *filter_str, bool set_str, + struct filter_parse_state **psp, + struct event_filter **filterp) +{ + struct event_filter *filter; + struct filter_parse_state *ps = NULL; + int err = 0; + + WARN_ON_ONCE(*psp || *filterp); + + /* allocate everything, and if any fails, free all and fail */ + filter = __alloc_filter(); + if (filter && set_str) + err = replace_filter_string(filter, filter_str); + + ps = kzalloc(sizeof(*ps), GFP_KERNEL); + + if (!filter || !ps || err) { + kfree(ps); + __free_filter(filter); + return -ENOMEM; + } + + /* we're committed to creating a new filter */ + *filterp = filter; + *psp = ps; + + parse_init(ps, filter_ops, filter_str); + err = filter_parse(ps); + if (err && set_str) + append_filter_err(ps, filter); + return err; +} + +static void create_filter_finish(struct filter_parse_state *ps) +{ + if (ps) { + filter_opstack_clear(ps); + postfix_clear(ps); + kfree(ps); + } +} + +/** + * create_filter - create a filter for a ftrace_event_call + * @call: ftrace_event_call to create a filter for + * @filter_str: filter string + * @set_str: remember @filter_str and enable detailed error in filter + * @filterp: out param for created filter (always updated on return) + * + * Creates a filter for @call with @filter_str. If @set_str is %true, + * @filter_str is copied and recorded in the new filter. + * + * On success, returns 0 and *@filterp points to the new filter. On + * failure, returns -errno and *@filterp may point to %NULL or to a new + * filter. In the latter case, the returned filter contains error + * information if @set_str is %true and the caller is responsible for + * freeing it. + */ +static int create_filter(struct ftrace_event_call *call, + char *filter_str, bool set_str, + struct event_filter **filterp) +{ + struct event_filter *filter = NULL; + struct filter_parse_state *ps = NULL; + int err; + + err = create_filter_start(filter_str, set_str, &ps, &filter); + if (!err) { + err = replace_preds(call, filter, ps, filter_str, false); + if (err && set_str) + append_filter_err(ps, filter); + } + create_filter_finish(ps); + + *filterp = filter; + return err; +} + +/** + * create_system_filter - create a filter for an event_subsystem + * @system: event_subsystem to create a filter for + * @filter_str: filter string + * @filterp: out param for created filter (always updated on return) + * + * Identical to create_filter() except that it creates a subsystem filter + * and always remembers @filter_str. + */ +static int create_system_filter(struct event_subsystem *system, + char *filter_str, struct event_filter **filterp) +{ + struct event_filter *filter = NULL; + struct filter_parse_state *ps = NULL; + int err; + + err = create_filter_start(filter_str, true, &ps, &filter); + if (!err) { + err = replace_system_preds(system, ps, filter_str); + if (!err) { + /* System filters just show a default message */ + kfree(filter->filter_string); + filter->filter_string = NULL; + } else { + append_filter_err(ps, filter); + } + } + create_filter_finish(ps); + + *filterp = filter; + return err; +} + int apply_event_filter(struct ftrace_event_call *call, char *filter_string) { - struct filter_parse_state *ps; struct event_filter *filter; - struct event_filter *tmp; int err = 0; mutex_lock(&event_mutex); @@ -1759,49 +1869,30 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) goto out_unlock; } - err = -ENOMEM; - ps = kzalloc(sizeof(*ps), GFP_KERNEL); - if (!ps) - goto out_unlock; - - filter = __alloc_filter(); - if (!filter) { - kfree(ps); - goto out_unlock; - } - - replace_filter_string(filter, filter_string); - - parse_init(ps, filter_ops, filter_string); - err = filter_parse(ps); - if (err) { - append_filter_err(ps, filter); - goto out; - } + err = create_filter(call, filter_string, true, &filter); - err = replace_preds(call, filter, ps, filter_string, false); - if (err) { - filter_disable(call); - append_filter_err(ps, filter); - } else - call->flags |= TRACE_EVENT_FL_FILTERED; -out: /* * Always swap the call filter with the new filter * even if there was an error. If there was an error * in the filter, we disable the filter and show the error * string */ - tmp = call->filter; - rcu_assign_pointer(call->filter, filter); - if (tmp) { - /* Make sure the call is done with the filter */ - synchronize_sched(); - __free_filter(tmp); + if (filter) { + struct event_filter *tmp = call->filter; + + if (!err) + call->flags |= TRACE_EVENT_FL_FILTERED; + else + filter_disable(call); + + rcu_assign_pointer(call->filter, filter); + + if (tmp) { + /* Make sure the call is done with the filter */ + synchronize_sched(); + __free_filter(tmp); + } } - filter_opstack_clear(ps); - postfix_clear(ps); - kfree(ps); out_unlock: mutex_unlock(&event_mutex); @@ -1811,7 +1902,6 @@ out_unlock: int apply_subsystem_event_filter(struct event_subsystem *system, char *filter_string) { - struct filter_parse_state *ps; struct event_filter *filter; int err = 0; @@ -1835,48 +1925,19 @@ int apply_subsystem_event_filter(struct event_subsystem *system, goto out_unlock; } - err = -ENOMEM; - ps = kzalloc(sizeof(*ps), GFP_KERNEL); - if (!ps) - goto out_unlock; - - filter = __alloc_filter(); - if (!filter) - goto out; - - /* System filters just show a default message */ - kfree(filter->filter_string); - filter->filter_string = NULL; - - /* - * No event actually uses the system filter - * we can free it without synchronize_sched(). - */ - __free_filter(system->filter); - system->filter = filter; - - parse_init(ps, filter_ops, filter_string); - err = filter_parse(ps); - if (err) - goto err_filter; - - err = replace_system_preds(system, ps, filter_string); - if (err) - goto err_filter; - -out: - filter_opstack_clear(ps); - postfix_clear(ps); - kfree(ps); + err = create_system_filter(system, filter_string, &filter); + if (filter) { + /* + * No event actually uses the system filter + * we can free it without synchronize_sched(). + */ + __free_filter(system->filter); + system->filter = filter; + } out_unlock: mutex_unlock(&event_mutex); return err; - -err_filter: - replace_filter_string(filter, filter_string); - append_filter_err(ps, system->filter); - goto out; } #ifdef CONFIG_PERF_EVENTS @@ -1894,7 +1955,6 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, { int err; struct event_filter *filter; - struct filter_parse_state *ps; struct ftrace_event_call *call; mutex_lock(&event_mutex); @@ -1909,33 +1969,10 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, if (event->filter) goto out_unlock; - filter = __alloc_filter(); - if (!filter) { - err = PTR_ERR(filter); - goto out_unlock; - } - - err = -ENOMEM; - ps = kzalloc(sizeof(*ps), GFP_KERNEL); - if (!ps) - goto free_filter; - - parse_init(ps, filter_ops, filter_str); - err = filter_parse(ps); - if (err) - goto free_ps; - - err = replace_preds(call, filter, ps, filter_str, false); + err = create_filter(call, filter_str, false, &filter); if (!err) event->filter = filter; - -free_ps: - filter_opstack_clear(ps); - postfix_clear(ps); - kfree(ps); - -free_filter: - if (err) + else __free_filter(filter); out_unlock: @@ -1954,43 +1991,6 @@ out_unlock: #define CREATE_TRACE_POINTS #include "trace_events_filter_test.h" -static int test_get_filter(char *filter_str, struct ftrace_event_call *call, - struct event_filter **pfilter) -{ - struct event_filter *filter; - struct filter_parse_state *ps; - int err = -ENOMEM; - - filter = __alloc_filter(); - if (!filter) - goto out; - - ps = kzalloc(sizeof(*ps), GFP_KERNEL); - if (!ps) - goto free_filter; - - parse_init(ps, filter_ops, filter_str); - err = filter_parse(ps); - if (err) - goto free_ps; - - err = replace_preds(call, filter, ps, filter_str, false); - if (!err) - *pfilter = filter; - - free_ps: - filter_opstack_clear(ps); - postfix_clear(ps); - kfree(ps); - - free_filter: - if (err) - __free_filter(filter); - - out: - return err; -} - #define DATA_REC(m, va, vb, vc, vd, ve, vf, vg, vh, nvisit) \ { \ .filter = FILTER, \ @@ -2109,12 +2109,13 @@ static __init int ftrace_test_event_filter(void) struct test_filter_data_t *d = &test_filter_data[i]; int err; - err = test_get_filter(d->filter, &event_ftrace_test_filter, - &filter); + err = create_filter(&event_ftrace_test_filter, d->filter, + false, &filter); if (err) { printk(KERN_INFO "Failed to get filter for '%s', err %d\n", d->filter, err); + __free_filter(filter); break; } diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 77575b386d97..d4545f49242e 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -13,6 +13,9 @@ #include <linux/sysctl.h> #include <linux/init.h> #include <linux/fs.h> + +#include <asm/setup.h> + #include "trace.h" #define STACK_TRACE_ENTRIES 500 @@ -133,7 +136,6 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip) static struct ftrace_ops trace_ops __read_mostly = { .func = stack_trace_call, - .flags = FTRACE_OPS_FL_GLOBAL, }; static ssize_t @@ -311,6 +313,21 @@ static const struct file_operations stack_trace_fops = { .release = seq_release, }; +static int +stack_trace_filter_open(struct inode *inode, struct file *file) +{ + return ftrace_regex_open(&trace_ops, FTRACE_ITER_FILTER, + inode, file); +} + +static const struct file_operations stack_trace_filter_fops = { + .open = stack_trace_filter_open, + .read = seq_read, + .write = ftrace_filter_write, + .llseek = ftrace_regex_lseek, + .release = ftrace_regex_release, +}; + int stack_trace_sysctl(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, @@ -338,8 +355,13 @@ stack_trace_sysctl(struct ctl_table *table, int write, return ret; } +static char stack_trace_filter_buf[COMMAND_LINE_SIZE+1] __initdata; + static __init int enable_stacktrace(char *str) { + if (strncmp(str, "_filter=", 8) == 0) + strncpy(stack_trace_filter_buf, str+8, COMMAND_LINE_SIZE); + stack_tracer_enabled = 1; last_stack_tracer_enabled = 1; return 1; @@ -358,6 +380,12 @@ static __init int stack_trace_init(void) trace_create_file("stack_trace", 0444, d_tracer, NULL, &stack_trace_fops); + trace_create_file("stack_trace_filter", 0444, d_tracer, + NULL, &stack_trace_filter_fops); + + if (stack_trace_filter_buf[0]) + ftrace_set_early_filter(&trace_ops, stack_trace_filter_buf, 1); + if (stack_tracer_enabled) register_ftrace_function(&trace_ops); diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index db110b8ae030..f1539decd99d 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -634,10 +634,11 @@ static int tracepoint_module_coming(struct module *mod) int ret = 0; /* - * We skip modules that tain the kernel, especially those with different - * module header (for forced load), to make sure we don't cause a crash. + * We skip modules that taint the kernel, especially those with different + * module headers (for forced load), to make sure we don't cause a crash. + * Staging and out-of-tree GPL modules are fine. */ - if (mod->taints) + if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP))) return 0; mutex_lock(&tracepoints_mutex); tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL); diff --git a/lib/Kconfig b/lib/Kconfig index 201e1b33d721..169eb7c598e5 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -286,25 +286,24 @@ config CORDIC calculations are in fixed point. Module will be called cordic. config MPILIB - tristate "Multiprecision maths library" + tristate help Multiprecision maths library from GnuPG. It is used to implement RSA digital signature verification, which is used by IMA/EVM digital signature extension. config MPILIB_EXTRA - bool "Multiprecision maths library - additional sources" + bool depends on MPILIB help - Multiprecision maths library from GnuPG. - It is used to implement RSA digital signature verification, - which is used by IMA/EVM digital signature extension. - This code in unnecessary for RSA digital signature verification, - and can be compiled if needed. + Additional sources of multiprecision maths library from GnuPG. + This code is unnecessary for RSA digital signature verification, + but can be compiled if needed. -config DIGSIG - tristate "In-kernel signature checker" - depends on KEYS +config SIGNATURE + tristate + depends on KEYS && CRYPTO + select CRYPTO_SHA1 select MPILIB help Digital signature verification. Currently only RSA is supported. diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 82928f5ea049..8745ac7d1f75 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -414,7 +414,7 @@ config SLUB_STATS config DEBUG_KMEMLEAK bool "Kernel memory leak detector" - depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \ + depends on DEBUG_KERNEL && EXPERIMENTAL && \ (X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE) select DEBUG_FS diff --git a/lib/Makefile b/lib/Makefile index dace162c7e1c..d71aae1b01b3 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -119,7 +119,7 @@ obj-$(CONFIG_CORDIC) += cordic.o obj-$(CONFIG_DQL) += dynamic_queue_limits.o obj-$(CONFIG_MPILIB) += mpi/ -obj-$(CONFIG_DIGSIG) += digsig.o +obj-$(CONFIG_SIGNATURE) += digsig.o hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c index fe84bb978e3b..716802b774ea 100644 --- a/lib/mpi/mpicoder.c +++ b/lib/mpi/mpicoder.c @@ -255,6 +255,8 @@ void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) if (!n) n++; /* avoid zero length allocation */ p = buffer = kmalloc(n, GFP_KERNEL); + if (!p) + return NULL; for (i = a->nlimbs - 1; i >= 0; i--) { alimb = a->d[i]; diff --git a/mm/hugetlb.c b/mm/hugetlb.c index ea8c3a4cd2ae..5f34bd8dda34 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2508,6 +2508,7 @@ static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma, { struct hstate *h = hstate_vma(vma); int ret = VM_FAULT_SIGBUS; + int anon_rmap = 0; pgoff_t idx; unsigned long size; struct page *page; @@ -2562,14 +2563,13 @@ retry: spin_lock(&inode->i_lock); inode->i_blocks += blocks_per_huge_page(h); spin_unlock(&inode->i_lock); - page_dup_rmap(page); } else { lock_page(page); if (unlikely(anon_vma_prepare(vma))) { ret = VM_FAULT_OOM; goto backout_unlocked; } - hugepage_add_new_anon_rmap(page, vma, address); + anon_rmap = 1; } } else { /* @@ -2582,7 +2582,6 @@ retry: VM_FAULT_SET_HINDEX(h - hstates); goto backout_unlocked; } - page_dup_rmap(page); } /* @@ -2606,6 +2605,10 @@ retry: if (!huge_pte_none(huge_ptep_get(ptep))) goto backout; + if (anon_rmap) + hugepage_add_new_anon_rmap(page, vma, address); + else + page_dup_rmap(page); new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_SHARED))); set_huge_pte_at(mm, address, ptep, new_pte); diff --git a/mm/kmemleak.c b/mm/kmemleak.c index f3b2a00fe9c1..c833addd94d7 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -100,6 +100,7 @@ #include <linux/kmemcheck.h> #include <linux/kmemleak.h> +#include <linux/memory_hotplug.h> /* * Kmemleak configuration and common defines. @@ -196,7 +197,9 @@ static atomic_t kmemleak_enabled = ATOMIC_INIT(0); static atomic_t kmemleak_initialized = ATOMIC_INIT(0); /* enables or disables early logging of the memory operations */ static atomic_t kmemleak_early_log = ATOMIC_INIT(1); -/* set if a fata kmemleak error has occurred */ +/* set if a kmemleak warning was issued */ +static atomic_t kmemleak_warning = ATOMIC_INIT(0); +/* set if a fatal kmemleak error has occurred */ static atomic_t kmemleak_error = ATOMIC_INIT(0); /* minimum and maximum address that may be valid pointers */ @@ -228,8 +231,10 @@ static int kmemleak_skip_disable; /* kmemleak operation type for early logging */ enum { KMEMLEAK_ALLOC, + KMEMLEAK_ALLOC_PERCPU, KMEMLEAK_FREE, KMEMLEAK_FREE_PART, + KMEMLEAK_FREE_PERCPU, KMEMLEAK_NOT_LEAK, KMEMLEAK_IGNORE, KMEMLEAK_SCAN_AREA, @@ -259,9 +264,10 @@ static void kmemleak_disable(void); /* * Print a warning and dump the stack trace. */ -#define kmemleak_warn(x...) do { \ - pr_warning(x); \ - dump_stack(); \ +#define kmemleak_warn(x...) do { \ + pr_warning(x); \ + dump_stack(); \ + atomic_set(&kmemleak_warning, 1); \ } while (0) /* @@ -403,8 +409,8 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias) object = prio_tree_entry(node, struct kmemleak_object, tree_node); if (!alias && object->pointer != ptr) { - pr_warning("Found object by alias at 0x%08lx\n", ptr); - dump_stack(); + kmemleak_warn("Found object by alias at 0x%08lx\n", + ptr); dump_object_info(object); object = NULL; } @@ -794,9 +800,13 @@ static void __init log_early(int op_type, const void *ptr, size_t size, unsigned long flags; struct early_log *log; + if (atomic_read(&kmemleak_error)) { + /* kmemleak stopped recording, just count the requests */ + crt_early_log++; + return; + } + if (crt_early_log >= ARRAY_SIZE(early_log)) { - pr_warning("Early log buffer exceeded, " - "please increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE\n"); kmemleak_disable(); return; } @@ -811,8 +821,7 @@ static void __init log_early(int op_type, const void *ptr, size_t size, log->ptr = ptr; log->size = size; log->min_count = min_count; - if (op_type == KMEMLEAK_ALLOC) - log->trace_len = __save_stack_trace(log->trace); + log->trace_len = __save_stack_trace(log->trace); crt_early_log++; local_irq_restore(flags); } @@ -846,6 +855,20 @@ out: rcu_read_unlock(); } +/* + * Log an early allocated block and populate the stack trace. + */ +static void early_alloc_percpu(struct early_log *log) +{ + unsigned int cpu; + const void __percpu *ptr = log->ptr; + + for_each_possible_cpu(cpu) { + log->ptr = per_cpu_ptr(ptr, cpu); + early_alloc(log); + } +} + /** * kmemleak_alloc - register a newly allocated object * @ptr: pointer to beginning of the object @@ -873,6 +896,34 @@ void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count, EXPORT_SYMBOL_GPL(kmemleak_alloc); /** + * kmemleak_alloc_percpu - register a newly allocated __percpu object + * @ptr: __percpu pointer to beginning of the object + * @size: size of the object + * + * This function is called from the kernel percpu allocator when a new object + * (memory block) is allocated (alloc_percpu). It assumes GFP_KERNEL + * allocation. + */ +void __ref kmemleak_alloc_percpu(const void __percpu *ptr, size_t size) +{ + unsigned int cpu; + + pr_debug("%s(0x%p, %zu)\n", __func__, ptr, size); + + /* + * Percpu allocations are only scanned and not reported as leaks + * (min_count is set to 0). + */ + if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + for_each_possible_cpu(cpu) + create_object((unsigned long)per_cpu_ptr(ptr, cpu), + size, 0, GFP_KERNEL); + else if (atomic_read(&kmemleak_early_log)) + log_early(KMEMLEAK_ALLOC_PERCPU, ptr, size, 0); +} +EXPORT_SYMBOL_GPL(kmemleak_alloc_percpu); + +/** * kmemleak_free - unregister a previously registered object * @ptr: pointer to beginning of the object * @@ -911,6 +962,28 @@ void __ref kmemleak_free_part(const void *ptr, size_t size) EXPORT_SYMBOL_GPL(kmemleak_free_part); /** + * kmemleak_free_percpu - unregister a previously registered __percpu object + * @ptr: __percpu pointer to beginning of the object + * + * This function is called from the kernel percpu allocator when an object + * (memory block) is freed (free_percpu). + */ +void __ref kmemleak_free_percpu(const void __percpu *ptr) +{ + unsigned int cpu; + + pr_debug("%s(0x%p)\n", __func__, ptr); + + if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr)) + for_each_possible_cpu(cpu) + delete_object_full((unsigned long)per_cpu_ptr(ptr, + cpu)); + else if (atomic_read(&kmemleak_early_log)) + log_early(KMEMLEAK_FREE_PERCPU, ptr, 0, 0); +} +EXPORT_SYMBOL_GPL(kmemleak_free_percpu); + +/** * kmemleak_not_leak - mark an allocated object as false positive * @ptr: pointer to beginning of the object * @@ -1220,9 +1293,9 @@ static void kmemleak_scan(void) #endif /* - * Struct page scanning for each node. The code below is not yet safe - * with MEMORY_HOTPLUG. + * Struct page scanning for each node. */ + lock_memory_hotplug(); for_each_online_node(i) { pg_data_t *pgdat = NODE_DATA(i); unsigned long start_pfn = pgdat->node_start_pfn; @@ -1241,6 +1314,7 @@ static void kmemleak_scan(void) scan_block(page, page + 1, NULL, 1); } } + unlock_memory_hotplug(); /* * Scanning the task stacks (may introduce false negatives). @@ -1467,9 +1541,6 @@ static const struct seq_operations kmemleak_seq_ops = { static int kmemleak_open(struct inode *inode, struct file *file) { - if (!atomic_read(&kmemleak_enabled)) - return -EBUSY; - return seq_open(file, &kmemleak_seq_ops); } @@ -1543,6 +1614,9 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, int buf_size; int ret; + if (!atomic_read(&kmemleak_enabled)) + return -EBUSY; + buf_size = min(size, (sizeof(buf) - 1)); if (strncpy_from_user(buf, user_buf, buf_size) < 0) return -EFAULT; @@ -1602,20 +1676,24 @@ static const struct file_operations kmemleak_fops = { }; /* - * Perform the freeing of the kmemleak internal objects after waiting for any - * current memory scan to complete. + * Stop the memory scanning thread and free the kmemleak internal objects if + * no previous scan thread (otherwise, kmemleak may still have some useful + * information on memory leaks). */ static void kmemleak_do_cleanup(struct work_struct *work) { struct kmemleak_object *object; + bool cleanup = scan_thread == NULL; mutex_lock(&scan_mutex); stop_scan_thread(); - rcu_read_lock(); - list_for_each_entry_rcu(object, &object_list, object_list) - delete_object_full(object->pointer); - rcu_read_unlock(); + if (cleanup) { + rcu_read_lock(); + list_for_each_entry_rcu(object, &object_list, object_list) + delete_object_full(object->pointer); + rcu_read_unlock(); + } mutex_unlock(&scan_mutex); } @@ -1632,7 +1710,6 @@ static void kmemleak_disable(void) return; /* stop any memory operation tracing */ - atomic_set(&kmemleak_early_log, 0); atomic_set(&kmemleak_enabled, 0); /* check whether it is too early for a kernel thread */ @@ -1659,6 +1736,17 @@ static int kmemleak_boot_config(char *str) } early_param("kmemleak", kmemleak_boot_config); +static void __init print_log_trace(struct early_log *log) +{ + struct stack_trace trace; + + trace.nr_entries = log->trace_len; + trace.entries = log->trace; + + pr_notice("Early log backtrace:\n"); + print_stack_trace(&trace, 2); +} + /* * Kmemleak initialization. */ @@ -1681,12 +1769,18 @@ void __init kmemleak_init(void) scan_area_cache = KMEM_CACHE(kmemleak_scan_area, SLAB_NOLEAKTRACE); INIT_PRIO_TREE_ROOT(&object_tree_root); + if (crt_early_log >= ARRAY_SIZE(early_log)) + pr_warning("Early log buffer exceeded (%d), please increase " + "DEBUG_KMEMLEAK_EARLY_LOG_SIZE\n", crt_early_log); + /* the kernel is still in UP mode, so disabling the IRQs is enough */ local_irq_save(flags); - if (!atomic_read(&kmemleak_error)) { + atomic_set(&kmemleak_early_log, 0); + if (atomic_read(&kmemleak_error)) { + local_irq_restore(flags); + return; + } else atomic_set(&kmemleak_enabled, 1); - atomic_set(&kmemleak_early_log, 0); - } local_irq_restore(flags); /* @@ -1701,12 +1795,18 @@ void __init kmemleak_init(void) case KMEMLEAK_ALLOC: early_alloc(log); break; + case KMEMLEAK_ALLOC_PERCPU: + early_alloc_percpu(log); + break; case KMEMLEAK_FREE: kmemleak_free(log->ptr); break; case KMEMLEAK_FREE_PART: kmemleak_free_part(log->ptr, log->size); break; + case KMEMLEAK_FREE_PERCPU: + kmemleak_free_percpu(log->ptr); + break; case KMEMLEAK_NOT_LEAK: kmemleak_not_leak(log->ptr); break; @@ -1720,7 +1820,13 @@ void __init kmemleak_init(void) kmemleak_no_scan(log->ptr); break; default: - WARN_ON(1); + kmemleak_warn("Unknown early log operation: %d\n", + log->op_type); + } + + if (atomic_read(&kmemleak_warning)) { + print_log_trace(log); + atomic_set(&kmemleak_warning, 0); } } } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3dbff4dcde35..556859fec4ef 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -379,7 +379,7 @@ static void mem_cgroup_put(struct mem_cgroup *memcg); static bool mem_cgroup_is_root(struct mem_cgroup *memcg); void sock_update_memcg(struct sock *sk) { - if (static_branch(&memcg_socket_limit_enabled)) { + if (mem_cgroup_sockets_enabled) { struct mem_cgroup *memcg; BUG_ON(!sk->sk_prot->proto_cgroup); @@ -411,7 +411,7 @@ EXPORT_SYMBOL(sock_update_memcg); void sock_release_memcg(struct sock *sk) { - if (static_branch(&memcg_socket_limit_enabled) && sk->sk_cgrp) { + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) { struct mem_cgroup *memcg; WARN_ON(!sk->sk_cgrp->memcg); memcg = sk->sk_cgrp->memcg; @@ -3247,7 +3247,7 @@ int mem_cgroup_prepare_migration(struct page *page, ctype = MEM_CGROUP_CHARGE_TYPE_CACHE; else ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM; - __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype); + __mem_cgroup_commit_charge(memcg, newpage, 1, pc, ctype); return ret; } diff --git a/mm/memory.c b/mm/memory.c index 5e30583c2605..fa2f04e0337c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -878,15 +878,24 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, } if (likely(!non_swap_entry(entry))) rss[MM_SWAPENTS]++; - else if (is_write_migration_entry(entry) && - is_cow_mapping(vm_flags)) { - /* - * COW mappings require pages in both parent - * and child to be set to read. - */ - make_migration_entry_read(&entry); - pte = swp_entry_to_pte(entry); - set_pte_at(src_mm, addr, src_pte, pte); + else if (is_migration_entry(entry)) { + page = migration_entry_to_page(entry); + + if (PageAnon(page)) + rss[MM_ANONPAGES]++; + else + rss[MM_FILEPAGES]++; + + if (is_write_migration_entry(entry) && + is_cow_mapping(vm_flags)) { + /* + * COW mappings require pages in both + * parent and child to be set to read. + */ + make_migration_entry_read(&entry); + pte = swp_entry_to_pte(entry); + set_pte_at(src_mm, addr, src_pte, pte); + } } } goto out_set_pte; @@ -1191,6 +1200,16 @@ again: if (!non_swap_entry(entry)) rss[MM_SWAPENTS]--; + else if (is_migration_entry(entry)) { + struct page *page; + + page = migration_entry_to_page(entry); + + if (PageAnon(page)) + rss[MM_ANONPAGES]--; + else + rss[MM_FILEPAGES]--; + } if (unlikely(!free_swap_and_cache(entry))) print_bad_pte(vma, addr, ptent, NULL); } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0027d8f4a1bb..d2186ecb36f7 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5413,7 +5413,25 @@ __count_immobile_pages(struct zone *zone, struct page *page, int count) bool is_pageblock_removable_nolock(struct page *page) { - struct zone *zone = page_zone(page); + struct zone *zone; + unsigned long pfn; + + /* + * We have to be careful here because we are iterating over memory + * sections which are not zone aware so we might end up outside of + * the zone but still within the section. + * We have to take care about the node as well. If the node is offline + * its NODE_DATA will be NULL - see page_zone. + */ + if (!node_online(page_to_nid(page))) + return false; + + zone = page_zone(page); + pfn = page_to_pfn(page); + if (zone->zone_start_pfn > pfn || + zone->zone_start_pfn + zone->spanned_pages <= pfn) + return false; + return __count_immobile_pages(zone, page, 0); } diff --git a/mm/percpu.c b/mm/percpu.c index 716eb4acf2fc..f47af9123af7 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -67,6 +67,7 @@ #include <linux/spinlock.h> #include <linux/vmalloc.h> #include <linux/workqueue.h> +#include <linux/kmemleak.h> #include <asm/cacheflush.h> #include <asm/sections.h> @@ -710,6 +711,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved) const char *err; int slot, off, new_alloc; unsigned long flags; + void __percpu *ptr; if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) { WARN(true, "illegal size (%zu) or align (%zu) for " @@ -802,7 +804,9 @@ area_found: mutex_unlock(&pcpu_alloc_mutex); /* return address relative to base address */ - return __addr_to_pcpu_ptr(chunk->base_addr + off); + ptr = __addr_to_pcpu_ptr(chunk->base_addr + off); + kmemleak_alloc_percpu(ptr, size); + return ptr; fail_unlock: spin_unlock_irqrestore(&pcpu_lock, flags); @@ -916,6 +920,8 @@ void free_percpu(void __percpu *ptr) if (!ptr) return; + kmemleak_free_percpu(ptr); + addr = __pcpu_ptr_to_addr(ptr); spin_lock_irqsave(&pcpu_lock, flags); @@ -1639,6 +1645,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, rc = -ENOMEM; goto out_free_areas; } + /* kmemleak tracks the percpu allocations separately */ + kmemleak_free(ptr); areas[group] = ptr; base = min(ptr, base); @@ -1753,6 +1761,8 @@ int __init pcpu_page_first_chunk(size_t reserved_size, "for cpu%u\n", psize_str, cpu); goto enomem; } + /* kmemleak tracks the percpu allocations separately */ + kmemleak_free(ptr); pages[j++] = virt_to_page(ptr); } diff --git a/mm/shmem.c b/mm/shmem.c index feead1943d92..269d049294ab 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -379,7 +379,7 @@ static int shmem_free_swap(struct address_space *mapping, /* * Pagevec may contain swap entries, so shuffle up pages before releasing. */ -static void shmem_pagevec_release(struct pagevec *pvec) +static void shmem_deswap_pagevec(struct pagevec *pvec) { int i, j; @@ -389,7 +389,36 @@ static void shmem_pagevec_release(struct pagevec *pvec) pvec->pages[j++] = page; } pvec->nr = j; - pagevec_release(pvec); +} + +/* + * SysV IPC SHM_UNLOCK restore Unevictable pages to their evictable lists. + */ +void shmem_unlock_mapping(struct address_space *mapping) +{ + struct pagevec pvec; + pgoff_t indices[PAGEVEC_SIZE]; + pgoff_t index = 0; + + pagevec_init(&pvec, 0); + /* + * Minor point, but we might as well stop if someone else SHM_LOCKs it. + */ + while (!mapping_unevictable(mapping)) { + /* + * Avoid pagevec_lookup(): find_get_pages() returns 0 as if it + * has finished, if it hits a row of PAGEVEC_SIZE swap entries. + */ + pvec.nr = shmem_find_get_pages_and_swap(mapping, index, + PAGEVEC_SIZE, pvec.pages, indices); + if (!pvec.nr) + break; + index = indices[pvec.nr - 1] + 1; + shmem_deswap_pagevec(&pvec); + check_move_unevictable_pages(pvec.pages, pvec.nr); + pagevec_release(&pvec); + cond_resched(); + } } /* @@ -440,7 +469,8 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) } unlock_page(page); } - shmem_pagevec_release(&pvec); + shmem_deswap_pagevec(&pvec); + pagevec_release(&pvec); mem_cgroup_uncharge_end(); cond_resched(); index++; @@ -470,7 +500,8 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) continue; } if (index == start && indices[0] > end) { - shmem_pagevec_release(&pvec); + shmem_deswap_pagevec(&pvec); + pagevec_release(&pvec); break; } mem_cgroup_uncharge_start(); @@ -494,7 +525,8 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) } unlock_page(page); } - shmem_pagevec_release(&pvec); + shmem_deswap_pagevec(&pvec); + pagevec_release(&pvec); mem_cgroup_uncharge_end(); index++; } @@ -1068,13 +1100,6 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) user_shm_unlock(inode->i_size, user); info->flags &= ~VM_LOCKED; mapping_clear_unevictable(file->f_mapping); - /* - * Ensure that a racing putback_lru_page() can see - * the pages of this mapping are evictable when we - * skip them due to !PageLRU during the scan. - */ - smp_mb__after_clear_bit(); - scan_mapping_unevictable_pages(file->f_mapping); } retval = 0; @@ -2445,6 +2470,10 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) return 0; } +void shmem_unlock_mapping(struct address_space *mapping) +{ +} + void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) { truncate_inode_pages_range(inode->i_mapping, lstart, lend); diff --git a/mm/vmscan.c b/mm/vmscan.c index 2880396f7953..c52b23552659 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -26,7 +26,6 @@ #include <linux/buffer_head.h> /* for try_to_release_page(), buffer_heads_over_limit */ #include <linux/mm_inline.h> -#include <linux/pagevec.h> #include <linux/backing-dev.h> #include <linux/rmap.h> #include <linux/topology.h> @@ -661,7 +660,7 @@ redo: * When racing with an mlock or AS_UNEVICTABLE clearing * (page is unlocked) make sure that if the other thread * does not observe our setting of PG_lru and fails - * isolation/check_move_unevictable_page, + * isolation/check_move_unevictable_pages, * we see PG_mlocked/AS_UNEVICTABLE cleared below and move * the page back to the evictable list. * @@ -3499,100 +3498,61 @@ int page_evictable(struct page *page, struct vm_area_struct *vma) return 1; } +#ifdef CONFIG_SHMEM /** - * check_move_unevictable_page - check page for evictability and move to appropriate zone lru list - * @page: page to check evictability and move to appropriate lru list - * @zone: zone page is in + * check_move_unevictable_pages - check pages for evictability and move to appropriate zone lru list + * @pages: array of pages to check + * @nr_pages: number of pages to check * - * Checks a page for evictability and moves the page to the appropriate - * zone lru list. + * Checks pages for evictability and moves them to the appropriate lru list. * - * Restrictions: zone->lru_lock must be held, page must be on LRU and must - * have PageUnevictable set. + * This function is only used for SysV IPC SHM_UNLOCK. */ -static void check_move_unevictable_page(struct page *page, struct zone *zone) +void check_move_unevictable_pages(struct page **pages, int nr_pages) { struct lruvec *lruvec; + struct zone *zone = NULL; + int pgscanned = 0; + int pgrescued = 0; + int i; - VM_BUG_ON(PageActive(page)); -retry: - ClearPageUnevictable(page); - if (page_evictable(page, NULL)) { - enum lru_list l = page_lru_base_type(page); - - __dec_zone_state(zone, NR_UNEVICTABLE); - lruvec = mem_cgroup_lru_move_lists(zone, page, - LRU_UNEVICTABLE, l); - list_move(&page->lru, &lruvec->lists[l]); - __inc_zone_state(zone, NR_INACTIVE_ANON + l); - __count_vm_event(UNEVICTABLE_PGRESCUED); - } else { - /* - * rotate unevictable list - */ - SetPageUnevictable(page); - lruvec = mem_cgroup_lru_move_lists(zone, page, LRU_UNEVICTABLE, - LRU_UNEVICTABLE); - list_move(&page->lru, &lruvec->lists[LRU_UNEVICTABLE]); - if (page_evictable(page, NULL)) - goto retry; - } -} - -/** - * scan_mapping_unevictable_pages - scan an address space for evictable pages - * @mapping: struct address_space to scan for evictable pages - * - * Scan all pages in mapping. Check unevictable pages for - * evictability and move them to the appropriate zone lru list. - */ -void scan_mapping_unevictable_pages(struct address_space *mapping) -{ - pgoff_t next = 0; - pgoff_t end = (i_size_read(mapping->host) + PAGE_CACHE_SIZE - 1) >> - PAGE_CACHE_SHIFT; - struct zone *zone; - struct pagevec pvec; - - if (mapping->nrpages == 0) - return; - - pagevec_init(&pvec, 0); - while (next < end && - pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { - int i; - int pg_scanned = 0; - - zone = NULL; - - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; - pgoff_t page_index = page->index; - struct zone *pagezone = page_zone(page); + for (i = 0; i < nr_pages; i++) { + struct page *page = pages[i]; + struct zone *pagezone; - pg_scanned++; - if (page_index > next) - next = page_index; - next++; + pgscanned++; + pagezone = page_zone(page); + if (pagezone != zone) { + if (zone) + spin_unlock_irq(&zone->lru_lock); + zone = pagezone; + spin_lock_irq(&zone->lru_lock); + } - if (pagezone != zone) { - if (zone) - spin_unlock_irq(&zone->lru_lock); - zone = pagezone; - spin_lock_irq(&zone->lru_lock); - } + if (!PageLRU(page) || !PageUnevictable(page)) + continue; - if (PageLRU(page) && PageUnevictable(page)) - check_move_unevictable_page(page, zone); + if (page_evictable(page, NULL)) { + enum lru_list lru = page_lru_base_type(page); + + VM_BUG_ON(PageActive(page)); + ClearPageUnevictable(page); + __dec_zone_state(zone, NR_UNEVICTABLE); + lruvec = mem_cgroup_lru_move_lists(zone, page, + LRU_UNEVICTABLE, lru); + list_move(&page->lru, &lruvec->lists[lru]); + __inc_zone_state(zone, NR_INACTIVE_ANON + lru); + pgrescued++; } - if (zone) - spin_unlock_irq(&zone->lru_lock); - pagevec_release(&pvec); - - count_vm_events(UNEVICTABLE_PGSCANNED, pg_scanned); } + if (zone) { + __count_vm_events(UNEVICTABLE_PGRESCUED, pgrescued); + __count_vm_events(UNEVICTABLE_PGSCANNED, pgscanned); + spin_unlock_irq(&zone->lru_lock); + } } +#endif /* CONFIG_SHMEM */ static void warn_scan_unevictable_pages(void) { diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index ef92864ac625..72eb187a5f60 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -71,19 +71,16 @@ static const char *const bt_slock_key_strings[BT_MAX_PROTO] = { "slock-AF_BLUETOOTH-BTPROTO_AVDTP", }; -static inline void bt_sock_reclassify_lock(struct socket *sock, int proto) +void bt_sock_reclassify_lock(struct sock *sk, int proto) { - struct sock *sk = sock->sk; - - if (!sk) - return; - + BUG_ON(!sk); BUG_ON(sock_owned_by_user(sk)); sock_lock_init_class_and_name(sk, bt_slock_key_strings[proto], &bt_slock_key[proto], bt_key_strings[proto], &bt_lock_key[proto]); } +EXPORT_SYMBOL(bt_sock_reclassify_lock); int bt_sock_register(int proto, const struct net_proto_family *ops) { @@ -145,7 +142,8 @@ static int bt_sock_create(struct net *net, struct socket *sock, int proto, if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { err = bt_proto[proto]->create(net, sock, proto, kern); - bt_sock_reclassify_lock(sock, proto); + if (!err) + bt_sock_reclassify_lock(sock->sk, proto); module_put(bt_proto[proto]->owner); } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3db432473ad5..07bc69ed9498 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -635,6 +635,10 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; + + /* encrypt must be pending if auth is also pending */ + set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); + cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 845da3ee56a0..5aeb62491198 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -55,7 +55,7 @@ #define AUTO_OFF_TIMEOUT 2000 -int enable_hs; +bool enable_hs; static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); @@ -640,7 +640,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Reset device */ skb_queue_purge(&hdev->cmd_q); atomic_set(&hdev->cmd_cnt, 1); - if (!test_bit(HCI_RAW, &hdev->flags)) { + if (!test_bit(HCI_RAW, &hdev->flags) && + test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { set_bit(HCI_INIT, &hdev->flags); __hci_request(hdev, hci_reset_req, 0, msecs_to_jiffies(250)); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index faf0b11ac1d3..32d338c30e65 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1018,10 +1018,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) hci_chan_del(conn->hchan); if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work_sync(&conn->info_timer); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) { - __cancel_delayed_work(&conn->security_timer); + cancel_delayed_work_sync(&conn->security_timer); smp_chan_destroy(conn); } @@ -1120,7 +1120,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr return c1; } -inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; @@ -2574,7 +2574,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && cmd->ident == conn->info_ident) { - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work(&conn->info_timer); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; conn->info_ident = 0; @@ -2970,7 +2970,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: sk->sk_err = ECONNRESET; - __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT)); l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -3120,7 +3121,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) return 0; - __cancel_delayed_work(&conn->info_timer); + cancel_delayed_work(&conn->info_timer); if (result != L2CAP_IR_SUCCESS) { conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; @@ -4478,7 +4479,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_ENC_TIMEOUT)); } else if (chan->sec_level == BT_SECURITY_HIGH) l2cap_chan_close(chan, ECONNREFUSED); } else { @@ -4499,7 +4501,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (hcon->type == LE_LINK) { smp_distribute_keys(conn, 0); - __cancel_delayed_work(&conn->security_timer); + cancel_delayed_work(&conn->security_timer); } rcu_read_lock(); @@ -4546,7 +4548,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) L2CAP_CONN_REQ, sizeof(req), &req); } else { __clear_chan_timer(chan); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); } } else if (chan->state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -4566,7 +4569,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) } } else { l2cap_state_change(chan, BT_DISCONN); - __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); + __set_chan_timer(chan, + msecs_to_jiffies(L2CAP_DISC_TIMEOUT)); res = L2CAP_CR_SEC_BLOCK; stat = L2CAP_CS_NO_INFO; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c61d967012b2..401d9428ae4c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -849,6 +849,8 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data) if (!sk) return NULL; + bt_sock_reclassify_lock(sk, BTPROTO_L2CAP); + l2cap_sock_init(sk, parent); return l2cap_pi(sk)->chan; @@ -1002,7 +1004,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p INIT_LIST_HEAD(&bt_sk(sk)->accept_q); sk->sk_destruct = l2cap_sock_destruct; - sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; + sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT); sock_reset_flag(sk, SOCK_ZAPPED); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 501649bf5596..8a602388f1e7 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -1164,12 +1164,18 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) break; case BT_DISCONN: - /* When socket is closed and we are not RFCOMM - * initiator rfcomm_process_rx already calls - * rfcomm_session_put() */ - if (s->sock->sk->sk_state != BT_CLOSED) - if (list_empty(&s->dlcs)) - rfcomm_session_put(s); + /* rfcomm_session_put is called later so don't do + * anything here otherwise we will mess up the session + * reference counter: + * + * (a) when we are the initiator dlc_unlink will drive + * the reference counter to 0 (there is no initial put + * after session_add) + * + * (b) when we are not the initiator rfcomm_rx_process + * will explicitly call put to balance the initial hold + * done after session add. + */ break; } } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index f066678faeee..22169c3f1482 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -956,6 +956,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * if (!sk) goto done; + bt_sock_reclassify_lock(sk, BTPROTO_RFCOMM); + rfcomm_sock_init(sk, parent); bacpy(&bt_sk(sk)->src, &src); bacpy(&bt_sk(sk)->dst, &dst); diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 673728add60b..82c57069415f 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -59,8 +59,6 @@ struct cfcnfg *get_cfcnfg(struct net *net) { struct caif_net *caifn; caifn = net_generic(net, caif_net_id); - if (!caifn) - return NULL; return caifn->cfg; } EXPORT_SYMBOL(get_cfcnfg); @@ -69,8 +67,6 @@ static struct caif_device_entry_list *caif_device_list(struct net *net) { struct caif_net *caifn; caifn = net_generic(net, caif_net_id); - if (!caifn) - return NULL; return &caifn->caifdevs; } @@ -99,8 +95,6 @@ static struct caif_device_entry *caif_device_alloc(struct net_device *dev) struct caif_device_entry *caifd; caifdevs = caif_device_list(dev_net(dev)); - if (!caifdevs) - return NULL; caifd = kzalloc(sizeof(*caifd), GFP_KERNEL); if (!caifd) @@ -120,8 +114,6 @@ static struct caif_device_entry *caif_get(struct net_device *dev) struct caif_device_entry_list *caifdevs = caif_device_list(dev_net(dev)); struct caif_device_entry *caifd; - if (!caifdevs) - return NULL; list_for_each_entry_rcu(caifd, &caifdevs->list, list) { if (caifd->netdev == dev) @@ -321,8 +313,6 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev, struct caif_device_entry_list *caifdevs; caifdevs = caif_device_list(dev_net(dev)); - if (!cfg || !caifdevs) - return; caifd = caif_device_alloc(dev); if (!caifd) return; @@ -374,8 +364,6 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, cfg = get_cfcnfg(dev_net(dev)); caifdevs = caif_device_list(dev_net(dev)); - if (!cfg || !caifdevs) - return 0; caifd = caif_get(dev); if (caifd == NULL && dev->type != ARPHRD_CAIF) @@ -507,9 +495,6 @@ static struct notifier_block caif_device_notifier = { static int caif_init_net(struct net *net) { struct caif_net *caifn = net_generic(net, caif_net_id); - if (WARN_ON(!caifn)) - return -EINVAL; - INIT_LIST_HEAD(&caifn->caifdevs.list); mutex_init(&caifn->caifdevs.lock); @@ -527,9 +512,6 @@ static void caif_exit_net(struct net *net) caif_device_list(net); struct cfcnfg *cfg = get_cfcnfg(net); - if (!cfg || !caifdevs) - return; - rtnl_lock(); mutex_lock(&caifdevs->lock); @@ -569,7 +551,7 @@ static int __init caif_device_init(void) { int result; - result = register_pernet_device(&caif_net_ops); + result = register_pernet_subsys(&caif_net_ops); if (result) return result; @@ -582,7 +564,7 @@ static int __init caif_device_init(void) static void __exit caif_device_exit(void) { - unregister_pernet_device(&caif_net_ops); + unregister_pernet_subsys(&caif_net_ops); unregister_netdevice_notifier(&caif_device_notifier); dev_remove_pack(&caif_packet_type); } diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 598aafb4cb51..ba9cfd47778a 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -309,7 +309,6 @@ int caif_connect_client(struct net *net, struct caif_connect_request *conn_req, int err; struct cfctrl_link_param param; struct cfcnfg *cfg = get_cfcnfg(net); - caif_assert(cfg != NULL); rcu_read_lock(); err = caif_connect_req_to_link_param(cfg, conn_req, ¶m); diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index 3a94eae7abe9..b79747c4b645 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c @@ -510,10 +510,15 @@ int crush_do_rule(struct crush_map *map, switch (rule->steps[step].op) { case CRUSH_RULE_TAKE: w[0] = rule->steps[step].arg1; - if (force_pos >= 0) { - BUG_ON(force_context[force_pos] != w[0]); + + /* find position in force_context/hierarchy */ + while (force_pos >= 0 && + force_context[force_pos] != w[0]) force_pos--; - } + /* and move past it */ + if (force_pos >= 0) + force_pos--; + wsize = 1; break; diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 85f3bc0a7062..b780cb7947dd 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -15,10 +15,9 @@ int ceph_crypto_key_clone(struct ceph_crypto_key *dst, const struct ceph_crypto_key *src) { memcpy(dst, src, sizeof(struct ceph_crypto_key)); - dst->key = kmalloc(src->len, GFP_NOFS); + dst->key = kmemdup(src->key, src->len, GFP_NOFS); if (!dst->key) return -ENOMEM; - memcpy(dst->key, src->key, src->len); return 0; } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index f4f3f58f5234..5e254055c910 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -29,8 +29,8 @@ static void __register_request(struct ceph_osd_client *osdc, struct ceph_osd_request *req); static void __unregister_linger_request(struct ceph_osd_client *osdc, struct ceph_osd_request *req); -static int __send_request(struct ceph_osd_client *osdc, - struct ceph_osd_request *req); +static void __send_request(struct ceph_osd_client *osdc, + struct ceph_osd_request *req); static int op_needs_trail(int op) { @@ -1022,8 +1022,8 @@ out: /* * caller should hold map_sem (for read) and request_mutex */ -static int __send_request(struct ceph_osd_client *osdc, - struct ceph_osd_request *req) +static void __send_request(struct ceph_osd_client *osdc, + struct ceph_osd_request *req) { struct ceph_osd_request_head *reqhead; @@ -1041,7 +1041,6 @@ static int __send_request(struct ceph_osd_client *osdc, ceph_msg_get(req->r_request); /* send consumes a ref */ ceph_con_send(&req->r_osd->o_con, req->r_request); req->r_sent = req->r_osd->o_incarnation; - return 0; } /* @@ -1726,17 +1725,9 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc, dout("send_request %p no up osds in pg\n", req); ceph_monc_request_next_osdmap(&osdc->client->monc); } else { - rc = __send_request(osdc, req); - if (rc) { - if (nofail) { - dout("osdc_start_request failed send, " - " will retry %lld\n", req->r_tid); - rc = 0; - } else { - __unregister_request(osdc, req); - } - } + __send_request(osdc, req); } + rc = 0; } out_unlock: diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 921aa2b4b415..369b41894527 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -1311,6 +1311,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_GRXCSUM: case ETHTOOL_GTXCSUM: case ETHTOOL_GSG: + case ETHTOOL_GSSET_INFO: case ETHTOOL_GSTRINGS: case ETHTOOL_GTSO: case ETHTOOL_GPERMADDR: diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 0985b9b14b80..a225089df5b6 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -1,4 +1,5 @@ #include <linux/skbuff.h> +#include <linux/export.h> #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/if_vlan.h> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index aefcd7acbffa..0e950fda9a0a 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -30,6 +30,20 @@ EXPORT_SYMBOL(init_net); #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ +static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; + +static struct net_generic *net_alloc_generic(void) +{ + struct net_generic *ng; + size_t generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]); + + ng = kzalloc(generic_size, GFP_KERNEL); + if (ng) + ng->len = max_gen_ptrs; + + return ng; +} + static int net_assign_generic(struct net *net, int id, void *data) { struct net_generic *ng, *old_ng; @@ -43,8 +57,7 @@ static int net_assign_generic(struct net *net, int id, void *data) if (old_ng->len >= id) goto assign; - ng = kzalloc(sizeof(struct net_generic) + - id * sizeof(void *), GFP_KERNEL); + ng = net_alloc_generic(); if (ng == NULL) return -ENOMEM; @@ -59,7 +72,6 @@ static int net_assign_generic(struct net *net, int id, void *data) * the old copy for kfree after a grace period. */ - ng->len = id; memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*)); rcu_assign_pointer(net->gen, ng); @@ -161,18 +173,6 @@ out_undo: goto out; } -static struct net_generic *net_alloc_generic(void) -{ - struct net_generic *ng; - size_t generic_size = sizeof(struct net_generic) + - INITIAL_NET_GEN_PTRS * sizeof(void *); - - ng = kzalloc(generic_size, GFP_KERNEL); - if (ng) - ng->len = INITIAL_NET_GEN_PTRS; - - return ng; -} #ifdef CONFIG_NET_NS static struct kmem_cache *net_cachep; @@ -483,6 +483,7 @@ again: } return error; } + max_gen_ptrs = max_t(unsigned int, max_gen_ptrs, *ops->id); } error = __register_pernet_operations(list, ops); if (error) { diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 65f80c7b1656..4d8ce93cd503 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -767,8 +767,8 @@ done: return i; } -static unsigned long num_arg(const char __user * user_buffer, - unsigned long maxlen, unsigned long *num) +static long num_arg(const char __user *user_buffer, unsigned long maxlen, + unsigned long *num) { int i; *num = 0; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index dbf2ddafd52d..65aebd450027 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1509,6 +1509,9 @@ errout: if (send_addr_notify) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + min_ifinfo_dump_size = max_t(u16, if_nlmsg_size(dev), + min_ifinfo_dump_size); + return err; } @@ -1960,7 +1963,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) sz_idx = type>>2; kind = type&3; - if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) + if (kind != 2 && !capable(CAP_NET_ADMIN)) return -EPERM; if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { diff --git a/net/core/sock.c b/net/core/sock.c index 5c5af9988f94..3e81fd2e3c75 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1827,7 +1827,7 @@ suppress_allocation: /* Alas. Undo changes. */ sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM; - sk_memory_allocated_sub(sk, amt, parent_status); + sk_memory_allocated_sub(sk, amt); return 0; } @@ -1840,7 +1840,7 @@ EXPORT_SYMBOL(__sk_mem_schedule); void __sk_mem_reclaim(struct sock *sk) { sk_memory_allocated_sub(sk, - sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT, 0); + sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT); sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1; if (sk_under_memory_pressure(sk) && diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index 69975e0bcdea..1531135130db 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -108,7 +108,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb) if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) return; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); /* Eventually we might send routing messages too */ diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 2e4e24476c4c..19d66cefd7d3 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -123,11 +123,14 @@ again: smallest_size = tb->num_owners; smallest_rover = rover; if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) { - spin_unlock(&head->lock); snum = smallest_rover; - goto have_snum; + goto tb_found; } } + if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) { + snum = rover; + goto tb_found; + } goto next; } break; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 2b53a1f7abf6..6b3ca5ba4450 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -422,6 +422,10 @@ static struct ip_tunnel *ipgre_tunnel_locate(struct net *net, if (register_netdevice(dev) < 0) goto failed_free; + /* Can use a lockless transmit, unless we generate output sequences */ + if (!(nt->parms.o_flags & GRE_SEQ)) + dev->features |= NETIF_F_LLTX; + dev_hold(dev); ipgre_tunnel_link(ign, nt); return nt; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index a057fe64debd..94d45e1f8882 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -431,7 +431,7 @@ __ipq_rcv_skb(struct sk_buff *skb) if (type <= IPQM_BASE) return; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); spin_lock_bh(&queue_lock); diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 3569d8ecaeac..6afc807ee2ad 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -216,7 +216,6 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPPartialUndo", LINUX_MIB_TCPPARTIALUNDO), SNMP_MIB_ITEM("TCPDSACKUndo", LINUX_MIB_TCPDSACKUNDO), SNMP_MIB_ITEM("TCPLossUndo", LINUX_MIB_TCPLOSSUNDO), - SNMP_MIB_ITEM("TCPLoss", LINUX_MIB_TCPLOSS), SNMP_MIB_ITEM("TCPLostRetransmit", LINUX_MIB_TCPLOSTRETRANSMIT), SNMP_MIB_ITEM("TCPRenoFailures", LINUX_MIB_TCPRENOFAILURES), SNMP_MIB_ITEM("TCPSackFailures", LINUX_MIB_TCPSACKFAILURES), diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 4aa7e9dc0cbb..4cb9cd2f2c39 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -814,6 +814,7 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) net->ipv4.sysctl_rt_cache_rebuild_count = 4; + tcp_init_mem(net); limit = nr_free_buffer_pages() / 8; limit = max(limit, 128UL); net->ipv4.sysctl_tcp_mem[0] = limit / 4 * 3; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9bcdec3ad772..06373b4a449a 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3216,6 +3216,16 @@ static int __init set_thash_entries(char *str) } __setup("thash_entries=", set_thash_entries); +void tcp_init_mem(struct net *net) +{ + /* Set per-socket limits to no more than 1/128 the pressure threshold */ + unsigned long limit = nr_free_buffer_pages() / 8; + limit = max(limit, 128UL); + net->ipv4.sysctl_tcp_mem[0] = limit / 4 * 3; + net->ipv4.sysctl_tcp_mem[1] = limit; + net->ipv4.sysctl_tcp_mem[2] = net->ipv4.sysctl_tcp_mem[0] * 2; +} + void __init tcp_init(void) { struct sk_buff *skb = NULL; @@ -3276,9 +3286,9 @@ void __init tcp_init(void) sysctl_tcp_max_orphans = cnt / 2; sysctl_max_syn_backlog = max(128, cnt / 256); - /* Set per-socket limits to no more than 1/128 the pressure threshold */ - limit = ((unsigned long)init_net.ipv4.sysctl_tcp_mem[1]) - << (PAGE_SHIFT - 7); + tcp_init_mem(&init_net); + limit = nr_free_buffer_pages() / 8; + limit = max(limit, 128UL); max_share = min(4UL*1024*1024, limit); sysctl_tcp_wmem[0] = SK_MEM_QUANTUM; diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c index 6187eb4d1dcf..f45e1c242440 100644 --- a/net/ipv4/tcp_bic.c +++ b/net/ipv4/tcp_bic.c @@ -63,7 +63,6 @@ static inline void bictcp_reset(struct bictcp *ca) { ca->cnt = 0; ca->last_max_cwnd = 0; - ca->loss_cwnd = 0; ca->last_cwnd = 0; ca->last_time = 0; ca->epoch_start = 0; @@ -72,7 +71,11 @@ static inline void bictcp_reset(struct bictcp *ca) static void bictcp_init(struct sock *sk) { - bictcp_reset(inet_csk_ca(sk)); + struct bictcp *ca = inet_csk_ca(sk); + + bictcp_reset(ca); + ca->loss_cwnd = 0; + if (initial_ssthresh) tcp_sk(sk)->snd_ssthresh = initial_ssthresh; } @@ -127,7 +130,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) } /* if in slow start or link utilization is very low */ - if (ca->loss_cwnd == 0) { + if (ca->last_max_cwnd == 0) { if (ca->cnt > 20) /* increase cwnd 5% per RTT */ ca->cnt = 20; } @@ -185,7 +188,7 @@ static u32 bictcp_undo_cwnd(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); const struct bictcp *ca = inet_csk_ca(sk); - return max(tp->snd_cwnd, ca->last_max_cwnd); + return max(tp->snd_cwnd, ca->loss_cwnd); } static void bictcp_state(struct sock *sk, u8 new_state) diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index f376b05cca81..a9077f441cb2 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -107,7 +107,6 @@ static inline void bictcp_reset(struct bictcp *ca) { ca->cnt = 0; ca->last_max_cwnd = 0; - ca->loss_cwnd = 0; ca->last_cwnd = 0; ca->last_time = 0; ca->bic_origin_point = 0; @@ -142,7 +141,10 @@ static inline void bictcp_hystart_reset(struct sock *sk) static void bictcp_init(struct sock *sk) { - bictcp_reset(inet_csk_ca(sk)); + struct bictcp *ca = inet_csk_ca(sk); + + bictcp_reset(ca); + ca->loss_cwnd = 0; if (hystart) bictcp_hystart_reset(sk); @@ -275,7 +277,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) * The initial growth of cubic function may be too conservative * when the available bandwidth is still unknown. */ - if (ca->loss_cwnd == 0 && ca->cnt > 20) + if (ca->last_max_cwnd == 0 && ca->cnt > 20) ca->cnt = 20; /* increase cwnd 5% per RTT */ /* TCP Friendly */ @@ -342,7 +344,7 @@ static u32 bictcp_undo_cwnd(struct sock *sk) { struct bictcp *ca = inet_csk_ca(sk); - return max(tcp_sk(sk)->snd_cwnd, ca->last_max_cwnd); + return max(tcp_sk(sk)->snd_cwnd, ca->loss_cwnd); } static void bictcp_state(struct sock *sk, u8 new_state) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2877c3e09587..976034f82320 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -105,7 +105,6 @@ int sysctl_tcp_abc __read_mostly; #define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ #define FLAG_DATA_SACKED 0x20 /* New SACK. */ #define FLAG_ECE 0x40 /* ECE in this ACK */ -#define FLAG_DATA_LOST 0x80 /* SACK detected data lossage. */ #define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ #define FLAG_ONLY_ORIG_SACKED 0x200 /* SACKs only non-rexmit sent before RTO */ #define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ @@ -1040,13 +1039,11 @@ static void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, * These 6 states form finite state machine, controlled by the following events: * 1. New ACK (+SACK) arrives. (tcp_sacktag_write_queue()) * 2. Retransmission. (tcp_retransmit_skb(), tcp_xmit_retransmit_queue()) - * 3. Loss detection event of one of three flavors: + * 3. Loss detection event of two flavors: * A. Scoreboard estimator decided the packet is lost. * A'. Reno "three dupacks" marks head of queue lost. - * A''. Its FACK modfication, head until snd.fack is lost. - * B. SACK arrives sacking data transmitted after never retransmitted - * hole was sent out. - * C. SACK arrives sacking SND.NXT at the moment, when the + * A''. Its FACK modification, head until snd.fack is lost. + * B. SACK arrives sacking SND.NXT at the moment, when the * segment was retransmitted. * 4. D-SACK added new rule: D-SACK changes any tag to S. * @@ -1153,7 +1150,7 @@ static int tcp_is_sackblock_valid(struct tcp_sock *tp, int is_dsack, } /* Check for lost retransmit. This superb idea is borrowed from "ratehalving". - * Event "C". Later note: FACK people cheated me again 8), we have to account + * Event "B". Later note: FACK people cheated me again 8), we have to account * for reordering! Ugly, but should help. * * Search retransmitted skbs from write_queue that were sent when snd_nxt was @@ -1844,10 +1841,6 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, if (found_dup_sack && ((i + 1) == first_sack_index)) next_dup = &sp[i + 1]; - /* Event "B" in the comment above. */ - if (after(end_seq, tp->high_seq)) - state.flag |= FLAG_DATA_LOST; - /* Skip too early cached blocks */ while (tcp_sack_cache_ok(tp, cache) && !before(start_seq, cache->end_seq)) @@ -2515,8 +2508,11 @@ static void tcp_timeout_skbs(struct sock *sk) tcp_verify_left_out(tp); } -/* Mark head of queue up as lost. With RFC3517 SACK, the packets is - * is against sacked "cnt", otherwise it's against facked "cnt" +/* Detect loss in event "A" above by marking head of queue up as lost. + * For FACK or non-SACK(Reno) senders, the first "packets" number of segments + * are considered lost. For RFC3517 SACK, a segment is considered lost if it + * has at least tp->reordering SACKed seqments above it; "packets" refers to + * the maximum SACKed segments to pass before reaching this limit. */ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head) { @@ -2525,6 +2521,8 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head) int cnt, oldcnt; int err; unsigned int mss; + /* Use SACK to deduce losses of new sequences sent during recovery */ + const u32 loss_high = tcp_is_sack(tp) ? tp->snd_nxt : tp->high_seq; WARN_ON(packets > tp->packets_out); if (tp->lost_skb_hint) { @@ -2546,7 +2544,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head) tp->lost_skb_hint = skb; tp->lost_cnt_hint = cnt; - if (after(TCP_SKB_CB(skb)->end_seq, tp->high_seq)) + if (after(TCP_SKB_CB(skb)->end_seq, loss_high)) break; oldcnt = cnt; @@ -3033,19 +3031,10 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, if (tcp_check_sack_reneging(sk, flag)) return; - /* C. Process data loss notification, provided it is valid. */ - if (tcp_is_fack(tp) && (flag & FLAG_DATA_LOST) && - before(tp->snd_una, tp->high_seq) && - icsk->icsk_ca_state != TCP_CA_Open && - tp->fackets_out > tp->reordering) { - tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering, 0); - NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSS); - } - - /* D. Check consistency of the current state. */ + /* C. Check consistency of the current state. */ tcp_verify_left_out(tp); - /* E. Check state exit conditions. State can be terminated + /* D. Check state exit conditions. State can be terminated * when high_seq is ACKed. */ if (icsk->icsk_ca_state == TCP_CA_Open) { WARN_ON(tp->retrans_out != 0); @@ -3077,7 +3066,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, } } - /* F. Process state. */ + /* E. Process state. */ switch (icsk->icsk_ca_state) { case TCP_CA_Recovery: if (!(flag & FLAG_SND_UNA_ADVANCED)) { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1eb4ad57670e..337ba4cca052 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -631,7 +631,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr) : NULL; + key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 8c8de2780c7a..4ff3b6dc74fc 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1141,11 +1141,9 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) sk_mem_uncharge(sk, len); sock_set_flag(sk, SOCK_QUEUE_SHRUNK); - /* Any change of skb->len requires recalculation of tso - * factor and mss. - */ + /* Any change of skb->len requires recalculation of tso factor. */ if (tcp_skb_pcount(skb) > 1) - tcp_set_skb_tso_segs(sk, skb, tcp_current_mss(sk)); + tcp_set_skb_tso_segs(sk, skb, tcp_skb_mss(skb)); return 0; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a225d5ee3c2f..c02280a4d126 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -502,29 +502,31 @@ static void addrconf_forward_change(struct net *net, __s32 newf) rcu_read_unlock(); } -static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) +static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) { struct net *net; + int old; + + if (!rtnl_trylock()) + return restart_syscall(); net = (struct net *)table->extra2; - if (p == &net->ipv6.devconf_dflt->forwarding) - return 0; + old = *p; + *p = newf; - if (!rtnl_trylock()) { - /* Restore the original values before restarting */ - *p = old; - return restart_syscall(); + if (p == &net->ipv6.devconf_dflt->forwarding) { + rtnl_unlock(); + return 0; } if (p == &net->ipv6.devconf_all->forwarding) { - __s32 newf = net->ipv6.devconf_all->forwarding; net->ipv6.devconf_dflt->forwarding = newf; addrconf_forward_change(net, newf); - } else if ((!*p) ^ (!old)) + } else if ((!newf) ^ (!old)) dev_forward_change((struct inet6_dev *)table->extra1); rtnl_unlock(); - if (*p) + if (newf) rt6_purge_dflt_routers(net); return 1; } @@ -4260,9 +4262,17 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, int *valp = ctl->data; int val = *valp; loff_t pos = *ppos; + ctl_table lctl; int ret; - ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + /* + * ctl->data points to idev->cnf.forwarding, we should + * not modify it until we get the rtnl lock. + */ + lctl = *ctl; + lctl.data = &val; + + ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); if (write) ret = addrconf_fixup_forwarding(ctl, valp, val); @@ -4300,26 +4310,27 @@ static void addrconf_disable_change(struct net *net, __s32 newf) rcu_read_unlock(); } -static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) +static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf) { struct net *net; + int old; + + if (!rtnl_trylock()) + return restart_syscall(); net = (struct net *)table->extra2; + old = *p; + *p = newf; - if (p == &net->ipv6.devconf_dflt->disable_ipv6) + if (p == &net->ipv6.devconf_dflt->disable_ipv6) { + rtnl_unlock(); return 0; - - if (!rtnl_trylock()) { - /* Restore the original values before restarting */ - *p = old; - return restart_syscall(); } if (p == &net->ipv6.devconf_all->disable_ipv6) { - __s32 newf = net->ipv6.devconf_all->disable_ipv6; net->ipv6.devconf_dflt->disable_ipv6 = newf; addrconf_disable_change(net, newf); - } else if ((!*p) ^ (!old)) + } else if ((!newf) ^ (!old)) dev_disable_change((struct inet6_dev *)table->extra1); rtnl_unlock(); @@ -4333,9 +4344,17 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write, int *valp = ctl->data; int val = *valp; loff_t pos = *ppos; + ctl_table lctl; int ret; - ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + /* + * ctl->data points to idev->cnf.disable_ipv6, we should + * not modify it until we get the rtnl lock. + */ + lctl = *ctl; + lctl.data = &val; + + ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); if (write) ret = addrconf_disable_ipv6(ctl, valp, val); diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index fb80a23c6640..a34c9e4c792c 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -432,7 +432,7 @@ __ipq_rcv_skb(struct sk_buff *skb) if (type <= IPQM_BASE) return; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); spin_lock_bh(&queue_lock); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 906c7ca43542..3edd05ae4388 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1083,7 +1083,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) #ifdef CONFIG_TCP_MD5SIG if (sk) - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr); + key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); #endif if (th->ack) diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index d21e7ebd91ca..55670ec3cd0f 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -393,11 +393,6 @@ static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb) { int rc; - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - - nf_reset(skb); - /* Charge it to the socket, dropping if the queue is full. */ rc = sock_queue_rcv_skb(sk, skb); if (rc < 0) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index a18e6c3d36e3..b9bef2c75026 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -713,6 +713,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb = NULL; struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); + unsigned long cpu_flags; size_t copied = 0; u32 peek_seq = 0; u32 *seq; @@ -838,7 +839,9 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, goto copy_uaddr; if (!(flags & MSG_PEEK)) { + spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); sk_eat_skb(sk, skb, 0); + spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); *seq = 0; } @@ -859,7 +862,9 @@ copy_uaddr: llc_cmsg_rcv(msg, skb); if (!(flags & MSG_PEEK)) { + spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); sk_eat_skb(sk, skb, 0); + spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); *seq = 0; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 831a5bd44fd0..2306d7514fff 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -909,6 +909,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", result); + ieee80211_led_init(local); + rtnl_lock(); result = ieee80211_init_rate_ctrl_alg(local, @@ -930,8 +932,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) rtnl_unlock(); - ieee80211_led_init(local); - local->network_latency_notifier.notifier_call = ieee80211_max_network_latency; result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2b5b1194dfc2..3ab85c02ef04 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -611,7 +611,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; if (!tid_agg_rx->reorder_buf[index] && - tid_agg_rx->stored_mpdu_num > 1) { + tid_agg_rx->stored_mpdu_num) { /* * No buffers ready to be released, but check whether any * frames in the reorder buffer have timed out. diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index b4f8d849480c..4d70785b953d 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -130,7 +130,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) const struct nfnetlink_subsystem *ss; int type, err; - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; /* All the messages must at least contain nfgenmsg */ diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index a403b618faa5..c29d2568c9e0 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -524,7 +524,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EOPNOTSUPP; if ((ops->flags & GENL_ADMIN_PERM) && - security_netlink_recv(skb, CAP_NET_ADMIN)) + !capable(CAP_NET_ADMIN)) return -EPERM; if (nlh->nlmsg_flags & NLM_F_DUMP) { diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index bb6ad81b671d..424ff622ab5f 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -68,7 +68,6 @@ static int rds_release(struct socket *sock) { struct sock *sk = sock->sk; struct rds_sock *rs; - unsigned long flags; if (!sk) goto out; @@ -94,10 +93,10 @@ static int rds_release(struct socket *sock) rds_rdma_drop_keys(rs); rds_notify_queue_get(rs, NULL); - spin_lock_irqsave(&rds_sock_lock, flags); + spin_lock_bh(&rds_sock_lock); list_del_init(&rs->rs_item); rds_sock_count--; - spin_unlock_irqrestore(&rds_sock_lock, flags); + spin_unlock_bh(&rds_sock_lock); rds_trans_put(rs->rs_transport); @@ -409,7 +408,6 @@ static const struct proto_ops rds_proto_ops = { static int __rds_create(struct socket *sock, struct sock *sk, int protocol) { - unsigned long flags; struct rds_sock *rs; sock_init_data(sock, sk); @@ -426,10 +424,10 @@ static int __rds_create(struct socket *sock, struct sock *sk, int protocol) spin_lock_init(&rs->rs_rdma_lock); rs->rs_rdma_keys = RB_ROOT; - spin_lock_irqsave(&rds_sock_lock, flags); + spin_lock_bh(&rds_sock_lock); list_add_tail(&rs->rs_item, &rds_sock_list); rds_sock_count++; - spin_unlock_irqrestore(&rds_sock_lock, flags); + spin_unlock_bh(&rds_sock_lock); return 0; } @@ -471,12 +469,11 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len, { struct rds_sock *rs; struct rds_incoming *inc; - unsigned long flags; unsigned int total = 0; len /= sizeof(struct rds_info_message); - spin_lock_irqsave(&rds_sock_lock, flags); + spin_lock_bh(&rds_sock_lock); list_for_each_entry(rs, &rds_sock_list, rs_item) { read_lock(&rs->rs_recv_lock); @@ -492,7 +489,7 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len, read_unlock(&rs->rs_recv_lock); } - spin_unlock_irqrestore(&rds_sock_lock, flags); + spin_unlock_bh(&rds_sock_lock); lens->nr = total; lens->each = sizeof(struct rds_info_message); @@ -504,11 +501,10 @@ static void rds_sock_info(struct socket *sock, unsigned int len, { struct rds_info_socket sinfo; struct rds_sock *rs; - unsigned long flags; len /= sizeof(struct rds_info_socket); - spin_lock_irqsave(&rds_sock_lock, flags); + spin_lock_bh(&rds_sock_lock); if (len < rds_sock_count) goto out; @@ -529,7 +525,7 @@ out: lens->nr = rds_sock_count; lens->each = sizeof(struct rds_info_socket); - spin_unlock_irqrestore(&rds_sock_lock, flags); + spin_unlock_bh(&rds_sock_lock); } static void rds_exit(void) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index e7e1d0b57b3d..2776012132ea 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -419,7 +419,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) cb = netem_skb_cb(skb); if (q->gap == 0 || /* not doing reordering */ - q->counter < q->gap || /* inside last reordering gap */ + q->counter < q->gap - 1 || /* inside last reordering gap */ q->reorder < get_crandom(&q->reorder_cor)) { psched_time_t now; psched_tdiff_t delay; diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 03b56bc3b659..465df9ae1046 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1641,6 +1641,7 @@ int cache_register_net(struct cache_detail *cd, struct net *net) sunrpc_destroy_cache_detail(cd); return ret; } +EXPORT_SYMBOL_GPL(cache_register_net); int cache_register(struct cache_detail *cd) { @@ -1653,6 +1654,7 @@ void cache_unregister_net(struct cache_detail *cd, struct net *net) remove_cache_proc_entries(cd, net); sunrpc_destroy_cache_detail(cd); } +EXPORT_SYMBOL_GPL(cache_unregister_net); void cache_unregister(struct cache_detail *cd) { diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 9d01d46b05f3..e4aabc02368b 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -167,6 +167,7 @@ svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools) fail_free: kfree(m->to_pool); + m->to_pool = NULL; fail: return -ENOMEM; } @@ -285,9 +286,10 @@ svc_pool_map_put(void) mutex_lock(&svc_pool_map_mutex); if (!--m->count) { - m->mode = SVC_POOL_DEFAULT; kfree(m->to_pool); + m->to_pool = NULL; kfree(m->pool_to); + m->pool_to = NULL; m->npools = 0; } @@ -527,17 +529,20 @@ svc_destroy(struct svc_serv *serv) printk("svc_destroy: no threads for serv=%p!\n", serv); del_timer_sync(&serv->sv_temptimer); - - svc_close_all(&serv->sv_tempsocks); + /* + * The set of xprts (contained in the sv_tempsocks and + * sv_permsocks lists) is now constant, since it is modified + * only by accepting new sockets (done by service threads in + * svc_recv) or aging old ones (done by sv_temptimer), or + * configuration changes (excluded by whatever locking the + * caller is using--nfsd_mutex in the case of nfsd). So it's + * safe to traverse those lists and shut everything down: + */ + svc_close_all(serv); if (serv->sv_shutdown) serv->sv_shutdown(serv); - svc_close_all(&serv->sv_permsocks); - - BUG_ON(!list_empty(&serv->sv_permsocks)); - BUG_ON(!list_empty(&serv->sv_tempsocks)); - cache_clean_deferred(serv); if (svc_serv_is_pooled(serv)) @@ -683,8 +688,8 @@ found_pool: * Create or destroy enough new threads to make the number * of threads the given number. If `pool' is non-NULL, applies * only to threads in that pool, otherwise round-robins between - * all pools. Must be called with a svc_get() reference and - * the BKL or another lock to protect access to svc_serv fields. + * all pools. Caller must ensure that mutual exclusion between this and + * server startup or shutdown. * * Destroying threads relies on the service threads filling in * rqstp->rq_task, which only the nfs ones do. Assumes the serv diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 38649cfa4e81..74cb0d8e9ca1 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -22,6 +22,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt); static int svc_deferred_recv(struct svc_rqst *rqstp); static struct cache_deferred_req *svc_defer(struct cache_req *req); static void svc_age_temp_xprts(unsigned long closure); +static void svc_delete_xprt(struct svc_xprt *xprt); /* apparently the "standard" is that clients close * idle connections after 5 minutes, servers after @@ -147,8 +148,8 @@ EXPORT_SYMBOL_GPL(svc_xprt_put); * Called by transport drivers to initialize the transport independent * portion of the transport instance. */ -void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt, - struct svc_serv *serv) +void svc_xprt_init(struct net *net, struct svc_xprt_class *xcl, + struct svc_xprt *xprt, struct svc_serv *serv) { memset(xprt, 0, sizeof(*xprt)); xprt->xpt_class = xcl; @@ -163,7 +164,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt, spin_lock_init(&xprt->xpt_lock); set_bit(XPT_BUSY, &xprt->xpt_flags); rpc_init_wait_queue(&xprt->xpt_bc_pending, "xpt_bc_pending"); - xprt->xpt_net = get_net(&init_net); + xprt->xpt_net = get_net(net); } EXPORT_SYMBOL_GPL(svc_xprt_init); @@ -878,7 +879,7 @@ static void call_xpt_users(struct svc_xprt *xprt) /* * Remove a dead transport */ -void svc_delete_xprt(struct svc_xprt *xprt) +static void svc_delete_xprt(struct svc_xprt *xprt) { struct svc_serv *serv = xprt->xpt_server; struct svc_deferred_req *dr; @@ -893,14 +894,7 @@ void svc_delete_xprt(struct svc_xprt *xprt) spin_lock_bh(&serv->sv_lock); if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags)) list_del_init(&xprt->xpt_list); - /* - * The only time we're called while xpt_ready is still on a list - * is while the list itself is about to be destroyed (in - * svc_destroy). BUT svc_xprt_enqueue could still be attempting - * to add new entries to the sp_sockets list, so we can't leave - * a freed xprt on it. - */ - list_del_init(&xprt->xpt_ready); + BUG_ON(!list_empty(&xprt->xpt_ready)); if (test_bit(XPT_TEMP, &xprt->xpt_flags)) serv->sv_tmpcnt--; spin_unlock_bh(&serv->sv_lock); @@ -928,22 +922,48 @@ void svc_close_xprt(struct svc_xprt *xprt) } EXPORT_SYMBOL_GPL(svc_close_xprt); -void svc_close_all(struct list_head *xprt_list) +static void svc_close_list(struct list_head *xprt_list) +{ + struct svc_xprt *xprt; + + list_for_each_entry(xprt, xprt_list, xpt_list) { + set_bit(XPT_CLOSE, &xprt->xpt_flags); + set_bit(XPT_BUSY, &xprt->xpt_flags); + } +} + +void svc_close_all(struct svc_serv *serv) { + struct svc_pool *pool; struct svc_xprt *xprt; struct svc_xprt *tmp; + int i; + + svc_close_list(&serv->sv_tempsocks); + svc_close_list(&serv->sv_permsocks); + for (i = 0; i < serv->sv_nrpools; i++) { + pool = &serv->sv_pools[i]; + + spin_lock_bh(&pool->sp_lock); + while (!list_empty(&pool->sp_sockets)) { + xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready); + list_del_init(&xprt->xpt_ready); + } + spin_unlock_bh(&pool->sp_lock); + } /* - * The server is shutting down, and no more threads are running. - * svc_xprt_enqueue() might still be running, but at worst it - * will re-add the xprt to sp_sockets, which will soon get - * freed. So we don't bother with any more locking, and don't - * leave the close to the (nonexistent) server threads: + * At this point the sp_sockets lists will stay empty, since + * svc_enqueue will not add new entries without taking the + * sp_lock and checking XPT_BUSY. */ - list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { - set_bit(XPT_CLOSE, &xprt->xpt_flags); + list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list) svc_delete_xprt(xprt); - } + list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list) + svc_delete_xprt(xprt); + + BUG_ON(!list_empty(&serv->sv_permsocks)); + BUG_ON(!list_empty(&serv->sv_tempsocks)); } /* diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 4653286fcc9e..464570906f80 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -739,7 +739,8 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) { int err, level, optname, one = 1; - svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv); + svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_udp_class, + &svsk->sk_xprt, serv); clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); svsk->sk_sk->sk_data_ready = svc_udp_data_ready; svsk->sk_sk->sk_write_space = svc_write_space; @@ -1343,7 +1344,8 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) { struct sock *sk = svsk->sk_sk; - svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv); + svc_xprt_init(sock_net(svsk->sk_sock->sk), &svc_tcp_class, + &svsk->sk_xprt, serv); set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags); if (sk->sk_state == TCP_LISTEN) { dprintk("setting up TCP socket for listening\n"); @@ -1659,7 +1661,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv, return ERR_PTR(-ENOMEM); xprt = &svsk->sk_xprt; - svc_xprt_init(&svc_tcp_bc_class, xprt, serv); + svc_xprt_init(net, &svc_tcp_bc_class, xprt, serv); serv->sv_bc_xprt = xprt; diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index ba1296d88de0..894cb42db91d 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -453,7 +453,7 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv, if (!cma_xprt) return NULL; - svc_xprt_init(&svc_rdma_class, &cma_xprt->sc_xprt, serv); + svc_xprt_init(&init_net, &svc_rdma_class, &cma_xprt->sc_xprt, serv); INIT_LIST_HEAD(&cma_xprt->sc_accept_q); INIT_LIST_HEAD(&cma_xprt->sc_dto_q); INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index aad8fb699989..85d3bb7490aa 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1918,7 +1918,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; unix_state_lock(sk); - skb = skb_dequeue(&sk->sk_receive_queue); + skb = skb_peek(&sk->sk_receive_queue); if (skb == NULL) { unix_sk(sk)->recursion_level = 0; if (copied >= target) @@ -1958,11 +1958,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (check_creds) { /* Never glue messages from different writers */ if ((UNIXCB(skb).pid != siocb->scm->pid) || - (UNIXCB(skb).cred != siocb->scm->cred)) { - skb_queue_head(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk, skb->len); + (UNIXCB(skb).cred != siocb->scm->cred)) break; - } } else { /* Copy credentials */ scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred); @@ -1977,8 +1974,6 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, chunk = min_t(unsigned int, skb->len, size); if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { - skb_queue_head(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk, skb->len); if (copied == 0) copied = -EFAULT; break; @@ -1993,13 +1988,10 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (UNIXCB(skb).fp) unix_detach_fds(siocb->scm, skb); - /* put the skb back if we didn't use it up.. */ - if (skb->len) { - skb_queue_head(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk, skb->len); + if (skb->len) break; - } + skb_unlink(skb, &sk->sk_receive_queue); consume_skb(skb); if (siocb->scm->fp) @@ -2010,9 +2002,6 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (UNIXCB(skb).fp) siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); - /* put message back and return */ - skb_queue_head(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk, skb->len); break; } } while (size); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 637f11a1e4df..66b84fbf2746 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2290,7 +2290,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) link = &xfrm_dispatch[type]; /* All operations require privileges, even GET */ - if (security_netlink_recv(skb, CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst index a57f5bd5a13d..d3bae5e7b601 100644 --- a/scripts/Makefile.headersinst +++ b/scripts/Makefile.headersinst @@ -4,12 +4,16 @@ # header-y - list files to be installed. They are preprocessed # to remove __KERNEL__ section of the file # objhdr-y - Same as header-y but for generated files +# genhdr-y - Same as objhdr-y but in a generated/ directory # # ========================================================================== # called may set destination dir (when installing to asm/) _dst := $(if $(dst),$(dst),$(obj)) +# generated header directory +gen := $(if $(gen),$(gen),$(subst include/,include/generated/,$(obj))) + kbuild-file := $(srctree)/$(obj)/Kbuild include $(kbuild-file) @@ -33,9 +37,10 @@ wrapper-files := $(filter $(header-y), $(generic-y)) # all headers files for this dir header-y := $(filter-out $(generic-y), $(header-y)) -all-files := $(header-y) $(objhdr-y) $(wrapper-files) +all-files := $(header-y) $(objhdr-y) $(genhdr-y) $(wrapper-files) input-files := $(addprefix $(srctree)/$(obj)/,$(header-y)) \ - $(addprefix $(objtree)/$(obj)/,$(objhdr-y)) + $(addprefix $(objtree)/$(obj)/,$(objhdr-y)) \ + $(addprefix $(objtree)/$(gen)/,$(genhdr-y)) output-files := $(addprefix $(install)/, $(all-files)) # Work out what needs to be removed @@ -52,6 +57,7 @@ quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\ cmd_install = \ $(PERL) $< $(srctree)/$(obj) $(install) $(SRCARCH) $(header-y); \ $(PERL) $< $(objtree)/$(obj) $(install) $(SRCARCH) $(objhdr-y); \ + $(PERL) $< $(objtree)/$(gen) $(install) $(SRCARCH) $(genhdr-y); \ for F in $(wrapper-files); do \ echo "\#include <asm-generic/$$F>" > $(install)/$$F; \ done; \ diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 5d986d9adf1b..00c368c6e996 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -93,9 +93,9 @@ obj-dirs := $(addprefix $(obj)/,$(obj-dirs)) # already # $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will # end up in (or would, if it gets compiled in) -# Note: It's possible that one object gets potentially linked into more -# than one module. In that case KBUILD_MODNAME will be set to foo_bar, -# where foo and bar are the name of the modules. +# Note: Files that end up in two or more modules are compiled without the +# KBUILD_MODNAME definition. The reason is that any made-up name would +# differ in different configs. name-fix = $(subst $(comma),_,$(subst -,_,$1)) basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" modname_flags = $(if $(filter 1,$(words $(modname))),\ @@ -264,7 +264,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb $(call cmd,dt_S_dtb) quiet_cmd_dtc = DTC $@ -cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) $< +cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) -d $(depfile) $< # Bzip2 # --------------------------------------------------------------------------- diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index 3ab316e52313..d24810fc6af6 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -198,11 +198,16 @@ EOF } syscall_list() { -sed -n -e '/^\#define/ s/[^_]*__NR_\([^[:space:]]*\).*/\ -\#if !defined \(__NR_\1\) \&\& !defined \(__IGNORE_\1\)\ -\#warning syscall \1 not implemented\ -\#endif/p' $1 + grep '^[0-9]' "$1" | sort -n | ( + while read nr abi name entry ; do + echo <<EOF +#if !defined(__NR_${name}) && !defined(__IGNORE_${name}) +#warning syscall ${name} not implemented +#endif +EOF + done + ) } -(ignore_list && syscall_list $(dirname $0)/../arch/x86/include/asm/unistd_32.h) | \ +(ignore_list && syscall_list $(dirname $0)/../arch/x86/syscalls/syscall_32.tbl) | \ $* -E -x c - > /dev/null diff --git a/scripts/coccicheck b/scripts/coccicheck index 1bb1a1bd2daa..3c2776466d87 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -9,14 +9,23 @@ if [ "$C" = "1" -o "$C" = "2" ]; then # FLAGS="-ignore_unknown_options -very_quiet" # OPTIONS=$* -# Workaround for Coccinelle < 0.2.3 - FLAGS="-I $srctree/include -very_quiet" - shift $(( $# - 1 )) - OPTIONS=$1 + if [ "$KBUILD_EXTMOD" = "" ] ; then + # Workaround for Coccinelle < 0.2.3 + FLAGS="-I $srctree/include -very_quiet" + shift $(( $# - 1 )) + OPTIONS=$1 + else + echo M= is not currently supported when C=1 or C=2 + exit 1 + fi else ONLINE=0 FLAGS="-very_quiet" - OPTIONS="-dir $srctree" + if [ "$KBUILD_EXTMOD" = "" ] ; then + OPTIONS="-dir $srctree" + else + OPTIONS="-dir $KBUILD_EXTMOD -patch $srctree -I $srctree/include -I $KBUILD_EXTMOD/include" + fi fi if [ ! -x "$SPATCH" ]; then diff --git a/scripts/coccinelle/api/devm_request_and_ioremap.cocci b/scripts/coccinelle/api/devm_request_and_ioremap.cocci new file mode 100644 index 000000000000..46beb81406ab --- /dev/null +++ b/scripts/coccinelle/api/devm_request_and_ioremap.cocci @@ -0,0 +1,105 @@ +/// Reimplement a call to devm_request_mem_region followed by a call to ioremap +/// or ioremap_nocache by a call to devm_request_and_ioremap. +/// Devm_request_and_ioremap was introduced in +/// 72f8c0bfa0de64c68ee59f40eb9b2683bffffbb0. It makes the code much more +/// concise. +/// +/// +// Confidence: High +// Copyright: (C) 2011 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2011 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual patch +virtual org +virtual report +virtual context + +@nm@ +expression myname; +identifier i; +@@ + +struct platform_driver i = { .driver = { .name = myname } }; + +@depends on patch@ +expression dev,res,size; +@@ + +-if (!devm_request_mem_region(dev, res->start, size, +- \(res->name\|dev_name(dev)\))) { +- ... +- return ...; +-} +... when != res->start +( +-devm_ioremap(dev,res->start,size) ++devm_request_and_ioremap(dev,res) +| +-devm_ioremap_nocache(dev,res->start,size) ++devm_request_and_ioremap(dev,res) +) +... when any + when != res->start + +// this rule is separate from the previous one, because a single file can +// have multiple values of myname +@depends on patch@ +expression dev,res,size; +expression nm.myname; +@@ + +-if (!devm_request_mem_region(dev, res->start, size,myname)) { +- ... +- return ...; +-} +... when != res->start +( +-devm_ioremap(dev,res->start,size) ++devm_request_and_ioremap(dev,res) +| +-devm_ioremap_nocache(dev,res->start,size) ++devm_request_and_ioremap(dev,res) +) +... when any + when != res->start + + +@pb depends on org || report || context@ +expression dev,res,size; +expression nm.myname; +position p1,p2; +@@ + +*if + (!devm_request_mem_region@p1(dev, res->start, size, + \(res->name\|dev_name(dev)\|myname\))) { + ... + return ...; +} +... when != res->start +( +*devm_ioremap@p2(dev,res->start,size) +| +*devm_ioremap_nocache@p2(dev,res->start,size) +) +... when any + when != res->start + +@script:python depends on org@ +p1 << pb.p1; +p2 << pb.p2; +@@ + +cocci.print_main("INFO: replace by devm_request_and_ioremap",p1) +cocci.print_secs("",p2) + +@script:python depends on report@ +p1 << pb.p1; +p2 << pb.p2; +@@ + +msg = "INFO: devm_request_mem_region followed by ioremap on line %s can be replaced by devm_request_and_ioremap" % (p2[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/scripts/coccinelle/api/kstrdup.cocci b/scripts/coccinelle/api/kstrdup.cocci index e0805ad08d39..07a74b2c6196 100644 --- a/scripts/coccinelle/api/kstrdup.cocci +++ b/scripts/coccinelle/api/kstrdup.cocci @@ -1,16 +1,19 @@ /// Use kstrdup rather than duplicating its implementation /// // Confidence: High -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers virtual patch +virtual context +virtual org +virtual report -@@ +@depends on patch@ expression from,to; expression flag,E1,E2; statement S; @@ -23,7 +26,7 @@ statement S; ... when != \(from = E2 \| to = E2 \) - strcpy(to, from); -@@ +@depends on patch@ expression x,from,to; expression flag,E1,E2,E3; statement S; @@ -37,3 +40,65 @@ statement S; if (to==NULL || ...) S ... when != \(x = E3 \| from = E3 \| to = E3 \) - memcpy(to, from, x); + +// --------------------------------------------------------------------- + +@r1 depends on !patch exists@ +expression from,to; +expression flag,E1,E2; +statement S; +position p1,p2; +@@ + +* to = kmalloc@p1(strlen(from) + 1,flag); + ... when != \(from = E1 \| to = E1 \) + if (to==NULL || ...) S + ... when != \(from = E2 \| to = E2 \) +* strcpy@p2(to, from); + +@r2 depends on !patch exists@ +expression x,from,to; +expression flag,E1,E2,E3; +statement S; +position p1,p2; +@@ + +* x = strlen(from) + 1; + ... when != \( x = E1 \| from = E1 \) +* to = \(kmalloc@p1\|kzalloc@p2\)(x,flag); + ... when != \(x = E2 \| from = E2 \| to = E2 \) + if (to==NULL || ...) S + ... when != \(x = E3 \| from = E3 \| to = E3 \) +* memcpy@p2(to, from, x); + +@script:python depends on org@ +p1 << r1.p1; +p2 << r1.p2; +@@ + +cocci.print_main("WARNING opportunity for kstrdep",p1) +cocci.print_secs("strcpy",p2) + +@script:python depends on org@ +p1 << r2.p1; +p2 << r2.p2; +@@ + +cocci.print_main("WARNING opportunity for kstrdep",p1) +cocci.print_secs("memcpy",p2) + +@script:python depends on report@ +p1 << r1.p1; +p2 << r1.p2; +@@ + +msg = "WARNING opportunity for kstrdep (strcpy on line %s)" % (p2[0].line) +coccilib.report.print_report(p1[0], msg) + +@script:python depends on report@ +p1 << r2.p1; +p2 << r2.p2; +@@ + +msg = "WARNING opportunity for kstrdep (memcpy on line %s)" % (p2[0].line) +coccilib.report.print_report(p1[0], msg) diff --git a/scripts/coccinelle/api/memdup.cocci b/scripts/coccinelle/api/memdup.cocci index b5d722077dc1..4dceab6d54de 100644 --- a/scripts/coccinelle/api/memdup.cocci +++ b/scripts/coccinelle/api/memdup.cocci @@ -1,14 +1,17 @@ /// Use kmemdup rather than duplicating its implementation /// // Confidence: High -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers virtual patch +virtual context +virtual org +virtual report @r1@ expression from,to; @@ -28,7 +31,7 @@ position p; ... when != \( x = E1 \| from = E1 \) to = \(kmalloc@p\|kzalloc@p\)(x,flag); -@@ +@depends on patch@ expression from,to,size,flag; position p != {r1.p,r2.p}; statement S; @@ -38,3 +41,26 @@ statement S; + to = kmemdup(from,size,flag); if (to==NULL || ...) S - memcpy(to, from, size); + +@r depends on !patch@ +expression from,to,size,flag; +position p != {r1.p,r2.p}; +statement S; +@@ + +* to = \(kmalloc@p\|kzalloc@p\)(size,flag); + to = kmemdup(from,size,flag); + if (to==NULL || ...) S +* memcpy(to, from, size); + +@script:python depends on org@ +p << r.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING opportunity for kmemdep") + +@script:python depends on report@ +p << r.p; +@@ + +coccilib.report.print_report(p[0], "WARNING opportunity for kmemdep") diff --git a/scripts/coccinelle/api/memdup_user.cocci b/scripts/coccinelle/api/memdup_user.cocci index 72ce012e878a..2efac289fd59 100644 --- a/scripts/coccinelle/api/memdup_user.cocci +++ b/scripts/coccinelle/api/memdup_user.cocci @@ -1,23 +1,25 @@ -/// Use kmemdup_user rather than duplicating its implementation +/// Use memdup_user rather than duplicating its implementation /// This is a little bit restricted to reduce false positives /// // Confidence: High -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers virtual patch +virtual context +virtual org +virtual report -@@ +@depends on patch@ expression from,to,size,flag; -position p; identifier l1,l2; @@ -- to = \(kmalloc@p\|kzalloc@p\)(size,flag); +- to = \(kmalloc\|kzalloc\)(size,flag); + to = memdup_user(from,size); if ( - to==NULL @@ -33,3 +35,26 @@ identifier l1,l2; - -EFAULT - ...+> - } + +@r depends on !patch@ +expression from,to,size,flag; +position p; +statement S1,S2; +@@ + +* to = \(kmalloc@p\|kzalloc@p\)(size,flag); + if (to==NULL || ...) S1 + if (copy_from_user(to, from, size) != 0) + S2 + +@script:python depends on org@ +p << r.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING opportunity for memdep_user") + +@script:python depends on report@ +p << r.p; +@@ + +coccilib.report.print_report(p[0], "WARNING opportunity for memdep_user") diff --git a/scripts/coccinelle/free/devm_free.cocci b/scripts/coccinelle/free/devm_free.cocci new file mode 100644 index 000000000000..0a1e36146d76 --- /dev/null +++ b/scripts/coccinelle/free/devm_free.cocci @@ -0,0 +1,71 @@ +/// Find uses of standard freeing functons on values allocated using devm_ +/// functions. Values allocated using the devm_functions are freed when +/// the device is detached, and thus the use of the standard freeing +/// function would cause a double free. +/// See Documentation/driver-model/devres.txt for more information. +/// +/// A difficulty of detecting this problem is that the standard freeing +/// function might be called from a different function than the one +/// containing the allocation function. It is thus necessary to make the +/// connection between the allocation function and the freeing function. +/// Here this is done using the specific argument text, which is prone to +/// false positives. There is no rule for the request_region and +/// request_mem_region variants because this heuristic seems to be a bit +/// less reliable in these cases. +/// +// Confidence: Moderate +// Copyright: (C) 2011 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2011 Gilles Muller, INRIA/LiP6. GPLv2. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: -no_includes -include_headers + +virtual org +virtual report +virtual context + +@r depends on context || org || report@ +expression x; +@@ + +( + x = devm_kzalloc(...) +| + x = devm_request_irq(...) +| + x = devm_ioremap(...) +| + x = devm_ioremap_nocache(...) +| + x = devm_ioport_map(...) +) + +@pb@ +expression r.x; +position p; +@@ + +( +* kfree@p(x) +| +* free_irq@p(x) +| +* iounmap@p(x) +| +* ioport_unmap@p(x) +) + +@script:python depends on org@ +p << pb.p; +@@ + +msg="WARNING: invalid free of devm_ allocated data" +coccilib.org.print_todo(p[0], msg) + +@script:python depends on report@ +p << pb.p; +@@ + +msg="WARNING: invalid free of devm_ allocated data" +coccilib.report.print_report(p[0], msg) + diff --git a/scripts/coccinelle/free/kfree.cocci b/scripts/coccinelle/free/kfree.cocci index f9f79d9245ee..d9ae6d89c2f5 100644 --- a/scripts/coccinelle/free/kfree.cocci +++ b/scripts/coccinelle/free/kfree.cocci @@ -5,9 +5,9 @@ //# SCTP_DBG_OBJCNT_DEC that do not actually evaluate their argument /// // Confidence: Moderate -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers @@ -23,7 +23,7 @@ position p1; kfree@p1(E) @print expression@ -constant char *c; +constant char [] c; expression free.E,E2; type T; position p; @@ -37,6 +37,10 @@ identifier f; | E@p != E2 | + E2 == E@p +| + E2 != E@p +| !E@p | E@p || ... @@ -113,5 +117,5 @@ p1 << free.p1; p2 << r.p2; @@ -msg = "reference preceded by free on line %s" % (p1[0].line) +msg = "ERROR: reference preceded by free on line %s" % (p1[0].line) coccilib.report.print_report(p2[0],msg) diff --git a/scripts/coccinelle/iterators/fen.cocci b/scripts/coccinelle/iterators/fen.cocci index 77bc108c3f59..0a40af828c43 100644 --- a/scripts/coccinelle/iterators/fen.cocci +++ b/scripts/coccinelle/iterators/fen.cocci @@ -2,16 +2,19 @@ /// is no point to call of_node_put on the final value. /// // Confidence: High -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers virtual patch +virtual context +virtual org +virtual report -@@ +@depends on patch@ iterator name for_each_node_by_name; expression np,E; identifier l; @@ -24,7 +27,7 @@ for_each_node_by_name(np,...) { ... when != np = E - of_node_put(np); -@@ +@depends on patch@ iterator name for_each_node_by_type; expression np,E; identifier l; @@ -37,7 +40,7 @@ for_each_node_by_type(np,...) { ... when != np = E - of_node_put(np); -@@ +@depends on patch@ iterator name for_each_compatible_node; expression np,E; identifier l; @@ -50,7 +53,7 @@ for_each_compatible_node(np,...) { ... when != np = E - of_node_put(np); -@@ +@depends on patch@ iterator name for_each_matching_node; expression np,E; identifier l; @@ -62,3 +65,59 @@ for_each_matching_node(np,...) { } ... when != np = E - of_node_put(np); + +// ---------------------------------------------------------------------- + +@r depends on !patch forall@ +//iterator name for_each_node_by_name; +//iterator name for_each_node_by_type; +//iterator name for_each_compatible_node; +//iterator name for_each_matching_node; +expression np,E; +identifier l; +position p1,p2; +@@ + +( +*for_each_node_by_name@p1(np,...) +{ + ... when != break; + when != goto l; +} +| +*for_each_node_by_type@p1(np,...) +{ + ... when != break; + when != goto l; +} +| +*for_each_compatible_node@p1(np,...) +{ + ... when != break; + when != goto l; +} +| +*for_each_matching_node@p1(np,...) +{ + ... when != break; + when != goto l; +} +) +... when != np = E +* of_node_put@p2(np); + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("unneeded of_node_put",p2) +cocci.print_secs("iterator",p1) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "ERROR: of_node_put not needed after iterator on line %s" % (p1[0].line) +coccilib.report.print_report(p2[0], msg) diff --git a/scripts/coccinelle/iterators/itnull.cocci b/scripts/coccinelle/iterators/itnull.cocci index baa4297a4ed1..259899f6838e 100644 --- a/scripts/coccinelle/iterators/itnull.cocci +++ b/scripts/coccinelle/iterators/itnull.cocci @@ -1,20 +1,24 @@ /// Many iterators have the property that the first argument is always bound -/// to a real list element, never NULL. False positives arise for some -/// iterators that do not have this property, or in cases when the loop -/// cursor is reassigned. The latter should only happen when the matched -/// code is on the way to a loop exit (break, goto, or return). +/// to a real list element, never NULL. +//# False positives arise for some iterators that do not have this property, +//# or in cases when the loop cursor is reassigned. The latter should only +//# happen when the matched code is on the way to a loop exit (break, goto, +//# or return). /// // Confidence: Moderate -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers virtual patch +virtual context +virtual org +virtual report -@@ +@depends on patch@ iterator I; expression x,E,E1,E2; statement S,S1,S2; @@ -55,4 +59,36 @@ I(x,...) { <... x != NULL + ) ) - ...> }
\ No newline at end of file + ...> } + +@r depends on !patch exists@ +iterator I; +expression x,E; +position p1,p2; +@@ + +*I@p1(x,...) +{ ... when != x = E +( +* x@p2 == NULL +| +* x@p2 != NULL +) + ... when any +} + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("iterator-bound variable",p1) +cocci.print_secs("useless NULL test",p2) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "ERROR: iterator variable bound on line %s cannot be NULL" % (p1[0].line) +coccilib.report.print_report(p2[0], msg) diff --git a/scripts/coccinelle/locks/call_kern.cocci b/scripts/coccinelle/locks/call_kern.cocci index 00af5344a68f..8f10b49603c3 100644 --- a/scripts/coccinelle/locks/call_kern.cocci +++ b/scripts/coccinelle/locks/call_kern.cocci @@ -1,17 +1,20 @@ /// Find functions that refer to GFP_KERNEL but are called with locks held. -/// The proposed change of converting the GFP_KERNEL is not necessarily the -/// correct one. It may be desired to unlock the lock, or to not call the -/// function under the lock in the first place. +//# The proposed change of converting the GFP_KERNEL is not necessarily the +//# correct one. It may be desired to unlock the lock, or to not call the +//# function under the lock in the first place. /// // Confidence: Moderate -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers virtual patch +virtual context +virtual org +virtual report @gfp exists@ identifier fn; @@ -32,28 +35,29 @@ fn(...) { ... when any } -@locked@ +@locked exists@ identifier gfp.fn; +position p1,p2; @@ ( -read_lock_irq +read_lock_irq@p1 | -write_lock_irq +write_lock_irq@p1 | -read_lock_irqsave +read_lock_irqsave@p1 | -write_lock_irqsave +write_lock_irqsave@p1 | -spin_lock +spin_lock@p1 | -spin_trylock +spin_trylock@p1 | -spin_lock_irq +spin_lock_irq@p1 | -spin_lock_irqsave +spin_lock_irqsave@p1 | -local_irq_disable +local_irq_disable@p1 ) (...) ... when != read_unlock_irq(...) @@ -64,11 +68,38 @@ local_irq_disable when != spin_unlock_irq(...) when != spin_unlock_irqrestore(...) when != local_irq_enable(...) -fn(...) +fn@p2(...) -@depends on locked@ +@depends on locked && patch@ position gfp.p; @@ - GFP_KERNEL@p + GFP_ATOMIC + +@depends on locked && !patch@ +position gfp.p; +@@ + +* GFP_KERNEL@p + +@script:python depends on !patch && org@ +p << gfp.p; +fn << gfp.fn; +p1 << locked.p1; +p2 << locked.p2; +@@ + +cocci.print_main("lock",p1) +cocci.print_secs("call",p2) +cocci.print_secs("GFP_KERNEL",p) + +@script:python depends on !patch && report@ +p << gfp.p; +fn << gfp.fn; +p1 << locked.p1; +p2 << locked.p2; +@@ + +msg = "ERROR: function %s called on line %s inside lock on line %s but uses GFP_KERNEL" % (fn,p2[0].line,p1[0].line) +coccilib.report.print_report(p[0], msg) diff --git a/scripts/coccinelle/locks/flags.cocci b/scripts/coccinelle/locks/flags.cocci index b4344d838097..1c4ffe6fd846 100644 --- a/scripts/coccinelle/locks/flags.cocci +++ b/scripts/coccinelle/locks/flags.cocci @@ -1,9 +1,9 @@ /// Find nested lock+irqsave functions that use the same flags variables /// // Confidence: High -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers @@ -12,7 +12,7 @@ virtual context virtual org virtual report -@r@ +@r exists@ expression lock1,lock2,flags; position p1,p2; @@ @@ -39,7 +39,7 @@ read_lock_irqsave@p2(lock2,flags) write_lock_irqsave@p2(lock2,flags) ) -@d@ +@d exists@ expression f <= r.flags; expression lock1,lock2,flags; position r.p1, r.p2; @@ -76,5 +76,5 @@ p1 << r.p1; p2 << r.p2; @@ -msg="ERROR: nested lock+irqsave that reuses flags from %s." % (p1[0].line) +msg="ERROR: nested lock+irqsave that reuses flags from line %s." % (p1[0].line) coccilib.report.print_report(p2[0], msg) diff --git a/scripts/coccinelle/locks/mini_lock.cocci b/scripts/coccinelle/locks/mini_lock.cocci index 7641a2925434..3267d7410bd5 100644 --- a/scripts/coccinelle/locks/mini_lock.cocci +++ b/scripts/coccinelle/locks/mini_lock.cocci @@ -6,13 +6,14 @@ /// function call that releases the lock. /// // Confidence: Moderate -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers +virtual context virtual org virtual report @@ -57,7 +58,7 @@ position r; for(...;...;...) { <+... return@r ...; ...+> } -@err@ +@err exists@ expression E1; position prelocked.p; position up != prelocked.p1; @@ -65,14 +66,14 @@ position r!=looped.r; identifier lock,unlock; @@ -lock(E1@p,...); +*lock(E1@p,...); <+... when != E1 if (...) { ... when != E1 - return@r ...; +* return@r ...; } ...+> -unlock@up(E1,...); +*unlock@up(E1,...); @script:python depends on org@ p << prelocked.p1; diff --git a/scripts/coccinelle/misc/doubleinit.cocci b/scripts/coccinelle/misc/doubleinit.cocci index 156b20adb351..cf74a00cf597 100644 --- a/scripts/coccinelle/misc/doubleinit.cocci +++ b/scripts/coccinelle/misc/doubleinit.cocci @@ -3,9 +3,9 @@ /// initialization. /// // Confidence: Low -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise // Options: -no_includes -include_headers @@ -49,5 +49,5 @@ pr << r.p; @@ if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)): - msg = "%s: first occurrence %s, second occurrence %s" % (fld,ps[0].line,pr[0].line) + msg = "%s: first occurrence line %s, second occurrence line %s" % (fld,ps[0].line,pr[0].line) coccilib.report.print_report(p0[0],msg) diff --git a/scripts/coccinelle/null/eno.cocci b/scripts/coccinelle/null/eno.cocci index 4c9c52b9c413..ed961a1f7d11 100644 --- a/scripts/coccinelle/null/eno.cocci +++ b/scripts/coccinelle/null/eno.cocci @@ -1,16 +1,19 @@ /// The various basic memory allocation functions don't return ERR_PTR /// // Confidence: High -// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2. -// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. -// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. +// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ // Comments: // Options: -no_includes -include_headers virtual patch +virtual context +virtual org +virtual report -@@ +@depends on patch@ expression x,E; @@ @@ -18,3 +21,28 @@ x = \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|kmem_cache ... when != x = E - IS_ERR(x) + !x + +@r depends on !patch exists@ +expression x,E; +position p1,p2; +@@ + +*x = \(kmalloc@p1\|kzalloc@p1\|kcalloc@p1\|kmem_cache_alloc@p1\|kmem_cache_zalloc@p1\|kmem_cache_alloc_node@p1\|kmalloc_node@p1\|kzalloc_node@p1\)(...) +... when != x = E +* IS_ERR@p2(x) + +@script:python depends on org@ +p1 << r.p1; +p2 << r.p2; +@@ + +cocci.print_main("alloc call",p1) +cocci.print_secs("IS_ERR that should be NULL tests",p2) + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +@@ + +msg = "ERROR: allocation function on line %s returns NULL not ERR_PTR on failure" % (p1[0].line) +coccilib.report.print_report(p2[0], msg) diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index cbc0193098e4..451c92d31b19 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -71,6 +71,7 @@ static void __attribute__ ((noreturn)) usage(void) fprintf(stderr, "\t\t\tasm - assembler source\n"); fprintf(stderr, "\t-V <output version>\n"); fprintf(stderr, "\t\tBlob version to produce, defaults to %d (relevant for dtb\n\t\tand asm output only)\n", DEFAULT_FDT_VERSION); + fprintf(stderr, "\t-d <output dependency file>\n"); fprintf(stderr, "\t-R <number>\n"); fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n"); fprintf(stderr, "\t-S <bytes>\n"); @@ -99,6 +100,7 @@ int main(int argc, char *argv[]) const char *inform = "dts"; const char *outform = "dts"; const char *outname = "-"; + const char *depname = NULL; int force = 0, check = 0, sort = 0; const char *arg; int opt; @@ -111,7 +113,8 @@ int main(int argc, char *argv[]) minsize = 0; padsize = 0; - while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:s")) != EOF) { + while ((opt = getopt(argc, argv, "hI:O:o:V:d:R:S:p:fcqb:vH:s")) + != EOF) { switch (opt) { case 'I': inform = optarg; @@ -125,6 +128,9 @@ int main(int argc, char *argv[]) case 'V': outversion = strtol(optarg, NULL, 0); break; + case 'd': + depname = optarg; + break; case 'R': reservenum = strtol(optarg, NULL, 0); break; @@ -188,6 +194,14 @@ int main(int argc, char *argv[]) fprintf(stderr, "DTC: %s->%s on file \"%s\"\n", inform, outform, arg); + if (depname) { + depfile = fopen(depname, "w"); + if (!depfile) + die("Couldn't open dependency file %s: %s\n", depname, + strerror(errno)); + fprintf(depfile, "%s:", outname); + } + if (streq(inform, "dts")) bi = dt_from_source(arg); else if (streq(inform, "fs")) @@ -197,6 +211,11 @@ int main(int argc, char *argv[]) else die("Unknown input format \"%s\"\n", inform); + if (depfile) { + fputc('\n', depfile); + fclose(depfile); + } + if (cmdline_boot_cpuid != -1) bi->boot_cpuid_phys = cmdline_boot_cpuid; diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index 2dbc874288ca..36a38e9f1a2c 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -40,6 +40,7 @@ static char *dirname(const char *path) return NULL; } +FILE *depfile; /* = NULL */ struct srcfile_state *current_srcfile; /* = NULL */ /* Detect infinite include recursion. */ @@ -67,6 +68,9 @@ FILE *srcfile_relative_open(const char *fname, char **fullnamep) strerror(errno)); } + if (depfile) + fprintf(depfile, " %s", fullname); + if (fullnamep) *fullnamep = fullname; else diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h index bd7966e56a53..ce980cafe588 100644 --- a/scripts/dtc/srcpos.h +++ b/scripts/dtc/srcpos.h @@ -30,6 +30,7 @@ struct srcfile_state { struct srcfile_state *prev; }; +extern FILE *depfile; /* = NULL */ extern struct srcfile_state *current_srcfile; /* = NULL */ FILE *srcfile_relative_open(const char *fname, char **fullnamep); diff --git a/scripts/genksyms/Makefile b/scripts/genksyms/Makefile index a5510903e874..aca33b98bf63 100644 --- a/scripts/genksyms/Makefile +++ b/scripts/genksyms/Makefile @@ -11,3 +11,4 @@ HOSTCFLAGS_lex.lex.o := -I$(src) # dependencies on generated files need to be listed explicitly $(obj)/lex.lex.o: $(obj)/keywords.hash.c $(obj)/parse.tab.h +clean-files := keywords.hash.c lex.lex.c parse.tab.c parse.tab.h diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 914833d99b06..79662658fb91 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -50,9 +50,8 @@ localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf # Create new linux.pot file # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files -# The symlink is used to repair a deficiency in arch/um update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h - $(Q)echo " GEN config" + $(Q)echo " GEN config.pot" $(Q)xgettext --default-domain=linux \ --add-comments --keyword=_ --keyword=N_ \ --from-code=UTF-8 \ @@ -63,10 +62,11 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \ $(srctree)/arch/*/um/Kconfig`; \ do \ - echo " GEN $$i"; \ + echo " GEN $$i"; \ $(obj)/kxgettext $$i \ >> $(obj)/config.pot; \ done ) + $(Q)echo " GEN linux.pot" $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ --output $(obj)/linux.pot $(Q)rm -f $(obj)/config.pot diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 5a58965d8800..7c7a5a6cc3f5 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -464,7 +464,7 @@ kconfig_print_comment(FILE *fp, const char *value, void *arg) fprintf(fp, "#"); if (l) { fprintf(fp, " "); - fwrite(p, l, 1, fp); + xfwrite(p, l, 1, fp); p += l; } fprintf(fp, "\n"); @@ -537,7 +537,7 @@ header_print_comment(FILE *fp, const char *value, void *arg) fprintf(fp, " *"); if (l) { fprintf(fp, " "); - fwrite(p, l, 1, fp); + xfwrite(p, l, 1, fp); p += l; } fprintf(fp, "\n"); diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 80fce57080cc..d4ecce8bc3a6 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -10,6 +10,7 @@ extern "C" { #endif +#include <assert.h> #include <stdio.h> #ifndef __cplusplus #include <stdbool.h> diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index 9f4438027df4..adc230638c5b 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -683,7 +683,7 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, - GTK_BUTTONS_CLOSE, intro_text); + GTK_BUTTONS_CLOSE, "%s", intro_text); g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog)); @@ -701,7 +701,7 @@ void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, - GTK_BUTTONS_CLOSE, about_text); + GTK_BUTTONS_CLOSE, "%s", about_text); g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog)); @@ -720,7 +720,7 @@ void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, - GTK_BUTTONS_CLOSE, license_text); + GTK_BUTTONS_CLOSE, "%s", license_text); g_signal_connect_swapped(GTK_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(dialog)); @@ -830,7 +830,7 @@ static void renderer_edited(GtkCellRendererText * cell, static void change_sym_value(struct menu *menu, gint col) { struct symbol *sym = menu->sym; - tristate oldval, newval; + tristate newval; if (!sym) return; @@ -847,7 +847,6 @@ static void change_sym_value(struct menu *menu, gint col) switch (sym_get_type(sym)) { case S_BOOLEAN: case S_TRISTATE: - oldval = sym_get_tristate_value(sym); if (!sym_tristate_within_range(sym, newval)) newval = yes; sym_set_tristate_value(sym, newval); @@ -1278,7 +1277,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst) gboolean valid; GtkTreeIter *sibling; struct symbol *sym; - struct property *prop; struct menu *menu1, *menu2; if (src == &rootmenu) @@ -1287,7 +1285,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst) valid = gtk_tree_model_iter_children(model2, child2, dst); for (child1 = src->list; child1; child1 = child1->next) { - prop = child1->prompt; sym = child1->sym; reparse: diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index b633bdb9f3d4..c18f2bd9c095 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -90,8 +90,10 @@ struct conf_printer { /* confdata.c and expr.c */ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) { - if (fwrite(str, len, count, out) < count) - fprintf(stderr, "\nError in writing or end of file.\n"); + assert(len != 0); + + if (fwrite(str, len, count, out) != count) + fprintf(stderr, "Error in writing or end of file.\n"); } /* menu.c */ diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 19e200d91120..2c6286c0bc1a 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -830,6 +830,8 @@ static int handle_exit(void) fprintf(stderr, _("\n\n" "Your configuration changes were NOT saved." "\n\n")); + if (res != KEY_ESC) + res = 0; } return res; diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh new file mode 100644 index 000000000000..ceadf0e150cf --- /dev/null +++ b/scripts/kconfig/merge_config.sh @@ -0,0 +1,117 @@ +#!/bin/sh +# merge_config.sh - Takes a list of config fragment values, and merges +# them one by one. Provides warnings on overridden values, and specified +# values that did not make it to the resulting .config file (due to missed +# dependencies or config symbol removal). +# +# Portions reused from kconf_check and generate_cfg: +# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check +# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg +# +# Copyright (c) 2009-2010 Wind River Systems, Inc. +# Copyright 2011 Linaro +# +# 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. + +clean_up() { + rm -f $TMP_FILE + exit +} +trap clean_up HUP INT TERM + +usage() { + echo "Usage: $0 [OPTIONS] [CONFIG [...]]" + echo " -h display this help text" + echo " -m only merge the fragments, do not execute the make command" + echo " -n use allnoconfig instead of alldefconfig" +} + +MAKE=true +ALLTARGET=alldefconfig + +while true; do + case $1 in + "-n") + ALLTARGET=allnoconfig + shift + continue + ;; + "-m") + MAKE=false + shift + continue + ;; + "-h") + usage + exit + ;; + *) + break + ;; + esac +done + + + +MERGE_LIST=$* +SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p" +TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) + +# Merge files, printing warnings on overrided values +for MERGE_FILE in $MERGE_LIST ; do + echo "Merging $MERGE_FILE" + CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE) + + for CFG in $CFG_LIST ; do + grep -q -w $CFG $TMP_FILE + if [ $? -eq 0 ] ; then + PREV_VAL=$(grep -w $CFG $TMP_FILE) + NEW_VAL=$(grep -w $CFG $MERGE_FILE) + if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then + echo Value of $CFG is redefined by fragment $MERGE_FILE: + echo Previous value: $PREV_VAL + echo New value: $NEW_VAL + echo + fi + sed -i "/$CFG[ =]/d" $TMP_FILE + fi + done + cat $MERGE_FILE >> $TMP_FILE +done + +if [ "$MAKE" = "false" ]; then + cp $TMP_FILE .config + echo "#" + echo "# merged configuration written to .config (needs make)" + echo "#" + clean_up + exit +fi + +# Use the merged file as the starting point for: +# alldefconfig: Fills in any missing symbols with Kconfig default +# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set +make KCONFIG_ALLCONFIG=$TMP_FILE $ALLTARGET + + +# Check all specified config values took (might have missed-dependency issues) +for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do + + REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) + ACTUAL_VAL=$(grep -w -e "$CFG" .config) + if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then + echo "Value requested for $CFG not in final .config" + echo "Requested value: $REQUESTED_VAL" + echo "Actual value: $ACTUAL_VAL" + echo "" + fi +done + +clean_up diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index ec7afce4c88d..bccf07ddd0b6 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -250,33 +250,61 @@ if ($kconfig) { read_kconfig($kconfig); } +sub convert_vars { + my ($line, %vars) = @_; + + my $process = ""; + + while ($line =~ s/^(.*?)(\$\((.*?)\))//) { + my $start = $1; + my $variable = $2; + my $var = $3; + + if (defined($vars{$var})) { + $process .= $start . $vars{$var}; + } else { + $process .= $start . $variable; + } + } + + $process .= $line; + + return $process; +} + # Read all Makefiles to map the configs to the objects foreach my $makefile (@makefiles) { - my $cont = 0; + my $line = ""; + my %make_vars; open(MIN,$makefile) || die "Can't open $makefile"; while (<MIN>) { + # if this line ends with a backslash, continue + chomp; + if (/^(.*)\\$/) { + $line .= $1; + next; + } + + $line .= $_; + $_ = $line; + $line = ""; + my $objs; - # is this a line after a line with a backslash? - if ($cont && /(\S.*)$/) { - $objs = $1; - } - $cont = 0; + $_ = convert_vars($_, %make_vars); # collect objects after obj-$(CONFIG_FOO_BAR) if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) { $var = $1; $objs = $2; + + # check if variables are set + } elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) { + $make_vars{$1} = $2; } if (defined($objs)) { - # test if the line ends with a backslash - if ($objs =~ m,(.*)\\$,) { - $objs = $1; - $cont = 1; - } - foreach my $obj (split /\s+/,$objs) { $obj =~ s/-/_/g; if ($obj =~ /(.*)\.o$/) { diff --git a/scripts/kernel-doc b/scripts/kernel-doc index d793001929cf..9b0c0b8b4ab4 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -5,7 +5,7 @@ use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## ## Copyright (C) 2001 Simon Huggins ## -## Copyright (C) 2005-2010 Randy Dunlap ## +## Copyright (C) 2005-2012 Randy Dunlap ## ## ## ## #define enhancements by Armin Kuster <akuster@mvista.com> ## ## Copyright (c) 2000 MontaVista Software, Inc. ## @@ -1785,6 +1785,7 @@ sub dump_function($$) { $prototype =~ s/__devinit +//; $prototype =~ s/__init +//; $prototype =~ s/__init_or_module +//; + $prototype =~ s/__must_check +//; $prototype =~ s/^#\s*define\s+//; #ak added $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 363ab4666b17..c0e14b3f2306 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -28,6 +28,7 @@ typedef Elf64_Addr kernel_ulong_t; #endif #include <ctype.h> +#include <stdbool.h> typedef uint32_t __u32; typedef uint16_t __u16; @@ -38,6 +39,35 @@ typedef unsigned char __u8; * we handle those differences explicitly below */ #include "../../include/linux/mod_devicetable.h" +/* This array collects all instances that use the generic do_table */ +struct devtable { + const char *device_id; /* name of table, __mod_<name>_device_table. */ + unsigned long id_size; + void *function; +}; + +/* We construct a table of pointers in an ELF section (pointers generally + * go unpadded by gcc). ld creates boundary syms for us. */ +extern struct devtable *__start___devtable[], *__stop___devtable[]; +#define ___cat(a,b) a ## b +#define __cat(a,b) ___cat(a,b) + +#if __GNUC__ == 3 && __GNUC_MINOR__ < 3 +# define __used __attribute__((__unused__)) +#else +# define __used __attribute__((__used__)) +#endif + +/* Add a table entry. We test function type matches while we're here. */ +#define ADD_TO_DEVTABLE(device_id, type, function) \ + static struct devtable __cat(devtable,__LINE__) = { \ + device_id + 0*sizeof((function)((const char *)NULL, \ + (type *)NULL, \ + (char *)NULL)), \ + sizeof(type), (function) }; \ + static struct devtable *__attribute__((section("__devtable"))) \ + __used __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__) + #define ADD(str, sep, cond, field) \ do { \ strcat(str, sep); \ @@ -289,6 +319,7 @@ static int do_hid_entry(const char *filename, return 1; } +ADD_TO_DEVTABLE("hid", struct hid_device_id, do_hid_entry); /* Looks like: ieee1394:venNmoNspNverN */ static int do_ieee1394_entry(const char *filename, @@ -313,6 +344,7 @@ static int do_ieee1394_entry(const char *filename, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("ieee1394", struct ieee1394_device_id, do_ieee1394_entry); /* Looks like: pci:vNdNsvNsdNbcNscNiN. */ static int do_pci_entry(const char *filename, @@ -356,6 +388,7 @@ static int do_pci_entry(const char *filename, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("pci", struct pci_device_id, do_pci_entry); /* looks like: "ccw:tNmNdtNdmN" */ static int do_ccw_entry(const char *filename, @@ -379,6 +412,7 @@ static int do_ccw_entry(const char *filename, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("ccw", struct ccw_device_id, do_ccw_entry); /* looks like: "ap:tN" */ static int do_ap_entry(const char *filename, @@ -387,6 +421,7 @@ static int do_ap_entry(const char *filename, sprintf(alias, "ap:t%02X*", id->dev_type); return 1; } +ADD_TO_DEVTABLE("ap", struct ap_device_id, do_ap_entry); /* looks like: "css:tN" */ static int do_css_entry(const char *filename, @@ -395,6 +430,7 @@ static int do_css_entry(const char *filename, sprintf(alias, "css:t%01X", id->type); return 1; } +ADD_TO_DEVTABLE("css", struct css_device_id, do_css_entry); /* Looks like: "serio:tyNprNidNexN" */ static int do_serio_entry(const char *filename, @@ -414,6 +450,7 @@ static int do_serio_entry(const char *filename, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("serio", struct serio_device_id, do_serio_entry); /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ static int do_acpi_entry(const char *filename, @@ -422,6 +459,7 @@ static int do_acpi_entry(const char *filename, sprintf(alias, "acpi*:%s:*", id->id); return 1; } +ADD_TO_DEVTABLE("acpi", struct acpi_device_id, do_acpi_entry); /* looks like: "pnp:dD" */ static void do_pnp_device_entry(void *symval, unsigned long size, @@ -544,8 +582,7 @@ static int do_pcmcia_entry(const char *filename, add_wildcard(alias); return 1; } - - +ADD_TO_DEVTABLE("pcmcia", struct pcmcia_device_id, do_pcmcia_entry); static int do_of_entry (const char *filename, struct of_device_id *of, char *alias) { @@ -568,6 +605,7 @@ static int do_of_entry (const char *filename, struct of_device_id *of, char *ali add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("of", struct of_device_id, do_of_entry); static int do_vio_entry(const char *filename, struct vio_device_id *vio, char *alias) @@ -585,6 +623,7 @@ static int do_vio_entry(const char *filename, struct vio_device_id *vio, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("vio", struct vio_device_id, do_vio_entry); #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -640,6 +679,7 @@ static int do_input_entry(const char *filename, struct input_device_id *id, do_input(alias, id->swbit, 0, INPUT_DEVICE_ID_SW_MAX); return 1; } +ADD_TO_DEVTABLE("input", struct input_device_id, do_input_entry); static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa, char *alias) @@ -650,6 +690,7 @@ static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa, strcat(alias, "*"); return 1; } +ADD_TO_DEVTABLE("eisa", struct eisa_device_id, do_eisa_entry); /* Looks like: parisc:tNhvNrevNsvN */ static int do_parisc_entry(const char *filename, struct parisc_device_id *id, @@ -669,6 +710,7 @@ static int do_parisc_entry(const char *filename, struct parisc_device_id *id, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("parisc", struct parisc_device_id, do_parisc_entry); /* Looks like: sdio:cNvNdN. */ static int do_sdio_entry(const char *filename, @@ -685,6 +727,7 @@ static int do_sdio_entry(const char *filename, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("sdio", struct sdio_device_id, do_sdio_entry); /* Looks like: ssb:vNidNrevN. */ static int do_ssb_entry(const char *filename, @@ -701,6 +744,7 @@ static int do_ssb_entry(const char *filename, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("ssb", struct ssb_device_id, do_ssb_entry); /* Looks like: bcma:mNidNrevNclN. */ static int do_bcma_entry(const char *filename, @@ -719,6 +763,7 @@ static int do_bcma_entry(const char *filename, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("bcma", struct bcma_device_id, do_bcma_entry); /* Looks like: virtio:dNvN */ static int do_virtio_entry(const char *filename, struct virtio_device_id *id, @@ -734,6 +779,7 @@ static int do_virtio_entry(const char *filename, struct virtio_device_id *id, add_wildcard(alias); return 1; } +ADD_TO_DEVTABLE("virtio", struct virtio_device_id, do_virtio_entry); /* * Looks like: vmbus:guid @@ -755,6 +801,7 @@ static int do_vmbus_entry(const char *filename, struct hv_vmbus_device_id *id, return 1; } +ADD_TO_DEVTABLE("vmbus", struct hv_vmbus_device_id, do_vmbus_entry); /* Looks like: i2c:S */ static int do_i2c_entry(const char *filename, struct i2c_device_id *id, @@ -764,6 +811,7 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id, return 1; } +ADD_TO_DEVTABLE("i2c", struct i2c_device_id, do_i2c_entry); /* Looks like: spi:S */ static int do_spi_entry(const char *filename, struct spi_device_id *id, @@ -773,6 +821,17 @@ static int do_spi_entry(const char *filename, struct spi_device_id *id, return 1; } +ADD_TO_DEVTABLE("spi", struct spi_device_id, do_spi_entry); + +/* Looks like: mcp:S */ +static int do_mcp_entry(const char *filename, struct mcp_device_id *id, + char *alias) +{ + sprintf(alias, MCP_MODULE_PREFIX "%s", id->name); + + return 1; +} +ADD_TO_DEVTABLE("mcp", struct mcp_device_id, do_mcp_entry); static const struct dmifield { const char *prefix; @@ -827,6 +886,7 @@ static int do_dmi_entry(const char *filename, struct dmi_system_id *id, strcat(alias, ":"); return 1; } +ADD_TO_DEVTABLE("dmi", struct dmi_system_id, do_dmi_entry); static int do_platform_entry(const char *filename, struct platform_device_id *id, char *alias) @@ -834,6 +894,7 @@ static int do_platform_entry(const char *filename, sprintf(alias, PLATFORM_MODULE_PREFIX "%s", id->name); return 1; } +ADD_TO_DEVTABLE("platform", struct platform_device_id, do_platform_entry); static int do_mdio_entry(const char *filename, struct mdio_device_id *id, char *alias) @@ -856,6 +917,7 @@ static int do_mdio_entry(const char *filename, return 1; } +ADD_TO_DEVTABLE("mdio", struct mdio_device_id, do_mdio_entry); /* Looks like: zorro:iN. */ static int do_zorro_entry(const char *filename, struct zorro_device_id *id, @@ -866,6 +928,7 @@ static int do_zorro_entry(const char *filename, struct zorro_device_id *id, ADD(alias, "i", id->id != ZORRO_WILDCARD, id->id); return 1; } +ADD_TO_DEVTABLE("zorro", struct zorro_device_id, do_zorro_entry); /* looks like: "pnp:dD" */ static int do_isapnp_entry(const char *filename, @@ -879,6 +942,7 @@ static int do_isapnp_entry(const char *filename, (id->function >> 12) & 0x0f, (id->function >> 8) & 0x0f); return 1; } +ADD_TO_DEVTABLE("isa", struct isapnp_device_id, do_isapnp_entry); /* * Append a match expression for a single masked hex digit. @@ -947,16 +1011,15 @@ static int do_amba_entry(const char *filename, return 1; } +ADD_TO_DEVTABLE("amba", struct amba_id, do_amba_entry); -/* Ignore any prefix, eg. some architectures prepend _ */ -static inline int sym_is(const char *symbol, const char *name) +/* Does namelen bytes of name exactly match the symbol? */ +static bool sym_is(const char *name, unsigned namelen, const char *symbol) { - const char *match; + if (namelen != strlen(symbol)) + return false; - match = strstr(symbol, name); - if (!match) - return 0; - return match[strlen(name)] == '\0'; + return memcmp(name, symbol, namelen) == 0; } static void do_table(void *symval, unsigned long size, @@ -989,11 +1052,25 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, { void *symval; char *zeros = NULL; + const char *name; + unsigned int namelen; /* We're looking for a section relative symbol */ if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) return; + /* All our symbols are of form <prefix>__mod_XXX_device_table. */ + name = strstr(symname, "__mod_"); + if (!name) + return; + name += strlen("__mod_"); + namelen = strlen(name); + if (namelen < strlen("_device_table")) + return; + if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) + return; + namelen -= strlen("_device_table"); + /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { zeros = calloc(1, sym->st_size); @@ -1004,121 +1081,24 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, + sym->st_value; } - if (sym_is(symname, "__mod_pci_device_table")) - do_table(symval, sym->st_size, - sizeof(struct pci_device_id), "pci", - do_pci_entry, mod); - else if (sym_is(symname, "__mod_usb_device_table")) - /* special case to handle bcdDevice ranges */ + /* First handle the "special" cases */ + if (sym_is(name, namelen, "usb")) do_usb_table(symval, sym->st_size, mod); - else if (sym_is(symname, "__mod_hid_device_table")) - do_table(symval, sym->st_size, - sizeof(struct hid_device_id), "hid", - do_hid_entry, mod); - else if (sym_is(symname, "__mod_ieee1394_device_table")) - do_table(symval, sym->st_size, - sizeof(struct ieee1394_device_id), "ieee1394", - do_ieee1394_entry, mod); - else if (sym_is(symname, "__mod_ccw_device_table")) - do_table(symval, sym->st_size, - sizeof(struct ccw_device_id), "ccw", - do_ccw_entry, mod); - else if (sym_is(symname, "__mod_ap_device_table")) - do_table(symval, sym->st_size, - sizeof(struct ap_device_id), "ap", - do_ap_entry, mod); - else if (sym_is(symname, "__mod_css_device_table")) - do_table(symval, sym->st_size, - sizeof(struct css_device_id), "css", - do_css_entry, mod); - else if (sym_is(symname, "__mod_serio_device_table")) - do_table(symval, sym->st_size, - sizeof(struct serio_device_id), "serio", - do_serio_entry, mod); - else if (sym_is(symname, "__mod_acpi_device_table")) - do_table(symval, sym->st_size, - sizeof(struct acpi_device_id), "acpi", - do_acpi_entry, mod); - else if (sym_is(symname, "__mod_pnp_device_table")) + else if (sym_is(name, namelen, "pnp")) do_pnp_device_entry(symval, sym->st_size, mod); - else if (sym_is(symname, "__mod_pnp_card_device_table")) + else if (sym_is(name, namelen, "pnp_card")) do_pnp_card_entries(symval, sym->st_size, mod); - else if (sym_is(symname, "__mod_pcmcia_device_table")) - do_table(symval, sym->st_size, - sizeof(struct pcmcia_device_id), "pcmcia", - do_pcmcia_entry, mod); - else if (sym_is(symname, "__mod_of_device_table")) - do_table(symval, sym->st_size, - sizeof(struct of_device_id), "of", - do_of_entry, mod); - else if (sym_is(symname, "__mod_vio_device_table")) - do_table(symval, sym->st_size, - sizeof(struct vio_device_id), "vio", - do_vio_entry, mod); - else if (sym_is(symname, "__mod_input_device_table")) - do_table(symval, sym->st_size, - sizeof(struct input_device_id), "input", - do_input_entry, mod); - else if (sym_is(symname, "__mod_eisa_device_table")) - do_table(symval, sym->st_size, - sizeof(struct eisa_device_id), "eisa", - do_eisa_entry, mod); - else if (sym_is(symname, "__mod_parisc_device_table")) - do_table(symval, sym->st_size, - sizeof(struct parisc_device_id), "parisc", - do_parisc_entry, mod); - else if (sym_is(symname, "__mod_sdio_device_table")) - do_table(symval, sym->st_size, - sizeof(struct sdio_device_id), "sdio", - do_sdio_entry, mod); - else if (sym_is(symname, "__mod_ssb_device_table")) - do_table(symval, sym->st_size, - sizeof(struct ssb_device_id), "ssb", - do_ssb_entry, mod); - else if (sym_is(symname, "__mod_bcma_device_table")) - do_table(symval, sym->st_size, - sizeof(struct bcma_device_id), "bcma", - do_bcma_entry, mod); - else if (sym_is(symname, "__mod_virtio_device_table")) - do_table(symval, sym->st_size, - sizeof(struct virtio_device_id), "virtio", - do_virtio_entry, mod); - else if (sym_is(symname, "__mod_vmbus_device_table")) - do_table(symval, sym->st_size, - sizeof(struct hv_vmbus_device_id), "vmbus", - do_vmbus_entry, mod); - else if (sym_is(symname, "__mod_i2c_device_table")) - do_table(symval, sym->st_size, - sizeof(struct i2c_device_id), "i2c", - do_i2c_entry, mod); - else if (sym_is(symname, "__mod_spi_device_table")) - do_table(symval, sym->st_size, - sizeof(struct spi_device_id), "spi", - do_spi_entry, mod); - else if (sym_is(symname, "__mod_dmi_device_table")) - do_table(symval, sym->st_size, - sizeof(struct dmi_system_id), "dmi", - do_dmi_entry, mod); - else if (sym_is(symname, "__mod_platform_device_table")) - do_table(symval, sym->st_size, - sizeof(struct platform_device_id), "platform", - do_platform_entry, mod); - else if (sym_is(symname, "__mod_mdio_device_table")) - do_table(symval, sym->st_size, - sizeof(struct mdio_device_id), "mdio", - do_mdio_entry, mod); - else if (sym_is(symname, "__mod_zorro_device_table")) - do_table(symval, sym->st_size, - sizeof(struct zorro_device_id), "zorro", - do_zorro_entry, mod); - else if (sym_is(symname, "__mod_isapnp_device_table")) - do_table(symval, sym->st_size, - sizeof(struct isapnp_device_id), "isa", - do_isapnp_entry, mod); - else if (sym_is(symname, "__mod_amba_device_table")) - do_table(symval, sym->st_size, - sizeof(struct amba_id), "amba", - do_amba_entry, mod); + else { + struct devtable **p; + + for (p = __start___devtable; p < __stop___devtable; p++) { + if (sym_is(name, namelen, (*p)->device_id)) { + do_table(symval, sym->st_size, (*p)->id_size, + (*p)->device_id, (*p)->function, mod); + break; + } + } + } free(zeros); } diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index f40a6af6bf40..54e35c1e5948 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -462,7 +462,7 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ succeed_file(); } if (w(txthdr->sh_type) != SHT_PROGBITS || - !(w(txthdr->sh_flags) & SHF_EXECINSTR)) + !(_w(txthdr->sh_flags) & SHF_EXECINSTR)) return NULL; return txtname; } diff --git a/scripts/tags.sh b/scripts/tags.sh index 38f6617a2cb1..833813a99e7c 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -132,7 +132,28 @@ exuberant() --regex-asm='/^(ENTRY|_GLOBAL)\(([^)]*)\).*/\2/' \ --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \ - --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/' + --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/' \ + --regex-c++='/PAGEFLAG\(([^,)]*).*/Page\1/' \ + --regex-c++='/PAGEFLAG\(([^,)]*).*/SetPage\1/' \ + --regex-c++='/PAGEFLAG\(([^,)]*).*/ClearPage\1/' \ + --regex-c++='/TESTSETFLAG\(([^,)]*).*/TestSetPage\1/' \ + --regex-c++='/TESTPAGEFLAG\(([^,)]*).*/Page\1/' \ + --regex-c++='/SETPAGEFLAG\(([^,)]*).*/SetPage\1/' \ + --regex-c++='/__SETPAGEFLAG\(([^,)]*).*/__SetPage\1/' \ + --regex-c++='/TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ + --regex-c++='/__TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ + --regex-c++='/CLEARPAGEFLAG\(([^,)]*).*/ClearPage\1/' \ + --regex-c++='/__CLEARPAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ + --regex-c++='/__PAGEFLAG\(([^,)]*).*/__SetPage\1/' \ + --regex-c++='/__PAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ + --regex-c++='/PAGEFLAG_FALSE\(([^,)]*).*/Page\1/' \ + --regex-c++='/TESTSCFLAG\(([^,)]*).*/TestSetPage\1/' \ + --regex-c++='/TESTSCFLAG\(([^,)]*).*/TestClearPage\1/' \ + --regex-c++='/SETPAGEFLAG_NOOP\(([^,)]*).*/SetPage\1/' \ + --regex-c++='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \ + --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ + --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ + --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' all_kconfigs | xargs $1 -a \ --langdef=kconfig --language-force=kconfig \ @@ -146,6 +167,8 @@ exuberant() --langdef=dotconfig --language-force=dotconfig \ --regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/' + # Remove structure forward declarations. + LANG=C sed -i -e '/^\([a-zA-Z_][a-zA-Z0-9_]*\)\t.*\t\/\^struct \1;.*\$\/;"\tx$/d' tags } emacs() @@ -154,7 +177,28 @@ emacs() --regex='/^(ENTRY|_GLOBAL)(\([^)]*\)).*/\2/' \ --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/' \ --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/' \ - --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/' + --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/' \ + --regex='/PAGEFLAG\(([^,)]*).*/Page\1/' \ + --regex='/PAGEFLAG\(([^,)]*).*/SetPage\1/' \ + --regex='/PAGEFLAG\(([^,)]*).*/ClearPage\1/' \ + --regex='/TESTSETFLAG\(([^,)]*).*/TestSetPage\1/' \ + --regex='/TESTPAGEFLAG\(([^,)]*).*/Page\1/' \ + --regex='/SETPAGEFLAG\(([^,)]*).*/SetPage\1/' \ + --regex='/__SETPAGEFLAG\(([^,)]*).*/__SetPage\1/' \ + --regex='/TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ + --regex='/__TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ + --regex='/CLEARPAGEFLAG\(([^,)]*).*/ClearPage\1/' \ + --regex='/__CLEARPAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ + --regex='/__PAGEFLAG\(([^,)]*).*/__SetPage\1/' \ + --regex='/__PAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ + --regex='/PAGEFLAG_FALSE\(([^,)]*).*/Page\1/' \ + --regex='/TESTSCFLAG\(([^,)]*).*/TestSetPage\1/' \ + --regex='/TESTSCFLAG\(([^,)]*).*/TestClearPage\1/' \ + --regex='/SETPAGEFLAG_NOOP\(([^,)]*).*/SetPage\1/' \ + --regex='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \ + --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ + --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ + --regex='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' all_kconfigs | xargs $1 -a \ --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 38ccaea08204..df3649560818 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -21,11 +21,11 @@ /* Control parameters settable through module/boot flags */ extern enum audit_mode aa_g_audit; -extern int aa_g_audit_header; -extern int aa_g_debug; -extern int aa_g_lock_policy; -extern int aa_g_logsyscall; -extern int aa_g_paranoid_load; +extern bool aa_g_audit_header; +extern bool aa_g_debug; +extern bool aa_g_lock_policy; +extern bool aa_g_logsyscall; +extern bool aa_g_paranoid_load; extern unsigned int aa_g_path_max; /* diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index d7f06f8b2837..97ce8fae49b3 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -136,16 +136,16 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, return 0; } -static int apparmor_capable(struct task_struct *task, const struct cred *cred, - struct user_namespace *ns, int cap, int audit) +static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, + int cap, int audit) { struct aa_profile *profile; /* cap_capable returns 0 on success, else -EPERM */ - int error = cap_capable(task, cred, ns, cap, audit); + int error = cap_capable(cred, ns, cap, audit); if (!error) { profile = aa_cred_profile(cred); if (!unconfined(profile)) - error = aa_capable(task, profile, cap, audit); + error = aa_capable(current, profile, cap, audit); } return error; } @@ -708,7 +708,7 @@ module_param_call(mode, param_set_mode, param_get_mode, &aa_g_profile_mode, S_IRUSR | S_IWUSR); /* Debug mode */ -int aa_g_debug; +bool aa_g_debug; module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR); /* Audit mode */ @@ -719,7 +719,7 @@ module_param_call(audit, param_set_audit, param_get_audit, /* Determines if audit header is included in audited messages. This * provides more context if the audit daemon is not running */ -int aa_g_audit_header = 1; +bool aa_g_audit_header = 1; module_param_named(audit_header, aa_g_audit_header, aabool, S_IRUSR | S_IWUSR); @@ -727,12 +727,12 @@ module_param_named(audit_header, aa_g_audit_header, aabool, * TODO: add in at boot loading of policy, which is the only way to * load policy, if lock_policy is set */ -int aa_g_lock_policy; +bool aa_g_lock_policy; module_param_named(lock_policy, aa_g_lock_policy, aalockpolicy, S_IRUSR | S_IWUSR); /* Syscall logging mode */ -int aa_g_logsyscall; +bool aa_g_logsyscall; module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR); /* Maximum pathname length before accesses will start getting rejected */ @@ -742,12 +742,12 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR); /* Determines how paranoid loading of policy is and how much verification * on the loaded policy is done. */ -int aa_g_paranoid_load = 1; +bool aa_g_paranoid_load = 1; module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUSR | S_IWUSR); /* Boot time disable flag */ -static unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE; +static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE; module_param_named(enabled, apparmor_enabled, aabool, S_IRUSR); static int __init apparmor_enabled_setup(char *str) diff --git a/security/capability.c b/security/capability.c index 3b5883b7179f..2f680eb02b59 100644 --- a/security/capability.c +++ b/security/capability.c @@ -998,7 +998,6 @@ void __init security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, sem_semctl); set_to_cap_if_null(ops, sem_semop); set_to_cap_if_null(ops, netlink_send); - set_to_cap_if_null(ops, netlink_recv); set_to_cap_if_null(ops, d_instantiate); set_to_cap_if_null(ops, getprocattr); set_to_cap_if_null(ops, setprocattr); diff --git a/security/commoncap.c b/security/commoncap.c index ee4f8486e5f5..7ce191ea29a0 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -56,17 +56,8 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb) return 0; } -int cap_netlink_recv(struct sk_buff *skb, int cap) -{ - if (!cap_raised(current_cap(), cap)) - return -EPERM; - return 0; -} -EXPORT_SYMBOL(cap_netlink_recv); - /** * cap_capable - Determine whether a task has a particular effective capability - * @tsk: The task to query * @cred: The credentials to use * @ns: The user namespace in which we need the capability * @cap: The capability to check for @@ -80,8 +71,8 @@ EXPORT_SYMBOL(cap_netlink_recv); * cap_has_capability() returns 0 when a task has a capability, but the * kernel's capable() and has_capability() returns 1 for this case. */ -int cap_capable(struct task_struct *tsk, const struct cred *cred, - struct user_namespace *targ_ns, int cap, int audit) +int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, + int cap, int audit) { for (;;) { /* The creator of the user namespace has all caps. */ @@ -222,9 +213,8 @@ static inline int cap_inh_is_capped(void) /* they are so limited unless the current task has the CAP_SETPCAP * capability */ - if (cap_capable(current, current_cred(), - current_cred()->user->user_ns, CAP_SETPCAP, - SECURITY_CAP_AUDIT) == 0) + if (cap_capable(current_cred(), current_cred()->user->user_ns, + CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) return 0; return 1; } @@ -874,7 +864,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, & (new->securebits ^ arg2)) /*[1]*/ || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ - || (cap_capable(current, current_cred(), + || (cap_capable(current_cred(), current_cred()->user->user_ns, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/ /* @@ -940,7 +930,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) { int cap_sys_admin = 0; - if (cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_ADMIN, + if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0) cap_sys_admin = 1; return __vm_enough_memory(mm, pages, cap_sys_admin); @@ -967,7 +957,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot, int ret = 0; if (addr < dac_mmap_min_addr) { - ret = cap_capable(current, current_cred(), &init_user_ns, CAP_SYS_RAWIO, + ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO, SECURITY_CAP_AUDIT); /* set PF_SUPERPRIV if it turns out we allow the low mmap */ if (ret == 0) diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index d384ea921482..5bd1cc1b4a54 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -3,11 +3,11 @@ config INTEGRITY def_bool y depends on IMA || EVM -config INTEGRITY_DIGSIG +config INTEGRITY_SIGNATURE boolean "Digital signature verification using multiple keyrings" depends on INTEGRITY && KEYS default n - select DIGSIG + select SIGNATURE help This option enables digital signature verification support using multiple keyrings. It defines separate keyrings for each diff --git a/security/integrity/Makefile b/security/integrity/Makefile index bece0563ee5e..d43799cc14f6 100644 --- a/security/integrity/Makefile +++ b/security/integrity/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_INTEGRITY) += integrity.o -obj-$(CONFIG_INTEGRITY_DIGSIG) += digsig.o +obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o integrity-y := iint.o diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index c5c5a72c30be..2ad942fb1e23 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c @@ -56,9 +56,11 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, audit_log_format(ab, " name="); audit_log_untrustedstring(ab, fname); } - if (inode) - audit_log_format(ab, " dev=%s ino=%lu", - inode->i_sb->s_id, inode->i_ino); + if (inode) { + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); + } audit_log_format(ab, " res=%d", !result ? 0 : 1); audit_log_end(ab); } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index d661afbe474c..d45061d02fee 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -99,6 +99,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, struct inode *inode, enum ima_hooks func, int mask) { struct task_struct *tsk = current; + const struct cred *cred = current_cred(); int i; if ((rule->flags & IMA_FUNC) && rule->func != func) @@ -108,7 +109,7 @@ static bool ima_match_rules(struct ima_measure_rule_entry *rule, if ((rule->flags & IMA_FSMAGIC) && rule->fsmagic != inode->i_sb->s_magic) return false; - if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) + if ((rule->flags & IMA_UID) && rule->uid != cred->uid) return false; for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 4da6ba81d153..7a25ecec5aaa 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -51,7 +51,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); #define INTEGRITY_KEYRING_IMA 2 #define INTEGRITY_KEYRING_MAX 3 -#ifdef CONFIG_INTEGRITY_DIGSIG +#ifdef CONFIG_INTEGRITY_SIGNATURE int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, const char *digest, int digestlen); @@ -65,7 +65,7 @@ static inline int integrity_digsig_verify(const unsigned int id, return -EOPNOTSUPP; } -#endif /* CONFIG_INTEGRITY_DIGSIG */ +#endif /* CONFIG_INTEGRITY_SIGNATURE */ /* set during initialization */ extern int iint_initialized; diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 41144f71d615..2d1bb8af7696 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -314,7 +314,7 @@ static struct key *request_user_key(const char *master_desc, u8 **master_key, goto error; down_read(&ukey->sem); - upayload = rcu_dereference(ukey->payload.data); + upayload = ukey->payload.data; *master_key = upayload->data; *master_keylen = upayload->datalen; error: @@ -810,7 +810,7 @@ static int encrypted_instantiate(struct key *key, const void *data, goto out; } - rcu_assign_pointer(key->payload.data, epayload); + rcu_assign_keypointer(key, epayload); out: kfree(datablob); return ret; @@ -874,7 +874,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen) memcpy(new_epayload->payload_data, epayload->payload_data, epayload->payload_datalen); - rcu_assign_pointer(key->payload.data, new_epayload); + rcu_assign_keypointer(key, new_epayload); call_rcu(&epayload->rcu, encrypted_rcu_free); out: kfree(buf); diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c index df87272e3f51..013f7e5d3a2f 100644 --- a/security/keys/encrypted-keys/masterkey_trusted.c +++ b/security/keys/encrypted-keys/masterkey_trusted.c @@ -18,6 +18,8 @@ #include <linux/module.h> #include <linux/err.h> #include <keys/trusted-type.h> +#include <keys/encrypted-type.h> +#include "encrypted.h" /* * request_trusted_key - request the trusted key @@ -37,7 +39,7 @@ struct key *request_trusted_key(const char *trusted_desc, goto error; down_read(&tkey->sem); - tpayload = rcu_dereference(tkey->payload.data); + tpayload = tkey->payload.data; *master_key = tpayload->key; *master_keylen = tpayload->key_len; error: diff --git a/security/keys/gc.c b/security/keys/gc.c index bf4d8da5a795..a42b45531aac 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -145,7 +145,9 @@ static void key_gc_keyring(struct key *keyring, time_t limit) if (!klist) goto unlock_dont_gc; - for (loop = klist->nkeys - 1; loop >= 0; loop--) { + loop = klist->nkeys; + smp_rmb(); + for (loop--; loop >= 0; loop--) { key = klist->keys[loop]; if (test_bit(KEY_FLAG_DEAD, &key->flags) || (key->expiry > 0 && key->expiry <= limit)) diff --git a/security/keys/internal.h b/security/keys/internal.h index c7a7caec4830..65647f825584 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -33,6 +33,7 @@ extern struct key_type key_type_dead; extern struct key_type key_type_user; +extern struct key_type key_type_logon; /*****************************************************************************/ /* diff --git a/security/keys/key.c b/security/keys/key.c index 4f64c7267afb..7ada8019be1f 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -999,6 +999,7 @@ void __init key_init(void) list_add_tail(&key_type_keyring.link, &key_types_list); list_add_tail(&key_type_dead.link, &key_types_list); list_add_tail(&key_type_user.link, &key_types_list); + list_add_tail(&key_type_logon.link, &key_types_list); /* record the root user tracking */ rb_link_node(&root_key_user.node, diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 37a7f3b28852..d605f75292e4 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -319,7 +319,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, struct key *keyring, *key; key_ref_t key_ref; long err; - int sp, kix; + int sp, nkeys, kix; keyring = key_ref_to_ptr(keyring_ref); possessed = is_key_possessed(keyring_ref); @@ -380,7 +380,9 @@ descend: goto not_this_keyring; /* iterate through the keys in this keyring first */ - for (kix = 0; kix < keylist->nkeys; kix++) { + nkeys = keylist->nkeys; + smp_rmb(); + for (kix = 0; kix < nkeys; kix++) { key = keylist->keys[kix]; kflags = key->flags; @@ -421,7 +423,9 @@ descend: /* search through the keyrings nested in this one */ kix = 0; ascend: - for (; kix < keylist->nkeys; kix++) { + nkeys = keylist->nkeys; + smp_rmb(); + for (; kix < nkeys; kix++) { key = keylist->keys[kix]; if (key->type != &key_type_keyring) continue; @@ -515,7 +519,7 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, struct keyring_list *klist; unsigned long possessed; struct key *keyring, *key; - int loop; + int nkeys, loop; keyring = key_ref_to_ptr(keyring_ref); possessed = is_key_possessed(keyring_ref); @@ -524,7 +528,9 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, klist = rcu_dereference(keyring->payload.subscriptions); if (klist) { - for (loop = 0; loop < klist->nkeys; loop++) { + nkeys = klist->nkeys; + smp_rmb(); + for (loop = 0; loop < nkeys ; loop++) { key = klist->keys[loop]; if (key->type == ktype && @@ -622,7 +628,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) struct keyring_list *keylist; struct key *subtree, *key; - int sp, kix, ret; + int sp, nkeys, kix, ret; rcu_read_lock(); @@ -645,7 +651,9 @@ descend: ascend: /* iterate through the remaining keys in this keyring */ - for (; kix < keylist->nkeys; kix++) { + nkeys = keylist->nkeys; + smp_rmb(); + for (; kix < nkeys; kix++) { key = keylist->keys[kix]; if (key == A) diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 0ed5fdf238a2..2d5d041f2049 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -993,7 +993,7 @@ out: kfree(datablob); kfree(options); if (!ret) - rcu_assign_pointer(key->payload.data, payload); + rcu_assign_keypointer(key, payload); else kfree(payload); return ret; @@ -1067,7 +1067,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen) goto out; } } - rcu_assign_pointer(key->payload.data, new_p); + rcu_assign_keypointer(key, new_p); call_rcu(&p->rcu, trusted_rcu_free); out: kfree(datablob); diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 69ff52c08e97..c7660a25a3e4 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -18,6 +18,8 @@ #include <asm/uaccess.h> #include "internal.h" +static int logon_vet_description(const char *desc); + /* * user defined keys take an arbitrary string as the description and an * arbitrary blob of data as the payload @@ -36,6 +38,24 @@ struct key_type key_type_user = { EXPORT_SYMBOL_GPL(key_type_user); /* + * This key type is essentially the same as key_type_user, but it does + * not define a .read op. This is suitable for storing username and + * password pairs in the keyring that you do not want to be readable + * from userspace. + */ +struct key_type key_type_logon = { + .name = "logon", + .instantiate = user_instantiate, + .update = user_update, + .match = user_match, + .revoke = user_revoke, + .destroy = user_destroy, + .describe = user_describe, + .vet_description = logon_vet_description, +}; +EXPORT_SYMBOL_GPL(key_type_logon); + +/* * instantiate a user defined key */ int user_instantiate(struct key *key, const void *data, size_t datalen) @@ -59,7 +79,7 @@ int user_instantiate(struct key *key, const void *data, size_t datalen) /* attach the data */ upayload->datalen = datalen; memcpy(upayload->data, data, datalen); - rcu_assign_pointer(key->payload.data, upayload); + rcu_assign_keypointer(key, upayload); ret = 0; error: @@ -98,7 +118,7 @@ int user_update(struct key *key, const void *data, size_t datalen) if (ret == 0) { /* attach the new data, displacing the old */ zap = key->payload.data; - rcu_assign_pointer(key->payload.data, upayload); + rcu_assign_keypointer(key, upayload); key->expiry = 0; } @@ -133,7 +153,7 @@ void user_revoke(struct key *key) key_payload_reserve(key, 0); if (upayload) { - rcu_assign_pointer(key->payload.data, NULL); + rcu_assign_keypointer(key, NULL); kfree_rcu(upayload, rcu); } } @@ -189,3 +209,20 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen) } EXPORT_SYMBOL_GPL(user_read); + +/* Vet the description for a "logon" key */ +static int logon_vet_description(const char *desc) +{ + char *p; + + /* require a "qualified" description string */ + p = strchr(desc, ':'); + if (!p) + return -EINVAL; + + /* also reject description with ':' as first char */ + if (p == desc) + return -EINVAL; + + return 0; +} diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 7bd6f138236b..293b8c45b1d1 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -232,13 +232,14 @@ static void dump_common_audit_data(struct audit_buffer *ab, case LSM_AUDIT_DATA_PATH: { struct inode *inode; - audit_log_d_path(ab, "path=", &a->u.path); + audit_log_d_path(ab, " path=", &a->u.path); inode = a->u.path.dentry->d_inode; - if (inode) - audit_log_format(ab, " dev=%s ino=%lu", - inode->i_sb->s_id, - inode->i_ino); + if (inode) { + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); + } break; } case LSM_AUDIT_DATA_DENTRY: { @@ -248,10 +249,11 @@ static void dump_common_audit_data(struct audit_buffer *ab, audit_log_untrustedstring(ab, a->u.dentry->d_name.name); inode = a->u.dentry->d_inode; - if (inode) - audit_log_format(ab, " dev=%s ino=%lu", - inode->i_sb->s_id, - inode->i_ino); + if (inode) { + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); + } break; } case LSM_AUDIT_DATA_INODE: { @@ -266,8 +268,9 @@ static void dump_common_audit_data(struct audit_buffer *ab, dentry->d_name.name); dput(dentry); } - audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id, - inode->i_ino); + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); break; } case LSM_AUDIT_DATA_TASK: @@ -315,7 +318,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, .dentry = u->dentry, .mnt = u->mnt }; - audit_log_d_path(ab, "path=", &path); + audit_log_d_path(ab, " path=", &path); break; } if (!u->addr) diff --git a/security/security.c b/security/security.c index 214502c772ab..d7542493454d 100644 --- a/security/security.c +++ b/security/security.c @@ -155,35 +155,16 @@ int security_capset(struct cred *new, const struct cred *old, effective, inheritable, permitted); } -int security_capable(struct user_namespace *ns, const struct cred *cred, +int security_capable(const struct cred *cred, struct user_namespace *ns, int cap) { - return security_ops->capable(current, cred, ns, cap, - SECURITY_CAP_AUDIT); + return security_ops->capable(cred, ns, cap, SECURITY_CAP_AUDIT); } -int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, - int cap) +int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, + int cap) { - const struct cred *cred; - int ret; - - cred = get_task_cred(tsk); - ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_AUDIT); - put_cred(cred); - return ret; -} - -int security_real_capable_noaudit(struct task_struct *tsk, - struct user_namespace *ns, int cap) -{ - const struct cred *cred; - int ret; - - cred = get_task_cred(tsk); - ret = security_ops->capable(tsk, cred, ns, cap, SECURITY_CAP_NOAUDIT); - put_cred(cred); - return ret; + return security_ops->capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); } int security_quotactl(int cmds, int type, int id, struct super_block *sb) @@ -994,12 +975,6 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb) return security_ops->netlink_send(sk, skb); } -int security_netlink_recv(struct sk_buff *skb, int cap) -{ - return security_ops->netlink_recv(skb, cap); -} -EXPORT_SYMBOL(security_netlink_recv); - int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { return security_ops->secid_to_secctx(secid, secdata, seclen); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7cd4c3affac8..6a3683e28426 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1415,8 +1415,7 @@ static int current_has_perm(const struct task_struct *tsk, #endif /* Check whether a task is allowed to use a capability. */ -static int task_has_capability(struct task_struct *tsk, - const struct cred *cred, +static int cred_has_capability(const struct cred *cred, int cap, int audit) { struct common_audit_data ad; @@ -1427,7 +1426,7 @@ static int task_has_capability(struct task_struct *tsk, int rc; COMMON_AUDIT_DATA_INIT(&ad, CAP); - ad.tsk = tsk; + ad.tsk = current; ad.u.cap = cap; switch (CAP_TO_INDEX(cap)) { @@ -1811,7 +1810,7 @@ static int selinux_ptrace_access_check(struct task_struct *child, if (rc) return rc; - if (mode == PTRACE_MODE_READ) { + if (mode & PTRACE_MODE_READ) { u32 sid = current_sid(); u32 csid = task_sid(child); return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); @@ -1868,16 +1867,16 @@ static int selinux_capset(struct cred *new, const struct cred *old, * the CAP_SETUID and CAP_SETGID capabilities using the capable hook. */ -static int selinux_capable(struct task_struct *tsk, const struct cred *cred, - struct user_namespace *ns, int cap, int audit) +static int selinux_capable(const struct cred *cred, struct user_namespace *ns, + int cap, int audit) { int rc; - rc = cap_capable(tsk, cred, ns, cap, audit); + rc = cap_capable(cred, ns, cap, audit); if (rc) return rc; - return task_has_capability(tsk, cred, cap, audit); + return cred_has_capability(cred, cap, audit); } static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) @@ -1954,8 +1953,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) { int rc, cap_sys_admin = 0; - rc = selinux_capable(current, current_cred(), - &init_user_ns, CAP_SYS_ADMIN, + rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); if (rc == 0) cap_sys_admin = 1; @@ -2859,8 +2857,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name * and lack of permission just means that we fall back to the * in-core context value, not a denial. */ - error = selinux_capable(current, current_cred(), - &init_user_ns, CAP_MAC_ADMIN, + error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); if (!error) error = security_sid_to_context_force(isec->sid, &context, @@ -2993,8 +2990,8 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, case KDSKBENT: case KDSKBSENT: - error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG, - SECURITY_CAP_AUDIT); + error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, + SECURITY_CAP_AUDIT); break; /* default case assumes that the command will go @@ -4718,24 +4715,6 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) return selinux_nlmsg_perm(sk, skb); } -static int selinux_netlink_recv(struct sk_buff *skb, int capability) -{ - int err; - struct common_audit_data ad; - u32 sid; - - err = cap_netlink_recv(skb, capability); - if (err) - return err; - - COMMON_AUDIT_DATA_INIT(&ad, CAP); - ad.u.cap = capability; - - security_task_getsecid(current, &sid); - return avc_has_perm(sid, sid, SECCLASS_CAPABILITY, - CAP_TO_MASK(capability), &ad); -} - static int ipc_alloc_security(struct task_struct *task, struct kern_ipc_perm *perm, u16 sclass) @@ -5464,7 +5443,6 @@ static struct security_operations selinux_ops = { .vm_enough_memory = selinux_vm_enough_memory, .netlink_send = selinux_netlink_send, - .netlink_recv = selinux_netlink_recv, .bprm_set_creds = selinux_bprm_set_creds, .bprm_committing_creds = selinux_bprm_committing_creds, diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 4a9b4b2eb755..867558c98334 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -492,13 +492,13 @@ static bool tomoyo_correct_word2(const char *string, size_t len) if (d < '0' || d > '7' || e < '0' || e > '7') break; c = tomoyo_make_byte(c, d, e); - if (tomoyo_invalid(c)) - continue; /* pattern is not \000 */ + if (c <= ' ' || c >= 127) + continue; } goto out; } else if (in_repetition && c == '/') { goto out; - } else if (tomoyo_invalid(c)) { + } else if (c <= ' ' || c >= 127) { goto out; } } diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index 6fd9391b3a6c..4fa1dbd8ee83 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -133,7 +133,7 @@ static int atmel_abdac_prepare_dma(struct atmel_abdac *dac, period_len = frames_to_bytes(runtime, runtime->period_size); cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len, - period_len, DMA_TO_DEVICE); + period_len, DMA_MEM_TO_DEV); if (IS_ERR(cdesc)) { dev_dbg(&dac->pdev->dev, "could not prepare cyclic DMA\n"); return PTR_ERR(cdesc); diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 73516f69ac7c..61dade698358 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -102,7 +102,7 @@ static void atmel_ac97c_dma_capture_period_done(void *arg) static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip, struct snd_pcm_substream *substream, - enum dma_data_direction direction) + enum dma_transfer_direction direction) { struct dma_chan *chan; struct dw_cyclic_desc *cdesc; @@ -118,7 +118,7 @@ static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip, return -EINVAL; } - if (direction == DMA_TO_DEVICE) + if (direction == DMA_MEM_TO_DEV) chan = chip->dma.tx_chan; else chan = chip->dma.rx_chan; @@ -133,7 +133,7 @@ static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip, return PTR_ERR(cdesc); } - if (direction == DMA_TO_DEVICE) { + if (direction == DMA_MEM_TO_DEV) { cdesc->period_callback = atmel_ac97c_dma_playback_period_done; set_bit(DMA_TX_READY, &chip->flags); } else { @@ -393,7 +393,7 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) if (cpu_is_at32ap7000()) { if (!test_bit(DMA_TX_READY, &chip->flags)) retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_TO_DEVICE); + DMA_MEM_TO_DEV); } else { /* Initialize and start the PDC */ writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR); @@ -484,7 +484,7 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) if (cpu_is_at32ap7000()) { if (!test_bit(DMA_RX_READY, &chip->flags)) retval = atmel_ac97c_prepare_dma(chip, substream, - DMA_FROM_DEVICE); + DMA_DEV_TO_MEM); } else { /* Initialize and start the PDC */ writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR); diff --git a/sound/core/Kconfig b/sound/core/Kconfig index ad409381f8cc..b413ed05e74d 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -12,6 +12,9 @@ config SND_HWDEP config SND_RAWMIDI tristate +config SND_COMPRESS_OFFLOAD + tristate + # To be effective this also requires INPUT - users should say: # select SND_JACK if INPUT=y || INPUT=SND # to avoid having to force INPUT on. @@ -154,16 +157,6 @@ config SND_DYNAMIC_MINORS If you are unsure about this, say N here. -config SND_COMPRESS_OFFLOAD - tristate "ALSA Compressed audio offload support" - default n - help - If you want support for offloading compressed audio and have such - a hardware, then you should say Y here and also to the DSP driver - of your platform. - - If you are unsure about this, say N here. - config SND_SUPPORT_OLD_API bool "Support old ALSA API" default y diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 762bb108c51c..f13ad536b2d5 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -268,8 +268,14 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) card->shortname, chip->io, chip->irq); // (4) Alloc components. + err = snd_vortex_mixer(chip); + if (err < 0) { + snd_card_free(card); + return err; + } // ADB pcm. - if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) { + err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_PCM); + if (err < 0) { snd_card_free(card); return err; } @@ -299,11 +305,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return err; } #endif - // snd_ac97_mixer and Vortex mixer. - if ((err = snd_vortex_mixer(chip)) < 0) { - snd_card_free(card); - return err; - } if ((err = snd_vortex_midi(chip)) < 0) { snd_card_free(card); return err; diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index 02f6e08f7592..bb938153a964 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -105,6 +105,7 @@ #define MIX_SPDIF(x) (vortex->mixspdif[x]) #define NR_WTPB 0x20 /* WT channels per each bank. */ +#define NR_PCM 0x10 /* Structs */ typedef struct { diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 0488633ea874..0ef2f9712208 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -168,6 +168,7 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) runtime->hw = snd_vortex_playback_hw_adb; #ifdef CHIP_AU8830 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + VORTEX_IS_QUAD(vortex) && VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { runtime->hw.channels_max = 4; snd_pcm_hw_constraint_list(runtime, 0, diff --git a/sound/pci/hda/alc880_quirks.c b/sound/pci/hda/alc880_quirks.c index 5b68435d195b..501501ef36a9 100644 --- a/sound/pci/hda/alc880_quirks.c +++ b/sound/pci/hda/alc880_quirks.c @@ -762,16 +762,22 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, /* Looks like the unsol event is incompatible with the standard * definition. 4bit tag is placed at 28 bit! */ - switch (res >> 28) { + res >>= 28; + switch (res) { case ALC_MIC_EVENT: alc88x_simple_mic_automute(codec); break; default: - alc_sku_unsol_event(codec, res); + alc_exec_unsol_event(codec, res); break; } } +static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) +{ + alc_exec_unsol_event(codec, res >> 28); +} + static void alc880_uniwill_p53_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -800,10 +806,11 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, /* Looks like the unsol event is incompatible with the standard * definition. 4bit tag is placed at 28 bit! */ - if ((res >> 28) == ALC_DCVOL_EVENT) + res >>= 28; + if (res == ALC_DCVOL_EVENT) alc880_uniwill_p53_dcvol_automute(codec); else - alc_sku_unsol_event(codec, res); + alc_exec_unsol_event(codec, res); } /* @@ -1677,7 +1684,7 @@ static const struct alc_config_preset alc880_presets[] = { .channel_mode = alc880_lg_ch_modes, .need_dac_fix = 1, .input_mux = &alc880_lg_capture_source, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc880_unsol_event, .setup = alc880_lg_setup, .init_hook = alc_hp_automute, #ifdef CONFIG_SND_HDA_POWER_SAVE diff --git a/sound/pci/hda/alc882_quirks.c b/sound/pci/hda/alc882_quirks.c index bdf0ed4ab3e2..bb364a53f546 100644 --- a/sound/pci/hda/alc882_quirks.c +++ b/sound/pci/hda/alc882_quirks.c @@ -730,6 +730,11 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) alc889A_mb31_automute(codec); } +static void alc882_unsol_event(struct hda_codec *codec, unsigned int res) +{ + alc_exec_unsol_event(codec, res >> 26); +} + /* * configuration and preset */ @@ -775,7 +780,7 @@ static const struct alc_config_preset alc882_presets[] = { .channel_mode = alc885_mba21_ch_modes, .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes), .input_mux = &alc882_capture_source, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc882_unsol_event, .setup = alc885_mba21_setup, .init_hook = alc_hp_automute, }, @@ -791,7 +796,7 @@ static const struct alc_config_preset alc882_presets[] = { .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc882_unsol_event, .setup = alc885_mbp3_setup, .init_hook = alc_hp_automute, }, @@ -806,7 +811,7 @@ static const struct alc_config_preset alc882_presets[] = { .input_mux = &mb5_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc882_unsol_event, .setup = alc885_mb5_setup, .init_hook = alc_hp_automute, }, @@ -821,7 +826,7 @@ static const struct alc_config_preset alc882_presets[] = { .input_mux = &macmini3_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc882_unsol_event, .setup = alc885_macmini3_setup, .init_hook = alc_hp_automute, }, @@ -836,7 +841,7 @@ static const struct alc_config_preset alc882_presets[] = { .input_mux = &alc889A_imac91_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_sku_unsol_event, + .unsol_event = alc882_unsol_event, .setup = alc885_imac91_setup, .init_hook = alc_hp_automute, }, diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0852e204a4c8..95dfb6874941 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -469,6 +469,7 @@ struct azx { unsigned int irq_pending_warned :1; unsigned int probing :1; /* codec probing phase */ unsigned int snoop:1; + unsigned int align_buffer_size:1; /* for debugging */ unsigned int last_cmd[AZX_MAX_CODECS]; @@ -1690,7 +1691,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) runtime->hw.rates = hinfo->rates; snd_pcm_limit_hw_rates(runtime); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (align_buffer_size) + if (chip->align_buffer_size) /* constrain buffer sizes to be multiple of 128 bytes. This is more efficient in terms of memory access but isn't required by the HDA spec and @@ -2498,6 +2499,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), + SND_PCI_QUIRK(0x10de, 0xcb89, "Macbook Pro 7,1", POS_FIX_LPIB), SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB), SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), @@ -2772,8 +2774,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } /* disable buffer size rounding to 128-byte multiples if supported */ + chip->align_buffer_size = align_buffer_size; if (chip->driver_caps & AZX_DCAPS_BUFSIZE) - align_buffer_size = 0; + chip->align_buffer_size = 0; /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 8a32a69c83c3..a7a5733aa4d2 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3027,7 +3027,7 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), + SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T510", CXT5066_AUTO), SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO), SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5e82acf77c5a..c95c8bde12d0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -185,7 +185,6 @@ struct alc_spec { unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ - unsigned int use_jack_tbl:1; /* 1 for model=auto */ /* auto-mute control */ int automute_mode; @@ -621,17 +620,10 @@ static void alc_mic_automute(struct hda_codec *codec) alc_mux_select(codec, 0, spec->int_mic_idx, false); } -/* unsolicited event for HP jack sensing */ -static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) +/* handle the specified unsol action (ALC_XXX_EVENT) */ +static void alc_exec_unsol_event(struct hda_codec *codec, int action) { - struct alc_spec *spec = codec->spec; - if (codec->vendor_id == 0x10ec0880) - res >>= 28; - else - res >>= 26; - if (spec->use_jack_tbl) - res = snd_hda_jack_get_action(codec, res); - switch (res) { + switch (action) { case ALC_HP_EVENT: alc_hp_automute(codec); break; @@ -645,6 +637,17 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) snd_hda_jack_report_sync(codec); } +/* unsolicited event for HP jack sensing */ +static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if (codec->vendor_id == 0x10ec0880) + res >>= 28; + else + res >>= 26; + res = snd_hda_jack_get_action(codec, res); + alc_exec_unsol_event(codec, res); +} + /* call init functions of standard auto-mute helpers */ static void alc_inithook(struct hda_codec *codec) { @@ -1883,7 +1886,7 @@ static const struct snd_kcontrol_new alc_beep_mixer[] = { }; #endif -static int alc_build_controls(struct hda_codec *codec) +static int __alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; struct snd_kcontrol *kctl = NULL; @@ -2029,11 +2032,16 @@ static int alc_build_controls(struct hda_codec *codec) alc_free_kctls(codec); /* no longer needed */ - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); + return 0; +} + +static int alc_build_controls(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err = __alc_build_controls(codec); if (err < 0) return err; - - return 0; + return snd_hda_jack_add_kctls(codec, &spec->autocfg); } @@ -3233,7 +3241,7 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, int i, err, noutputs; noutputs = cfg->line_outs; - if (spec->multi_ios > 0) + if (spec->multi_ios > 0 && cfg->line_outs < 3) noutputs += spec->multi_ios; for (i = 0; i < noutputs; i++) { @@ -3904,7 +3912,6 @@ static void set_capture_mixer(struct hda_codec *codec) static void alc_auto_init_std(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - spec->use_jack_tbl = 1; alc_auto_init_multi_out(codec); alc_auto_init_extra_out(codec); alc_auto_init_analog_input(codec); @@ -4168,6 +4175,8 @@ static int patch_alc880(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC_MODEL_AUTO) spec->init_hook = alc_auto_init_std; + else + codec->patch_ops.build_controls = __alc_build_controls; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc880_loopbacks; @@ -4297,6 +4306,8 @@ static int patch_alc260(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC_MODEL_AUTO) spec->init_hook = alc_auto_init_std; + else + codec->patch_ops.build_controls = __alc_build_controls; spec->shutup = alc_eapd_shutup; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) @@ -4691,6 +4702,8 @@ static int patch_alc882(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC_MODEL_AUTO) spec->init_hook = alc_auto_init_std; + else + codec->patch_ops.build_controls = __alc_build_controls; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 87e684fa830f..336cfcd324f9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1596,7 +1596,7 @@ static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, "Dell Studio 1557", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe, - "Dell Studio XPS 1645", STAC_DELL_M6_BOTH), + "Dell Studio XPS 1645", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, "Dell Studio 1558", STAC_DELL_M6_DMIC), {} /* terminator */ @@ -1608,7 +1608,7 @@ static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a, "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, - "Alienware M17x", STAC_ALIENWARE_M17X), + "Alienware M17x R3", STAC_DELL_EQ), {} /* terminator */ }; @@ -4163,13 +4163,15 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, return 1; } -static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) +static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) { int i; for (i = 0; i < cfg->hp_outs; i++) if (cfg->hp_pins[i] == nid) return 1; /* nid is a HP-Out */ - + for (i = 0; i < cfg->line_outs; i++) + if (cfg->line_out_pins[i] == nid) + return 1; /* nid is a line-Out */ return 0; /* nid is not a HP-Out */ }; @@ -4375,7 +4377,7 @@ static int stac92xx_init(struct hda_codec *codec) continue; } - if (is_nid_hp_pin(cfg, nid)) + if (is_nid_out_jack_pin(cfg, nid)) continue; /* already has an unsol event */ pinctl = snd_hda_codec_read(codec, nid, 0, diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 40b181bab930..9f3b01bb72c8 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -95,13 +95,13 @@ module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); module_param(buggy_semaphore, bool, 0444); MODULE_PARM_DESC(buggy_semaphore, "Enable workaround for hardwares with problematic codec semaphores."); -module_param(buggy_irq, bool, 0444); +module_param(buggy_irq, bint, 0444); MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); module_param(xbox, bool, 0444); MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection."); module_param(spdif_aclink, int, 0444); MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); -module_param(inside_vm, bool, 0444); +module_param(inside_vm, bint, 0444); MODULE_PARM_DESC(inside_vm, "KVM/Parallels optimization."); /* just for backward compatibility */ diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 478303e6c2b0..63cff90706bf 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -177,6 +177,7 @@ static void wm8776_registers_init(struct oxygen *chip) struct xonar_wm87x6 *data = chip->model_data; wm8776_write(chip, WM8776_RESET, 0); + wm8776_write(chip, WM8776_PHASESWAP, WM8776_PH_MASK); wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN | WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT); wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0); diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig index e908a8123110..a56104040e83 100644 --- a/sound/soc/au1x/Kconfig +++ b/sound/soc/au1x/Kconfig @@ -1,13 +1,13 @@ ## -## Au1200/Au1550 PSC + DBDMA +## Au1200/Au1550/Au1300 PSC + DBDMA ## config SND_SOC_AU1XPSC - tristate "SoC Audio for Au1200/Au1250/Au1550" + tristate "SoC Audio for Au12xx/Au13xx/Au1550" depends on MIPS_ALCHEMY help This option enables support for the Programmable Serial Controllers in AC97 and I2S mode, and the Descriptor-Based DMA - Controller (DBDMA) as found on the Au1200/Au1250/Au1550 SoC. + Controller (DBDMA) as found on the Au12xx/Au13xx/Au1550 SoC. config SND_SOC_AU1XPSC_I2S tristate @@ -51,12 +51,14 @@ config SND_SOC_DB1000 of boards (DB1000/DB1500/DB1100). config SND_SOC_DB1200 - tristate "DB1200 AC97+I2S audio support" + tristate "DB1200/DB1300/DB1550 Audio support" depends on SND_SOC_AU1XPSC select SND_SOC_AU1XPSC_AC97 select SND_SOC_AC97_CODEC + select SND_SOC_WM9712 select SND_SOC_AU1XPSC_I2S select SND_SOC_WM8731 help - Select this option to enable audio (AC97 or I2S) on the - Alchemy/AMD/RMI DB1200 demoboard. + Select this option to enable audio (AC97 and I2S) on the + Alchemy/AMD/RMI/NetLogic Db1200, Db1550 and Db1300 evaluation boards. + If you need Db1300 touchscreen support, you definitely want to say Y. diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index 1c629393df78..30ea513d81d7 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c @@ -1,5 +1,5 @@ /* - * DB1200 ASoC audio fabric support code. + * DB1200/DB1300/DB1550 ASoC audio fabric support code. * * (c) 2008-2011 Manuel Lauss <manuel.lauss@googlemail.com> * @@ -28,6 +28,18 @@ static struct platform_device_id db1200_pids[] = { }, { .name = "db1200-i2s", .driver_data = 1, + }, { + .name = "db1300-ac97", + .driver_data = 2, + }, { + .name = "db1300-i2s", + .driver_data = 3, + }, { + .name = "db1550-ac97", + .driver_data = 4, + }, { + .name = "db1550-i2s", + .driver_data = 5, }, {}, }; @@ -50,6 +62,27 @@ static struct snd_soc_card db1200_ac97_machine = { .num_links = 1, }; +static struct snd_soc_dai_link db1300_ac97_dai = { + .name = "AC97", + .stream_name = "AC97 HiFi", + .codec_dai_name = "wm9712-hifi", + .cpu_dai_name = "au1xpsc_ac97.1", + .platform_name = "au1xpsc-pcm.1", + .codec_name = "wm9712-codec.1", +}; + +static struct snd_soc_card db1300_ac97_machine = { + .name = "DB1300_AC97", + .dai_link = &db1300_ac97_dai, + .num_links = 1, +}; + +static struct snd_soc_card db1550_ac97_machine = { + .name = "DB1550_AC97", + .dai_link = &db1200_ac97_dai, + .num_links = 1, +}; + /*------------------------- I2S PART ---------------------------*/ static int db1200_i2s_startup(struct snd_pcm_substream *substream) @@ -100,11 +133,47 @@ static struct snd_soc_card db1200_i2s_machine = { .num_links = 1, }; +static struct snd_soc_dai_link db1300_i2s_dai = { + .name = "WM8731", + .stream_name = "WM8731 PCM", + .codec_dai_name = "wm8731-hifi", + .cpu_dai_name = "au1xpsc_i2s.2", + .platform_name = "au1xpsc-pcm.2", + .codec_name = "wm8731.0-001b", + .ops = &db1200_i2s_wm8731_ops, +}; + +static struct snd_soc_card db1300_i2s_machine = { + .name = "DB1300_I2S", + .dai_link = &db1300_i2s_dai, + .num_links = 1, +}; + +static struct snd_soc_dai_link db1550_i2s_dai = { + .name = "WM8731", + .stream_name = "WM8731 PCM", + .codec_dai_name = "wm8731-hifi", + .cpu_dai_name = "au1xpsc_i2s.3", + .platform_name = "au1xpsc-pcm.3", + .codec_name = "wm8731.0-001b", + .ops = &db1200_i2s_wm8731_ops, +}; + +static struct snd_soc_card db1550_i2s_machine = { + .name = "DB1550_I2S", + .dai_link = &db1550_i2s_dai, + .num_links = 1, +}; + /*------------------------- COMMON PART ---------------------------*/ static struct snd_soc_card *db1200_cards[] __devinitdata = { &db1200_ac97_machine, &db1200_i2s_machine, + &db1300_ac97_machine, + &db1300_i2s_machine, + &db1550_ac97_machine, + &db1550_i2s_machine, }; static int __devinit db1200_audio_probe(struct platform_device *pdev) @@ -138,5 +207,5 @@ static struct platform_driver db1200_audio_driver = { module_platform_driver(db1200_audio_driver); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("DB1200 ASoC audio support"); +MODULE_DESCRIPTION("DB1200/DB1300/DB1550 ASoC audio support"); MODULE_AUTHOR("Manuel Lauss"); diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index d7bd91831611..f8863ebb4304 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1457,5 +1457,5 @@ static void __exit sgtl5000_exit(void) module_exit(sgtl5000_exit); MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver"); -MODULE_AUTHOR("Zeng Zhaoming <zhaoming.zeng@freescale.com>"); +MODULE_AUTHOR("Zeng Zhaoming <zengzm.kernel@gmail.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 2b40c93601ed..7c7fd925db8d 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -444,6 +444,12 @@ static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source, /* Enable the FLL */ snd_soc_write(codec, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA); + /* Both overestimates */ + if (Fref < 1000000) + msleep(3); + else + msleep(1); + dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); wm8993->fll_fref = Fref; diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c index 3fc96130d1a6..de8390449873 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.c +++ b/sound/soc/ep93xx/ep93xx-pcm.c @@ -113,9 +113,9 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream) rtd->dma_data.name = dma_params->name; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - rtd->dma_data.direction = DMA_TO_DEVICE; + rtd->dma_data.direction = DMA_MEM_TO_DEV; else - rtd->dma_data.direction = DMA_FROM_DEVICE; + rtd->dma_data.direction = DMA_DEV_TO_MEM; rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter, &rtd->dma_data); diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c index 1cf2fe889f6a..5780c9b9d569 100644 --- a/sound/soc/imx/imx-pcm-dma-mx2.c +++ b/sound/soc/imx/imx-pcm-dma-mx2.c @@ -88,11 +88,13 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream, iprtd->dma_data.dma_request = dma_params->dma; /* Try to grab a DMA channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); - if (!iprtd->dma_chan) - return -EINVAL; + if (!iprtd->dma_chan) { + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); + if (!iprtd->dma_chan) + return -EINVAL; + } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -107,12 +109,12 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream, } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - slave_config.direction = DMA_TO_DEVICE; + slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = dma_params->dma_addr; slave_config.dst_addr_width = buswidth; slave_config.dst_maxburst = dma_params->burstsize; } else { - slave_config.direction = DMA_FROM_DEVICE; + slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = dma_params->dma_addr; slave_config.src_addr_width = buswidth; slave_config.src_maxburst = dma_params->burstsize; @@ -159,7 +161,7 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, iprtd->period_bytes * iprtd->periods, iprtd->period_bytes, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); + DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); if (!iprtd->desc) { dev_err(&chan->dev->device, "cannot prepare slave dma\n"); return -EINVAL; diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index 0e12f4e0a76d..105f42a394df 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c @@ -136,7 +136,7 @@ static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream, iprtd->period_bytes * iprtd->periods, iprtd->period_bytes, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); + DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); if (!iprtd->desc) { dev_err(&chan->dev->device, "cannot prepare slave dma\n"); return -EINVAL; diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index 45d11ddaeea9..946020a647db 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -366,7 +366,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev) goto out3; /* enbale ac97 multifunction pin */ - mfp_set_groupg(nuc900_audio->dev, "nuc900-audio"); + mfp_set_groupg(nuc900_audio->dev, NULL); return 0; diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 427ae0d9817b..e4ba17ce6b32 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -86,7 +86,7 @@ static void dma_enqueue(struct snd_pcm_substream *substream) dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); dma_info.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); dma_info.fp = audio_buffdone; dma_info.fp_param = substream; dma_info.period = prtd->dma_period; @@ -171,7 +171,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream, dma_info.client = prtd->params->client; dma_info.direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); dma_info.width = prtd->params->dma_size; dma_info.fifo = prtd->params->dma_addr; prtd->params->ch = prtd->params->ops->request( diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index f8f681690a71..0193e595d415 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -131,7 +131,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info, sg_dma_address(&sg) = buff; desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan, - &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dev_err(dev, "Failed to allocate a dma descriptor\n"); return -ENOMEM; @@ -181,7 +181,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info, sg_dma_address(&sg) = buff; desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan, - &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dev_err(dev, "Failed to allocate dma descriptor\n"); return -ENOMEM; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3986520b4677..b5ecf6d23214 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -907,6 +907,10 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) if (err < 0) printk(KERN_ERR "asoc: failed to remove %s\n", platform->name); } + + /* Make sure all DAPM widgets are freed */ + snd_soc_dapm_free(&platform->dapm); + platform->probed = 0; list_del(&platform->card_list); module_put(platform->dev->driver->owner); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3ad1f59b8028..1f55ded4047f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1426,7 +1426,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) dapm->target_bias_level = SND_SOC_BIAS_ON; break; case SND_SOC_DAPM_STREAM_STOP: - if (dapm->codec->active) + if (dapm->codec && dapm->codec->active) dapm->target_bias_level = SND_SOC_BIAS_ON; else dapm->target_bias_level = SND_SOC_BIAS_STANDBY; diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 93931def0dce..21554611557c 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -134,7 +134,7 @@ txx9aclc_dma_submit(struct txx9aclc_dmadata *dmadata, dma_addr_t buf_dma_addr) sg_dma_address(&sg) = buf_dma_addr; desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dmadata->substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - DMA_TO_DEVICE : DMA_FROM_DEVICE, + DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { dev_err(&chan->dev->device, "cannot prepare slave dma\n"); diff --git a/tools/nfsd/inject_fault.sh b/tools/nfsd/inject_fault.sh new file mode 100755 index 000000000000..06a399ac8b2f --- /dev/null +++ b/tools/nfsd/inject_fault.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com> +# +# Script for easier NFSD fault injection + +# Check that debugfs has been mounted +DEBUGFS=`cat /proc/mounts | grep debugfs` +if [ "$DEBUGFS" == "" ]; then + echo "debugfs does not appear to be mounted!" + echo "Please mount debugfs and try again" + exit 1 +fi + +# Check that the fault injection directory exists +DEBUGDIR=`echo $DEBUGFS | awk '{print $2}'`/nfsd +if [ ! -d "$DEBUGDIR" ]; then + echo "$DEBUGDIR does not exist" + echo "Check that your .config selects CONFIG_NFSD_FAULT_INJECTION" + exit 1 +fi + +function help() +{ + echo "Usage $0 injection_type [count]" + echo "" + echo "Injection types are:" + ls $DEBUGDIR + exit 1 +} + +if [ $# == 0 ]; then + help +elif [ ! -f $DEBUGDIR/$1 ]; then + help +elif [ $# != 2 ]; then + COUNT=0 +else + COUNT=$2 +fi + +BEFORE=`mktemp` +AFTER=`mktemp` +dmesg > $BEFORE +echo $COUNT > $DEBUGDIR/$1 +dmesg > $AFTER +# Capture lines that only exist in the $AFTER file +diff $BEFORE $AFTER | grep ">" +rm -f $BEFORE $AFTER diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 7a527f7e9da9..ddc22525228d 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -21,6 +21,8 @@ EVENT MODIFIERS Events can optionally have a modifer by appending a colon and one or more modifiers. Modifiers allow the user to restrict when events are counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor. +Additional modifiers are 'G' for guest counting (in KVM guests) and 'H' +for host counting (not in KVM guests). The 'p' modifier can be used for specifying how precise the instruction address should be. The 'p' modifier is currently only implemented for diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index c12659d8cb26..1078c5fadd5b 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -1,4 +1,5 @@ tools/perf +include/linux/const.h include/linux/perf_event.h include/linux/rbtree.h include/linux/list.h diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 214ba7f9f577..806e0a286634 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -235,7 +235,7 @@ out_delete: } static const char * const annotate_usage[] = { - "perf annotate [<options>] <command>", + "perf annotate [<options>]", NULL }; @@ -313,10 +313,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) annotate.sym_hist_filter = argv[0]; } - if (field_sep && *field_sep == '.') { - pr_err("'.' is the only non valid --field-separator argument\n"); - return -1; - } - return __cmd_annotate(&annotate); } diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index fe1ad8f21961..39104c0beea3 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -108,7 +108,9 @@ static void setup_cpunode_map(void) continue; cpunode_map[cpu] = mem; } + closedir(dir2); } + closedir(dir1); } static void insert_alloc_stat(unsigned long call_site, unsigned long ptr, @@ -645,6 +647,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg) break; if (sort_dimension__add(tok, sort_list) < 0) { error("Unknown --sort key: '%s'", tok); + free(str); return -1; } } diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 032324a76b87..9fc6e0fa3dce 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -22,9 +22,6 @@ static const char *file_name; static char name_buffer[256]; -bool perf_host = 1; -bool perf_guest; - static const char * const kvm_usage[] = { "perf kvm [<options>] {top|record|report|diff|buildid-list}", NULL @@ -107,7 +104,8 @@ static int __cmd_buildid_list(int argc, const char **argv) int cmd_kvm(int argc, const char **argv, const char *prefix __used) { - perf_host = perf_guest = 0; + perf_host = 0; + perf_guest = 1; argc = parse_options(argc, argv, kvm_options, kvm_usage, PARSE_OPT_STOP_AT_NON_OPTION); diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index fd1909afcfd6..bb68ddf257b7 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1018,13 +1018,17 @@ static char *get_script_path(const char *script_root, const char *suffix) __script_root = get_script_root(&script_dirent, suffix); if (__script_root && !strcmp(script_root, __script_root)) { free(__script_root); + closedir(lang_dir); + closedir(scripts_dir); snprintf(script_path, MAXPATHLEN, "%s/%s", lang_path, script_dirent.d_name); return strdup(script_path); } free(__script_root); } + closedir(lang_dir); } + closedir(scripts_dir); return NULL; } diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 2b9a7f497a20..3854e869dce1 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -1396,7 +1396,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __used) NULL, }; const struct option test_options[] = { - OPT_INTEGER('v', "verbose", &verbose, + OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_END() }; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4f81eeb99875..8f80df896038 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -235,7 +235,6 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, if (he == NULL) return NULL; - evsel->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); return he; } @@ -889,6 +888,10 @@ try_again: ui__warning("The %s event is not supported.\n", event_name(counter)); goto out_err; + } else if (err == EMFILE) { + ui__warning("Too many events are opened.\n" + "Try again after reducing the number of events\n"); + goto out_err; } ui__warning("The sys_perf_event_open() syscall " diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index fa1837088ca8..3f16e08a5c8d 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -111,8 +111,11 @@ int perf_evlist__add_default(struct perf_evlist *evlist) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, }; - struct perf_evsel *evsel = perf_evsel__new(&attr, 0); + struct perf_evsel *evsel; + + event_attr_init(&attr); + evsel = perf_evsel__new(&attr, 0); if (evsel == NULL) goto error; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index abef2703cd24..6f505d1abac7 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -76,21 +76,21 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h) } } -static void hist_entry__add_cpumode_period(struct hist_entry *self, +static void hist_entry__add_cpumode_period(struct hist_entry *he, unsigned int cpumode, u64 period) { switch (cpumode) { case PERF_RECORD_MISC_KERNEL: - self->period_sys += period; + he->period_sys += period; break; case PERF_RECORD_MISC_USER: - self->period_us += period; + he->period_us += period; break; case PERF_RECORD_MISC_GUEST_KERNEL: - self->period_guest_sys += period; + he->period_guest_sys += period; break; case PERF_RECORD_MISC_GUEST_USER: - self->period_guest_us += period; + he->period_guest_us += period; break; default: break; @@ -165,18 +165,18 @@ void hists__decay_entries_threaded(struct hists *hists, static struct hist_entry *hist_entry__new(struct hist_entry *template) { size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; - struct hist_entry *self = malloc(sizeof(*self) + callchain_size); + struct hist_entry *he = malloc(sizeof(*he) + callchain_size); - if (self != NULL) { - *self = *template; - self->nr_events = 1; - if (self->ms.map) - self->ms.map->referenced = true; + if (he != NULL) { + *he = *template; + he->nr_events = 1; + if (he->ms.map) + he->ms.map->referenced = true; if (symbol_conf.use_callchain) - callchain_init(self->callchain); + callchain_init(he->callchain); } - return self; + return he; } static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) @@ -677,15 +677,16 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self, return ret; } -static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, - u64 total_samples, int left_margin) +static size_t hist_entry_callchain__fprintf(struct hist_entry *he, + u64 total_samples, int left_margin, + FILE *fp) { struct rb_node *rb_node; struct callchain_node *chain; size_t ret = 0; u32 entries_printed = 0; - rb_node = rb_first(&self->sorted_chain); + rb_node = rb_first(&he->sorted_chain); while (rb_node) { double percent; @@ -730,35 +731,35 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows) } } -static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, +static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s, size_t size, struct hists *pair_hists, bool show_displacement, long displacement, - bool color, u64 session_total) + bool color, u64 total_period) { u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; u64 nr_events; const char *sep = symbol_conf.field_sep; int ret; - if (symbol_conf.exclude_other && !self->parent) + if (symbol_conf.exclude_other && !he->parent) return 0; if (pair_hists) { - period = self->pair ? self->pair->period : 0; - nr_events = self->pair ? self->pair->nr_events : 0; + period = he->pair ? he->pair->period : 0; + nr_events = he->pair ? he->pair->nr_events : 0; total = pair_hists->stats.total_period; - period_sys = self->pair ? self->pair->period_sys : 0; - period_us = self->pair ? self->pair->period_us : 0; - period_guest_sys = self->pair ? self->pair->period_guest_sys : 0; - period_guest_us = self->pair ? self->pair->period_guest_us : 0; + period_sys = he->pair ? he->pair->period_sys : 0; + period_us = he->pair ? he->pair->period_us : 0; + period_guest_sys = he->pair ? he->pair->period_guest_sys : 0; + period_guest_us = he->pair ? he->pair->period_guest_us : 0; } else { - period = self->period; - nr_events = self->nr_events; - total = session_total; - period_sys = self->period_sys; - period_us = self->period_us; - period_guest_sys = self->period_guest_sys; - period_guest_us = self->period_guest_us; + period = he->period; + nr_events = he->nr_events; + total = total_period; + period_sys = he->period_sys; + period_us = he->period_us; + period_guest_sys = he->period_guest_sys; + period_guest_us = he->period_guest_us; } if (total) { @@ -812,8 +813,8 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s, if (total > 0) old_percent = (period * 100.0) / total; - if (session_total > 0) - new_percent = (self->period * 100.0) / session_total; + if (total_period > 0) + new_percent = (he->period * 100.0) / total_period; diff = new_percent - old_percent; @@ -862,9 +863,10 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size, return ret; } -int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, - struct hists *pair_hists, bool show_displacement, - long displacement, FILE *fp, u64 session_total) +static int hist_entry__fprintf(struct hist_entry *he, size_t size, + struct hists *hists, struct hists *pair_hists, + bool show_displacement, long displacement, + u64 total_period, FILE *fp) { char bf[512]; int ret; @@ -874,14 +876,14 @@ int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists, show_displacement, displacement, - true, session_total); + true, total_period); hist_entry__snprintf(he, bf + ret, size - ret, hists); return fprintf(fp, "%s\n", bf); } -static size_t hist_entry__fprintf_callchain(struct hist_entry *self, - struct hists *hists, FILE *fp, - u64 session_total) +static size_t hist_entry__fprintf_callchain(struct hist_entry *he, + struct hists *hists, + u64 total_period, FILE *fp) { int left_margin = 0; @@ -889,11 +891,10 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, struct sort_entry *se = list_first_entry(&hist_entry__sort_list, typeof(*se), list); left_margin = hists__col_len(hists, se->se_width_idx); - left_margin -= thread__comm_len(self->thread); + left_margin -= thread__comm_len(he->thread); } - return hist_entry_callchain__fprintf(fp, self, session_total, - left_margin); + return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); } size_t hists__fprintf(struct hists *hists, struct hists *pair, @@ -903,6 +904,7 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, 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; @@ -917,20 +919,6 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); - if (symbol_conf.show_nr_samples) { - if (sep) - fprintf(fp, "%cSamples", *sep); - else - fputs(" Samples ", fp); - } - - if (symbol_conf.show_total_period) { - if (sep) - ret += fprintf(fp, "%cPeriod", *sep); - else - ret += fprintf(fp, " Period "); - } - if (symbol_conf.show_cpu_utilization) { if (sep) { ret += fprintf(fp, "%csys", *sep); @@ -940,8 +928,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, ret += fprintf(fp, "%cguest us", *sep); } } else { - ret += fprintf(fp, " sys "); - ret += fprintf(fp, " us "); + ret += fprintf(fp, " sys "); + ret += fprintf(fp, " us "); if (perf_guest) { ret += fprintf(fp, " guest sys "); ret += fprintf(fp, " guest us "); @@ -949,6 +937,20 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, } } + if (symbol_conf.show_nr_samples) { + if (sep) + fprintf(fp, "%cSamples", *sep); + else + fputs(" Samples ", fp); + } + + if (symbol_conf.show_total_period) { + if (sep) + ret += fprintf(fp, "%cPeriod", *sep); + else + ret += fprintf(fp, " Period "); + } + if (pair) { if (sep) ret += fprintf(fp, "%cDelta", *sep); @@ -993,6 +995,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair, goto print_entries; fprintf(fp, "# ........"); + if (symbol_conf.show_cpu_utilization) + fprintf(fp, " ....... ......."); if (symbol_conf.show_nr_samples) fprintf(fp, " .........."); if (symbol_conf.show_total_period) @@ -1025,6 +1029,8 @@ 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); @@ -1040,11 +1046,10 @@ print_entries: ++position; } ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement, - displacement, fp, hists->stats.total_period); + displacement, total_period, fp); if (symbol_conf.use_callchain) - ret += hist_entry__fprintf_callchain(h, hists, fp, - hists->stats.total_period); + ret += hist_entry__fprintf_callchain(h, hists, total_period, fp); if (max_rows && ++nr_rows >= max_rows) goto out; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ff6f9d56ea41..f55f0a8d1f81 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -66,11 +66,8 @@ struct hists { struct hist_entry *__hists__add_entry(struct hists *self, struct addr_location *al, struct symbol *parent, u64 period); -extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); -extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); -int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists, - struct hists *pair_hists, bool show_displacement, - long displacement, FILE *fp, u64 session_total); +int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); +int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size, struct hists *hists); void hist_entry__free(struct hist_entry *); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 531c283fc0c5..b029296d20d9 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -735,8 +735,8 @@ static int parse_event_modifier(const char **strp, struct perf_event_attr *attr) { const char *str = *strp; - int exclude = 0; - int eu = 0, ek = 0, eh = 0, precise = 0; + int exclude = 0, exclude_GH = 0; + int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0; if (!*str) return 0; @@ -760,6 +760,14 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) if (!exclude) exclude = eu = ek = eh = 1; eh = 0; + } else if (*str == 'G') { + if (!exclude_GH) + exclude_GH = eG = eH = 1; + eG = 0; + } else if (*str == 'H') { + if (!exclude_GH) + exclude_GH = eG = eH = 1; + eH = 0; } else if (*str == 'p') { precise++; } else @@ -776,6 +784,8 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) attr->exclude_kernel = ek; attr->exclude_hv = eh; attr->precise_ip = precise; + attr->exclude_host = eH; + attr->exclude_guest = eG; return 0; } @@ -838,6 +848,7 @@ int parse_events(struct perf_evlist *evlist , const char *str, int unset __used) for (;;) { ostr = str; memset(&attr, 0, sizeof(attr)); + event_attr_init(&attr); ret = parse_event_symbols(evlist, &str, &attr); if (ret == EVT_FAILED) return -1; diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index ac6830d8292b..fc22cf5c605f 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -18,7 +18,6 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#include <ctype.h> #include "util.h" #include <dirent.h> #include <mntent.h> diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 5b3ea49aa63e..813141047fc2 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -1,6 +1,21 @@ +#include "../perf.h" #include "util.h" #include <sys/mman.h> +/* + * XXX We need to find a better place for these things... + */ +bool perf_host = true; +bool perf_guest = true; + +void event_attr_init(struct perf_event_attr *attr) +{ + if (!perf_host) + attr->exclude_host = 1; + if (!perf_guest) + attr->exclude_guest = 1; +} + int mkdir_p(char *path, mode_t mode) { struct stat st; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 37be34dff798..b9c530cce79a 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -242,6 +242,10 @@ int strtailcmp(const char *s1, const char *s2); unsigned long convert_unit(unsigned long value, char *unit); int readn(int fd, void *buf, size_t size); +struct perf_event_attr; + +void event_attr_init(struct perf_event_attr *attr); + #define _STR(x) #x #define STR(x) _STR(x) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 3c6f7808efae..310d3dd5e547 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -811,6 +811,8 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) case 0x2C: /* Westmere EP - Gulftown */ case 0x2A: /* SNB */ case 0x2D: /* SNB Xeon */ + case 0x3A: /* IVB */ + case 0x3D: /* IVB Xeon */ return 1; case 0x2E: /* Nehalem-EX Xeon - Beckton */ case 0x2F: /* Westmere-EX Xeon - Eagleton */ diff --git a/tools/testing/ktest/compare-ktest-sample.pl b/tools/testing/ktest/compare-ktest-sample.pl index 9a571e71683c..a373a5bfff68 100755 --- a/tools/testing/ktest/compare-ktest-sample.pl +++ b/tools/testing/ktest/compare-ktest-sample.pl @@ -2,7 +2,9 @@ open (IN,"ktest.pl"); while (<IN>) { + # hashes are now used if (/\$opt\{"?([A-Z].*?)(\[.*\])?"?\}/ || + /^\s*"?([A-Z].*?)"?\s*=>\s*/ || /set_test_option\("(.*?)"/) { $opt{$1} = 1; } @@ -11,7 +13,7 @@ close IN; open (IN, "sample.conf"); while (<IN>) { - if (/^\s*#?\s*(\S+)\s*=/) { + if (/^\s*#?\s*([A-Z]\S*)\s*=/) { $samp{$1} = 1; } } diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 8b4c2535b266..62a134dc421a 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -18,40 +18,50 @@ $| = 1; my %opt; my %repeat_tests; my %repeats; -my %default; #default opts -$default{"NUM_TESTS"} = 1; -$default{"REBOOT_TYPE"} = "grub"; -$default{"TEST_TYPE"} = "test"; -$default{"BUILD_TYPE"} = "randconfig"; -$default{"MAKE_CMD"} = "make"; -$default{"TIMEOUT"} = 120; -$default{"TMP_DIR"} = "/tmp/ktest/\${MACHINE}"; -$default{"SLEEP_TIME"} = 60; # sleep time between tests -$default{"BUILD_NOCLEAN"} = 0; -$default{"REBOOT_ON_ERROR"} = 0; -$default{"POWEROFF_ON_ERROR"} = 0; -$default{"REBOOT_ON_SUCCESS"} = 1; -$default{"POWEROFF_ON_SUCCESS"} = 0; -$default{"BUILD_OPTIONS"} = ""; -$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects -$default{"PATCHCHECK_SLEEP_TIME"} = 60; # sleep time between patch checks -$default{"CLEAR_LOG"} = 0; -$default{"BISECT_MANUAL"} = 0; -$default{"BISECT_SKIP"} = 1; -$default{"SUCCESS_LINE"} = "login:"; -$default{"DETECT_TRIPLE_FAULT"} = 1; -$default{"NO_INSTALL"} = 0; -$default{"BOOTED_TIMEOUT"} = 1; -$default{"DIE_ON_FAILURE"} = 1; -$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND"; -$default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE"; -$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot"; -$default{"STOP_AFTER_SUCCESS"} = 10; -$default{"STOP_AFTER_FAILURE"} = 60; -$default{"STOP_TEST_AFTER"} = 600; -$default{"LOCALVERSION"} = "-test"; +my %default = ( + "NUM_TESTS" => 1, + "TEST_TYPE" => "build", + "BUILD_TYPE" => "randconfig", + "MAKE_CMD" => "make", + "TIMEOUT" => 120, + "TMP_DIR" => "/tmp/ktest/\${MACHINE}", + "SLEEP_TIME" => 60, # sleep time between tests + "BUILD_NOCLEAN" => 0, + "REBOOT_ON_ERROR" => 0, + "POWEROFF_ON_ERROR" => 0, + "REBOOT_ON_SUCCESS" => 1, + "POWEROFF_ON_SUCCESS" => 0, + "BUILD_OPTIONS" => "", + "BISECT_SLEEP_TIME" => 60, # sleep time between bisects + "PATCHCHECK_SLEEP_TIME" => 60, # sleep time between patch checks + "CLEAR_LOG" => 0, + "BISECT_MANUAL" => 0, + "BISECT_SKIP" => 1, + "SUCCESS_LINE" => "login:", + "DETECT_TRIPLE_FAULT" => 1, + "NO_INSTALL" => 0, + "BOOTED_TIMEOUT" => 1, + "DIE_ON_FAILURE" => 1, + "SSH_EXEC" => "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND", + "SCP_TO_TARGET" => "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE", + "REBOOT" => "ssh \$SSH_USER\@\$MACHINE reboot", + "STOP_AFTER_SUCCESS" => 10, + "STOP_AFTER_FAILURE" => 60, + "STOP_TEST_AFTER" => 600, + +# required, and we will ask users if they don't have them but we keep the default +# value something that is common. + "REBOOT_TYPE" => "grub", + "LOCALVERSION" => "-test", + "SSH_USER" => "root", + "BUILD_TARGET" => "arch/x86/boot/bzImage", + "TARGET_IMAGE" => "/boot/vmlinuz-test", + + "LOG_FILE" => undef, + "IGNORE_UNUSED" => 0, +); my $ktest_config; my $version; @@ -73,6 +83,8 @@ my $reboot_script; my $power_cycle; my $reboot; my $reboot_on_error; +my $switch_to_good; +my $switch_to_test; my $poweroff_on_error; my $die_on_failure; my $powercycle_after_reboot; @@ -92,17 +104,24 @@ my $start_minconfig; my $start_minconfig_defined; my $output_minconfig; my $ignore_config; +my $ignore_errors; my $addconfig; my $in_bisect = 0; -my $bisect_bad = ""; +my $bisect_bad_commit = ""; my $reverse_bisect; my $bisect_manual; my $bisect_skip; my $config_bisect_good; +my $bisect_ret_good; +my $bisect_ret_bad; +my $bisect_ret_skip; +my $bisect_ret_abort; +my $bisect_ret_default; my $in_patchcheck = 0; my $run_test; my $redirect; my $buildlog; +my $testlog; my $dmesg; my $monitor_fp; my $monitor_pid; @@ -112,6 +131,7 @@ my $bisect_sleep_time; my $patchcheck_sleep_time; my $ignore_warnings; my $store_failures; +my $store_successes; my $test_name; my $timeout; my $booted_timeout; @@ -124,10 +144,34 @@ my $stop_after_failure; my $stop_test_after; my $build_target; my $target_image; +my $checkout; my $localversion; my $iteration = 0; my $successes = 0; +my $bisect_good; +my $bisect_bad; +my $bisect_type; +my $bisect_start; +my $bisect_replay; +my $bisect_files; +my $bisect_reverse; +my $bisect_check; + +my $config_bisect; +my $config_bisect_type; + +my $patchcheck_type; +my $patchcheck_start; +my $patchcheck_end; + +# set when a test is something other that just building or install +# which would require more options. +my $buildonly = 1; + +# set when creating a new config +my $newconfig = 0; + my %entered_configs; my %config_help; my %variable; @@ -136,11 +180,99 @@ my %force_config; # do not force reboots on config problems my $no_reboot = 1; +my %option_map = ( + "MACHINE" => \$machine, + "SSH_USER" => \$ssh_user, + "TMP_DIR" => \$tmpdir, + "OUTPUT_DIR" => \$outputdir, + "BUILD_DIR" => \$builddir, + "TEST_TYPE" => \$test_type, + "BUILD_TYPE" => \$build_type, + "BUILD_OPTIONS" => \$build_options, + "PRE_BUILD" => \$pre_build, + "POST_BUILD" => \$post_build, + "PRE_BUILD_DIE" => \$pre_build_die, + "POST_BUILD_DIE" => \$post_build_die, + "POWER_CYCLE" => \$power_cycle, + "REBOOT" => \$reboot, + "BUILD_NOCLEAN" => \$noclean, + "MIN_CONFIG" => \$minconfig, + "OUTPUT_MIN_CONFIG" => \$output_minconfig, + "START_MIN_CONFIG" => \$start_minconfig, + "IGNORE_CONFIG" => \$ignore_config, + "TEST" => \$run_test, + "ADD_CONFIG" => \$addconfig, + "REBOOT_TYPE" => \$reboot_type, + "GRUB_MENU" => \$grub_menu, + "POST_INSTALL" => \$post_install, + "NO_INSTALL" => \$no_install, + "REBOOT_SCRIPT" => \$reboot_script, + "REBOOT_ON_ERROR" => \$reboot_on_error, + "SWITCH_TO_GOOD" => \$switch_to_good, + "SWITCH_TO_TEST" => \$switch_to_test, + "POWEROFF_ON_ERROR" => \$poweroff_on_error, + "DIE_ON_FAILURE" => \$die_on_failure, + "POWER_OFF" => \$power_off, + "POWERCYCLE_AFTER_REBOOT" => \$powercycle_after_reboot, + "POWEROFF_AFTER_HALT" => \$poweroff_after_halt, + "SLEEP_TIME" => \$sleep_time, + "BISECT_SLEEP_TIME" => \$bisect_sleep_time, + "PATCHCHECK_SLEEP_TIME" => \$patchcheck_sleep_time, + "IGNORE_WARNINGS" => \$ignore_warnings, + "IGNORE_ERRORS" => \$ignore_errors, + "BISECT_MANUAL" => \$bisect_manual, + "BISECT_SKIP" => \$bisect_skip, + "CONFIG_BISECT_GOOD" => \$config_bisect_good, + "BISECT_RET_GOOD" => \$bisect_ret_good, + "BISECT_RET_BAD" => \$bisect_ret_bad, + "BISECT_RET_SKIP" => \$bisect_ret_skip, + "BISECT_RET_ABORT" => \$bisect_ret_abort, + "BISECT_RET_DEFAULT" => \$bisect_ret_default, + "STORE_FAILURES" => \$store_failures, + "STORE_SUCCESSES" => \$store_successes, + "TEST_NAME" => \$test_name, + "TIMEOUT" => \$timeout, + "BOOTED_TIMEOUT" => \$booted_timeout, + "CONSOLE" => \$console, + "DETECT_TRIPLE_FAULT" => \$detect_triplefault, + "SUCCESS_LINE" => \$success_line, + "REBOOT_SUCCESS_LINE" => \$reboot_success_line, + "STOP_AFTER_SUCCESS" => \$stop_after_success, + "STOP_AFTER_FAILURE" => \$stop_after_failure, + "STOP_TEST_AFTER" => \$stop_test_after, + "BUILD_TARGET" => \$build_target, + "SSH_EXEC" => \$ssh_exec, + "SCP_TO_TARGET" => \$scp_to_target, + "CHECKOUT" => \$checkout, + "TARGET_IMAGE" => \$target_image, + "LOCALVERSION" => \$localversion, + + "BISECT_GOOD" => \$bisect_good, + "BISECT_BAD" => \$bisect_bad, + "BISECT_TYPE" => \$bisect_type, + "BISECT_START" => \$bisect_start, + "BISECT_REPLAY" => \$bisect_replay, + "BISECT_FILES" => \$bisect_files, + "BISECT_REVERSE" => \$bisect_reverse, + "BISECT_CHECK" => \$bisect_check, + + "CONFIG_BISECT" => \$config_bisect, + "CONFIG_BISECT_TYPE" => \$config_bisect_type, + + "PATCHCHECK_TYPE" => \$patchcheck_type, + "PATCHCHECK_START" => \$patchcheck_start, + "PATCHCHECK_END" => \$patchcheck_end, +); + +# Options may be used by other options, record them. +my %used_options; + # default variables that can be used chomp ($variable{"PWD"} = `pwd`); $config_help{"MACHINE"} = << "EOF" The machine hostname that you will test. + For build only tests, it is still needed to differentiate log files. EOF ; $config_help{"SSH_USER"} = << "EOF" @@ -150,11 +282,15 @@ EOF ; $config_help{"BUILD_DIR"} = << "EOF" The directory that contains the Linux source code (full path). + You can use \${PWD} that will be the path where ktest.pl is run, or use + \${THIS_DIR} which is assigned \${PWD} but may be changed later. EOF ; $config_help{"OUTPUT_DIR"} = << "EOF" The directory that the objects will be built (full path). (can not be same as BUILD_DIR) + You can use \${PWD} that will be the path where ktest.pl is run, or use + \${THIS_DIR} which is assigned \${PWD} but may be changed later. EOF ; $config_help{"BUILD_TARGET"} = << "EOF" @@ -162,6 +298,11 @@ $config_help{"BUILD_TARGET"} = << "EOF" (relative to OUTPUT_DIR) EOF ; +$config_help{"BUILD_OPTIONS"} = << "EOF" + Options to add to \"make\" when building. + i.e. -j20 +EOF + ; $config_help{"TARGET_IMAGE"} = << "EOF" The place to put your image on the test machine. EOF @@ -227,20 +368,36 @@ $config_help{"REBOOT_SCRIPT"} = << "EOF" EOF ; -sub read_yn { - my ($prompt) = @_; +sub read_prompt { + my ($cancel, $prompt) = @_; my $ans; for (;;) { - print "$prompt [Y/n] "; + if ($cancel) { + print "$prompt [y/n/C] "; + } else { + print "$prompt [Y/n] "; + } $ans = <STDIN>; chomp $ans; if ($ans =~ /^\s*$/) { - $ans = "y"; + if ($cancel) { + $ans = "c"; + } else { + $ans = "y"; + } } last if ($ans =~ /^y$/i || $ans =~ /^n$/i); - print "Please answer either 'y' or 'n'.\n"; + if ($cancel) { + last if ($ans =~ /^c$/i); + print "Please answer either 'y', 'n' or 'c'.\n"; + } else { + print "Please answer either 'y' or 'n'.\n"; + } + } + if ($ans =~ /^c/i) { + exit; } if ($ans !~ /^y$/i) { return 0; @@ -248,6 +405,18 @@ sub read_yn { return 1; } +sub read_yn { + my ($prompt) = @_; + + return read_prompt 0, $prompt; +} + +sub read_ync { + my ($prompt) = @_; + + return read_prompt 1, $prompt; +} + sub get_ktest_config { my ($config) = @_; my $ans; @@ -261,7 +430,7 @@ sub get_ktest_config { for (;;) { print "$config = "; - if (defined($default{$config})) { + if (defined($default{$config}) && length($default{$config})) { print "\[$default{$config}\] "; } $ans = <STDIN>; @@ -274,22 +443,37 @@ sub get_ktest_config { next; } } - $entered_configs{$config} = process_variables($ans); + $entered_configs{$config} = ${ans}; last; } } sub get_ktest_configs { get_ktest_config("MACHINE"); - get_ktest_config("SSH_USER"); get_ktest_config("BUILD_DIR"); get_ktest_config("OUTPUT_DIR"); - get_ktest_config("BUILD_TARGET"); - get_ktest_config("TARGET_IMAGE"); - get_ktest_config("POWER_CYCLE"); - get_ktest_config("CONSOLE"); + + if ($newconfig) { + get_ktest_config("BUILD_OPTIONS"); + } + + # options required for other than just building a kernel + if (!$buildonly) { + get_ktest_config("POWER_CYCLE"); + get_ktest_config("CONSOLE"); + } + + # options required for install and more + if ($buildonly != 1) { + get_ktest_config("SSH_USER"); + get_ktest_config("BUILD_TARGET"); + get_ktest_config("TARGET_IMAGE"); + } + get_ktest_config("LOCALVERSION"); + return if ($buildonly); + my $rtype = $opt{"REBOOT_TYPE"}; if (!defined($rtype)) { @@ -303,8 +487,6 @@ sub get_ktest_configs { if ($rtype eq "grub") { get_ktest_config("GRUB_MENU"); - } else { - get_ktest_config("REBOOT_SCRIPT"); } } @@ -334,6 +516,10 @@ sub process_variables { } else { # put back the origin piece. $retval = "$retval\$\{$var\}"; + # This could be an option that is used later, save + # it so we don't warn if this option is not one of + # ktests options. + $used_options{$var} = 1; } $value = $end; } @@ -348,6 +534,19 @@ sub process_variables { sub set_value { my ($lvalue, $rvalue, $override, $overrides, $name) = @_; + my $prvalue = process_variables($rvalue); + + if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { + # Note if a test is something other than build, then we + # will need other manditory options. + if ($prvalue ne "install") { + $buildonly = 0; + } else { + # install still limits some manditory options. + $buildonly = 2; + } + } + if (defined($opt{$lvalue})) { if (!$override || defined(${$overrides}{$lvalue})) { my $extra = ""; @@ -356,13 +555,12 @@ sub set_value { } die "$name: $.: Option $lvalue defined more than once!\n$extra"; } - ${$overrides}{$lvalue} = $rvalue; + ${$overrides}{$lvalue} = $prvalue; } if ($rvalue =~ /^\s*$/) { delete $opt{$lvalue}; } else { - $rvalue = process_variables($rvalue); - $opt{$lvalue} = $rvalue; + $opt{$lvalue} = $prvalue; } } @@ -712,6 +910,15 @@ sub __read_config { return $test_case; } +sub get_test_case { + print "What test case would you like to run?\n"; + print " (build, install or boot)\n"; + print " Other tests are available but require editing the config file\n"; + my $ans = <STDIN>; + chomp $ans; + $default{"TEST_TYPE"} = $ans; +} + sub read_config { my ($config) = @_; @@ -726,10 +933,7 @@ sub read_config { # was a test specified? if (!$test_case) { print "No test case specified.\n"; - print "What test case would you like to run?\n"; - my $ans = <STDIN>; - chomp $ans; - $default{"TEST_TYPE"} = $ans; + get_test_case; } # set any defaults @@ -739,6 +943,37 @@ sub read_config { $opt{$default} = $default{$default}; } } + + if ($opt{"IGNORE_UNUSED"} == 1) { + return; + } + + my %not_used; + + # check if there are any stragglers (typos?) + foreach my $option (keys %opt) { + my $op = $option; + # remove per test labels. + $op =~ s/\[.*\]//; + if (!exists($option_map{$op}) && + !exists($default{$op}) && + !exists($used_options{$op})) { + $not_used{$op} = 1; + } + } + + if (%not_used) { + my $s = "s are"; + $s = " is" if (keys %not_used == 1); + print "The following option$s not used; could be a typo:\n"; + foreach my $option (keys %not_used) { + print "$option\n"; + } + print "Set IGRNORE_UNUSED = 1 to have ktest ignore unused variables\n"; + if (!read_yn "Do you want to continue?") { + exit -1; + } + } } sub __eval_option { @@ -873,6 +1108,17 @@ sub reboot { } } +sub reboot_to_good { + my ($time) = @_; + + if (defined($switch_to_good)) { + run_command $switch_to_good; + return; + } + + reboot $time; +} + sub do_not_reboot { my $i = $iteration; @@ -889,7 +1135,7 @@ sub dodie { if ($reboot_on_error && !do_not_reboot) { doprint "REBOOTING\n"; - reboot; + reboot_to_good; } elsif ($poweroff_on_error && defined($power_off)) { doprint "POWERING OFF\n"; @@ -975,6 +1221,43 @@ sub wait_for_monitor { print "** Monitor flushed **\n"; } +sub save_logs { + my ($result, $basedir) = @_; + my @t = localtime; + my $date = sprintf "%04d%02d%02d%02d%02d%02d", + 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0]; + + my $type = $build_type; + if ($type =~ /useconfig/) { + $type = "useconfig"; + } + + my $dir = "$machine-$test_type-$type-$result-$date"; + + $dir = "$basedir/$dir"; + + if (!-d $dir) { + mkpath($dir) or + die "can't create $dir"; + } + + my %files = ( + "config" => $output_config, + "buildlog" => $buildlog, + "dmesg" => $dmesg, + "testlog" => $testlog, + ); + + while (my ($name, $source) = each(%files)) { + if (-f "$source") { + cp "$source", "$dir/$name" or + die "failed to copy $source"; + } + } + + doprint "*** Saved info to $dir ***\n"; +} + sub fail { if ($die_on_failure) { @@ -988,7 +1271,7 @@ sub fail { # no need to reboot for just building. if (!do_not_reboot) { doprint "REBOOTING\n"; - reboot $sleep_time; + reboot_to_good $sleep_time; } my $name = ""; @@ -1003,38 +1286,9 @@ sub fail { doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; - return 1 if (!defined($store_failures)); - - my @t = localtime; - my $date = sprintf "%04d%02d%02d%02d%02d%02d", - 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0]; - - my $type = $build_type; - if ($type =~ /useconfig/) { - $type = "useconfig"; - } - - my $dir = "$machine-$test_type-$type-fail-$date"; - my $faildir = "$store_failures/$dir"; - - if (!-d $faildir) { - mkpath($faildir) or - die "can't create $faildir"; - } - if (-f "$output_config") { - cp "$output_config", "$faildir/config" or - die "failed to copy .config"; - } - if (-f $buildlog) { - cp $buildlog, "$faildir/buildlog" or - die "failed to move $buildlog"; - } - if (-f $dmesg) { - cp $dmesg, "$faildir/dmesg" or - die "failed to move $dmesg"; - } - - doprint "*** Saved info to $faildir ***\n"; + if (defined($store_failures)) { + save_logs "fail", $store_failures; + } return 1; } @@ -1170,13 +1424,16 @@ sub wait_for_input } sub reboot_to { + if (defined($switch_to_test)) { + run_command $switch_to_test; + } + if ($reboot_type eq "grub") { run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'"; - reboot; - return; + } elsif (defined $reboot_script) { + run_command "$reboot_script"; } - - run_command "$reboot_script"; + reboot; } sub get_sha1 { @@ -1274,7 +1531,7 @@ sub monitor { } if ($full_line =~ /call trace:/i) { - if (!$bug && !$skip_call_trace) { + if (!$ignore_errors && !$bug && !$skip_call_trace) { $bug = 1; $failure_start = time; } @@ -1341,12 +1598,19 @@ sub monitor { return 1; } +sub eval_kernel_version { + my ($option) = @_; + + $option =~ s/\$KERNEL_VERSION/$version/g; + + return $option; +} + sub do_post_install { return if (!defined($post_install)); - my $cp_post_install = $post_install; - $cp_post_install =~ s/\$KERNEL_VERSION/$version/g; + my $cp_post_install = eval_kernel_version $post_install; run_command "$cp_post_install" or dodie "Failed to run post install"; } @@ -1355,7 +1619,9 @@ sub install { return if ($no_install); - run_scp "$outputdir/$build_target", "$target_image" or + my $cp_target = eval_kernel_version $target_image; + + run_scp "$outputdir/$build_target", "$cp_target" or dodie "failed to copy image"; my $install_mods = 0; @@ -1640,9 +1906,13 @@ sub success { doprint "*******************************************\n"; doprint "*******************************************\n"; + if (defined($store_successes)) { + save_logs "success", $store_successes; + } + if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { doprint "Reboot and wait $sleep_time seconds\n"; - reboot $sleep_time; + reboot_to_good $sleep_time; } } @@ -1669,7 +1939,10 @@ sub child_run_test { $poweroff_on_error = 0; $die_on_failure = 1; + $redirect = "$testlog"; run_command $run_test or $failed = 1; + undef $redirect; + exit $failed; } @@ -1744,6 +2017,43 @@ sub do_run_test { waitpid $child_pid, 0; $child_exit = $?; + if (!$bug && $in_bisect) { + if (defined($bisect_ret_good)) { + if ($child_exit == $bisect_ret_good) { + return 1; + } + } + if (defined($bisect_ret_skip)) { + if ($child_exit == $bisect_ret_skip) { + return -1; + } + } + if (defined($bisect_ret_abort)) { + if ($child_exit == $bisect_ret_abort) { + fail "test abort" and return -2; + } + } + if (defined($bisect_ret_bad)) { + if ($child_exit == $bisect_ret_skip) { + return 0; + } + } + if (defined($bisect_ret_default)) { + if ($bisect_ret_default eq "good") { + return 1; + } elsif ($bisect_ret_default eq "bad") { + return 0; + } elsif ($bisect_ret_default eq "skip") { + return -1; + } elsif ($bisect_ret_default eq "abort") { + return -2; + } else { + fail "unknown default action: $bisect_ret_default" + and return -2; + } + } + } + if ($bug || $child_exit) { return 0 if $in_bisect; fail "test failed" and return 0; @@ -1770,7 +2080,7 @@ sub run_git_bisect { if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) { doprint "$1 [$2]\n"; } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) { - $bisect_bad = $1; + $bisect_bad_commit = $1; doprint "Found bad commit... $1\n"; return 0; } else { @@ -1783,7 +2093,7 @@ sub run_git_bisect { sub bisect_reboot { doprint "Reboot and sleep $bisect_sleep_time seconds\n"; - reboot $bisect_sleep_time; + reboot_to_good $bisect_sleep_time; } # returns 1 on success, 0 on failure, -1 on skip @@ -1868,21 +2178,28 @@ sub run_bisect { } } +sub update_bisect_replay { + my $tmp_log = "$tmpdir/ktest_bisect_log"; + run_command "git bisect log > $tmp_log" or + die "can't create bisect log"; + return $tmp_log; +} + sub bisect { my ($i) = @_; my $result; - die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"})); - die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"})); - die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"})); + die "BISECT_GOOD[$i] not defined\n" if (!defined($bisect_good)); + die "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad)); + die "BISECT_TYPE[$i] not defined\n" if (!defined($bisect_type)); - my $good = $opt{"BISECT_GOOD[$i]"}; - my $bad = $opt{"BISECT_BAD[$i]"}; - my $type = $opt{"BISECT_TYPE[$i]"}; - my $start = $opt{"BISECT_START[$i]"}; - my $replay = $opt{"BISECT_REPLAY[$i]"}; - my $start_files = $opt{"BISECT_FILES[$i]"}; + my $good = $bisect_good; + my $bad = $bisect_bad; + my $type = $bisect_type; + my $start = $bisect_start; + my $replay = $bisect_replay; + my $start_files = $bisect_files; if (defined($start_files)) { $start_files = " -- " . $start_files; @@ -1894,8 +2211,7 @@ sub bisect { $good = get_sha1($good); $bad = get_sha1($bad); - if (defined($opt{"BISECT_REVERSE[$i]"}) && - $opt{"BISECT_REVERSE[$i]"} == 1) { + if (defined($bisect_reverse) && $bisect_reverse == 1) { doprint "Performing a reverse bisect (bad is good, good is bad!)\n"; $reverse_bisect = 1; } else { @@ -1907,8 +2223,31 @@ sub bisect { $type = "boot"; } - my $check = $opt{"BISECT_CHECK[$i]"}; - if (defined($check) && $check ne "0") { + # Check if a bisect was running + my $bisect_start_file = "$builddir/.git/BISECT_START"; + + my $check = $bisect_check; + my $do_check = defined($check) && $check ne "0"; + + if ( -f $bisect_start_file ) { + print "Bisect in progress found\n"; + if ($do_check) { + print " If you say yes, then no checks of good or bad will be done\n"; + } + if (defined($replay)) { + print "** BISECT_REPLAY is defined in config file **"; + print " Ignore config option and perform new git bisect log?\n"; + if (read_ync " (yes, no, or cancel) ") { + $replay = update_bisect_replay; + $do_check = 0; + } + } elsif (read_yn "read git log and continue?") { + $replay = update_bisect_replay; + $do_check = 0; + } + } + + if ($do_check) { # get current HEAD my $head = get_sha1("HEAD"); @@ -1973,7 +2312,7 @@ sub bisect { run_command "git bisect reset" or dodie "could not reset git bisect"; - doprint "Bad commit was [$bisect_bad]\n"; + doprint "Bad commit was [$bisect_bad_commit]\n"; success $i; } @@ -2129,7 +2468,7 @@ sub run_config_bisect { } doprint "***** RUN TEST ***\n"; - my $type = $opt{"CONFIG_BISECT_TYPE[$iteration]"}; + my $type = $config_bisect_type; my $ret; my %current_config; @@ -2233,7 +2572,7 @@ sub run_config_bisect { sub config_bisect { my ($i) = @_; - my $start_config = $opt{"CONFIG_BISECT[$i]"}; + my $start_config = $config_bisect; my $tmpconfig = "$tmpdir/use_config"; @@ -2346,29 +2685,29 @@ sub config_bisect { sub patchcheck_reboot { doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; - reboot $patchcheck_sleep_time; + reboot_to_good $patchcheck_sleep_time; } sub patchcheck { my ($i) = @_; die "PATCHCHECK_START[$i] not defined\n" - if (!defined($opt{"PATCHCHECK_START[$i]"})); + if (!defined($patchcheck_start)); die "PATCHCHECK_TYPE[$i] not defined\n" - if (!defined($opt{"PATCHCHECK_TYPE[$i]"})); + if (!defined($patchcheck_type)); - my $start = $opt{"PATCHCHECK_START[$i]"}; + my $start = $patchcheck_start; my $end = "HEAD"; - if (defined($opt{"PATCHCHECK_END[$i]"})) { - $end = $opt{"PATCHCHECK_END[$i]"}; + if (defined($patchcheck_end)) { + $end = $patchcheck_end; } # Get the true sha1's since we can use things like HEAD~3 $start = get_sha1($start); $end = get_sha1($end); - my $type = $opt{"PATCHCHECK_TYPE[$i]"}; + my $type = $patchcheck_type; # Can't have a test without having a test to run if ($type eq "test" && !defined($run_test)) { @@ -2963,7 +3302,7 @@ sub make_min_config { } doprint "Reboot and wait $sleep_time seconds\n"; - reboot $sleep_time; + reboot_to_good $sleep_time; } success $i; @@ -2985,13 +3324,27 @@ if ($#ARGV == 0) { } if (! -f $ktest_config) { + $newconfig = 1; + get_test_case; open(OUT, ">$ktest_config") or die "Can not create $ktest_config"; print OUT << "EOF" # Generated by ktest.pl # + +# PWD is a ktest.pl variable that will result in the process working +# directory that ktest.pl is executed in. + +# THIS_DIR is automatically assigned the PWD of the path that generated +# the config file. It is best to use this variable when assigning other +# directory paths within this directory. This allows you to easily +# move the test cases to other locations or to other machines. +# +THIS_DIR := $variable{"PWD"} + # Define each test with TEST_START # The config options below it will override the defaults TEST_START +TEST_TYPE = $default{"TEST_TYPE"} DEFAULTS EOF @@ -3011,7 +3364,7 @@ if ($#new_configs >= 0) { open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config"; foreach my $config (@new_configs) { print OUT "$config = $entered_configs{$config}\n"; - $opt{$config} = $entered_configs{$config}; + $opt{$config} = process_variables($entered_configs{$config}); } } @@ -3091,61 +3444,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { my $makecmd = set_test_option("MAKE_CMD", $i); - $machine = set_test_option("MACHINE", $i); - $ssh_user = set_test_option("SSH_USER", $i); - $tmpdir = set_test_option("TMP_DIR", $i); - $outputdir = set_test_option("OUTPUT_DIR", $i); - $builddir = set_test_option("BUILD_DIR", $i); - $test_type = set_test_option("TEST_TYPE", $i); - $build_type = set_test_option("BUILD_TYPE", $i); - $build_options = set_test_option("BUILD_OPTIONS", $i); - $pre_build = set_test_option("PRE_BUILD", $i); - $post_build = set_test_option("POST_BUILD", $i); - $pre_build_die = set_test_option("PRE_BUILD_DIE", $i); - $post_build_die = set_test_option("POST_BUILD_DIE", $i); - $power_cycle = set_test_option("POWER_CYCLE", $i); - $reboot = set_test_option("REBOOT", $i); - $noclean = set_test_option("BUILD_NOCLEAN", $i); - $minconfig = set_test_option("MIN_CONFIG", $i); - $output_minconfig = set_test_option("OUTPUT_MIN_CONFIG", $i); - $start_minconfig = set_test_option("START_MIN_CONFIG", $i); - $ignore_config = set_test_option("IGNORE_CONFIG", $i); - $run_test = set_test_option("TEST", $i); - $addconfig = set_test_option("ADD_CONFIG", $i); - $reboot_type = set_test_option("REBOOT_TYPE", $i); - $grub_menu = set_test_option("GRUB_MENU", $i); - $post_install = set_test_option("POST_INSTALL", $i); - $no_install = set_test_option("NO_INSTALL", $i); - $reboot_script = set_test_option("REBOOT_SCRIPT", $i); - $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i); - $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i); - $die_on_failure = set_test_option("DIE_ON_FAILURE", $i); - $power_off = set_test_option("POWER_OFF", $i); - $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i); - $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i); - $sleep_time = set_test_option("SLEEP_TIME", $i); - $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i); - $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i); - $ignore_warnings = set_test_option("IGNORE_WARNINGS", $i); - $bisect_manual = set_test_option("BISECT_MANUAL", $i); - $bisect_skip = set_test_option("BISECT_SKIP", $i); - $config_bisect_good = set_test_option("CONFIG_BISECT_GOOD", $i); - $store_failures = set_test_option("STORE_FAILURES", $i); - $test_name = set_test_option("TEST_NAME", $i); - $timeout = set_test_option("TIMEOUT", $i); - $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i); - $console = set_test_option("CONSOLE", $i); - $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i); - $success_line = set_test_option("SUCCESS_LINE", $i); - $reboot_success_line = set_test_option("REBOOT_SUCCESS_LINE", $i); - $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); - $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); - $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); - $build_target = set_test_option("BUILD_TARGET", $i); - $ssh_exec = set_test_option("SSH_EXEC", $i); - $scp_to_target = set_test_option("SCP_TO_TARGET", $i); - $target_image = set_test_option("TARGET_IMAGE", $i); - $localversion = set_test_option("LOCALVERSION", $i); + # Load all the options into their mapped variable names + foreach my $opt (keys %option_map) { + ${$option_map{$opt}} = set_test_option($opt, $i); + } $start_minconfig_defined = 1; @@ -3166,26 +3468,26 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $ENV{"SSH_USER"} = $ssh_user; $ENV{"MACHINE"} = $machine; - $target = "$ssh_user\@$machine"; - $buildlog = "$tmpdir/buildlog-$machine"; + $testlog = "$tmpdir/testlog-$machine"; $dmesg = "$tmpdir/dmesg-$machine"; $make = "$makecmd O=$outputdir"; $output_config = "$outputdir/.config"; - if ($reboot_type eq "grub") { - dodie "GRUB_MENU not defined" if (!defined($grub_menu)); - } elsif (!defined($reboot_script)) { - dodie "REBOOT_SCRIPT not defined" + if (!$buildonly) { + $target = "$ssh_user\@$machine"; + if ($reboot_type eq "grub") { + dodie "GRUB_MENU not defined" if (!defined($grub_menu)); + } } my $run_type = $build_type; if ($test_type eq "patchcheck") { - $run_type = $opt{"PATCHCHECK_TYPE[$i]"}; + $run_type = $patchcheck_type; } elsif ($test_type eq "bisect") { - $run_type = $opt{"BISECT_TYPE[$i]"}; + $run_type = $bisect_type; } elsif ($test_type eq "config_bisect") { - $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"}; + $run_type = $config_bisect_type; } if ($test_type eq "make_min_config") { @@ -3205,6 +3507,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { unlink $dmesg; unlink $buildlog; + unlink $testlog; if (defined($addconfig)) { my $min = $minconfig; @@ -3216,7 +3519,6 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $minconfig = "$tmpdir/add_config"; } - my $checkout = $opt{"CHECKOUT[$i]"}; if (defined($checkout)) { run_command "git checkout $checkout" or die "failed to checkout $checkout"; @@ -3267,7 +3569,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { if ($opt{"POWEROFF_ON_SUCCESS"}) { halt; } elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) { - reboot; + reboot_to_good; } doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n"; diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 553c06b7d6f2..5ea04c6a71bf 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -346,7 +346,10 @@ #GRUB_MENU = Test Kernel # A script to reboot the target into the test kernel -# (Only mandatory if REBOOT_TYPE = script) +# This and SWITCH_TO_TEST are about the same, except +# SWITCH_TO_TEST is run even for REBOOT_TYPE = grub. +# This may be left undefined. +# (default undefined) #REBOOT_SCRIPT = #### Optional Config Options (all have defaults) #### @@ -468,6 +471,27 @@ # The test will not modify that file. #REBOOT_TYPE = grub +# If you are using a machine that doesn't boot with grub, and +# perhaps gets its kernel from a remote server (tftp), then +# you can use this option to update the target image with the +# test image. +# +# You could also do the same with POST_INSTALL, but the difference +# between that option and this option is that POST_INSTALL runs +# after the install, where this one runs just before a reboot. +# (default undefined) +#SWITCH_TO_TEST = cp ${OUTPUT_DIR}/${BUILD_TARGET} ${TARGET_IMAGE} + +# If you are using a machine that doesn't boot with grub, and +# perhaps gets its kernel from a remote server (tftp), then +# you can use this option to update the target image with the +# the known good image to reboot safely back into. +# +# This option holds a command that will execute before needing +# to reboot to a good known image. +# (default undefined) +#SWITCH_TO_GOOD = ssh ${SSH_USER}/${MACHINE} cp good_image ${TARGET_IMAGE} + # The min config that is needed to build for the machine # A nice way to create this is with the following: # @@ -589,6 +613,12 @@ # (default undefined) #STORE_FAILURES = /home/test/failures +# Directory to store success directories on success. If this is not +# set, the .config, dmesg and bootlog will not be saved if a +# test succeeds. +# (default undefined) +#STORE_SUCCESSES = /home/test/successes + # Build without doing a make mrproper, or removing .config # (default 0) #BUILD_NOCLEAN = 0 @@ -700,6 +730,25 @@ # (default 1) #DETECT_TRIPLE_FAULT = 0 +# All options in the config file should be either used by ktest +# or could be used within a value of another option. If an option +# in the config file is not used, ktest will warn about it and ask +# if you want to continue. +# +# If you don't care if there are non-used options, enable this +# option. Be careful though, a non-used option is usually a sign +# of an option name being typed incorrectly. +# (default 0) +#IGNORE_UNUSED = 1 + +# When testing a kernel that happens to have WARNINGs, and call +# traces, ktest.pl will detect these and fail a boot or test run +# due to warnings. By setting this option, ktest will ignore +# call traces, and will not fail a test if the kernel produces +# an oops. Use this option with care. +# (default 0) +#IGNORE_ERRORS = 1 + #### Per test run options #### # The following options are only allowed in TEST_START sections. # They are ignored in the DEFAULTS sections. @@ -862,6 +911,42 @@ # BISECT_BAD with BISECT_CHECK = good or # BISECT_CHECK = bad, respectively. # +# BISECT_RET_GOOD = 0 (optional, default undefined) +# +# In case the specificed test returns something other than just +# 0 for good, and non-zero for bad, you can override 0 being +# good by defining BISECT_RET_GOOD. +# +# BISECT_RET_BAD = 1 (optional, default undefined) +# +# In case the specificed test returns something other than just +# 0 for good, and non-zero for bad, you can override non-zero being +# bad by defining BISECT_RET_BAD. +# +# BISECT_RET_ABORT = 255 (optional, default undefined) +# +# If you need to abort the bisect if the test discovers something +# that was wrong, you can define BISECT_RET_ABORT to be the error +# code returned by the test in order to abort the bisect. +# +# BISECT_RET_SKIP = 2 (optional, default undefined) +# +# If the test detects that the current commit is neither good +# nor bad, but something else happened (another bug detected) +# you can specify BISECT_RET_SKIP to an error code that the +# test returns when it should skip the current commit. +# +# BISECT_RET_DEFAULT = good (optional, default undefined) +# +# You can override the default of what to do when the above +# options are not hit. This may be one of, "good", "bad", +# "abort" or "skip" (without the quotes). +# +# Note, if you do not define any of the previous BISECT_RET_* +# and define BISECT_RET_DEFAULT, all bisects results will do +# what the BISECT_RET_DEFAULT has. +# +# # Example: # TEST_START # TEST_TYPE = bisect diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index 0fb448e6a1a3..a457d2138f49 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -32,7 +32,7 @@ #include <linux/iommu.h> #include <linux/intel-iommu.h> -static int allow_unsafe_assigned_interrupts; +static bool allow_unsafe_assigned_interrupts; module_param_named(allow_unsafe_assigned_interrupts, allow_unsafe_assigned_interrupts, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(allow_unsafe_assigned_interrupts, |